+++ /dev/null
-/*
- * PROJECT: ReactOS Sound System "MME Buddy" Library
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: lib/drivers/sound/mmebuddy/wave/streaming.c
- *
- * PURPOSE: Wave streaming
- *
- * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
-*/
-
-#include "precomp.h"
-
-
-/*
- DoWaveStreaming
- Check if there is streaming to be done, and if so, do it.
-*/
-
-VOID
-DoWaveStreaming(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
-{
- MMRESULT Result;
- MMDEVICE_TYPE DeviceType;
- PSOUND_DEVICE SoundDevice;
- PMMFUNCTION_TABLE FunctionTable;
- PWAVEHDR Header;
- PWAVEHDR_EXTENSION HeaderExtension;
-
- Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
- SND_ASSERT( MMSUCCESS(Result) );
-
- Result = GetSoundDeviceType(SoundDevice, &DeviceType);
- SND_ASSERT( MMSUCCESS(Result) );
-
- Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
- SND_ASSERT( MMSUCCESS(Result) );
- SND_ASSERT( FunctionTable );
- SND_ASSERT( FunctionTable->CommitWaveBuffer );
-
- /* No point in doing anything if no resources available to use */
- if ( SoundDeviceInstance->OutstandingBuffers >= SoundDeviceInstance->BufferCount )
- {
- SND_TRACE(L"DoWaveStreaming: No available buffers to stream with - doing nothing\n");
- return;
- }
-
- /* Is there any work to do? */
- Header = SoundDeviceInstance->HeadWaveHeader;
-
- if ( ! Header )
- {
- SND_TRACE(L"DoWaveStreaming: No work to do - doing nothing\n");
- return;
- }
-
- while ( ( SoundDeviceInstance->OutstandingBuffers < SoundDeviceInstance->BufferCount ) &&
- ( Header ) && SoundDeviceInstance->ResetInProgress == FALSE)
- {
- HeaderExtension = (PWAVEHDR_EXTENSION) Header->reserved;
- SND_ASSERT( HeaderExtension );
-
- /* Saniy checks */
- SND_ASSERT(Header->dwFlags & WHDR_PREPARED);
- SND_ASSERT(Header->dwFlags & WHDR_INQUEUE);
-
- /* Can never be *above* the length */
- SND_ASSERT( HeaderExtension->BytesCommitted <= Header->dwBufferLength );
-
- /* Is this header entirely committed? */
- if ( HeaderExtension->BytesCommitted == Header->dwBufferLength )
- {
- {
- /* Move on to the next header */
- SND_ASSERT(Header != Header->lpNext);
- Header = Header->lpNext;
- }
- }
- else
- {
- PSOUND_OVERLAPPED Overlap;
- LPVOID OffsetPtr;
- DWORD BytesRemaining, BytesToCommit;
- BOOL OK;
-
- /* Where within the header buffer to stream from */
- OffsetPtr = Header->lpData + HeaderExtension->BytesCommitted;
-
- /* How much of this header has not been committed */
- BytesRemaining = Header->dwBufferLength - HeaderExtension->BytesCommitted;
-
- /* We can commit anything up to the buffer size limit */
- BytesToCommit = BytesRemaining > SoundDeviceInstance->FrameSize ?
- SoundDeviceInstance->FrameSize :
- BytesRemaining;
-
- /* Should always have something to commit by this point */
- SND_ASSERT( BytesToCommit > 0 );
-
- /* We need a new overlapped info structure for each buffer */
- Overlap = AllocateStruct(SOUND_OVERLAPPED);
-
- if ( Overlap )
- {
- ZeroMemory(Overlap, sizeof(SOUND_OVERLAPPED));
- Overlap->SoundDeviceInstance = SoundDeviceInstance;
- Overlap->Header = Header;
-
- /* Don't complete this header if it's part of a loop */
- Overlap->PerformCompletion = TRUE;
-// ( SoundDeviceInstance->LoopsRemaining > 0 );
-
- /* Adjust the commit-related counters */
- HeaderExtension->BytesCommitted += BytesToCommit;
- ++ SoundDeviceInstance->OutstandingBuffers;
-
- OK = MMSUCCESS(FunctionTable->CommitWaveBuffer(SoundDeviceInstance,
- OffsetPtr,
- BytesToCommit,
- Overlap,
- CompleteIO));
-
- if ( ! OK )
- {
- /* Clean-up and try again on the next iteration (is this OK?) */
- SND_WARN(L"FAILED\n");
-
- FreeMemory(Overlap);
- HeaderExtension->BytesCommitted -= BytesToCommit;
- -- SoundDeviceInstance->OutstandingBuffers;
- }
- }
- }
- }
-}
-
-
-/*
- CompleteIO
- An APC called as a result of a call to CommitWaveHeaderToKernelDevice.
- This will count up the number of bytes which have been dealt with,
- and when the entire wave header has been dealt with, will call
- CompleteWaveHeader to have the wave header returned to the client.
-
- CommitWaveHeaderToKernelDevice
- Sends portions of the buffer described by the wave header to a kernel
- device. This must only be called from within the context of the sound
- thread. The caller supplies either their own commit routine, or uses
- WriteFileEx_Committer. The committer is called with portions of the
- buffer specified in the wave header.
-
- WriteFileEx_Committer
- Commit buffers using the WriteFileEx API.
-*/
-
-VOID CALLBACK
-CompleteIO(
- IN DWORD dwErrorCode,
- IN DWORD dwNumberOfBytesTransferred,
- IN LPOVERLAPPED lpOverlapped)
-{
- MMDEVICE_TYPE DeviceType;
- PSOUND_DEVICE SoundDevice;
- PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
- PSOUND_OVERLAPPED SoundOverlapped = (PSOUND_OVERLAPPED) lpOverlapped;
- PWAVEHDR WaveHdr;
- PWAVEHDR_EXTENSION HdrExtension;
- MMRESULT Result;
- DWORD Bytes;
-
- WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
- SND_ASSERT( WaveHdr );
-
- HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
- SND_ASSERT( HdrExtension );
-
- SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
-
- Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
- SND_ASSERT( MMSUCCESS(Result) );
-
- Result = GetSoundDeviceType(SoundDevice, &DeviceType);
- SND_ASSERT( MMSUCCESS(Result) );
-
- do
- {
-
- /* We have an available buffer now */
- -- SoundDeviceInstance->OutstandingBuffers;
-
- /* Did we finish a WAVEHDR and aren't looping? */
- if ( HdrExtension->BytesCompleted + dwNumberOfBytesTransferred >= WaveHdr->dwBufferLength &&
- SoundOverlapped->PerformCompletion )
- {
- /* Wave buffer fully completed */
- Bytes = WaveHdr->dwBufferLength - HdrExtension->BytesCompleted;
-
- HdrExtension->BytesCompleted += Bytes;
- dwNumberOfBytesTransferred -= Bytes;
-
- CompleteWaveHeader(SoundDeviceInstance, WaveHdr);
- SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
- }
- else
- {
- /* Partially completed */
- HdrExtension->BytesCompleted += dwNumberOfBytesTransferred;
- SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
- break;
- }
-
- /* Move to next wave header */
- WaveHdr = WaveHdr->lpNext;
-
- if (!WaveHdr)
- {
- /* No following WaveHdr */
- SND_ASSERT(dwNumberOfBytesTransferred == 0);
- break;
- }
-
- HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
- SND_ASSERT( HdrExtension );
-
-
- }while(dwNumberOfBytesTransferred);
-
- // AUDIO-BRANCH DIFF
- // completion callback is performed in a thread
- DoWaveStreaming(SoundDeviceInstance);
-
- //CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
-
- FreeMemory(lpOverlapped);
-}
-
-MMRESULT
-WriteFileEx_Committer(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- IN PVOID OffsetPtr,
- IN DWORD Length,
- IN PSOUND_OVERLAPPED Overlap,
- IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
-{
- HANDLE Handle;
-
- VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
- VALIDATE_MMSYS_PARAMETER( OffsetPtr );
- VALIDATE_MMSYS_PARAMETER( Overlap );
- VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
-
- GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
-
- if ( ! WriteFileEx(Handle, OffsetPtr, Length, (LPOVERLAPPED)Overlap, CompletionRoutine) )
- {
- // TODO
- }
-
- return MMSYSERR_NOERROR;
-}
-
-
-/*
- Stream control functions
- (External/internal thread pairs)
-
- TODO - Move elsewhere as these shouldn't be wave specific!
-*/
-
-MMRESULT
-StopStreamingInSoundThread(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- IN PVOID Parameter)
-{
- MMDEVICE_TYPE DeviceType;
- PMMFUNCTION_TABLE FunctionTable;
- MMRESULT Result;
- PSOUND_DEVICE SoundDevice;
-
- /* set state reset in progress */
- SoundDeviceInstance->ResetInProgress = TRUE;
-
- /* Get sound device */
- Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
- SND_ASSERT( Result == MMSYSERR_NOERROR );
-
- /* Obtain the function table */
- Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
- SND_ASSERT( Result == MMSYSERR_NOERROR );
-
- /* Obtain device instance type */
- Result = GetSoundDeviceType(SoundDevice, &DeviceType);
- SND_ASSERT( Result == MMSYSERR_NOERROR );
-
- /* Check if reset function is supported */
- if (FunctionTable->ResetStream)
- {
- /* cancel all current audio buffers */
- FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, TRUE);
- }
- while(SoundDeviceInstance->OutstandingBuffers)
- {
- SND_TRACE(L"StopStreamingInSoundThread OutStandingBufferCount %lu\n", SoundDeviceInstance->OutstandingBuffers);
- /* wait until pending i/o has completed */
- SleepEx(10, TRUE);
- }
-
- /* complete all current headers */
- while( SoundDeviceInstance->HeadWaveHeader )
- {
- SND_TRACE(L"StopStreamingInSoundThread: Completing Header %p\n", SoundDeviceInstance->HeadWaveHeader);
- CompleteWaveHeader( SoundDeviceInstance, SoundDeviceInstance->HeadWaveHeader );
- }
-
- /* there should be no oustanding buffers now */
- SND_ASSERT(SoundDeviceInstance->OutstandingBuffers == 0);
-
-
- /* Check if reset function is supported */
- if (FunctionTable->ResetStream)
- {
- /* finish the reset */
- FunctionTable->ResetStream(SoundDeviceInstance, DeviceType, FALSE);
- }
-
- /* clear state reset in progress */
- SoundDeviceInstance->ResetInProgress = FALSE;
-
-
- return MMSYSERR_NOERROR;
-}
-
-MMRESULT
-StopStreaming(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
-{
- MMRESULT Result;
- PSOUND_DEVICE SoundDevice;
- MMDEVICE_TYPE DeviceType;
-
- if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
- return MMSYSERR_INVALHANDLE;
-
- Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
- if ( ! MMSUCCESS(Result) )
- return TranslateInternalMmResult(Result);
-
- Result = GetSoundDeviceType(SoundDevice, &DeviceType);
- if ( ! MMSUCCESS(Result) )
- return TranslateInternalMmResult(Result);
-
- if ( DeviceType != WAVE_OUT_DEVICE_TYPE && DeviceType != WAVE_IN_DEVICE_TYPE )
- return MMSYSERR_NOTSUPPORTED;
-
- return CallSoundThread(SoundDeviceInstance,
- StopStreamingInSoundThread,
- NULL);
-}
-
-MMRESULT
-PerformWaveStreaming(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- IN PVOID Parameter)
-{
- DoWaveStreaming(SoundDeviceInstance);
-
- return MMSYSERR_NOERROR;
-}
-
-DWORD
-WINAPI
-WaveActivateSoundStreaming(
- IN PVOID lpParameter)
-{
- CallSoundThread((PSOUND_DEVICE_INSTANCE)lpParameter,
- PerformWaveStreaming,
- NULL);
-
- ExitThread(0);
-}
-
-VOID
-InitiateSoundStreaming(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
-{
- HANDLE hThread;
-
- hThread = CreateThread(NULL, 0, WaveActivateSoundStreaming, (PVOID)SoundDeviceInstance, 0, NULL);
-
- if (hThread != NULL)
- CloseHandle(hThread);
-}