/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: lib/drivers/sound/mmebuddy/header.c
+ * FILE: lib/drivers/sound/mmebuddy/wave/header.c
*
- * PURPOSE: Wave header preparation routines
+ * PURPOSE: Wave header preparation and submission routines
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include <mmddk.h>
#include <ntddsnd.h>
#include <mmebuddy.h>
+#include <sndtypes.h>
/*
}
+/*
+ SanitizeWaveHeader
+ Clean up a header / reinitialize
+*/
+
+VOID
+SanitizeWaveHeader(
+ PWAVEHDR Header)
+{
+ PWAVEHDR_EXTENSION Extension = (PWAVEHDR_EXTENSION) Header->reserved;
+ SND_ASSERT( Extension );
+
+ Header->dwBytesRecorded = 0;
+
+ Extension->BytesCommitted = 0;
+ Extension->BytesCompleted = 0;
+}
+
+
/*
The following routines are basically handlers for:
- WODM_PREPARE
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PMMFUNCTION_TABLE FunctionTable;
+ PWAVEHDR_EXTENSION Extension;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Header );
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
- if ( ! FunctionTable->PrepareWaveHeader )
- return MMSYSERR_NOTSUPPORTED;
+ Extension = AllocateStruct(WAVEHDR_EXTENSION);
+ if ( ! Extension )
+ return MMSYSERR_NOMEM;
+
+ Header->reserved = (DWORD_PTR) Extension;
+ Extension->BytesCommitted = 0;
+ Extension->BytesCompleted = 0;
+
+ /* Configure the flags */
+ Header->dwFlags |= WHDR_PREPARED;
- return WaveHeaderOperation(FunctionTable->PrepareWaveHeader,
- SoundDeviceInstance,
- Header);
+ return MMSYSERR_NOERROR;
}
MMRESULT
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PMMFUNCTION_TABLE FunctionTable;
+ PWAVEHDR_EXTENSION Extension;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Header );
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
- if ( ! FunctionTable->UnprepareWaveHeader )
- return MMSYSERR_NOTSUPPORTED;
+ SND_ASSERT( Header->reserved );
+ Extension = (PWAVEHDR_EXTENSION) Header->reserved;
+ FreeMemory(Extension);
- return WaveHeaderOperation(FunctionTable->UnprepareWaveHeader,
- SoundDeviceInstance,
- Header);
+ /* Configure the flags */
+ Header->dwFlags &= ~WHDR_PREPARED;
+
+ return MMSYSERR_NOERROR;
}
MMRESULT
-EnqueueWaveHeader(
+WriteWaveHeader(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN PWAVEHDR Header)
{
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
- if ( ! FunctionTable->SubmitWaveHeader )
+ if ( ! FunctionTable->CommitWaveBuffer )
return MMSYSERR_NOTSUPPORTED;
/*
VALIDATE_MMSYS_PARAMETER( Header->dwFlags & WHDR_PREPARED );
VALIDATE_MMSYS_PARAMETER( ! (Header->dwFlags & WHDR_INQUEUE) );
+ SanitizeWaveHeader(Header);
+
/* Clear the "done" flag for the buffer */
Header->dwFlags &= ~WHDR_DONE;
- Result = WaveHeaderOperation(FunctionTable->SubmitWaveHeader,
- SoundDeviceInstance,
- Header);
+ Result = CallSoundThread(SoundDeviceInstance,
+ EnqueueWaveHeader,
+ Header);
- if ( ! MMSUCCESS(Result) )
+ return Result;
+}
+
+
+/*
+ EnqueueWaveHeader
+ Put the header in the record/playback queue. This is performed within
+ the context of the sound thread, it must NEVER be called from another
+ thread.
+
+ CompleteWaveHeader
+ Set the header information to indicate that it has finished playing,
+ and return it to the client application. This again must be called
+ within the context of the sound thread.
+*/
+
+MMRESULT
+EnqueueWaveHeader(
+ PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PVOID Parameter)
+{
+ PWAVEHDR WaveHeader = (PWAVEHDR) Parameter;
+
+ VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
+ VALIDATE_MMSYS_PARAMETER( Parameter );
+
+ /* Initialise */
+ WaveHeader->lpNext = NULL;
+
+ /* Set the "in queue" flag */
+ WaveHeader->dwFlags |= WHDR_INQUEUE;
+
+ if ( ! SoundDeviceInstance->HeadWaveHeader )
+ {
+ /* This is the first header in the queue */
+ SND_TRACE(L"Enqueued first wave header\n");
+ SoundDeviceInstance->HeadWaveHeader = WaveHeader;
+ SoundDeviceInstance->TailWaveHeader = WaveHeader;
+
+ DoWaveStreaming(SoundDeviceInstance);
+ }
+ else
{
- return Result;
+ /* There are already queued headers - make this one the tail */
+ SND_TRACE(L"Enqueued next wave header\n");
+ SoundDeviceInstance->TailWaveHeader->lpNext = WaveHeader;
+ SoundDeviceInstance->TailWaveHeader = WaveHeader;
+
+ DoWaveStreaming(SoundDeviceInstance);
}
- /* Set the "in queue" flag if everything was OK */
- Header->dwFlags |= WHDR_INQUEUE;
+ DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
return MMSYSERR_NOERROR;
}
+
+VOID
+CompleteWaveHeader(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PWAVEHDR Header)
+{
+ PWAVEHDR PrevHdr = NULL, CurrHdr = NULL;
+ PWAVEHDR_EXTENSION Extension;
+ PSOUND_DEVICE SoundDevice;
+ MMDEVICE_TYPE DeviceType;
+ MMRESULT Result;
+
+ SND_TRACE(L"BUFFER COMPLETE :)\n");
+
+ // TODO: Set header flags?
+ // TODO: Call client
+ // TODO: Streaming
+
+ //DoWaveStreaming(SoundDeviceInstance);
+
+ Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
+ SND_ASSERT( MMSUCCESS(Result) );
+ Result = GetSoundDeviceType(SoundDevice, &DeviceType);
+ SND_ASSERT( MMSUCCESS(Result) );
+
+ Extension = (PWAVEHDR_EXTENSION)Header->reserved;
+ SND_ASSERT( Extension );
+
+ /* Remove the header from the queue, like so */
+ if ( SoundDeviceInstance->HeadWaveHeader == Header )
+ {
+ SoundDeviceInstance->HeadWaveHeader = Header->lpNext;
+
+ SND_TRACE(L"Dropping head node\n");
+
+ /* If nothing after the head, then there is no tail */
+ if ( Header->lpNext == NULL )
+ {
+ SND_TRACE(L"Dropping tail node\n");
+ SoundDeviceInstance->TailWaveHeader = NULL;
+ }
+ }
+ else
+ {
+ PrevHdr = NULL;
+ CurrHdr = SoundDeviceInstance->HeadWaveHeader;
+
+ SND_TRACE(L"Relinking nodes\n");
+
+ while ( CurrHdr != Header )
+ {
+ PrevHdr = CurrHdr;
+ CurrHdr = CurrHdr->lpNext;
+ SND_ASSERT( CurrHdr );
+ }
+
+ SND_ASSERT( PrevHdr );
+
+ PrevHdr->lpNext = CurrHdr->lpNext;
+
+ /* If this is the tail node, update the tail */
+ if ( Header->lpNext == NULL )
+ {
+ SND_TRACE(L"Updating tail node\n");
+ SoundDeviceInstance->TailWaveHeader = PrevHdr;
+ }
+ }
+
+ /* Make sure we're not using this as the current buffer any more, either! */
+/*
+ if ( SoundDeviceInstance->CurrentWaveHeader == Header )
+ {
+ SoundDeviceInstance->CurrentWaveHeader = Header->lpNext;
+ }
+*/
+
+ DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
+
+ SND_TRACE(L"Returning buffer to client...\n");
+
+ /* Update the header */
+ Header->dwFlags &= ~WHDR_INQUEUE;
+ Header->dwFlags |= WHDR_DONE;
+
+ if ( DeviceType == WAVE_IN_DEVICE_TYPE )
+ {
+ // FIXME: We won't be called on incomplete buffer!
+ Header->dwBytesRecorded = Extension->BytesCompleted;
+ }
+
+ /* Safe to do this without thread protection, as we're done with the header */
+ NotifyMmeClient(SoundDeviceInstance,
+ DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_DONE : WIM_DATA,
+ (DWORD) Header);
+}