mirror of
https://github.com/reactos/reactos.git
synced 2024-11-19 05:22:59 +00:00
356 lines
9.4 KiB
C
356 lines
9.4 KiB
C
/*
|
|
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: lib/drivers/sound/mmebuddy/devicelist.c
|
|
*
|
|
* PURPOSE: Manages lists of sound devices.
|
|
*
|
|
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
ULONG SoundDeviceCounts[SOUND_DEVICE_TYPES];
|
|
PSOUND_DEVICE SoundDeviceListHeads[SOUND_DEVICE_TYPES];
|
|
PSOUND_DEVICE SoundDeviceListTails[SOUND_DEVICE_TYPES];
|
|
|
|
/*
|
|
Handles the allocation and initialisation of a SOUND_DEVICE structure.
|
|
*/
|
|
MMRESULT
|
|
AllocateSoundDevice(
|
|
IN MMDEVICE_TYPE DeviceType,
|
|
OUT PSOUND_DEVICE* SoundDevice)
|
|
{
|
|
PSOUND_DEVICE NewDevice;
|
|
|
|
SND_ASSERT( IsValidSoundDeviceType(DeviceType) );
|
|
SND_ASSERT( SoundDevice );
|
|
|
|
SND_TRACE(L"Allocating a SOUND_DEVICE structure\n");
|
|
|
|
NewDevice = AllocateStruct(SOUND_DEVICE);
|
|
|
|
if ( ! NewDevice )
|
|
return MMSYSERR_NOMEM;
|
|
|
|
NewDevice->Type = DeviceType;
|
|
|
|
/* Return the new structure to the caller and report success */
|
|
*SoundDevice = NewDevice;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
Handles the cleanup and freeing of a SOUND_DEVICE structure.
|
|
*/
|
|
VOID
|
|
FreeSoundDevice(
|
|
IN PSOUND_DEVICE SoundDevice)
|
|
{
|
|
SND_ASSERT( SoundDevice );
|
|
|
|
SND_TRACE(L"Freeing a SOUND_DEVICE structure");
|
|
|
|
/* For safety the whole struct gets zeroed */
|
|
ZeroMemory(SoundDevice, sizeof(SOUND_DEVICE));
|
|
FreeMemory(SoundDevice);
|
|
}
|
|
|
|
/*
|
|
Returns the number of devices of the specified type which have been added
|
|
to the device lists. If an invalid device type is specified, the function
|
|
returns zero.
|
|
*/
|
|
ULONG
|
|
GetSoundDeviceCount(
|
|
IN MMDEVICE_TYPE DeviceType)
|
|
{
|
|
ULONG Index = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
|
|
|
|
if ( ! IsValidSoundDeviceType(DeviceType) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
SND_TRACE(L"Returning a count of %d devices\n", SoundDeviceCounts[Index]);
|
|
return SoundDeviceCounts[Index];
|
|
}
|
|
|
|
/*
|
|
Determines if a sound device structure pointer is valid, firstly by
|
|
ensuring that it is not NULL, and then by checking that the device itself
|
|
exists in one of the device lists.
|
|
*/
|
|
BOOLEAN
|
|
IsValidSoundDevice(
|
|
IN PSOUND_DEVICE SoundDevice)
|
|
{
|
|
UCHAR TypeIndex;
|
|
PSOUND_DEVICE CurrentDevice;
|
|
|
|
if ( ! SoundDevice )
|
|
return FALSE;
|
|
|
|
/* Go through all the device lists */
|
|
for ( TypeIndex = 0; TypeIndex < SOUND_DEVICE_TYPES; ++ TypeIndex )
|
|
{
|
|
CurrentDevice = SoundDeviceListHeads[TypeIndex];
|
|
|
|
while ( CurrentDevice )
|
|
{
|
|
if ( CurrentDevice == SoundDevice )
|
|
{
|
|
/* Found the device */
|
|
return TRUE;
|
|
}
|
|
|
|
CurrentDevice = CurrentDevice->Next;
|
|
}
|
|
}
|
|
|
|
/* If we get here, nothing was found */
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
Informs the MME-Buddy library that it should take ownership of a device.
|
|
The DevicePath is typically used for storing a device path (for subsequent
|
|
opening using CreateFile) but it can be a wide-string representing any
|
|
information that makes sense to your MME driver implementation.
|
|
|
|
MME components which operate solely in user-mode (for example, MIDI
|
|
loopback devices) won't need to communicate with a kernel-mode device,
|
|
so in these situations DevicePath is likely to be NULL.
|
|
|
|
Upon successful addition to the sound device list, the pointer to the new
|
|
device's SOUND_DEVICE structure is returned via SoundDevice.
|
|
*/
|
|
MMRESULT
|
|
ListSoundDevice(
|
|
IN MMDEVICE_TYPE DeviceType,
|
|
IN PVOID Identifier OPTIONAL,
|
|
OUT PSOUND_DEVICE* SoundDevice OPTIONAL)
|
|
{
|
|
MMRESULT Result;
|
|
PSOUND_DEVICE NewDevice;
|
|
UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
|
|
|
|
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
|
|
|
|
Result = AllocateSoundDevice(DeviceType, &NewDevice);
|
|
|
|
if ( ! MMSUCCESS(Result) )
|
|
{
|
|
SND_ERR(L"Failed to allocate SOUND_DEVICE structure\n");
|
|
return Result;
|
|
}
|
|
|
|
if ( ! SoundDeviceListHeads[TypeIndex] )
|
|
{
|
|
SND_TRACE(L"Putting first entry into device list %d\n", DeviceType);
|
|
SoundDeviceListHeads[TypeIndex] = NewDevice;
|
|
SoundDeviceListTails[TypeIndex] = NewDevice;
|
|
}
|
|
else
|
|
{
|
|
SND_TRACE(L"Putting another entry into device list %d\n", DeviceType);
|
|
SoundDeviceListTails[TypeIndex]->Next = NewDevice;
|
|
SoundDeviceListTails[TypeIndex] = NewDevice;
|
|
}
|
|
|
|
/* Add to the count */
|
|
++ SoundDeviceCounts[TypeIndex];
|
|
|
|
/* Set up the default function table */
|
|
SetSoundDeviceFunctionTable(NewDevice, NULL);
|
|
|
|
/* Set up other members of the structure */
|
|
NewDevice->Identifier = Identifier;
|
|
NewDevice->HeadInstance = NULL;
|
|
NewDevice->TailInstance = NULL;
|
|
|
|
/* Fill in the caller's PSOUND_DEVICE */
|
|
if ( SoundDevice )
|
|
{
|
|
*SoundDevice = NewDevice;
|
|
}
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
Removes a sound device from the list, and frees the memory associated
|
|
with its description.
|
|
*/
|
|
MMRESULT
|
|
UnlistSoundDevice(
|
|
IN MMDEVICE_TYPE DeviceType,
|
|
IN PSOUND_DEVICE SoundDevice)
|
|
{
|
|
PSOUND_DEVICE CurrentDevice, PreviousDevice;
|
|
|
|
UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
|
|
|
|
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
|
|
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
|
|
|
PreviousDevice = NULL;
|
|
CurrentDevice = SoundDeviceListHeads[TypeIndex];
|
|
|
|
while ( CurrentDevice )
|
|
{
|
|
if ( CurrentDevice == SoundDevice )
|
|
{
|
|
if ( ! PreviousDevice )
|
|
{
|
|
/* This is the head node */
|
|
SND_TRACE(L"Removing head node from device list %d\n", DeviceType);
|
|
SoundDeviceListHeads[TypeIndex] =
|
|
SoundDeviceListHeads[TypeIndex]->Next;
|
|
}
|
|
else
|
|
{
|
|
SND_TRACE(L"Removing node from device list %d\n", DeviceType);
|
|
/* There are nodes before this one - cut our device out */
|
|
PreviousDevice->Next = CurrentDevice->Next;
|
|
}
|
|
|
|
if ( ! CurrentDevice->Next )
|
|
{
|
|
/* This is the tail node */
|
|
SND_TRACE(L"Removing tail node from device list %d\n", DeviceType);
|
|
SoundDeviceListTails[TypeIndex] = PreviousDevice;
|
|
}
|
|
}
|
|
|
|
PreviousDevice = CurrentDevice;
|
|
CurrentDevice = CurrentDevice->Next;
|
|
}
|
|
|
|
/* Subtract from the count */
|
|
-- SoundDeviceCounts[TypeIndex];
|
|
|
|
/* Finally, free up the deleted entry */
|
|
FreeSoundDevice(SoundDevice);
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
Removes all devices from one of the device lists.
|
|
*/
|
|
MMRESULT
|
|
UnlistSoundDevices(
|
|
IN MMDEVICE_TYPE DeviceType)
|
|
{
|
|
UCHAR TypeIndex;
|
|
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
|
|
|
|
SND_TRACE(L"Unlisting all sound devices of type %d\n", DeviceType);
|
|
|
|
TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
|
|
|
|
/* Munch away at the head of the list until it's drained */
|
|
while ( SoundDeviceCounts[TypeIndex] > 0 )
|
|
{
|
|
MMRESULT Result;
|
|
Result = UnlistSoundDevice(DeviceType, SoundDeviceListHeads[TypeIndex]);
|
|
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
|
}
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
Removes all devices from all lists.
|
|
*/
|
|
VOID
|
|
UnlistAllSoundDevices()
|
|
{
|
|
MMDEVICE_TYPE Type;
|
|
|
|
SND_TRACE(L"Unlisting all sound devices\n");
|
|
|
|
for ( Type = MIN_SOUND_DEVICE_TYPE; Type <= MAX_SOUND_DEVICE_TYPE; ++ Type )
|
|
{
|
|
MMRESULT Result;
|
|
Result = UnlistSoundDevices(Type);
|
|
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
|
}
|
|
}
|
|
|
|
/*
|
|
Provides the caller with a pointer to its desired sound device, based on
|
|
the device type and index.
|
|
*/
|
|
MMRESULT
|
|
GetSoundDevice(
|
|
IN MMDEVICE_TYPE DeviceType,
|
|
IN DWORD DeviceIndex,
|
|
OUT PSOUND_DEVICE* SoundDevice)
|
|
{
|
|
UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
|
|
DWORD CurrentIndex = 0;
|
|
PSOUND_DEVICE CurrentDevice;
|
|
|
|
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
|
|
|
|
if ( DeviceIndex >= SoundDeviceCounts[TypeIndex] )
|
|
{
|
|
SND_ERR(L"Invalid device ID %d for type %d\n", DeviceIndex, DeviceType);
|
|
return MMSYSERR_BADDEVICEID;
|
|
}
|
|
|
|
CurrentDevice = SoundDeviceListHeads[TypeIndex];
|
|
|
|
/* Following the earlier checks, the index should be valid here. */
|
|
for ( CurrentIndex = 0; CurrentIndex != DeviceIndex; ++ CurrentIndex )
|
|
{
|
|
SND_ASSERT( CurrentDevice );
|
|
CurrentDevice = CurrentDevice->Next;
|
|
}
|
|
|
|
SND_TRACE(L"Returning sound device %x\n", CurrentDevice);
|
|
|
|
*SoundDevice = CurrentDevice;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
Provides the caller with the device path of the specified sound device.
|
|
This will normally be the path to a device provided by a kernel-mode
|
|
driver.
|
|
*/
|
|
MMRESULT
|
|
GetSoundDeviceIdentifier(
|
|
IN PSOUND_DEVICE SoundDevice,
|
|
OUT PVOID* Identifier)
|
|
{
|
|
VALIDATE_MMSYS_PARAMETER( SoundDevice );
|
|
VALIDATE_MMSYS_PARAMETER( Identifier );
|
|
|
|
/* The caller should not modify this! */
|
|
*Identifier = SoundDevice->Identifier;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*
|
|
Provides the caller with the device type of the specified sound device.
|
|
This will be, for example, WAVE_OUT_DEVICE_TYPE, WAVE_IN_DEVICE_TYPE ...
|
|
*/
|
|
MMRESULT
|
|
GetSoundDeviceType(
|
|
IN PSOUND_DEVICE SoundDevice,
|
|
OUT PMMDEVICE_TYPE DeviceType)
|
|
{
|
|
VALIDATE_MMSYS_PARAMETER( SoundDevice );
|
|
VALIDATE_MMSYS_PARAMETER( DeviceType );
|
|
|
|
*DeviceType = SoundDevice->Type;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|