ReactOS Fundraising Campaign 2012
 
€ 4,060 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

streaming.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/streaming.c
00005  *
00006  * PURPOSE:     Wave streaming
00007  *
00008  * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
00009 */
00010 
00011 #include "precomp.h"
00012 
00013 
00014 /*
00015     DoWaveStreaming
00016         Check if there is streaming to be done, and if so, do it.
00017 */
00018 
00019 VOID
00020 DoWaveStreaming(
00021     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
00022 {
00023     MMRESULT Result;
00024     MMDEVICE_TYPE DeviceType;
00025     PSOUND_DEVICE SoundDevice;
00026     PMMFUNCTION_TABLE FunctionTable;
00027     PWAVEHDR Header;
00028     PWAVEHDR_EXTENSION HeaderExtension;
00029 
00030     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
00031     SND_ASSERT( MMSUCCESS(Result) );
00032 
00033     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
00034     SND_ASSERT( MMSUCCESS(Result) );
00035 
00036     Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
00037     SND_ASSERT( MMSUCCESS(Result) );
00038     SND_ASSERT( FunctionTable );
00039     SND_ASSERT( FunctionTable->CommitWaveBuffer );
00040 
00041     /* No point in doing anything if no resources available to use */
00042     if ( SoundDeviceInstance->OutstandingBuffers >= SoundDeviceInstance->BufferCount )
00043     {
00044         SND_TRACE(L"DoWaveStreaming: No available buffers to stream with - doing nothing\n");
00045         return;
00046     }
00047 
00048     /* Is there any work to do? */
00049     Header = SoundDeviceInstance->HeadWaveHeader;
00050 
00051     if ( ! Header )
00052     {
00053         SND_TRACE(L"DoWaveStreaming: No work to do - doing nothing\n");
00054         return;
00055     }
00056 
00057     while ( ( SoundDeviceInstance->OutstandingBuffers < SoundDeviceInstance->BufferCount ) &&
00058             ( Header ) && SoundDeviceInstance->ResetInProgress == FALSE)
00059     {
00060         HeaderExtension = (PWAVEHDR_EXTENSION) Header->reserved;
00061         SND_ASSERT( HeaderExtension );
00062 
00063         /* Saniy checks */
00064         SND_ASSERT(Header->dwFlags & WHDR_PREPARED);
00065         SND_ASSERT(Header->dwFlags & WHDR_INQUEUE);
00066 
00067         /* Can never be *above* the length */
00068         SND_ASSERT( HeaderExtension->BytesCommitted <= Header->dwBufferLength );
00069 
00070         /* Is this header entirely committed? */
00071         if ( HeaderExtension->BytesCommitted == Header->dwBufferLength )
00072         {
00073             {
00074                 /* Move on to the next header */
00075                 SND_ASSERT(Header != Header->lpNext);
00076                 Header = Header->lpNext;
00077             }
00078         }
00079         else
00080         {
00081             PSOUND_OVERLAPPED Overlap;
00082             LPVOID OffsetPtr;
00083             DWORD BytesRemaining, BytesToCommit;
00084             BOOL OK;
00085 
00086             /* Where within the header buffer to stream from */
00087             OffsetPtr = Header->lpData + HeaderExtension->BytesCommitted;
00088 
00089             /* How much of this header has not been committed */
00090             BytesRemaining = Header->dwBufferLength - HeaderExtension->BytesCommitted;
00091 
00092             /* We can commit anything up to the buffer size limit */
00093             BytesToCommit = BytesRemaining > SoundDeviceInstance->FrameSize ?
00094                             SoundDeviceInstance->FrameSize :
00095                             BytesRemaining;
00096 
00097             /* Should always have something to commit by this point */
00098             SND_ASSERT( BytesToCommit > 0 );
00099 
00100             /* We need a new overlapped info structure for each buffer */
00101             Overlap = AllocateStruct(SOUND_OVERLAPPED);
00102 
00103             if ( Overlap )
00104             {
00105                 ZeroMemory(Overlap, sizeof(SOUND_OVERLAPPED));
00106                 Overlap->SoundDeviceInstance = SoundDeviceInstance;
00107                 Overlap->Header = Header;
00108 
00109                 /* Don't complete this header if it's part of a loop */
00110                 Overlap->PerformCompletion = TRUE;
00111 //                    ( SoundDeviceInstance->LoopsRemaining > 0 );
00112 
00113                 /* Adjust the commit-related counters */
00114                 HeaderExtension->BytesCommitted += BytesToCommit;
00115                 ++ SoundDeviceInstance->OutstandingBuffers;
00116 
00117                 OK = MMSUCCESS(FunctionTable->CommitWaveBuffer(SoundDeviceInstance,
00118                                                                OffsetPtr,
00119                                                                BytesToCommit,
00120                                                                Overlap,
00121                                                                CompleteIO));
00122 
00123                 if ( ! OK )
00124                 {
00125                     /* Clean-up and try again on the next iteration (is this OK?) */
00126                     SND_WARN(L"FAILED\n");
00127 
00128                     FreeMemory(Overlap);
00129                     HeaderExtension->BytesCommitted -= BytesToCommit;
00130                     -- SoundDeviceInstance->OutstandingBuffers;
00131                 }
00132             }
00133         }
00134     }
00135 }
00136 
00137 
00138 /*
00139     CompleteIO
00140         An APC called as a result of a call to CommitWaveHeaderToKernelDevice.
00141         This will count up the number of bytes which have been dealt with,
00142         and when the entire wave header has been dealt with, will call
00143         CompleteWaveHeader to have the wave header returned to the client.
00144 
00145     CommitWaveHeaderToKernelDevice
00146         Sends portions of the buffer described by the wave header to a kernel
00147         device. This must only be called from within the context of the sound
00148         thread. The caller supplies either their own commit routine, or uses
00149         WriteFileEx_Committer. The committer is called with portions of the
00150         buffer specified in the wave header.
00151 
00152     WriteFileEx_Committer
00153         Commit buffers using the WriteFileEx API.
00154 */
00155 
00156 VOID CALLBACK
00157 CompleteIO(
00158     IN  DWORD dwErrorCode,
00159     IN  DWORD dwNumberOfBytesTransferred,
00160     IN  LPOVERLAPPED lpOverlapped)
00161 {
00162     MMDEVICE_TYPE DeviceType;
00163     PSOUND_DEVICE SoundDevice;
00164     PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
00165     PSOUND_OVERLAPPED SoundOverlapped = (PSOUND_OVERLAPPED) lpOverlapped;
00166     PWAVEHDR WaveHdr;
00167     PWAVEHDR_EXTENSION HdrExtension;
00168     MMRESULT Result;
00169     DWORD Bytes;
00170 
00171     WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
00172     SND_ASSERT( WaveHdr );
00173 
00174     HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
00175     SND_ASSERT( HdrExtension );
00176 
00177     SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
00178 
00179     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
00180     SND_ASSERT( MMSUCCESS(Result) );
00181 
00182     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
00183     SND_ASSERT( MMSUCCESS(Result) );
00184 
00185     do
00186     {
00187 
00188         /* We have an available buffer now */
00189         -- SoundDeviceInstance->OutstandingBuffers;
00190 
00191         /* Did we finish a WAVEHDR and aren't looping? */
00192         if ( HdrExtension->BytesCompleted + dwNumberOfBytesTransferred >= WaveHdr->dwBufferLength &&
00193             SoundOverlapped->PerformCompletion )
00194         {
00195             /* Wave buffer fully completed */
00196             Bytes = WaveHdr->dwBufferLength - HdrExtension->BytesCompleted;
00197 
00198             HdrExtension->BytesCompleted += Bytes;
00199             dwNumberOfBytesTransferred -= Bytes;
00200 
00201             CompleteWaveHeader(SoundDeviceInstance, WaveHdr);
00202             SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
00203         }
00204         else
00205         {
00206             /* Partially completed */
00207             HdrExtension->BytesCompleted += dwNumberOfBytesTransferred;
00208             SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
00209             break;
00210         }
00211 
00212         /* Move to next wave header */
00213         WaveHdr = WaveHdr->lpNext;
00214 
00215         if (!WaveHdr)
00216         {
00217             /* No following WaveHdr */
00218             SND_ASSERT(dwNumberOfBytesTransferred == 0);
00219             break;
00220         }
00221 
00222         HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
00223         SND_ASSERT( HdrExtension );
00224 
00225 
00226     }while(dwNumberOfBytesTransferred);
00227 
00228     // AUDIO-BRANCH DIFF
00229     // completion callback is performed in a thread
00230     DoWaveStreaming(SoundDeviceInstance);
00231 
00232     //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
00233 
00234     FreeMemory(lpOverlapped);
00235 }
00236 
00237 MMRESULT
00238 WriteFileEx_Committer(
00239     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
00240     IN  PVOID OffsetPtr,
00241     IN  DWORD Length,
00242     IN  PSOUND_OVERLAPPED Overlap,
00243     IN  LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
00244 {
00245     HANDLE Handle;
00246 
00247     VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
00248     VALIDATE_MMSYS_PARAMETER( OffsetPtr );
00249     VALIDATE_MMSYS_PARAMETER( Overlap );
00250     VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
00251 
00252     GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
00253 
00254     if ( ! WriteFileEx(Handle, OffsetPtr, Length, (LPOVERLAPPED)Overlap, CompletionRoutine) )
00255     {
00256         // TODO
00257     }
00258 
00259     return MMSYSERR_NOERROR;
00260 }
00261 
00262 
00263 /*
00264     Stream control functions
00265     (External/internal thread pairs)
00266 
00267     TODO - Move elsewhere as these shouldn't be wave specific!
00268 */
00269 
00270 MMRESULT
00271 StopStreamingInSoundThread(
00272     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
00273     IN  PVOID Parameter)
00274 {
00275     MMDEVICE_TYPE DeviceType;
00276     PMMFUNCTION_TABLE FunctionTable;
00277     MMRESULT Result;
00278     PSOUND_DEVICE SoundDevice;
00279 
00280     /* set state reset in progress */
00281     SoundDeviceInstance->ResetInProgress = TRUE;
00282 
00283     /* Get sound device */
00284     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
00285     SND_ASSERT( Result == MMSYSERR_NOERROR );
00286 
00287     /* Obtain the function table */
00288     Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
00289     SND_ASSERT( Result == MMSYSERR_NOERROR );
00290 
00291     /* Obtain device instance type */
00292     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
00293     SND_ASSERT( Result == MMSYSERR_NOERROR );
00294 
00295     /* Check if reset function is supported */
00296     if (FunctionTable->ResetStream)
00297     {
00298          /* cancel all current audio buffers */
00299          FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, TRUE);
00300     }
00301     while(SoundDeviceInstance->OutstandingBuffers)
00302     {
00303         SND_TRACE(L"StopStreamingInSoundThread OutStandingBufferCount %lu\n", SoundDeviceInstance->OutstandingBuffers);
00304         /* wait until pending i/o has completed */
00305         SleepEx(10, TRUE);
00306     }
00307 
00308     /* complete all current headers */
00309     while( SoundDeviceInstance->HeadWaveHeader )
00310     {
00311         SND_TRACE(L"StopStreamingInSoundThread: Completing Header %p\n", SoundDeviceInstance->HeadWaveHeader);
00312         CompleteWaveHeader( SoundDeviceInstance, SoundDeviceInstance->HeadWaveHeader );
00313     }
00314 
00315     /* there should be no oustanding buffers now */
00316     SND_ASSERT(SoundDeviceInstance->OutstandingBuffers == 0);
00317 
00318 
00319     /* Check if reset function is supported */
00320     if (FunctionTable->ResetStream)
00321     {
00322         /* finish the reset */
00323         FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, FALSE);
00324     }
00325 
00326     /* clear state reset in progress */
00327     SoundDeviceInstance->ResetInProgress = FALSE;
00328 
00329 
00330     return MMSYSERR_NOERROR;
00331 }
00332 
00333 MMRESULT
00334 StopStreaming(
00335     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
00336 {
00337     MMRESULT Result;
00338     PSOUND_DEVICE SoundDevice;
00339     MMDEVICE_TYPE DeviceType;
00340 
00341     if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
00342         return MMSYSERR_INVALHANDLE;
00343 
00344     Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
00345     if ( ! MMSUCCESS(Result) )
00346         return TranslateInternalMmResult(Result);
00347 
00348     Result = GetSoundDeviceType(SoundDevice, &DeviceType);
00349     if ( ! MMSUCCESS(Result) )
00350         return TranslateInternalMmResult(Result);
00351 
00352     if ( DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceType != WAVE_IN_DEVICE_TYPE )
00353         return MMSYSERR_NOTSUPPORTED;
00354 
00355     return CallSoundThread(SoundDeviceInstance,
00356                            StopStreamingInSoundThread,
00357                            NULL);
00358 }
00359 
00360 MMRESULT
00361 PerformWaveStreaming(
00362     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
00363     IN  PVOID Parameter)
00364 {
00365     DoWaveStreaming(SoundDeviceInstance);
00366 
00367     return MMSYSERR_NOERROR;
00368 }
00369 
00370 DWORD
00371 WINAPI
00372 WaveActivateSoundStreaming(
00373     IN PVOID lpParameter)
00374 {
00375     CallSoundThread((PSOUND_DEVICE_INSTANCE)lpParameter,
00376                     PerformWaveStreaming,
00377                     NULL);
00378 
00379     ExitThread(0);
00380 }
00381 
00382 VOID
00383 InitiateSoundStreaming(
00384     IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
00385 {
00386     HANDLE hThread;
00387 
00388     hThread = CreateThread(NULL, 0, WaveActivateSoundStreaming, (PVOID)SoundDeviceInstance, 0, NULL);
00389 
00390     if (hThread != NULL)
00391         CloseHandle(hThread);
00392 }

Generated on Tue May 22 2012 04:40:25 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.