reactos/sdk/lib/drivers/sound/mmebuddy/deviceinstance.c

369 lines
10 KiB
C

/*
* PROJECT: ReactOS Sound System "MME Buddy" Library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: lib/drivers/sound/mmebuddy/deviceinstance.c
*
* PURPOSE: Manages instances of sound devices.
*
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
*/
#include "precomp.h"
/*
Restrain ourselves from flooding the kernel device!
*/
#define SOUND_KERNEL_BUFFER_COUNT 10
#define SOUND_KERNEL_BUFFER_SIZE 16384
MMRESULT
AllocateSoundDeviceInstance(
OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
{
PSOUND_DEVICE_INSTANCE NewInstance;
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
/* Allocate memory for the new instance */
NewInstance = AllocateStruct(SOUND_DEVICE_INSTANCE);
if ( ! NewInstance )
return MMSYSERR_NOMEM;
/* Use default frame size */
NewInstance->FrameSize = SOUND_KERNEL_BUFFER_SIZE;
/* Use default buffer count */
NewInstance->BufferCount = SOUND_KERNEL_BUFFER_COUNT;
/* Provide the caller with the new instance pointer */
*SoundDeviceInstance = NewInstance;
return MMSYSERR_NOERROR;
}
VOID
FreeSoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
/*
Device is marked as invalid by now, but we can still do some sanity
checking.
*/
SND_ASSERT( SoundDeviceInstance->Thread == NULL );
ZeroMemory(SoundDeviceInstance, sizeof(SOUND_DEVICE_INSTANCE));
FreeMemory(SoundDeviceInstance);
}
BOOLEAN
IsValidSoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
PSOUND_DEVICE SoundDevice;
PSOUND_DEVICE_INSTANCE CurrentInstance;
if ( ! SoundDeviceInstance )
return FALSE;
/* GetSoundDeviceFromInstance would send us into a recursive loop... */
SoundDevice = SoundDeviceInstance->Device;
SND_ASSERT(SoundDevice);
CurrentInstance = SoundDevice->HeadInstance;
while ( CurrentInstance )
{
if ( CurrentInstance == SoundDeviceInstance )
return TRUE;
CurrentInstance = CurrentInstance->Next;
}
return FALSE;
}
MMRESULT
ListSoundDeviceInstance(
IN PSOUND_DEVICE SoundDevice,
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
SND_TRACE(L"Listing sound device instance\n");
if ( ! SoundDevice->HeadInstance )
{
/* First entry - assign to head and tail */
SoundDevice->HeadInstance = SoundDeviceInstance;
SoundDevice->TailInstance = SoundDeviceInstance;
}
else
{
/* Attach to the end */
SoundDevice->TailInstance->Next = SoundDeviceInstance;
SoundDevice->TailInstance = SoundDeviceInstance;
}
return MMSYSERR_NOERROR;
}
MMRESULT
UnlistSoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
MMRESULT Result;
PSOUND_DEVICE SoundDevice;
PSOUND_DEVICE_INSTANCE CurrentInstance, PreviousInstance;
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
SND_TRACE(L"Unlisting sound device instance\n");
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
SND_ASSERT( MMSUCCESS(Result) );
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
PreviousInstance = NULL;
CurrentInstance = SoundDevice->HeadInstance;
while ( CurrentInstance )
{
if ( CurrentInstance == SoundDeviceInstance )
{
if ( ! PreviousInstance )
{
/* This is the head node */
SoundDevice->HeadInstance = SoundDevice->HeadInstance->Next;
}
else
{
/* There are nodes before this one - cut ours out */
PreviousInstance->Next = CurrentInstance->Next;
}
if ( ! CurrentInstance->Next )
{
/* This is the tail node */
SoundDevice->TailInstance = PreviousInstance;
}
}
PreviousInstance = CurrentInstance;
CurrentInstance = CurrentInstance->Next;
}
return MMSYSERR_NOERROR;
}
MMRESULT
CreateSoundDeviceInstance(
IN PSOUND_DEVICE SoundDevice,
OUT PSOUND_DEVICE_INSTANCE* SoundDeviceInstance)
{
MMRESULT Result;
PMMFUNCTION_TABLE FunctionTable;
SND_TRACE(L"Creating a sound device instance\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance != NULL );
Result = AllocateSoundDeviceInstance(SoundDeviceInstance);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Get the "open" routine from the function table, and validate it */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
if ( ! MMSUCCESS(Result) )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
if ( FunctionTable->Open == NULL )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return MMSYSERR_NOTSUPPORTED;
}
/* Set up the members of the structure */
(*SoundDeviceInstance)->Next = NULL;
(*SoundDeviceInstance)->Device = SoundDevice;
(*SoundDeviceInstance)->Handle = NULL;
(*SoundDeviceInstance)->Thread = NULL;
(*SoundDeviceInstance)->WinMM.Handle = INVALID_HANDLE_VALUE;
(*SoundDeviceInstance)->WinMM.ClientCallback = 0;
(*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0;
(*SoundDeviceInstance)->WinMM.Flags = 0;
/* Initialise the members of the struct used by the sound thread */
(*SoundDeviceInstance)->HeadWaveHeader = NULL;
(*SoundDeviceInstance)->TailWaveHeader = NULL;
(*SoundDeviceInstance)->OutstandingBuffers = 0;
(*SoundDeviceInstance)->LoopsRemaining = 0;
/* Create the streaming thread (TODO - is this for wave only?) */
Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread);
if ( ! MMSUCCESS(Result) )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
/* Add the instance to the list */
Result = ListSoundDeviceInstance(SoundDevice, *SoundDeviceInstance);
if ( ! MMSUCCESS(Result) )
{
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
/* Try and open the device */
Result = FunctionTable->Open(SoundDevice, (&(*SoundDeviceInstance)->Handle));
if ( ! MMSUCCESS(Result) )
{
UnlistSoundDeviceInstance(*SoundDeviceInstance);
FreeSoundDeviceInstance(*SoundDeviceInstance);
return TranslateInternalMmResult(Result);
}
return MMSYSERR_NOERROR;
}
MMRESULT
DestroySoundDeviceInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
{
MMRESULT Result;
PMMFUNCTION_TABLE FunctionTable;
PSOUND_DEVICE SoundDevice;
PVOID Handle;
SND_TRACE(L"Destroying a sound device instance\n");
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Get the "close" routine from the function table, and validate it */
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
SND_ASSERT( FunctionTable->Close );
if ( FunctionTable->Close == NULL )
{
/* This indicates bad practice, really! If you can open, why not close?! */
return MMSYSERR_NOTSUPPORTED;
}
/* Stop the streaming thread */
if ( SoundDeviceInstance->Thread )
{
Result = DestroySoundThread(SoundDeviceInstance->Thread);
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
if ( ! MMSUCCESS(Result ) )
{
return TranslateInternalMmResult(Result);
}
}
/* Blank this out here */
SoundDeviceInstance->Thread = NULL;
/* Try and close the device */
Result = FunctionTable->Close(SoundDeviceInstance, Handle);
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
/* Drop it from the list */
Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
if ( ! MMSUCCESS(Result) )
return TranslateInternalMmResult(Result);
FreeSoundDeviceInstance(SoundDeviceInstance);
return MMSYSERR_NOERROR;
}
MMRESULT
DestroyAllSoundDeviceInstances(
IN PSOUND_DEVICE SoundDevice)
{
MMRESULT Result;
PSOUND_DEVICE_INSTANCE SoundDeviceInstance, NextDeviceInstance;
SoundDeviceInstance = SoundDevice->HeadInstance;
while ( SoundDeviceInstance )
{
NextDeviceInstance = SoundDeviceInstance->Next;
Result = DestroySoundDeviceInstance(SoundDeviceInstance);
SND_ASSERT( MMSUCCESS(Result) );
SoundDeviceInstance = NextDeviceInstance;
}
return MMSYSERR_NOERROR;
}
MMRESULT
GetSoundDeviceFromInstance(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
OUT PSOUND_DEVICE* SoundDevice)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( SoundDevice );
*SoundDevice = SoundDeviceInstance->Device;
return MMSYSERR_NOERROR;
}
MMRESULT
GetSoundDeviceInstanceHandle(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
OUT PVOID* Handle)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
VALIDATE_MMSYS_PARAMETER( Handle );
*Handle = SoundDeviceInstance->Handle;
return MMSYSERR_NOERROR;
}
MMRESULT
SetSoundDeviceInstanceMmeData(
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
IN HDRVR MmeHandle,
IN DWORD_PTR ClientCallback,
IN DWORD_PTR ClientCallbackData,
IN DWORD Flags)
{
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
SND_TRACE(L"Setting MME data - handle %x, callback %x, instance data %x, flags %x\n",
MmeHandle, ClientCallback, ClientCallbackData, Flags);
SoundDeviceInstance->WinMM.Handle = MmeHandle;
SoundDeviceInstance->WinMM.ClientCallback = ClientCallback;
SoundDeviceInstance->WinMM.ClientCallbackInstanceData = ClientCallbackData;
SoundDeviceInstance->WinMM.Flags = Flags;
return MMSYSERR_NOERROR;
}