Author: silverblade
Date: Wed Jul 9 18:43:44 2008
New Revision: 34398
URL:
http://svn.reactos.org/svn/reactos?rev=34398&view=rev
Log:
Rewrote sound threading code. No point in having a single thread per audio
device when all it's doing is swapping buffers over. Also rewrote the wave
streaming code. It can now stream multiple WAVEHDRs and split them up as
needed. Playback not very smooth in places - need to double-buffer the
audio data.
Modified:
branches/silverblade-audio/dll/win32/mmdrv/testing.c
branches/silverblade-audio/dll/win32/sndblst/sndblst.c
branches/silverblade-audio/include/reactos/libs/sound/mmebuddy.h
branches/silverblade-audio/lib/drivers/sound/mmebuddy/devices.c
branches/silverblade-audio/lib/drivers/sound/mmebuddy/instances.c
branches/silverblade-audio/lib/drivers/sound/mmebuddy/kernel.c
branches/silverblade-audio/lib/drivers/sound/mmebuddy/mme/wodMessage.c
branches/silverblade-audio/lib/drivers/sound/mmebuddy/thread.c
branches/silverblade-audio/lib/drivers/sound/mmebuddy/wave/wavethread.c
Modified: branches/silverblade-audio/dll/win32/mmdrv/testing.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/dll/win32/mmd…
==============================================================================
--- branches/silverblade-audio/dll/win32/mmdrv/testing.c [iso-8859-1] (original)
+++ branches/silverblade-audio/dll/win32/mmdrv/testing.c [iso-8859-1] Wed Jul 9 18:43:44
2008
@@ -45,7 +45,7 @@
{
/* MessageBox(0, DevicePath, L"CALLBACK", MB_OK | MB_TASKMODAL);*/
- AddSoundDevice(DeviceType, DevicePath);
+ AddSoundDevice(DeviceType, DevicePath, NULL);
return TRUE;
}
@@ -106,7 +106,7 @@
PSOUND_DEVICE Device;
MMRESULT Result;
- AddSoundDevice(WAVE_OUT_DEVICE_TYPE, L"\\\\.\\SBWaveOut0");
+ AddSoundDevice(WAVE_OUT_DEVICE_TYPE, L"\\\\.\\SBWaveOut0", NULL);
Result = GetSoundDevice(WAVE_OUT_DEVICE_TYPE, 0, &Device);
if ( Result != MMSYSERR_NOERROR )
@@ -136,7 +136,7 @@
MMRESULT Result;
WAVEFORMATEX fmt;
- AddSoundDevice(WAVE_OUT_DEVICE_TYPE, L"\\\\.\\SBWaveOut0");
+ AddSoundDevice(WAVE_OUT_DEVICE_TYPE, L"\\\\.\\SBWaveOut0", NULL);
Result = GetSoundDevice(WAVE_OUT_DEVICE_TYPE, 0, &Device);
if ( Result != MMSYSERR_NOERROR )
@@ -179,86 +179,6 @@
}
-VOID
-TestPlaybackHackingly()
-{
- WCHAR msg[1024];
- MMRESULT Result;
- WAVEFORMATEX fmt;
- ULONG i;
-
- for ( i = 0; i < 65536; ++ i )
- JunkBuffer[i] = rand();
-
- AddSoundDevice(WAVE_OUT_DEVICE_TYPE, L"\\\\.\\SBWaveOut0");
- Result = GetSoundDevice(WAVE_OUT_DEVICE_TYPE, 0, &Device);
-
- if ( Result != MMSYSERR_NOERROR )
- {
- MessageBox(0, L"Fail 1", L"Fail", MB_OK | MB_TASKMODAL);
- return;
- }
-
-/* Result = OpenKernelSoundDevice(Device, GENERIC_READ | GENERIC_WRITE);
- if ( Result != MMSYSERR_NOERROR )
- {
- MessageBox(0, L"Fail open", L"Fail", MB_OK | MB_TASKMODAL);
- return;
- }
- wsprintf(msg, L"Opened handle %x", Device->Handle);
- MessageBox(0, msg, L"Result", MB_OK | MB_TASKMODAL);
-*/
-
- Result = CreateSoundDeviceInstance(Device, &Instance);
- if ( Result != MMSYSERR_NOERROR )
- {
- MessageBox(0, L"Fail 2", L"Fail 2", MB_OK | MB_TASKMODAL);
- return;
- }
-
- /* Request a valid format */
- fmt.wFormatTag = WAVE_FORMAT_PCM;
- fmt.nChannels = 1;
- fmt.nSamplesPerSec = 22050;
- fmt.wBitsPerSample = 16;
- fmt.nBlockAlign = fmt.nChannels * (fmt.wBitsPerSample / 8);
- fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
- fmt.cbSize = 0;
-
- Result = SetWaveDeviceFormat(Instance, &fmt, sizeof(WAVEFORMATEX));
-
- wsprintf(msg, L"Format support set result: %d\nClick to play!", Result);
- MessageBox(0, msg, L"Result", MB_OK | MB_TASKMODAL);
-
- //SOUND_DEBUG_HEX(Instance->Device->Handle);
-
- Result = StartWaveThread(Instance);
- if ( Result != MMSYSERR_NOERROR )
- {
- MessageBox(0, L"Failed to start thread", L"Fail 3", MB_OK |
MB_TASKMODAL);
- return;
- }
-
- //SOUND_DEBUG_HEX(Instance->Device->Handle);
-
- waveheader.lpData = (PVOID) JunkBuffer;
- waveheader.dwBufferLength = 65536;
- waveheader.dwFlags = WHDR_PREPARED;
-
- Result = QueueWaveDeviceBuffer(Instance, &waveheader);
-// CallSoundThread(Instance, WAVEREQUEST_QUEUE_BUFFER, &waveheader);
-/*
- Result = WriteSoundDeviceBuffer(Instance,
- JunkBuffer, 65535, OverlappedCallback);
-*/
- wsprintf(msg, L"Play result: %d", Result);
- MessageBox(0, msg, L"Result", MB_OK | MB_TASKMODAL);
-
- StopWaveThread(Instance);
- DestroySoundDeviceInstance(Instance);
-}
-
-
APIENTRY VOID
TestDevEnum()
{
@@ -281,44 +201,6 @@
}
-WINAPI VOID
-TestThreading()
-{
- MMRESULT Result;
- PSOUND_DEVICE Device;
- PSOUND_DEVICE_INSTANCE Instance;
-
- AddSoundDevice(WAVE_OUT_DEVICE_TYPE, L"\\\\.\\SBWaveOut0");
- Result = GetSoundDevice(WAVE_OUT_DEVICE_TYPE, 0, &Device);
- if ( Result != MMSYSERR_NOERROR )
- {
- MessageBox(0, L"Fail 1", L"Fail 1", MB_OK | MB_TASKMODAL);
- return;
- }
-
- Result = CreateSoundDeviceInstance(Device, &Instance);
- if ( Result != MMSYSERR_NOERROR )
- {
- MessageBox(0, L"Fail 2", L"Fail 2", MB_OK | MB_TASKMODAL);
- return;
- }
-
- Result = StartWaveThread(Instance);
- if ( Result != MMSYSERR_NOERROR )
- {
- MessageBox(0, L"Fail 3", L"Fail 3", MB_OK | MB_TASKMODAL);
- return;
- }
-
- MessageBox(0, L"Click to send a request", L"Bai", MB_OK |
MB_TASKMODAL);
- CallSoundThread(Instance, 69, NULL);
-
- MessageBox(0, L"Click to kill thread", L"Bai", MB_OK |
MB_TASKMODAL);
-
- StopWaveThread(Instance);
-}
-
-
VOID
wodTest()
{
@@ -353,14 +235,6 @@
LPWSTR lpCmdLine,
int nCmdShow)
{
-// TestDeviceDetection();
-// wodTest();
-// TestFormatQuery();
- TestPlaybackHackingly();
-// TestDevEnum();
-/*
- TestThreading();
-*/
MessageBox(0, L"Le end", L"Bai", MB_OK | MB_TASKMODAL);
return 0;
}
Modified: branches/silverblade-audio/dll/win32/sndblst/sndblst.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/dll/win32/snd…
==============================================================================
--- branches/silverblade-audio/dll/win32/sndblst/sndblst.c [iso-8859-1] (original)
+++ branches/silverblade-audio/dll/win32/sndblst/sndblst.c [iso-8859-1] Wed Jul 9
18:43:44 2008
@@ -96,10 +96,15 @@
0,
FoundDevice);
+ /* TODO: Check return value */
+ StartSoundThread();
+
return 1L;
case DRV_FREE :
SOUND_DEBUG(L"DRV_FREE");
+
+ StopSoundThread();
RemoveAllSoundDevices();
@@ -139,7 +144,7 @@
FILE* f;
f = fopen("27may2_a.wav", "rb");
- fseek(f, 50, SEEK_SET);
+ fseek(f, 48, SEEK_SET);
fread(Buffer, 1, 5340000, f);
fclose(f);
@@ -160,7 +165,7 @@
/* WODM_OPEN */
Format.wFormatTag = WAVE_FORMAT_PCM;
Format.nChannels = 2;
- Format.nSamplesPerSec = 44100;
+ Format.nSamplesPerSec = 22050;
Format.wBitsPerSample = 16;
Format.nBlockAlign = Format.nChannels * (Format.wBitsPerSample / 8);
Format.nAvgBytesPerSec = Format.nSamplesPerSec * Format.nBlockAlign;
@@ -189,6 +194,14 @@
WaveHeaders[2].dwBufferLength = 1000000;
WaveHeaders[2].dwFlags = WHDR_PREPARED;
+ WaveHeaders[3].lpData = (PVOID) ((PCHAR)Buffer + (1000000 *3));
+ WaveHeaders[3].dwBufferLength = 1000000;
+ WaveHeaders[3].dwFlags = WHDR_PREPARED;
+
+ WaveHeaders[4].lpData = (PVOID) ((PCHAR)Buffer + (1000000 *4));
+ WaveHeaders[4].dwBufferLength = 1000000;
+ WaveHeaders[4].dwFlags = WHDR_PREPARED;
+
// WaveHeader2.lpData = (PVOID) Buffer2;
// WaveHeader2.dwBufferLength = 10;
// WaveHeader2.dwFlags = WHDR_PREPARED;
@@ -196,6 +209,8 @@
Result = wodMessage(0, WODM_WRITE, (DWORD) InstanceData, (DWORD) &WaveHeaders[0],
0);
Result = wodMessage(0, WODM_WRITE, (DWORD) InstanceData, (DWORD) &WaveHeaders[1],
0);
Result = wodMessage(0, WODM_WRITE, (DWORD) InstanceData, (DWORD) &WaveHeaders[2],
0);
+ Result = wodMessage(0, WODM_WRITE, (DWORD) InstanceData, (DWORD) &WaveHeaders[3],
0);
+ Result = wodMessage(0, WODM_WRITE, (DWORD) InstanceData, (DWORD) &WaveHeaders[4],
0);
//Result = wodMessage(0, WODM_WRITE, (DWORD) InstanceData, (DWORD) &WaveHeader2,
0);
Modified: branches/silverblade-audio/include/reactos/libs/sound/mmebuddy.h
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/include/react…
==============================================================================
--- 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] Wed Jul
9 18:43:44 2008
@@ -21,6 +21,9 @@
/*
Hacky debug macro
*/
+
+#include <stdio.h>
+#define SOUND_TRACE printf
#define SOUND_DEBUG(x) \
MessageBox(0, x, L"Debug", MB_OK | MB_TASKMODAL);
@@ -90,6 +93,50 @@
} UNIVERSAL_CAPS, *PUNIVERSAL_CAPS;
+
+/* New sound thread code */
+
+typedef MMRESULT (*SOUND_THREAD_REQUEST_HANDLER)(
+ IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
+ IN OPTIONAL PVOID Parameter);
+
+typedef struct _SOUND_THREAD_REQUEST
+{
+ /* The sound device instance this request relates to */
+ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
+ /* What function to call */
+ SOUND_THREAD_REQUEST_HANDLER RequestHandler;
+ /* Caller-defined parameter */
+ PVOID Parameter;
+ /* This will contain the return code of the request function */
+ MMRESULT ReturnValue;
+} SOUND_THREAD_REQUEST, *PSOUND_THREAD_REQUEST;
+
+typedef VOID (*SOUND_THREAD_IO_COMPLETION_HANDLER)(
+ IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
+ IN PVOID Parameter OPTIONAL,
+ IN DWORD BytesWritten);
+
+typedef struct _SOUND_THREAD_COMPLETED_IO
+{
+ struct _SOUND_THREAD_COMPLETED_IO* Previous;
+ struct _SOUND_THREAD_COMPLETED_IO* Next;
+
+ struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
+ SOUND_THREAD_IO_COMPLETION_HANDLER CompletionHandler;
+ PVOID Parameter;
+ DWORD BytesTransferred;
+} SOUND_THREAD_COMPLETED_IO, *PSOUND_THREAD_COMPLETED_IO;
+
+typedef struct _SOUND_THREAD_OVERLAPPED
+{
+ OVERLAPPED General;
+
+ /* Pointer to structure to fill with completion data */
+ PSOUND_THREAD_COMPLETED_IO CompletionData;
+} SOUND_THREAD_OVERLAPPED, *PSOUND_THREAD_OVERLAPPED;
+
+#if 0
/*
Used internally to shuttle data to/from the sound processing thread.
*/
@@ -117,11 +164,6 @@
PSOUND_THREAD_COMPLETED_IO CompletionData;
} SOUND_THREAD_OVERLAPPED, *PSOUND_THREAD_OVERLAPPED;
-typedef MMRESULT (*SOUND_THREAD_REQUEST_HANDLER)(
- IN struct _SOUND_DEVICE_INSTANCE* Instance,
- IN PVOID PrivateThreadData,
- IN DWORD RequestId,
- IN PVOID Data);
typedef VOID (*SOUND_THREAD_IO_COMPLETION_HANDLER)(
IN struct _SOUND_DEVICE_INSTANCE* Instance,
@@ -147,25 +189,16 @@
PSOUND_THREAD_COMPLETED_IO FirstCompletedIo;
SOUND_THREAD_IO_COMPLETION_HANDLER IoCompletionHandler;
} SOUND_THREAD, *PSOUND_THREAD;
+#endif
/*
Wave thread
*/
-
-typedef struct _WAVE_OVERLAPPED
-{
- OVERLAPPED General;
- struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
- struct _WAVE_THREAD_DATA* ThreadData;
- PWAVEHDR Header;
-} WAVE_OVERLAPPED, *PWAVE_OVERLAPPED;
-
+#if 0
typedef struct _WAVE_THREAD_DATA
{
/* Wave thread specific */
- WAVE_OVERLAPPED Overlapped;
-
DWORD BufferCount;
PWAVEHDR CurrentBuffer;
PWAVEHDR FirstBuffer;
@@ -174,6 +207,7 @@
/* How much data is waiting with the driver */
DWORD RemainingBytes;
} WAVE_THREAD_DATA, *PWAVE_THREAD_DATA;
+#endif
/*
Audio device function table
@@ -234,17 +268,36 @@
Represents an individual instance of an audio device
*/
+typedef struct _WAVE_STREAM_INFO
+{
+ /* Buffer queue head and tail */
+ PWAVEHDR BufferQueueHead;
+ PWAVEHDR BufferQueueTail;
+ /* 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;
+} WAVE_STREAM_INFO, *PWAVE_STREAM_INFO;
+
typedef struct _SOUND_DEVICE_INSTANCE
{
struct _SOUND_DEVICE_INSTANCE* Next;
PSOUND_DEVICE Device;
- PSOUND_THREAD Thread;
+/* PSOUND_THREAD Thread;*/
/* Stuff generously donated to us from WinMM */
struct
{
DWORD ClientCallback;
} WinMM;
+
+ /* Device-specific parameters */
+ union
+ {
+ WAVE_STREAM_INFO Wave;
+ } Streaming;
} SOUND_DEVICE_INSTANCE, *PSOUND_DEVICE_INSTANCE;
@@ -493,60 +546,38 @@
DefaultInstanceDestructor(
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance);
+
+/*
+ thread.c
+*/
+
+MMRESULT
+OverlappedSoundDeviceIo(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PVOID Buffer,
+ IN DWORD BufferSize,
+ IN SOUND_THREAD_IO_COMPLETION_HANDLER IoCompletionHandler,
+ IN PVOID CompletionParameter OPTIONAL);
+
+MMRESULT
+StartSoundThread();
+
+MMRESULT
+StopSoundThread();
+
+MMRESULT
+CallUsingSoundThread(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
+ IN PVOID Parameter);
+
+
+
MMRESULT
QueueWaveDeviceBuffer(
IN PSOUND_DEVICE_INSTANCE Instance,
IN PWAVEHDR BufferHeader);
-
-/*
- thread.c
-*/
-
-MMRESULT
-StartSoundThread(
- IN PSOUND_DEVICE_INSTANCE Instance,
- IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
- IN SOUND_THREAD_IO_COMPLETION_HANDLER IoCompletionHandler,
- IN LPVOID PrivateThreadData);
-
-MMRESULT
-StopSoundThread(
- IN PSOUND_DEVICE_INSTANCE Instance);
-
-MMRESULT
-CallSoundThread(
- IN PSOUND_DEVICE_INSTANCE Instance,
- IN DWORD RequestId,
- IN PVOID RequestData);
-
-MMRESULT
-GetSoundThreadPrivateData(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- OUT PVOID* PrivateData);
-
-VOID CALLBACK
-CompleteSoundThreadIo(
- IN DWORD dwErrorCode,
- IN DWORD dwNumberOfBytesTransferred,
- IN LPOVERLAPPED lpOverlapped);
-
-MMRESULT
-OverlappedWriteToSoundDevice(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- IN PVOID ContextData,
- IN PVOID Buffer,
- IN DWORD BufferSize);
-
-
-
-MMRESULT
-StartWaveThread(
- IN PSOUND_DEVICE_INSTANCE Instance);
-
-MMRESULT
-StopWaveThread(
- IN PSOUND_DEVICE_INSTANCE Instance);
/*
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/devices.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/s…
==============================================================================
--- branches/silverblade-audio/lib/drivers/sound/mmebuddy/devices.c [iso-8859-1]
(original)
+++ branches/silverblade-audio/lib/drivers/sound/mmebuddy/devices.c [iso-8859-1] Wed Jul
9 18:43:44 2008
@@ -570,36 +570,3 @@
ASSERT(Result == MMSYSERR_NOERROR);
}
-
-
-MMRESULT
-QueueWaveDeviceBuffer(
- IN PSOUND_DEVICE_INSTANCE Instance,
- IN PWAVEHDR BufferHeader)
-{
- MMRESULT Result;
-
- if ( ! Instance )
- return MMSYSERR_INVALPARAM;
-
- if ( ! BufferHeader )
- return MMSYSERR_INVALPARAM;
-
- if ( ! BufferHeader->lpData )
- return MMSYSERR_INVALPARAM;
-
- if ( ! BufferHeader->dwBufferLength )
- return MMSYSERR_INVALPARAM;
-
- if ( ! (BufferHeader->dwFlags & WHDR_PREPARED ) )
- return WAVERR_UNPREPARED;
-
- /* TODO: WHDR_INQUEUE */
-
- BufferHeader->dwFlags &= ~WHDR_DONE;
- BufferHeader->lpNext = NULL;
-
- Result = CallSoundThread(Instance, WAVEREQUEST_QUEUE_BUFFER, BufferHeader);
-
- return Result;
-}
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/instances.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/s…
==============================================================================
--- branches/silverblade-audio/lib/drivers/sound/mmebuddy/instances.c [iso-8859-1]
(original)
+++ branches/silverblade-audio/lib/drivers/sound/mmebuddy/instances.c [iso-8859-1] Wed Jul
9 18:43:44 2008
@@ -30,7 +30,6 @@
/* Initialise */
SoundDeviceInstance->Next = NULL;
SoundDeviceInstance->Device = NULL;
- SoundDeviceInstance->Thread = NULL;
/* TODO: WinMM callback entry */
}
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/kernel.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/s…
==============================================================================
--- branches/silverblade-audio/lib/drivers/sound/mmebuddy/kernel.c [iso-8859-1]
(original)
+++ branches/silverblade-audio/lib/drivers/sound/mmebuddy/kernel.c [iso-8859-1] Wed Jul 9
18:43:44 2008
@@ -217,10 +217,13 @@
{
WCHAR msg[128];
if ( ( ! SoundDeviceInstance ) || ( ! Buffer ) || ( BufferSize == 0 ) )
- return MMSYSERR_INVALPARAM;
-
- wsprintf(msg, L"Writing to handle %x",
SoundDeviceInstance->Device->Handle);
- SOUND_DEBUG(msg);
+ {
+ SOUND_DEBUG(L"Invalid parameter!\n");
+ return MMSYSERR_INVALPARAM;
+ }
+
+ /*wsprintf(msg, L"Writing to handle %x",
SoundDeviceInstance->Device->Handle);*/
+ /*SOUND_DEBUG(msg);*/
if ( ! WriteFileEx(SoundDeviceInstance->Device->Handle,
Buffer,
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/mme/wodMessage.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/s…
==============================================================================
--- branches/silverblade-audio/lib/drivers/sound/mmebuddy/mme/wodMessage.c [iso-8859-1]
(original)
+++ branches/silverblade-audio/lib/drivers/sound/mmebuddy/mme/wodMessage.c [iso-8859-1]
Wed Jul 9 18:43:44 2008
@@ -33,7 +33,7 @@
PSOUND_DEVICE_INSTANCE Instance =
(PSOUND_DEVICE_INSTANCE)private_handle;
- SOUND_DEBUG(L"wodMessageStub called\n");
+ SOUND_TRACE("wodMessageStub called\n");
switch ( message )
{
@@ -64,7 +64,7 @@
{
WAVEOPENDESC* OpenParameters = (WAVEOPENDESC*) parameter1;
- SOUND_DEBUG(L"In WODM_OPEN");
+ SOUND_TRACE("In WODM_OPEN\n");
Result = GetSoundDevice(WAVE_OUT_DEVICE_TYPE, device_id, &Device);
if ( Result != MMSYSERR_NOERROR )
return Result;
@@ -94,15 +94,6 @@
return Result;
}
- /* Start the wave handling thread */
- Result = StartWaveThread(Instance);
- if ( Result != MMSYSERR_NOERROR )
- {
- /* TODO: Do we need to do anything more */
- DestroySoundDeviceInstance(Instance);
- return Result;
- }
-
/* Provide winmm with instance handle */
*((PSOUND_DEVICE_INSTANCE*)private_handle) = Instance;
@@ -117,9 +108,6 @@
SOUND_ASSERT(Instance != NULL);
/* TODO: Ensure its OK to close */
-
- Result = StopWaveThread(Instance);
- SOUND_ASSERT(Result == MMSYSERR_NOERROR);
Result = DestroySoundDeviceInstance(Instance);
SOUND_DEBUG_HEX(Result);
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/thread.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/s…
==============================================================================
--- 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] Wed Jul 9
18:43:44 2008
@@ -12,16 +12,7 @@
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.
-*/
-
-/*
- This is used internally by the internal routines
- (my, how recursive of you...)
+ 9 July 2008 - Rewritten to have a single streaming thread
*/
#include <windows.h>
@@ -29,309 +20,29 @@
#include <mmebuddy.h>
-
-/*
- This is the sound thread's processing loop. Its job is to aid in
- asynchronous streaming of sound data with a kernel-mode driver. It's
- basically a loop in which we wait for a request from the client, or
- completed data from the kernel-mode driver.
-
- When either of these events occur, the relevant details get passed on
- to one of the routines specified when the thread was started.
-*/
-DWORD WINAPI
-SoundThreadProc(
- IN LPVOID lpParameter)
-{
- PSOUND_DEVICE_INSTANCE Instance;
- PSOUND_THREAD Thread;
-
- Instance = (PSOUND_DEVICE_INSTANCE) lpParameter;
- Thread = Instance->Thread;
-
- Thread->Running = TRUE;
-
- /* We're ready to do work */
- SetEvent(Thread->ReadyEvent);
-
- /*MessageBox(0, L"Hi from thread!", L"Hi!", MB_OK |
MB_TASKMODAL);*/
-
- while ( Thread->Running )
- {
- DWORD WaitResult;
-
- /* Wait for some work, or I/O completion */
- WaitResult = WaitForSingleObjectEx(Thread->RequestEvent, INFINITE, TRUE);
-
- if ( WaitResult == WAIT_OBJECT_0 )
- {
- /* Do the work (request 0 kills the thread) */
- Thread->Request.Result =
- Thread->RequestHandler(Instance,
- Thread->PrivateData,
- Thread->Request.RequestId,
- Thread->Request.Data);
-
- if ( Thread->Request.RequestId == 0 )
- {
- Thread->Running = FALSE;
- Thread->Request.Result = MMSYSERR_NOERROR;
- }
-
- /* Notify the caller that the work is done */
- SetEvent(Thread->ReadyEvent);
- SetEvent(Thread->DoneEvent);
- }
- else if ( WaitResult == WAIT_IO_COMPLETION )
- {
- /* This gets called after I/O completion */
- PSOUND_THREAD_COMPLETED_IO CompletionData;
- SOUND_ASSERT(Thread->FirstCompletedIo);
-
- //SOUND_DEBUG(L"Outside I/O completion APC");
-
- /*
- Purge the completed data queue
- FIXME? This will be done in the WRONG ORDER!
- Is this such a problem? The caller won't care. We'll need
- to remove them from our queue though!
- */
- while ( (CompletionData = Thread->FirstCompletedIo) )
- {
- /* Call high-level custom I/O completion routine */
- Thread->IoCompletionHandler(Instance,
- Thread->PrivateData,
- CompletionData->ContextData,
- CompletionData->BytesTransferred);
-
- /* TODO: I'm sure I've forgotten something ... */
-
- Thread->FirstCompletedIo = CompletionData->Next;
- FreeMemory(CompletionData);
- }
- }
- }
-
- /*MessageBox(0, L"Bye from thread!", L"Bye!", MB_OK |
MB_TASKMODAL);*/
-
- ExitThread(0);
- return 0;
-}
-
-MMRESULT
-CreateThreadEvents(
- IN PSOUND_THREAD Thread)
-{
- /* Create the request event */
- Thread->RequestEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- if ( ! Thread->RequestEvent )
- {
- return MMSYSERR_NOMEM;
- }
-
- /* Create the 'ready' event */
- Thread->ReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- if ( ! Thread->ReadyEvent )
- {
- CloseHandle(Thread->RequestEvent);
- return MMSYSERR_NOMEM;
- }
-
- /* Create the 'done' event */
- Thread->DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- if ( ! Thread->DoneEvent )
- {
- CloseHandle(Thread->ReadyEvent);
- CloseHandle(Thread->RequestEvent);
- return MMSYSERR_NOMEM;
- }
-
- return MMSYSERR_NOERROR;
-}
-
-MMRESULT
-DestroyThreadEvents(
- IN PSOUND_THREAD Thread)
-{
- CloseHandle(Thread->RequestEvent);
- Thread->RequestEvent = INVALID_HANDLE_VALUE;
-
- CloseHandle(Thread->ReadyEvent);
- Thread->ReadyEvent = INVALID_HANDLE_VALUE;
-
- CloseHandle(Thread->DoneEvent);
- Thread->DoneEvent = INVALID_HANDLE_VALUE;
-
- return MMSYSERR_NOERROR;
-}
-
-
-MMRESULT
-StartSoundThread(
- IN PSOUND_DEVICE_INSTANCE Instance,
- IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
- IN SOUND_THREAD_IO_COMPLETION_HANDLER IoCompletionHandler,
- IN LPVOID PrivateThreadData)
-{
- PSOUND_THREAD SoundThread = NULL;
-
- /* Validate parameters */
- if ( ! Instance )
- return MMSYSERR_INVALPARAM;
-
- if ( ! RequestHandler )
- return MMSYSERR_INVALPARAM;
-
- /* Only allowed one thread per instance */
- if ( Instance->Thread )
- return MMSYSERR_ERROR;
-
- /* Allocate memory for the thread info */
- SoundThread = AllocateMemoryFor(SOUND_THREAD);
-
- if ( ! SoundThread )
- return MMSYSERR_NOMEM;
-
- /* Initialise */
- SoundThread->PrivateData = PrivateThreadData;
- SoundThread->Running = FALSE;
- SoundThread->Handle = INVALID_HANDLE_VALUE;
-
- SoundThread->RequestHandler = RequestHandler;
- SoundThread->ReadyEvent = INVALID_HANDLE_VALUE;
- SoundThread->RequestEvent = INVALID_HANDLE_VALUE;
- SoundThread->DoneEvent = INVALID_HANDLE_VALUE;
-
- SoundThread->IoCompletionHandler = IoCompletionHandler;
- SoundThread->FirstCompletedIo = NULL;
-
- /* No need to initialise the requests */
-
- /* Create the events */
- if ( CreateThreadEvents(SoundThread) != MMSYSERR_NOERROR )
- {
- FreeMemory(SoundThread);
- return MMSYSERR_NOMEM;
- }
-
- if ( ! SoundThread->RequestEvent )
- {
- CloseHandle(SoundThread->RequestEvent);
- FreeMemory(SoundThread);
- return MMSYSERR_NOMEM;
- }
-
- /* Do the creation thang */
- SoundThread->Handle = CreateThread(NULL,
- 0,
- &SoundThreadProc,
- (LPVOID) Instance,
- CREATE_SUSPENDED,
- NULL);
-
- if (SoundThread->Handle == INVALID_HANDLE_VALUE )
- {
- FreeMemory(SoundThread);
- return Win32ErrorToMmResult(GetLastError());
- }
-
- /* Assign the thread to the instance */
- Instance->Thread = SoundThread;
-
- /* Go! */
- ResumeThread(SoundThread->Handle);
-
- return MMSYSERR_NOERROR;
-}
-
-MMRESULT
-StopSoundThread(
- IN PSOUND_DEVICE_INSTANCE Instance)
-{
- if ( ! Instance )
- return MMSYSERR_INVALPARAM;
-
- if ( ! Instance->Thread )
- return MMSYSERR_ERROR;
-
- /* Send request zero to ask the thread to end */
- CallSoundThread(Instance, 0, NULL);
-
- /* Wait for the thread to exit */
- WaitForSingleObject(Instance->Thread->Handle, INFINITE);
-
- /* Finish with the thread */
- CloseHandle(Instance->Thread->Handle);
- Instance->Thread->Handle = INVALID_HANDLE_VALUE;
-
- /* Clean up the thread events */
- DestroyThreadEvents(Instance->Thread);
-
- /* Free memory associated with the thread */
- FreeMemory(Instance->Thread);
- Instance->Thread = NULL;
-
- return MMSYSERR_NOERROR;
-}
-
-MMRESULT
-CallSoundThread(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- IN DWORD RequestId,
- IN PVOID RequestData)
-{
- MMRESULT Result;
-
- if ( ! SoundDeviceInstance )
- return MMSYSERR_INVALPARAM;
-
- if ( ! SoundDeviceInstance->Thread )
- return MMSYSERR_ERROR;
-
- //SOUND_DEBUG(L"Waiting for Ready event");
-
- /* Wait for the thread to be ready */
- WaitForSingleObject(SoundDeviceInstance->Thread->ReadyEvent, INFINITE);
-
- /* Load the request */
- SoundDeviceInstance->Thread->Request.DeviceInstance = SoundDeviceInstance;
- SoundDeviceInstance->Thread->Request.RequestId = RequestId;
- SoundDeviceInstance->Thread->Request.Data = RequestData;
- SoundDeviceInstance->Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
-
- /* Notify the thread that there's a request to be processed */
- SetEvent(SoundDeviceInstance->Thread->RequestEvent);
-
- /* Wait for the thread to be ready (request complete) */
- WaitForSingleObject(SoundDeviceInstance->Thread->DoneEvent, INFINITE);
-
- /* Grab the result */
- Result = SoundDeviceInstance->Thread->Request.Result;
-
- return Result;
-}
-
-MMRESULT
-GetSoundThreadPrivateData(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- OUT PVOID* PrivateData)
-{
- if ( ! SoundDeviceInstance )
- return MMSYSERR_INVALPARAM;
-
- if ( ! SoundDeviceInstance->Thread )
- return MMSYSERR_ERROR;
-
- if ( ! PrivateData )
- return MMSYSERR_INVALPARAM;
-
- *PrivateData = SoundDeviceInstance->Thread->PrivateData;
-
- return MMSYSERR_NOERROR;
-}
+/* HAX */
+#include <stdio.h>
+
+static BOOLEAN ThreadRunning = FALSE;
+static HANDLE SoundThread = INVALID_HANDLE_VALUE;
+static HANDLE ReadyEvent = INVALID_HANDLE_VALUE;
+static HANDLE RequestEvent = INVALID_HANDLE_VALUE;
+static HANDLE DoneEvent = INVALID_HANDLE_VALUE;
+
+static SOUND_THREAD_REQUEST CurrentRequest =
+{
+ NULL,
+ NULL,
+ NULL,
+ MMSYSERR_NOERROR
+};
+
+static SOUND_THREAD_COMPLETED_IO* CompletedIoListHead = NULL;
+static SOUND_THREAD_COMPLETED_IO* CompletedIoListTail = NULL;
+
+
+VOID
+CleanupThreadEvents();
VOID CALLBACK
CompleteSoundThreadIo(
@@ -339,85 +50,337 @@
IN DWORD dwNumberOfBytesTransferred,
IN LPOVERLAPPED lpOverlapped)
{
- PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
- PSOUND_THREAD_OVERLAPPED SoundThreadOverlapped;
PSOUND_THREAD_COMPLETED_IO CompletionData;
-
- SoundThreadOverlapped = (PSOUND_THREAD_OVERLAPPED) lpOverlapped;
- SOUND_ASSERT(SoundThreadOverlapped);
-
- CompletionData = SoundThreadOverlapped->CompletionData;
+ PSOUND_THREAD_OVERLAPPED SoundOverlapped;
+
+ printf("Overlapped I/O completion APC called\n");
+
+ SoundOverlapped = (PSOUND_THREAD_OVERLAPPED) lpOverlapped;
+ SOUND_ASSERT(SoundOverlapped);
+
+ CompletionData = SoundOverlapped->CompletionData;
SOUND_ASSERT(CompletionData);
- SoundDeviceInstance = SoundThreadOverlapped->SoundDeviceInstance;
- SOUND_ASSERT(SoundDeviceInstance);
- SOUND_ASSERT(SoundDeviceInstance->Thread);
-
- //SOUND_DEBUG(L"New I/O Completion Callback Called");
-
- /* This is going at the start of the list */
- CompletionData->Next = SoundDeviceInstance->Thread->FirstCompletedIo;
- SoundDeviceInstance->Thread->FirstCompletedIo = CompletionData;
-
- /* Whatever information was supplied to us originally by the caller */
- CompletionData->ContextData = SoundThreadOverlapped->ContextData;
-
- /* How much data was transferred */
CompletionData->BytesTransferred = dwNumberOfBytesTransferred;
- /* Overlapped structure gets freed now, but we still need the completion */
- FreeMemory(SoundThreadOverlapped);
-
- //SOUND_DEBUG(L"New I/O Completion Callback Done");
-}
-
-MMRESULT
-OverlappedWriteToSoundDevice(
+ /* Is this the first completion? */
+ if ( ! CompletedIoListHead )
+ {
+ printf("First completion - making new head and tail\n");
+ /* This is the first completion */
+ SOUND_ASSERT(CompletedIoListTail == NULL);
+
+ CompletionData->Previous = NULL;
+ CompletionData->Next = NULL;
+
+ CompletedIoListHead = CompletionData;
+ CompletedIoListTail = CompletionData;
+ }
+ else
+ {
+ printf("Not the first completion - making new tail\n");
+ /* This is not the first completion */
+ CompletionData->Previous = CompletedIoListTail;
+ CompletionData->Next = NULL;
+
+ /* Completion data gets made the new tail */
+ CompletedIoListTail->Next = CompletionData;
+ CompletedIoListTail = CompletionData;
+ }
+
+ /* We keep the completion data, but no longer need this: */
+ FreeMemory(SoundOverlapped);
+}
+
+MMRESULT
+OverlappedSoundDeviceIo(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- IN PVOID ContextData,
IN PVOID Buffer,
- IN DWORD BufferSize)
+ IN DWORD BufferSize,
+ IN SOUND_THREAD_IO_COMPLETION_HANDLER IoCompletionHandler,
+ IN PVOID CompletionParameter OPTIONAL)
{
PSOUND_THREAD_OVERLAPPED Overlapped;
- PSOUND_THREAD_COMPLETED_IO CompletedIo;
if ( ! SoundDeviceInstance )
return MMSYSERR_INVALPARAM;
- if ( ! SoundDeviceInstance->Thread )
- return MMSYSERR_ERROR; /* FIXME - better return code? */
-
if ( ! Buffer )
return MMSYSERR_INVALPARAM;
- /* This will contain information about the write operation */
+ if ( BufferSize == 0 )
+ return MMSYSERR_INVALPARAM;
+
+ if ( ! IoCompletionHandler )
+ return MMSYSERR_INVALPARAM;
+
+ /* Allocate memory for the overlapped I/O structure (auto-zeroed) */
Overlapped = AllocateMemoryFor(SOUND_THREAD_OVERLAPPED);
+
if ( ! Overlapped )
return MMSYSERR_NOMEM;
- /* We collect this on I/O completion */
- CompletedIo = AllocateMemoryFor(SOUND_THREAD_COMPLETED_IO);
- if ( ! CompletedIo )
+ /* We also need memory for the completion data (auto-zeroed) */
+ Overlapped->CompletionData = AllocateMemoryFor(SOUND_THREAD_COMPLETED_IO);
+
+ if ( ! Overlapped->CompletionData )
{
FreeMemory(Overlapped);
return MMSYSERR_NOMEM;
}
- ZeroMemory(Overlapped, sizeof(SOUND_THREAD_OVERLAPPED));
- ZeroMemory(CompletedIo, sizeof(SOUND_THREAD_COMPLETED_IO));
-
- /* We'll want to know which device to queue completion data to */
- Overlapped->SoundDeviceInstance = SoundDeviceInstance;
-
- /* Caller-supplied data, gets passed back on completion */
- Overlapped->ContextData = ContextData;
-
- /* The completion data buffer which will be filled later */
- Overlapped->CompletionData = CompletedIo;
-
+ /* Information to be passed to the completion routine */
+ Overlapped->CompletionData->SoundDeviceInstance = SoundDeviceInstance;
+ Overlapped->CompletionData->CompletionHandler = IoCompletionHandler;
+ Overlapped->CompletionData->Parameter = CompletionParameter;
+ Overlapped->CompletionData->BytesTransferred = 0;
+
+ printf("Performing overlapped I/O\n");
return WriteSoundDeviceBuffer(SoundDeviceInstance,
Buffer,
BufferSize,
CompleteSoundThreadIo,
(LPOVERLAPPED) Overlapped);
}
+
+MMRESULT
+ProcessThreadExitRequest(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance OPTIONAL,
+ IN PVOID Parameter OPTIONAL)
+{
+ printf("ProcessThreadExitRequest called\n");
+ ThreadRunning = FALSE;
+ return MMSYSERR_NOERROR;
+}
+
+DWORD WINAPI
+SoundThreadProc(
+ IN LPVOID lpParameter OPTIONAL)
+{
+ ThreadRunning = TRUE;
+
+ /* We're ready to do work */
+ SetEvent(ReadyEvent);
+
+ while ( ThreadRunning )
+ {
+ DWORD WaitResult;
+
+ /* Wait for a request, or an I/O completion */
+ WaitResult = WaitForSingleObjectEx(RequestEvent, INFINITE, TRUE);
+
+ if ( WaitResult == WAIT_OBJECT_0 )
+ {
+ /* Process the request */
+
+ SOUND_ASSERT(CurrentRequest.RequestHandler != NULL);
+ if ( CurrentRequest.RequestHandler != NULL )
+ {
+ CurrentRequest.ReturnValue = CurrentRequest.RequestHandler(
+ CurrentRequest.SoundDeviceInstance,
+ CurrentRequest.Parameter);
+ }
+ else
+ {
+ CurrentRequest.ReturnValue = MMSYSERR_ERROR;
+ }
+
+ /* Announce completion of the request */
+ SetEvent(DoneEvent);
+ /* Accept new requests */
+ SetEvent(ReadyEvent);
+ }
+ else if ( WaitResult == WAIT_IO_COMPLETION )
+ {
+ PSOUND_THREAD_COMPLETED_IO CurrentCompletion;
+
+ /* Process the I/O Completion */
+
+ CurrentCompletion = CompletedIoListHead;
+ SOUND_ASSERT(CurrentCompletion);
+
+ while ( CurrentCompletion )
+ {
+ PSOUND_THREAD_COMPLETED_IO PreviousCompletion;
+
+ /* Call the completion handler */
+ CurrentCompletion->CompletionHandler(
+ CurrentCompletion->SoundDeviceInstance,
+ CurrentCompletion->Parameter,
+ CurrentCompletion->BytesTransferred);
+
+ /* Get the next completion but destroy the previous */
+ PreviousCompletion = CurrentCompletion;
+ CurrentCompletion = CurrentCompletion->Next;
+ FreeMemory(PreviousCompletion);
+ }
+
+ /* Nothing in the completion queue/list now */
+ CompletedIoListHead = NULL;
+ CompletedIoListTail = NULL;
+ }
+ else
+ {
+ /* Shouldn't happen! */
+ SOUND_ASSERT(FALSE);
+ }
+ }
+
+ printf("THREAD: Exiting\n");
+
+ ExitThread(0);
+ return 0;
+}
+
+MMRESULT
+CreateThreadEvents()
+{
+ ReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if ( ReadyEvent == INVALID_HANDLE_VALUE )
+ {
+ CleanupThreadEvents();
+ return MMSYSERR_NOMEM;
+ }
+
+ RequestEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if ( RequestEvent == INVALID_HANDLE_VALUE )
+ {
+ CleanupThreadEvents();
+ return MMSYSERR_NOMEM;
+ }
+
+ DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if ( DoneEvent == INVALID_HANDLE_VALUE )
+ {
+ CleanupThreadEvents();
+ return MMSYSERR_NOMEM;
+ }
+
+ return MMSYSERR_NOERROR;
+}
+
+VOID
+CleanupThreadEvents()
+{
+ if ( ReadyEvent != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle(ReadyEvent);
+ ReadyEvent = INVALID_HANDLE_VALUE;
+ }
+
+ if ( RequestEvent != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle(RequestEvent);
+ RequestEvent = INVALID_HANDLE_VALUE;
+ }
+
+ if ( DoneEvent != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle(DoneEvent);
+ DoneEvent = INVALID_HANDLE_VALUE;
+ }
+}
+
+MMRESULT
+StartSoundThread()
+{
+ MMRESULT Result;
+
+ /* Create the thread events */
+ Result = CreateThreadEvents();
+
+ if ( Result != MMSYSERR_NOERROR )
+ {
+ return Result;
+ }
+
+ /* Create the thread */
+ SoundThread = CreateThread(NULL,
+ 0,
+ &SoundThreadProc,
+ (LPVOID) NULL, /* Parameter */
+ CREATE_SUSPENDED,
+ NULL);
+
+ if ( SoundThread == INVALID_HANDLE_VALUE )
+ {
+ CleanupThreadEvents();
+ return Win32ErrorToMmResult(GetLastError());
+ }
+
+ printf("Starting sound thread\n");
+
+ /* We're all set to go, so let's start the thread up */
+ ResumeThread(SoundThread);
+
+ return MMSYSERR_NOERROR;
+}
+
+MMRESULT
+CallUsingSoundThread(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance OPTIONAL,
+ IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
+ IN PVOID Parameter OPTIONAL)
+{
+ if ( ! RequestHandler )
+ return MMSYSERR_INVALPARAM;
+
+ SOUND_ASSERT(SoundThread != INVALID_HANDLE_VALUE);
+ if ( SoundThread == INVALID_HANDLE_VALUE )
+ {
+ return MMSYSERR_ERROR;
+ }
+
+ /* Wait for the sound thread to be ready for a request */
+ WaitForSingleObject(ReadyEvent, INFINITE);
+
+ /* Fill in the information about the request */
+ CurrentRequest.SoundDeviceInstance = SoundDeviceInstance;
+ CurrentRequest.RequestHandler = RequestHandler;
+ CurrentRequest.Parameter = Parameter;
+ CurrentRequest.ReturnValue = MMSYSERR_ERROR;
+
+ /* Tell the sound thread there is a request waiting */
+ SetEvent(RequestEvent);
+
+ /* Wait for our request to be dealt with */
+ WaitForSingleObject(DoneEvent, INFINITE);
+
+ return CurrentRequest.ReturnValue;
+}
+
+MMRESULT
+StopSoundThread()
+{
+ MMRESULT Result;
+
+ SOUND_ASSERT(SoundThread != INVALID_HANDLE_VALUE);
+ if ( SoundThread == INVALID_HANDLE_VALUE )
+ {
+ return MMSYSERR_ERROR;
+ }
+
+ printf("Calling thread shutdown function\n");
+
+ Result = CallUsingSoundThread(NULL,
+ ProcessThreadExitRequest,
+ NULL);
+
+ /* Our request didn't get processed? */
+ SOUND_ASSERT(Result != MMSYSERR_NOERROR);
+ if ( Result != MMSYSERR_NOERROR )
+ return Result;
+
+ WaitForSingleObject(SoundThread, INFINITE);
+
+ printf("Sound thread has quit\n");
+
+ /* Clean up */
+ CloseHandle(SoundThread);
+ CleanupThreadEvents();
+
+ return MMSYSERR_NOERROR;
+}
Modified: branches/silverblade-audio/lib/drivers/sound/mmebuddy/wave/wavethread.c
URL:
http://svn.reactos.org/svn/reactos/branches/silverblade-audio/lib/drivers/s…
==============================================================================
--- 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]
Wed Jul 9 18:43:44 2008
@@ -30,312 +30,236 @@
Should it be configurable? Some sound drivers let you set buffer size...
*/
-#define MAX_SOUND_BUFFER_SIZE 1500000
-
-
-/*
- 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.
-*/
+#define MAX_SOUND_BUFFER_SIZE 65536
+
+
+
+VOID
+CompleteWaveBuffer(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PVOID Parameter,
+ IN DWORD BytesWritten);
+
+
MMRESULT
-StreamWaveData(
- IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
- 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);
-
- /* Work out how much data can be streamed with the driver */
- BytesAvailable = MAX_SOUND_BUFFER_SIZE - ThreadData->RemainingBytes;
-
- while ( ( Buffer = ThreadData->CurrentBuffer ) && ( BytesAvailable > 0
) )
- {
- /* The 'reserved' member of Buffer contains the offset */
- BufferOffset = Buffer->reserved;
-
- /*
- 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;
-
- /*
- We may find that there's nothing to be done with the current
- buffer, either on initial entry to this loop or after having
- been through a few iterations. Once the buffer has been squeezed
- dry, move on to the next victim...
+StreamWaveIo(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
+{
+ PWAVE_STREAM_INFO StreamInfo;
+ DWORD BytesAvailable, BytesToStream;
+
+ 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 )
{
- /* TODO */
- SOUND_DEBUG(L"Advancing buffer");
- ThreadData->CurrentBuffer = ThreadData->CurrentBuffer->lpNext;
+ SOUND_TRACE("No bytes to stream\n");
+ StreamInfo->CurrentBuffer = StreamInfo->CurrentBuffer->lpNext;
+ StreamInfo->BufferOffset = 0;
continue;
}
/*
- 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 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 )
{
- /* 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.
- */
- SOUND_DEBUG(L"Writing data");
- Result = OverlappedWriteToSoundDevice(SoundDeviceInstance,
- (PVOID) Buffer,
- 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 these get updated, too */
- ThreadData->RemainingBytes += BytesToStream;
- BytesAvailable = MAX_SOUND_BUFFER_SIZE - ThreadData->RemainingBytes;
-
- /*
- If the offset is now equal to the buffer length, this will be
- because the entirety of the buffer has been sent.
- */
-/*
- if ( BufferOffset == Buffer->dwBufferLength )
+ 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
+
+ return MMSYSERR_NOERROR;
+}
+
+
+VOID
+CompleteWaveBuffer(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PVOID Parameter,
+ IN DWORD BytesWritten)
+{
+ SOUND_TRACE("CompleteWaveBuffer called - wrote %d bytes\n",
(int)BytesWritten);
+
+ SoundDeviceInstance->Streaming.Wave.BytesOutstanding -= BytesWritten;
+
+ StreamWaveIo(SoundDeviceInstance);
+}
+
+
+MMRESULT
+QueueBuffer_Request(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PVOID Parameter)
+{
+ PWAVEHDR WaveHeader = (PWAVEHDR) Parameter;
+ PWAVE_STREAM_INFO StreamInfo;
+
+ if ( ! SoundDeviceInstance )
+ return MMSYSERR_INVALPARAM;
+
+ if ( ! WaveHeader )
+ return MMSYSERR_INVALPARAM;
+
+ /* To avoid stupidly long variable names we alias this */
+ StreamInfo = &SoundDeviceInstance->Streaming.Wave;
+
+ SOUND_TRACE("QueueBuffer_Request\n");
+
+ /* Initialise fields of interest to us */
+ WaveHeader->lpNext = NULL;
+ WaveHeader->reserved = 0;
+
+ /*
+ Is this the first buffer being queued? Streaming only needs to be
+ done here if there's nothing else playing.
+ */
+ if ( ! StreamInfo->BufferQueueHead )
+ {
+ SOUND_TRACE("This is the first buffer being queued\n");
+
+ /* Set head, tail and current to this buffer */
+ StreamInfo->BufferQueueHead = WaveHeader;
+ StreamInfo->BufferQueueTail = WaveHeader;
+ StreamInfo->CurrentBuffer = WaveHeader;
+
+ /* Initialise the stream state */
+ StreamInfo->BufferOffset = 0;
+ StreamInfo->BytesOutstanding = 0;
+
+ /* Get the streaming started */
+ StreamWaveIo(SoundDeviceInstance);
+ }
+ else
+ {
+ SOUND_TRACE("This is not the first buffer being queued\n");
+
+ /* Point the existing tail to the new buffer */
+ StreamInfo->BufferQueueTail->lpNext = WaveHeader;
+ /* ...and set the buffer as the new tail */
+ StreamInfo->BufferQueueTail = WaveHeader;
+
+ if ( ! StreamInfo->CurrentBuffer )
{
- SOUND_DEBUG(L"Advancing buffer");
- ThreadData->CurrentBuffer = ThreadData->CurrentBuffer->lpNext;
+ /* All buffers so far have been committed to the sound driver */
+ StreamInfo->CurrentBuffer = WaveHeader;
}
-*/
- }
-
- SOUND_DEBUG(L"Leaving");
+ }
return MMSYSERR_NOERROR;
}
-/*
- Private thread dispatch routines
-*/
-
MMRESULT
-SubmitWaveBuffer(
- IN PSOUND_DEVICE_INSTANCE Instance,
- IN PWAVE_THREAD_DATA ThreadData,
- IN PWAVEHDR Buffer)
-{
-/* DWORD BytesSubmitted = 0;*/
-
- SOUND_ASSERT(Instance != NULL);
- SOUND_ASSERT(Buffer != NULL);
- SOUND_ASSERT(Instance->Thread != NULL);
-
- /* 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 )
- {
- SOUND_DEBUG(L"First buffer");
- ThreadData->FirstBuffer = Buffer;
- }
-
- /* Attach the buffer to the end of the list, unless this is the first */
- if ( ThreadData->LastBuffer )
- {
- SOUND_DEBUG(L"Adding to end of list");
- ThreadData->LastBuffer->lpNext = Buffer;
- }
-
- /* Update our record of the last buffer */
- ThreadData->LastBuffer = Buffer;
-
- /* Increment the number of buffers queued */
- ++ ThreadData->BufferCount;
-
- /* If nothing is playing, we'll need to start things off */
- if ( ThreadData->RemainingBytes == 0 )
- {
- SOUND_DEBUG(L"Kicking off processing");
- ThreadData->CurrentBuffer = ThreadData->FirstBuffer;
- StreamWaveData(Instance, ThreadData);
- }
-
- return MMSYSERR_NOERROR;
-}
-
-
-/*
- Thread request dispatcher
-*/
-
-MMRESULT
-ProcessWaveThreadRequest(
- IN PSOUND_DEVICE_INSTANCE Instance,
- IN PVOID PrivateThreadData,
- IN DWORD RequestId,
- IN PVOID Data)
-{
- PWAVE_THREAD_DATA WaveThreadData =
- (PWAVE_THREAD_DATA) PrivateThreadData;
-
- /* Just some temporary testing code for now */
- WCHAR msg[128];
- wsprintf(msg, L"Request %d received", RequestId);
-
- MessageBox(0, msg, L"Request", MB_OK | MB_TASKMODAL);
-
- SOUND_ASSERT(Instance != NULL);
-
- switch ( RequestId )
- {
- case WAVEREQUEST_QUEUE_BUFFER :
- {
- PWAVEHDR Buffer = (PWAVEHDR) Data;
-
- return SubmitWaveBuffer(Instance, WaveThreadData, Buffer);
- }
- }
-
- return MMSYSERR_NOTSUPPORTED;
-}
-
-
-/*
- I/O completion
- Called from outside the overlapped I/O completion APC
-*/
-
-VOID
-ProcessWaveIoCompletion(
- IN struct _SOUND_DEVICE_INSTANCE* Instance,
- IN PVOID PrivateThreadData,
- IN PVOID ContextData,
- IN DWORD BytesTransferred)
-{
- PWAVE_THREAD_DATA ThreadData = (PWAVE_THREAD_DATA) PrivateThreadData;
- PWAVEHDR WaveHeader = (PWAVEHDR) ContextData;
- SOUND_ASSERT(ThreadData);
- WCHAR msg[1024];
-
- /*SOUND_DEBUG(L"ProcessWaveIoCompletion called :)");*/
- /*SOUND_DEBUG_HEX(WaveHeader);*/
-
- /*
- At this point we know:
- - The sound device instance involved in the transaction
- - The wave header for the buffer which just completed
- - How much data was transferred
-
- The next task is to figure out how much of the buffer
- got played, and enqueue the next buffer if the current
- one has been completed.
-
- Basically, this routine is responsible for keeping the
- stream of audio data to/from the sound driver going.
-
- When no more WAVEHDRs are queued (ie, WaveHeader->lpNext
- is NULL), no more buffers are submitted and the sound
- 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",
- WaveHeader,
- WaveHeader->reserved,
- BytesTransferred,
- ThreadData->RemainingBytes);
-
- MessageBox(0, msg, L"I/O COMPLETE", MB_OK | MB_TASKMODAL);
-
- /* TODO: Check return value */
- StreamWaveData(Instance, ThreadData);
-}
-
-
-/*
- Wave thread start/stop routines
-*/
-
-MMRESULT
-StartWaveThread(
- IN PSOUND_DEVICE_INSTANCE Instance)
-{
- MMRESULT Result = MMSYSERR_NOERROR;
- PWAVE_THREAD_DATA WaveThreadData = NULL;
-
- if ( ! Instance )
- return MMSYSERR_INVALPARAM;
-
- WaveThreadData = AllocateMemoryFor(WAVE_THREAD_DATA);
-
- if ( ! WaveThreadData )
- return MMSYSERR_NOMEM;
-
- /* Initialise our data */
- WaveThreadData->CurrentBuffer = NULL;
- WaveThreadData->FirstBuffer = NULL;
- WaveThreadData->LastBuffer = NULL;
- WaveThreadData->BufferCount = 0;
- /* TODO: More */
-
- /* Kick off the thread */
- Result = StartSoundThread(Instance,
- ProcessWaveThreadRequest,
- ProcessWaveIoCompletion,
- WaveThreadData);
- if ( Result != MMSYSERR_NOERROR )
- {
- FreeMemory(WaveThreadData);
- return Result;
- }
-
- /* AddSoundThreadOperation(Instance, 69, SayHello); */
- return MMSYSERR_NOERROR;
-}
-
-MMRESULT
-StopWaveThread(
- IN PSOUND_DEVICE_INSTANCE Instance)
-{
- MMRESULT Result;
- PWAVE_THREAD_DATA WaveThreadData = NULL;
-
- if ( ! Instance )
- return MMSYSERR_INVALPARAM;
-
- Result = GetSoundThreadPrivateData(Instance, (PVOID*) &WaveThreadData);
- SOUND_ASSERT( Result == MMSYSERR_NOERROR );
-
- /* This shouldn't fail... */
- Result = StopSoundThread(Instance);
- SOUND_ASSERT( Result == MMSYSERR_NOERROR );
-
- FreeMemory(WaveThreadData);
-
- return MMSYSERR_NOERROR;
-}
+QueueWaveDeviceBuffer(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PWAVEHDR BufferHeader)
+{
+ if ( ! SoundDeviceInstance )
+ return MMSYSERR_INVALPARAM;
+
+ if ( ! BufferHeader )
+ return MMSYSERR_INVALPARAM;
+
+ if ( ! BufferHeader->lpData )
+ return MMSYSERR_INVALPARAM;
+
+ if ( ! BufferHeader->dwBufferLength )
+ return MMSYSERR_INVALPARAM;
+
+ if ( ! (BufferHeader->dwFlags & WHDR_PREPARED ) )
+ return WAVERR_UNPREPARED;
+
+ /* TODO: WHDR_INQUEUE */
+
+ BufferHeader->dwFlags &= ~WHDR_DONE;
+ BufferHeader->lpNext = NULL;
+
+ return CallUsingSoundThread(SoundDeviceInstance,
+ QueueBuffer_Request,
+ BufferHeader);
+}