Author: silverblade Date: Mon Jul 7 17:59:45 2008 New Revision: 34360
URL: http://svn.reactos.org/svn/reactos?rev=34360&view=rev Log: Wave buffers are now split up into chunks before being fed to the sound driver. Testing by writing 65,536 bytes using an un-even block size of 16,383. Results in 4 x 16,383 byte blocks and 1 x 4 byte block, as expected. Completion of one buffer results in submission of the next. Doesn't handle multiple WAVEHDRs yet.
Modified: branches/silverblade-audio/include/reactos/libs/sound/mmebuddy.h branches/silverblade-audio/lib/drivers/sound/mmebuddy/thread.c branches/silverblade-audio/lib/drivers/sound/mmebuddy/wave/wavethread.c
Modified: branches/silverblade-audio/include/reactos/libs/sound/mmebuddy.h URL: http://svn.reactos.org/svn/reactos/branches/silverblade-audio/include/reacto... ============================================================================== --- branches/silverblade-audio/include/reactos/libs/sound/mmebuddy.h [iso-8859-1] (original) +++ branches/silverblade-audio/include/reactos/libs/sound/mmebuddy.h [iso-8859-1] Mon Jul 7 17:59:45 2008 @@ -169,7 +169,8 @@ PWAVEHDR FirstBuffer; PWAVEHDR LastBuffer;
- /*DWORD RemainingBytes;*/ + /* How much data is waiting with the driver */ + DWORD RemainingBytes; } WAVE_THREAD_DATA, *PWAVE_THREAD_DATA;
/*
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/thread.c URL: http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/so... ============================================================================== --- branches/silverblade-audio/lib/drivers/sound/mmebuddy/thread.c [iso-8859-1] (original) +++ branches/silverblade-audio/lib/drivers/sound/mmebuddy/thread.c [iso-8859-1] Mon Jul 7 17:59:45 2008 @@ -12,6 +12,11 @@ 4 July 2008 - Created 5 July 2008 - Implemented basic request processing 6 July 2008 - Added I/O completion handling + + Possible improvements: + Spawn *one* thread to deal with requests and I/O completion, rather + than have a thread per sound device instance. This wouldn't be too + hard to do but not worth doing right now. */
/*
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/wave/wavethread.c URL: http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/so... ============================================================================== --- branches/silverblade-audio/lib/drivers/sound/mmebuddy/wave/wavethread.c [iso-8859-1] (original) +++ branches/silverblade-audio/lib/drivers/sound/mmebuddy/wave/wavethread.c [iso-8859-1] Mon Jul 7 17:59:45 2008 @@ -23,23 +23,97 @@
/* - Just a neat wrapper around the writing routine. -*/ - -MMRESULT -WriteWaveBufferToSoundDevice( + How much we can feed to the driver at a time. + This is deliberately set low at the moment for testing purposes, and + intentionally set to be "one out" from 16384 so that writing 65536 bytes + results in 4x16383 byte buffers followed by 1x4 byte buffer. + + Should it be configurable? Some sound drivers let you set buffer size... +*/ +#define MAX_SOUND_BUFFER_SIZE 16383 + + +/* + Audio buffer I/O streaming handler. Slices 'n dices your buffers and + serves them up on a platter with a side dressing of your choice. + + It's safe to update the buffer information post-submission within this + routine since any completion will be done in an APC for the same thread, + so we're not likely to be rudely interrupted by a completion routine + bursting through the door. +*/ +MMRESULT +StreamWaveData( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance, - IN PWAVE_THREAD_DATA ThreadData, - IN PWAVEHDR WaveHeader) -{ - SOUND_ASSERT(SoundDeviceInstance); - SOUND_ASSERT(ThreadData); - SOUND_ASSERT(WaveHeader); - - return OverlappedWriteToSoundDevice(SoundDeviceInstance, - (PVOID) WaveHeader, - WaveHeader->lpData, - WaveHeader->dwBufferLength); + IN PWAVE_THREAD_DATA ThreadData) +{ + PWAVEHDR Buffer = ThreadData->CurrentBuffer; + DWORD BufferOffset, BytesToStream, BytesAvailable; + MMRESULT Result; + + SOUND_ASSERT(ThreadData->RemainingBytes <= MAX_SOUND_BUFFER_SIZE); + SOUND_ASSERT(Buffer); + + /* The 'reserved' member of Buffer contains the offset */ + BufferOffset = Buffer->reserved; + + /* Work out how much data can be streamed with the driver */ + BytesAvailable = MAX_SOUND_BUFFER_SIZE - ThreadData->RemainingBytes; + + /* + If no space available, don't do anything. The routine will be revisited + as buffers complete, at which point the backlog will start being + dealt with. + */ + if ( BytesAvailable == 0 ) + return MMSYSERR_NOERROR; + + /* + Adjust the amount of data to be streamed based on how much of the + current buffer has actually been dealt with already. + */ + BytesToStream = Buffer->dwBufferLength - BufferOffset; + + /* + No point in doing work unless we have to... This is, however, a + completed buffer, so it should be dealt with!! + */ + if ( BytesToStream == 0 ) + { + /* TODO */ + return MMSYSERR_NOERROR; + } + + /* + Now we know how much buffer is waiting to be provided to the driver, + we need to consider how much the driver can accept. + */ + if ( BytesToStream > BytesAvailable ) + { + /* Buffer can't fit entirely - fill the available space */ + BytesToStream = BytesAvailable; + } + + /* + Now the audio buffer sets sail on its merry way to the sound driver... + NOTE: Will need to implement a 'read' function, too. + */ + Result = OverlappedWriteToSoundDevice(SoundDeviceInstance, + (PVOID) ThreadData, + Buffer->lpData + BufferOffset, + BytesToStream); + + if ( Result != MMSYSERR_NOERROR ) + return Result; + + /* Update the offset ready for the next streaming operation */ + BufferOffset += BytesToStream; + Buffer->reserved = BufferOffset; + + /* More data has been sent to the driver, so this is updated, too */ + ThreadData->RemainingBytes += BytesToStream; + + return MMSYSERR_NOERROR; }
@@ -53,12 +127,15 @@ IN PWAVE_THREAD_DATA ThreadData, IN PWAVEHDR Buffer) { +/* DWORD BytesSubmitted = 0;*/ + SOUND_ASSERT(Instance != NULL); SOUND_ASSERT(Buffer != NULL); SOUND_ASSERT(Instance->Thread != NULL);
- /* Store the device instance */ - Buffer->reserved = (DWORD) Instance; + /* This is used to mark the offset within the buffer */ + Buffer->reserved = 0; + /* TODO: Clear completion flag */
/* Set the head of the buffer list if this is the first buffer */ if ( ! ThreadData->FirstBuffer ) @@ -78,18 +155,13 @@ /* Increment the number of buffers queued */ ++ ThreadData->BufferCount;
- /* HACK */ - ThreadData->CurrentBuffer = ThreadData->FirstBuffer; - - WriteWaveBufferToSoundDevice(Instance, ThreadData, Buffer); - -/* - Result = WriteSoundDeviceBuffer(Instance, - ThreadData->CurrentBuffer->lpData, - ThreadData->CurrentBuffer->dwBufferLength, - WaveBufferCompleted, - (LPOVERLAPPED) &Thread->Wave.Overlapped); -*/ + /* If nothing is playing, we'll need to start things off */ + if ( ThreadData->RemainingBytes == 0 ) + { + ThreadData->CurrentBuffer = ThreadData->FirstBuffer; + StreamWaveData(Instance, ThreadData); + } + return MMSYSERR_NOERROR; }
@@ -141,10 +213,12 @@ IN PVOID ContextData, IN DWORD BytesTransferred) { - LPWAVEHDR WaveHeader = (LPWAVEHDR) ContextData; - - SOUND_DEBUG(L"ProcessWaveIoCompletion called :)"); - SOUND_DEBUG_HEX(WaveHeader); + PWAVE_THREAD_DATA ThreadData = (PWAVE_THREAD_DATA) ContextData; + SOUND_ASSERT(ThreadData); + WCHAR msg[1024]; + + /*SOUND_DEBUG(L"ProcessWaveIoCompletion called :)");*/ + /*SOUND_DEBUG_HEX(WaveHeader);*/
/* At this point we know: @@ -164,6 +238,21 @@ thread will wait for more requests from the client before it does anything else. */ + + /* Discount the amount of buffer which has been processed */ + SOUND_ASSERT(BytesTransferred <= ThreadData->RemainingBytes); + ThreadData->RemainingBytes -= BytesTransferred; + + wsprintf(msg, L"Wave header: %x\nOffset: %d\nTransferred: %d bytes\nRemaining: %d bytes", + ThreadData->CurrentBuffer, + ThreadData->CurrentBuffer->reserved, + BytesTransferred, + ThreadData->RemainingBytes); + + MessageBox(0, msg, L"I/O COMPLETE", MB_OK | MB_TASKMODAL); + + /* TODO: Check return value */ + StreamWaveData(Instance, ThreadData); }