Author: silverblade Date: Thu Jul 10 18:32:48 2008 New Revision: 34416
URL: http://svn.reactos.org/svn/reactos?rev=34416&view=rev Log: Replaced threaded wave stream playback code again, to overcome stuttering playback issue caused by limiting playback to a single buffer at a time. This was causing playback to only go smoothly when the buffer got split up (ie, it became double-buffered). Need to fix a bug occuring when buffers are exhausted still.
Modified: branches/silverblade-audio/dll/win32/sndblst/sndblst.c branches/silverblade-audio/include/reactos/libs/sound/mmebuddy.h branches/silverblade-audio/lib/drivers/sound/mmebuddy/wave/wavethread.c
Modified: branches/silverblade-audio/dll/win32/sndblst/sndblst.c URL: http://svn.reactos.org/svn/reactos/branches/silverblade-audio/dll/win32/sndb... ============================================================================== --- branches/silverblade-audio/dll/win32/sndblst/sndblst.c [iso-8859-1] (original) +++ branches/silverblade-audio/dll/win32/sndblst/sndblst.c [iso-8859-1] Thu Jul 10 18:32:48 2008 @@ -165,7 +165,7 @@ /* WODM_OPEN */ Format.wFormatTag = WAVE_FORMAT_PCM; Format.nChannels = 2; - Format.nSamplesPerSec = 22050; + Format.nSamplesPerSec = 44100; Format.wBitsPerSample = 16; Format.nBlockAlign = Format.nChannels * (Format.wBitsPerSample / 8); Format.nAvgBytesPerSec = Format.nSamplesPerSec * Format.nBlockAlign;
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] Thu Jul 10 18:32:48 2008 @@ -75,6 +75,13 @@ CopyMemory(dest, source, StringLengthToBytes(WCHAR, wcslen(source)))
+#define MinimumOf(value_a, value_b) \ + ( value_a < value_b ? value_a : value_b ) + +#define MaximumOf(value_a, value_b) \ + ( value_a > value_b ? value_a : value_b ) + + struct _SOUND_DEVICE; struct _SOUND_DEVICE_INSTANCE;
@@ -136,79 +143,6 @@ PSOUND_THREAD_COMPLETED_IO CompletionData; } SOUND_THREAD_OVERLAPPED, *PSOUND_THREAD_OVERLAPPED;
-#if 0 -/* - Used internally to shuttle data to/from the sound processing thread. -*/ -typedef struct _THREAD_REQUEST -{ - struct _SOUND_DEVICE_INSTANCE* DeviceInstance; - DWORD RequestId; - PVOID Data; - MMRESULT Result; -} THREAD_REQUEST, *PTHREAD_REQUEST; - -typedef struct _SOUND_THREAD_COMPLETED_IO -{ - struct _SOUND_THREAD_COMPLETED_IO* Next; - PVOID ContextData; /* eg: PWAVEHDR */ - DWORD BytesTransferred; -} SOUND_THREAD_COMPLETED_IO, *PSOUND_THREAD_COMPLETED_IO; - -typedef struct _SOUND_THREAD_OVERLAPPED -{ - OVERLAPPED General; - struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance; - PVOID PrivateThreadData; - PVOID ContextData; /* eg: PWAVEHDR */ - PSOUND_THREAD_COMPLETED_IO CompletionData; -} SOUND_THREAD_OVERLAPPED, *PSOUND_THREAD_OVERLAPPED; - - -typedef VOID (*SOUND_THREAD_IO_COMPLETION_HANDLER)( - IN struct _SOUND_DEVICE_INSTANCE* Instance, - IN PVOID PrivateThreadData, - IN PVOID ContextData, - IN DWORD BytesTransferred); - -typedef struct _SOUND_THREAD -{ - /* Thread management */ - HANDLE Handle; - PVOID PrivateData; - BOOLEAN Running; - - HANDLE ReadyEvent; /* Thread waiting for a request */ - HANDLE RequestEvent; /* Caller sending a request */ - HANDLE DoneEvent; /* Thread completed a request */ - - SOUND_THREAD_REQUEST_HANDLER RequestHandler; - THREAD_REQUEST Request; - - SOUND_THREAD_OVERLAPPED Overlapped; - PSOUND_THREAD_COMPLETED_IO FirstCompletedIo; - SOUND_THREAD_IO_COMPLETION_HANDLER IoCompletionHandler; -} SOUND_THREAD, *PSOUND_THREAD; -#endif - - -/* - Wave thread -*/ -#if 0 -typedef struct _WAVE_THREAD_DATA -{ - /* Wave thread specific */ - DWORD BufferCount; - PWAVEHDR CurrentBuffer; - PWAVEHDR FirstBuffer; - PWAVEHDR LastBuffer; - - /* How much data is waiting with the driver */ - DWORD RemainingBytes; -} WAVE_THREAD_DATA, *PWAVE_THREAD_DATA; -#endif - /* Audio device function table */ @@ -276,9 +210,9 @@ /* The buffer currently being processed */ PWAVEHDR CurrentBuffer; /* How far into the current buffer we've gone */ - DWORD BufferOffset; - /* How much data we're expecting back */ - DWORD BytesOutstanding; + //DWORD BufferOffset; + /* How many I/O operations have been submitted */ + DWORD BuffersOutstanding; } WAVE_STREAM_INFO, *PWAVE_STREAM_INFO;
typedef struct _SOUND_DEVICE_INSTANCE
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] Thu Jul 10 18:32:48 2008 @@ -23,16 +23,15 @@
/* - 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... + How much we can feed to the driver at a time. For example, 2 buffers + of 65536 would mean we can send 65536 bytes in a single I/O operation, + and a total of 2 buffers (not necessarily full). + + If a single WAVEHDR is larger than MAX_SOUND_BUFFER_SIZE then a second + buffer will be used. */ #define MAX_SOUND_BUFFER_SIZE 65536 - - +#define MAX_SOUND_BUFFERS 2
VOID CompleteWaveBuffer( @@ -40,122 +39,95 @@ IN PVOID Parameter, IN DWORD BytesWritten);
+BOOLEAN +StreamReadyForData( + IN PWAVE_STREAM_INFO StreamInfo) +{ + SOUND_ASSERT(StreamInfo); + + return (StreamInfo->BuffersOutstanding < MAX_SOUND_BUFFERS); +} + +BOOLEAN +StreamHasBuffersQueued( + IN PWAVE_STREAM_INFO StreamInfo) +{ + SOUND_ASSERT(StreamInfo); + + return (StreamInfo->CurrentBuffer != NULL); +} + +DWORD +PerformWaveIo( + IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) +{ + PWAVE_STREAM_INFO StreamInfo; + DWORD BytesToStream, BytesStreamed = 0; + + SOUND_ASSERT(SoundDeviceInstance); + + StreamInfo = &SoundDeviceInstance->Streaming.Wave; + SOUND_ASSERT(StreamInfo->CurrentBuffer); + + /* Work out how much buffer can be submitted */ + BytesToStream = MinimumOf(StreamInfo->CurrentBuffer->dwBufferLength - + StreamInfo->CurrentBuffer->reserved, + MAX_SOUND_BUFFER_SIZE); + + SOUND_TRACE("Writing %p + %d (%d bytes) - buffer length is %d bytes\n", + StreamInfo->CurrentBuffer->lpData, + (int) StreamInfo->CurrentBuffer->reserved, + (int) BytesToStream, + (int) StreamInfo->CurrentBuffer->dwBufferLength); + + /* TODO: Error checking */ + OverlappedSoundDeviceIo(SoundDeviceInstance, + (PCHAR) StreamInfo->CurrentBuffer->lpData + + StreamInfo->CurrentBuffer->reserved, + BytesToStream, + CompleteWaveBuffer, + (PVOID) StreamInfo->CurrentBuffer); + + /* FIXME? - find out how much was actually sent? */ + BytesStreamed = BytesToStream; + + /* Advance the offset */ + StreamInfo->CurrentBuffer->reserved += BytesStreamed; + + /* If we've hit the end of the buffer, move to the next one */ + if ( StreamInfo->CurrentBuffer->reserved == + StreamInfo->CurrentBuffer->dwBufferLength ) + { + SOUND_TRACE("Advancing to next buffer\n"); + StreamInfo->CurrentBuffer = StreamInfo->CurrentBuffer->lpNext; + } + + /* Increase the number of outstanding buffers */ + ++ StreamInfo->BuffersOutstanding; + + return BytesStreamed; +}
MMRESULT -StreamWaveIo( +StreamWaveBuffers( IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance) { PWAVE_STREAM_INFO StreamInfo; - DWORD BytesAvailable, BytesToStream; + SOUND_ASSERT(SoundDeviceInstance); + + StreamInfo = &SoundDeviceInstance->Streaming.Wave;
SOUND_TRACE("<== Streaming wave I/O ==>\n"); - - SOUND_ASSERT(SoundDeviceInstance); - - /* Get the streaming info */ - StreamInfo = &SoundDeviceInstance->Streaming.Wave; - - BytesAvailable = MAX_SOUND_BUFFER_SIZE - StreamInfo->BytesOutstanding; - - if ( ! BytesAvailable ) - { - SOUND_TRACE("NO BUFFER SPACE AVAILABLE\n"); - } - - if ( ! StreamInfo->CurrentBuffer ) - { - SOUND_TRACE("NO CURRENT BUFFER\n"); - } - - while ( StreamInfo->CurrentBuffer && BytesAvailable ) - { - /* - Determine how much of the current buffer remains to be - streamed. - */ - BytesToStream = StreamInfo->CurrentBuffer->dwBufferLength - - StreamInfo->BufferOffset; - - SOUND_TRACE("Buffer %p, offset %d, length %d\nAvailable %d | BytesToStream %d | BytesOutstanding %d\n", - StreamInfo->CurrentBuffer, - (int) StreamInfo->BufferOffset, - (int) StreamInfo->CurrentBuffer->dwBufferLength, - (int) BytesAvailable, - (int) BytesToStream, - (int) StreamInfo->BytesOutstanding); - - - /* - We may receive a buffer with no bytes left to stream, for - example as a result of an I/O completion triggering this - routine, or if on a previous iteration of this loop we managed - to finish sending a buffer. - */ - if ( BytesToStream == 0 ) - { - SOUND_TRACE("No bytes to stream\n"); - StreamInfo->CurrentBuffer = StreamInfo->CurrentBuffer->lpNext; - StreamInfo->BufferOffset = 0; - continue; - } - - /* - If the buffer can't be sent in its entirety to the sound driver, - send a portion of it to fill the available space. - */ - if ( BytesToStream > BytesAvailable ) - { - BytesToStream = BytesAvailable; - } - - SOUND_TRACE("Writing %d bytes from buffer %p, offset %d\n", - (int) BytesToStream, - StreamInfo->CurrentBuffer->lpData, - (int)StreamInfo->BufferOffset); - - /* TODO: Do the streaming */ - OverlappedSoundDeviceIo(SoundDeviceInstance, - (PCHAR) StreamInfo->CurrentBuffer->lpData + - StreamInfo->BufferOffset, - BytesToStream, - CompleteWaveBuffer, - (PVOID) StreamInfo->CurrentBuffer); - - /* - Keep track of the amount of data currently in the hands of the - sound driver, so we know how much space is being used up so - far, and how many bytes will be announced to the completion - routines. - */ - StreamInfo->BytesOutstanding += BytesToStream; - - /* - Update the offset within the buffer to reflect the amount of - data being transferred in this transaction. - */ - StreamInfo->BufferOffset += BytesToStream; - - /* - Update the number of bytes available for the next iteration. - */ - BytesAvailable = MAX_SOUND_BUFFER_SIZE - StreamInfo->BytesOutstanding; - - } - - SOUND_TRACE("<== Done filling stream ==>\n"); - -#if 0 - /* TODO: Check result */ - OverlappedSoundDeviceIo(SoundDeviceInstance, - WaveHeader->lpData, - WaveHeader->dwBufferLength, - CompleteWaveBuffer, - (PVOID) WaveHeader); -#endif + while ( StreamReadyForData(StreamInfo) && + StreamHasBuffersQueued(StreamInfo) ) + { + SOUND_TRACE("Performing wave I/O ...\n"); + PerformWaveIo(SoundDeviceInstance); + } + SOUND_TRACE("<== Done streaming ==>\n");
return MMSYSERR_NOERROR; } -
VOID CompleteWaveBuffer( @@ -163,13 +135,22 @@ IN PVOID Parameter, IN DWORD BytesWritten) { - SOUND_TRACE("CompleteWaveBuffer called - wrote %d bytes\n", (int)BytesWritten); - - SoundDeviceInstance->Streaming.Wave.BytesOutstanding -= BytesWritten; - - StreamWaveIo(SoundDeviceInstance); -} - + PWAVE_STREAM_INFO StreamInfo; + + SOUND_TRACE("Wave completion routine\n"); + + SOUND_ASSERT(SoundDeviceInstance); + + StreamInfo = &SoundDeviceInstance->Streaming.Wave; + + /* Decrease the number of outstanding buffers */ + SOUND_ASSERT(StreamInfo->BuffersOutstanding > 0); + -- StreamInfo->BuffersOutstanding; + + PerformWaveIo(SoundDeviceInstance); + + SOUND_TRACE("Wave completion routine done\n"); +}
MMRESULT QueueBuffer_Request( @@ -208,11 +189,12 @@ StreamInfo->CurrentBuffer = WaveHeader;
/* Initialise the stream state */ - StreamInfo->BufferOffset = 0; - StreamInfo->BytesOutstanding = 0; + //StreamInfo->BufferOffset = 0; + //StreamInfo->BytesOutstanding = 0; + StreamInfo->BuffersOutstanding = 0;
/* Get the streaming started */ - StreamWaveIo(SoundDeviceInstance); + StreamWaveBuffers(SoundDeviceInstance); } else {