Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenheader.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Sound System "MME Buddy" Library 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: lib/drivers/sound/mmebuddy/wave/header.c 00005 * 00006 * PURPOSE: Wave header preparation and submission routines 00007 * 00008 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org) 00009 */ 00010 00011 #include "precomp.h" 00012 00013 00014 /* 00015 This structure gets used locally within functions as a way to shuttle data 00016 to the sound thread. It's safe to use locally since CallSoundThread will 00017 not return until the operation has been carried out. 00018 */ 00019 00020 typedef struct 00021 { 00022 MMWAVEHEADER_FUNC Function; 00023 PWAVEHDR Header; 00024 } THREADED_WAVEHEADER_PARAMETERS; 00025 00026 00027 /* 00028 Helper routines to simplify the call to the sound thread for the header 00029 functions. 00030 */ 00031 00032 MMRESULT 00033 WaveHeaderOperationInSoundThread( 00034 PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 00035 IN PVOID Parameter) 00036 { 00037 THREADED_WAVEHEADER_PARAMETERS* Parameters = (THREADED_WAVEHEADER_PARAMETERS*) Parameter; 00038 return Parameters->Function(SoundDeviceInstance, Parameters->Header); 00039 } 00040 00041 MMRESULT 00042 WaveHeaderOperation( 00043 MMWAVEHEADER_FUNC Function, 00044 PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 00045 PWAVEHDR Header) 00046 { 00047 THREADED_WAVEHEADER_PARAMETERS Parameters; 00048 00049 Parameters.Function = Function; 00050 Parameters.Header = Header; 00051 00052 return CallSoundThread(SoundDeviceInstance, 00053 WaveHeaderOperationInSoundThread, 00054 &Parameters); 00055 } 00056 00057 00058 /* 00059 SanitizeWaveHeader 00060 Clean up a header / reinitialize 00061 */ 00062 00063 VOID 00064 SanitizeWaveHeader( 00065 PWAVEHDR Header) 00066 { 00067 PWAVEHDR_EXTENSION Extension = (PWAVEHDR_EXTENSION) Header->reserved; 00068 SND_ASSERT( Extension ); 00069 00070 Header->dwBytesRecorded = 0; 00071 00072 Extension->BytesCommitted = 0; 00073 Extension->BytesCompleted = 0; 00074 } 00075 00076 00077 /* 00078 The following routines are basically handlers for: 00079 - WODM_PREPARE 00080 - WODM_UNPREPARE 00081 - WODM_WRITE 00082 00083 All of these calls are ultimately dealt with in the context of the 00084 appropriate sound thread, so the implementation should expect itself to 00085 be running in this other thread when any of these operations take place. 00086 */ 00087 00088 MMRESULT 00089 PrepareWaveHeader( 00090 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 00091 IN PWAVEHDR Header) 00092 { 00093 MMRESULT Result; 00094 PSOUND_DEVICE SoundDevice; 00095 PMMFUNCTION_TABLE FunctionTable; 00096 PWAVEHDR_EXTENSION Extension; 00097 00098 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 00099 VALIDATE_MMSYS_PARAMETER( Header ); 00100 00101 SND_TRACE(L"Preparing wave header\n"); 00102 00103 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 00104 if ( ! MMSUCCESS(Result) ) 00105 return TranslateInternalMmResult(Result); 00106 00107 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 00108 if ( ! MMSUCCESS(Result) ) 00109 return TranslateInternalMmResult(Result); 00110 00111 Extension = AllocateStruct(WAVEHDR_EXTENSION); 00112 if ( ! Extension ) 00113 return MMSYSERR_NOMEM; 00114 00115 Header->reserved = (DWORD_PTR) Extension; 00116 Extension->BytesCommitted = 0; 00117 Extension->BytesCompleted = 0; 00118 00119 /* Configure the flags */ 00120 Header->dwFlags |= WHDR_PREPARED; 00121 00122 return MMSYSERR_NOERROR; 00123 } 00124 00125 MMRESULT 00126 UnprepareWaveHeader( 00127 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 00128 IN PWAVEHDR Header) 00129 { 00130 MMRESULT Result; 00131 PSOUND_DEVICE SoundDevice; 00132 PMMFUNCTION_TABLE FunctionTable; 00133 PWAVEHDR_EXTENSION Extension; 00134 00135 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 00136 VALIDATE_MMSYS_PARAMETER( Header ); 00137 00138 SND_TRACE(L"Un-preparing wave header\n"); 00139 00140 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 00141 if ( ! MMSUCCESS(Result) ) 00142 return TranslateInternalMmResult(Result); 00143 00144 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 00145 if ( ! MMSUCCESS(Result) ) 00146 return TranslateInternalMmResult(Result); 00147 00148 SND_ASSERT( Header->reserved ); 00149 Extension = (PWAVEHDR_EXTENSION) Header->reserved; 00150 FreeMemory(Extension); 00151 00152 /* Configure the flags */ 00153 Header->dwFlags &= ~WHDR_PREPARED; 00154 00155 return MMSYSERR_NOERROR; 00156 } 00157 00158 MMRESULT 00159 WriteWaveHeader( 00160 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 00161 IN PWAVEHDR Header) 00162 { 00163 MMRESULT Result; 00164 PSOUND_DEVICE SoundDevice; 00165 PMMFUNCTION_TABLE FunctionTable; 00166 00167 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) ); 00168 VALIDATE_MMSYS_PARAMETER( Header ); 00169 00170 SND_TRACE(L"Submitting wave header\n"); 00171 00172 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 00173 if ( ! MMSUCCESS(Result) ) 00174 return TranslateInternalMmResult(Result); 00175 00176 Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable); 00177 if ( ! MMSUCCESS(Result) ) 00178 return TranslateInternalMmResult(Result); 00179 00180 if ( ! FunctionTable->CommitWaveBuffer ) 00181 return MMSYSERR_NOTSUPPORTED; 00182 00183 /* 00184 A few minor sanity checks - any custom checks should've been carried 00185 out during wave header preparation etc. 00186 */ 00187 VALIDATE_MMSYS_PARAMETER( Header->lpData != NULL ); 00188 VALIDATE_MMSYS_PARAMETER( Header->dwBufferLength > 0 ); 00189 VALIDATE_MMSYS_PARAMETER( Header->dwFlags & WHDR_PREPARED ); 00190 VALIDATE_MMSYS_PARAMETER( ! (Header->dwFlags & WHDR_INQUEUE) ); 00191 00192 SanitizeWaveHeader(Header); 00193 00194 /* Clear the "done" flag for the buffer */ 00195 Header->dwFlags &= ~WHDR_DONE; 00196 00197 Result = CallSoundThread(SoundDeviceInstance, 00198 EnqueueWaveHeader, 00199 Header); 00200 00201 return Result; 00202 } 00203 00204 00205 /* 00206 EnqueueWaveHeader 00207 Put the header in the record/playback queue. This is performed within 00208 the context of the sound thread, it must NEVER be called from another 00209 thread. 00210 00211 CompleteWaveHeader 00212 Set the header information to indicate that it has finished playing, 00213 and return it to the client application. This again must be called 00214 within the context of the sound thread. 00215 */ 00216 00217 MMRESULT 00218 EnqueueWaveHeader( 00219 PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 00220 IN PVOID Parameter) 00221 { 00222 PWAVEHDR WaveHeader = (PWAVEHDR) Parameter; 00223 00224 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance ); 00225 VALIDATE_MMSYS_PARAMETER( Parameter ); 00226 00227 /* Initialise */ 00228 WaveHeader->lpNext = NULL; 00229 00230 /* Set the "in queue" flag */ 00231 WaveHeader->dwFlags |= WHDR_INQUEUE; 00232 00233 if ( ! SoundDeviceInstance->HeadWaveHeader ) 00234 { 00235 /* This is the first header in the queue */ 00236 SND_TRACE(L"Enqueued first wave header\n"); 00237 SoundDeviceInstance->HeadWaveHeader = WaveHeader; 00238 SoundDeviceInstance->TailWaveHeader = WaveHeader; 00239 00240 /* Only do wave streaming when the stream has not been paused */ 00241 if (SoundDeviceInstance->bPaused == FALSE) 00242 { 00243 DoWaveStreaming(SoundDeviceInstance); 00244 } 00245 } 00246 else 00247 { 00248 /* There are already queued headers - make this one the tail */ 00249 SND_TRACE(L"Enqueued next wave header\n"); 00250 00251 /* FIXME - Make sure that the buffer has not already been added to the list */ 00252 if ( SoundDeviceInstance->TailWaveHeader != WaveHeader ) 00253 { 00254 SND_ASSERT(SoundDeviceInstance->TailWaveHeader != WaveHeader); 00255 00256 SoundDeviceInstance->TailWaveHeader->lpNext = WaveHeader; 00257 SoundDeviceInstance->TailWaveHeader = WaveHeader; 00258 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance); 00259 00260 /* Only do wave streaming when the stream has not been paused */ 00261 if ( SoundDeviceInstance->bPaused == FALSE ) 00262 { 00263 DoWaveStreaming(SoundDeviceInstance); 00264 } 00265 } 00266 } 00267 00268 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance); 00269 00270 return MMSYSERR_NOERROR; 00271 } 00272 00273 VOID 00274 CompleteWaveHeader( 00275 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, 00276 IN PWAVEHDR Header) 00277 { 00278 PWAVEHDR PrevHdr = NULL, CurrHdr = NULL; 00279 PWAVEHDR_EXTENSION Extension; 00280 PSOUND_DEVICE SoundDevice; 00281 MMDEVICE_TYPE DeviceType; 00282 MMRESULT Result; 00283 00284 SND_TRACE(L"BUFFER COMPLETE :)\n"); 00285 00286 // TODO: Set header flags? 00287 // TODO: Call client 00288 // TODO: Streaming 00289 00290 //DoWaveStreaming(SoundDeviceInstance); 00291 00292 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice); 00293 SND_ASSERT( MMSUCCESS(Result) ); 00294 Result = GetSoundDeviceType(SoundDevice, &DeviceType); 00295 SND_ASSERT( MMSUCCESS(Result) ); 00296 00297 Extension = (PWAVEHDR_EXTENSION)Header->reserved; 00298 SND_ASSERT( Extension ); 00299 00300 /* Remove the header from the queue, like so */ 00301 if ( SoundDeviceInstance->HeadWaveHeader == Header ) 00302 { 00303 SoundDeviceInstance->HeadWaveHeader = Header->lpNext; 00304 00305 SND_TRACE(L"Dropping head node\n"); 00306 00307 /* If nothing after the head, then there is no tail */ 00308 if ( Header->lpNext == NULL ) 00309 { 00310 SND_TRACE(L"Dropping tail node\n"); 00311 SoundDeviceInstance->TailWaveHeader = NULL; 00312 } 00313 } 00314 else 00315 { 00316 PrevHdr = NULL; 00317 CurrHdr = SoundDeviceInstance->HeadWaveHeader; 00318 00319 SND_TRACE(L"Relinking nodes\n"); 00320 00321 while ( CurrHdr != Header ) 00322 { 00323 PrevHdr = CurrHdr; 00324 CurrHdr = CurrHdr->lpNext; 00325 SND_ASSERT( CurrHdr ); 00326 } 00327 00328 SND_ASSERT( PrevHdr ); 00329 00330 PrevHdr->lpNext = CurrHdr->lpNext; 00331 00332 /* If this is the tail node, update the tail */ 00333 if ( Header->lpNext == NULL ) 00334 { 00335 SND_TRACE(L"Updating tail node\n"); 00336 SoundDeviceInstance->TailWaveHeader = PrevHdr; 00337 } 00338 } 00339 00340 /* Make sure we're not using this as the current buffer any more, either! */ 00341 /* 00342 if ( SoundDeviceInstance->CurrentWaveHeader == Header ) 00343 { 00344 SoundDeviceInstance->CurrentWaveHeader = Header->lpNext; 00345 } 00346 */ 00347 00348 DUMP_WAVEHDR_QUEUE(SoundDeviceInstance); 00349 00350 SND_TRACE(L"Returning buffer to client...\n"); 00351 00352 /* Update the header */ 00353 Header->dwFlags &= ~WHDR_INQUEUE; 00354 Header->dwFlags |= WHDR_DONE; 00355 00356 if ( DeviceType == WAVE_IN_DEVICE_TYPE ) 00357 { 00358 // FIXME: We won't be called on incomplete buffer! 00359 Header->dwBytesRecorded = Extension->BytesCompleted; 00360 } 00361 00362 /* Safe to do this without thread protection, as we're done with the header */ 00363 NotifyMmeClient(SoundDeviceInstance, 00364 DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_DONE : WIM_DATA, 00365 (DWORD_PTR)Header); 00366 } Generated on Sun May 27 2012 04:22:59 for ReactOS by
1.7.6.1
|