mirror of
https://github.com/reactos/reactos.git
synced 2025-04-19 04:07:16 +00:00
Abandoning silverblade-audio branch.
General user-mode audio support libraries added. svn path=/trunk/; revision=39252
This commit is contained in:
parent
607f12562e
commit
5bc7ecd049
36 changed files with 4269 additions and 0 deletions
480
reactos/lib/drivers/sound/legacy/devname.c
Normal file
480
reactos/lib/drivers/sound/legacy/devname.c
Normal file
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Device naming & creation helper routines
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
25 May 2008 - Created
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <debug.h>
|
||||
|
||||
|
||||
/*
|
||||
Default device names
|
||||
|
||||
Just to keep things tidy, we define a structure to hold both the \\Device
|
||||
and \\DosDevices names, and then fill this structure with the default
|
||||
device names that can be found in NTDDSND.H
|
||||
*/
|
||||
|
||||
typedef struct _DEVICE_NAME_GROUP
|
||||
{
|
||||
PCWSTR DeviceName;
|
||||
PCWSTR DosDeviceName;
|
||||
} DEVICE_NAME_GROUP;
|
||||
|
||||
DEVICE_NAME_GROUP SoundDeviceNameBodies[6] =
|
||||
{
|
||||
{
|
||||
DD_WAVE_IN_DEVICE_NAME_U,
|
||||
DD_WAVE_IN_DOS_DEVICE_NAME_U
|
||||
},
|
||||
{
|
||||
DD_WAVE_OUT_DEVICE_NAME_U,
|
||||
DD_WAVE_OUT_DOS_DEVICE_NAME_U
|
||||
},
|
||||
{
|
||||
DD_MIDI_IN_DEVICE_NAME_U,
|
||||
DD_MIDI_IN_DOS_DEVICE_NAME_U
|
||||
},
|
||||
{
|
||||
DD_MIDI_OUT_DEVICE_NAME_U,
|
||||
DD_MIDI_OUT_DOS_DEVICE_NAME_U
|
||||
},
|
||||
{
|
||||
DD_MIX_DEVICE_NAME_U,
|
||||
DD_MIX_DOS_DEVICE_NAME_U
|
||||
},
|
||||
{
|
||||
DD_AUX_DEVICE_NAME_U,
|
||||
DD_AUX_DOS_DEVICE_NAME_U
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
ConstructDeviceName
|
||||
|
||||
This takes a wide-character string containing the device name body (for
|
||||
example, "\\Device\\WaveOut") and appends the device index, forming a
|
||||
string like "\\Device\\WaveOut0", and so on.
|
||||
|
||||
The resulting device name is a unicode string.
|
||||
*/
|
||||
|
||||
NTSTATUS
|
||||
ConstructDeviceName(
|
||||
IN PCWSTR Path,
|
||||
IN UCHAR Index,
|
||||
OUT PUNICODE_STRING DeviceName)
|
||||
{
|
||||
UNICODE_STRING UnicodePath;
|
||||
UNICODE_STRING UnicodeIndex;
|
||||
WCHAR IndexStringBuffer[5];
|
||||
USHORT Size;
|
||||
USHORT LastCharacterIndex;
|
||||
|
||||
/* Check for NULL parameters */
|
||||
if ( ( ! Path ) || ( ! DeviceName ) )
|
||||
{
|
||||
DPRINT("Unexpected NULL parameter");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Range-check */
|
||||
if ( Index >= SOUND_MAX_DEVICES )
|
||||
{
|
||||
DPRINT("Device index %d out of range", Index);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Initialise the unicode path string */
|
||||
RtlInitUnicodeString(&UnicodePath, Path);
|
||||
|
||||
/* Calculate the length to hold the full string */
|
||||
Size = UnicodePath.Length +
|
||||
sizeof(IndexStringBuffer) +
|
||||
sizeof(UNICODE_NULL);
|
||||
|
||||
/* Allocate memory for DeviceName */
|
||||
DeviceName->Buffer = ExAllocatePool(PagedPool, Size);
|
||||
DeviceName->MaximumLength = Size;
|
||||
|
||||
if ( ! DeviceName->Buffer )
|
||||
{
|
||||
DPRINT("Couldn't allocate memory for device name string");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* Copy the path */
|
||||
RtlCopyUnicodeString(DeviceName, &UnicodePath);
|
||||
|
||||
/* Convert Index to string and append */
|
||||
UnicodeIndex.Buffer = IndexStringBuffer;
|
||||
UnicodeIndex.MaximumLength = sizeof(IndexStringBuffer);
|
||||
|
||||
RtlIntegerToUnicodeString((ULONG)Index, 10, &UnicodeIndex);
|
||||
RtlAppendUnicodeStringToString(DeviceName, &UnicodeIndex);
|
||||
|
||||
/* Terminate the string */
|
||||
LastCharacterIndex = DeviceName->Length / sizeof(UNICODE_NULL);
|
||||
DeviceName->Buffer[LastCharacterIndex] = UNICODE_NULL;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
FreeUnicodeStringBuffer
|
||||
|
||||
A small helper routine to free a unicode string buffer, nullify the
|
||||
buffer and reset the lengths to zero.
|
||||
*/
|
||||
|
||||
VOID
|
||||
FreeUnicodeStringBuffer(IN PUNICODE_STRING String)
|
||||
{
|
||||
ASSERT(String != NULL);
|
||||
ASSERT(String->Buffer != NULL);
|
||||
|
||||
ExFreePool(String->Buffer);
|
||||
|
||||
String->Buffer = NULL;
|
||||
String->Length = 0;
|
||||
String->MaximumLength = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
GetDefaultSoundDeviceNameBodies
|
||||
|
||||
Simply accesses the SoundDeviceNameBodies struct defined earlier and
|
||||
fills the DeviceNameBody and DosDeviceNameBody parameters accordingly.
|
||||
|
||||
Basically a "safe" way to access the array and perform two assignments
|
||||
with one call, as this will assign the name and DOS name if a valid
|
||||
DeviceType is passed, otherwise it will fail with STATUS_INVALID_PARAMETER.
|
||||
*/
|
||||
|
||||
NTSTATUS
|
||||
GetDefaultSoundDeviceNameBodies(
|
||||
IN UCHAR DeviceType,
|
||||
OUT PCWSTR* DeviceNameBody,
|
||||
OUT PCWSTR* DosDeviceNameBody)
|
||||
{
|
||||
if ( ! VALID_SOUND_DEVICE_TYPE(DeviceType) )
|
||||
{
|
||||
DPRINT("Invalid device type");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if ( DeviceNameBody )
|
||||
{
|
||||
DPRINT("Reporting device name\n");
|
||||
*DeviceNameBody = SoundDeviceNameBodies[DeviceType].DeviceName;
|
||||
DPRINT("%ws\n", *DeviceNameBody);
|
||||
}
|
||||
|
||||
if ( DosDeviceNameBody )
|
||||
{
|
||||
DPRINT("Reporting DOS device name\n");
|
||||
*DosDeviceNameBody = SoundDeviceNameBodies[DeviceType].DosDeviceName;
|
||||
DPRINT("%ws\n", *DosDeviceNameBody);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ConstructSoundDeviceNames
|
||||
|
||||
Given two wide-character strings and a device index, convert these into
|
||||
two unicode strings with the index appended to the end.
|
||||
|
||||
This is intended for converting a device name and a DOS device name at
|
||||
the same time.
|
||||
*/
|
||||
|
||||
NTSTATUS
|
||||
ConstructSoundDeviceNames(
|
||||
IN PCWSTR DeviceNameBody,
|
||||
IN PCWSTR DosDeviceNameBody,
|
||||
IN UCHAR Index,
|
||||
OUT PUNICODE_STRING FullDeviceName,
|
||||
OUT PUNICODE_STRING FullDosDeviceName)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Check for NULL parameters */
|
||||
if ( ( ! DeviceNameBody ) || ( ! DosDeviceNameBody ) ||
|
||||
( ! FullDeviceName ) || ( ! FullDosDeviceName ) )
|
||||
{
|
||||
DPRINT("Unexpected NULL parameter");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Range-check */
|
||||
if ( Index >= SOUND_MAX_DEVICES )
|
||||
{
|
||||
DPRINT("Device %d exceeds maximum", Index);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = ConstructDeviceName(DeviceNameBody, Index, FullDeviceName);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
/* No need to clean up on failure here */
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = ConstructDeviceName(DosDeviceNameBody, Index, FullDosDeviceName);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
/* We need to free the string we successfully got earlier */
|
||||
FreeUnicodeStringBuffer(FullDeviceName);
|
||||
return Status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
CreateSoundDevice
|
||||
|
||||
Creates a device and symbolically-links a DOS device to this. Use this
|
||||
when you want to specify alternative device names to the defaults
|
||||
(eg: "\\Device\\MySoundDev" rather than "\\Device\\WaveOut")
|
||||
*/
|
||||
|
||||
NTSTATUS
|
||||
CreateSoundDevice(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN PCWSTR WideDeviceName,
|
||||
IN PCWSTR WideDosDeviceName,
|
||||
IN UCHAR Index,
|
||||
IN ULONG ExtensionSize,
|
||||
OUT PDEVICE_OBJECT* DeviceObject)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
UNICODE_STRING DeviceName;
|
||||
UNICODE_STRING DosDeviceName;
|
||||
|
||||
/* Check for NULL parameters */
|
||||
if ( ( ! DriverObject ) || ( ! DeviceObject ) ||
|
||||
( ! WideDeviceName ) || ( ! WideDosDeviceName ) )
|
||||
{
|
||||
DPRINT("Unexpected NULL parameter");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Range-check */
|
||||
if ( Index >= SOUND_MAX_DEVICES )
|
||||
{
|
||||
DPRINT("Device index %d exceeds maximum", Index);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Construct the device and DOS device names */
|
||||
Status = ConstructSoundDeviceNames(WideDeviceName,
|
||||
WideDosDeviceName,
|
||||
Index,
|
||||
&DeviceName,
|
||||
&DosDeviceName);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
DPRINT("Creating device %ws\n", DeviceName.Buffer);
|
||||
|
||||
/* Now create the device */
|
||||
Status = IoCreateDevice(DriverObject,
|
||||
ExtensionSize,
|
||||
&DeviceName,
|
||||
FILE_DEVICE_SOUND,
|
||||
0,
|
||||
FALSE,
|
||||
DeviceObject);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
/* These will have been allocated by ConstructSoundDeviceNames */
|
||||
FreeUnicodeStringBuffer(&DeviceName);
|
||||
FreeUnicodeStringBuffer(&DosDeviceName);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
DPRINT("Creating link %ws\n", DosDeviceName.Buffer);
|
||||
|
||||
/* Create a symbolic link for the DOS deviec name */
|
||||
Status = IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
IoDeleteDevice(*DeviceObject);
|
||||
|
||||
/* These will have been allocated by ConstructSoundDeviceNames */
|
||||
FreeUnicodeStringBuffer(&DeviceName);
|
||||
FreeUnicodeStringBuffer(&DosDeviceName);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
CreateSoundDeviceWithDefaultName
|
||||
|
||||
Similar to CreateSoundDevice, except this uses the default device names
|
||||
("\\Device\\WaveOut" etc.) based on the DeviceType parameter.
|
||||
*/
|
||||
|
||||
NTSTATUS
|
||||
CreateSoundDeviceWithDefaultName(
|
||||
IN PDRIVER_OBJECT DriverObject,
|
||||
IN UCHAR DeviceType,
|
||||
IN UCHAR Index,
|
||||
IN ULONG ExtensionSize,
|
||||
OUT PDEVICE_OBJECT* DeviceObject)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PCWSTR WideDeviceName = NULL;
|
||||
PCWSTR WideDosDeviceName = NULL;
|
||||
|
||||
/* Check for NULL parameters */
|
||||
if ( ( ! DriverObject ) || ( ! DeviceObject ) )
|
||||
{
|
||||
DPRINT("Unexpected NULL parameter");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Range-check */
|
||||
if ( Index >= SOUND_MAX_DEVICES )
|
||||
{
|
||||
DPRINT("Device index %d exceeds maximum", Index);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Look-up the default name based on the device type */
|
||||
Status = GetDefaultSoundDeviceNameBodies(DeviceType,
|
||||
&WideDeviceName,
|
||||
&WideDosDeviceName);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Go create the device! */
|
||||
Status = CreateSoundDevice(DriverObject,
|
||||
WideDeviceName,
|
||||
WideDosDeviceName,
|
||||
Index,
|
||||
ExtensionSize,
|
||||
DeviceObject);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
/* No clean-up to do */
|
||||
return Status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
DestroySoundDevice(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PCWSTR WideDosDeviceName,
|
||||
IN UCHAR Index)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING DosDeviceName;
|
||||
|
||||
/* Check for NULL parameters */
|
||||
if ( ( ! WideDosDeviceName ) || ( ! DeviceObject ) )
|
||||
{
|
||||
DPRINT("Unexpected NULL parameter");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Range-check */
|
||||
if ( Index >= SOUND_MAX_DEVICES )
|
||||
{
|
||||
DPRINT("Device %d exceeds maximum", Index);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Status = ConstructDeviceName(WideDosDeviceName, Index, &DosDeviceName);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
DPRINT("Deleting symlink %ws\n", DosDeviceName.Buffer);
|
||||
|
||||
Status = IoDeleteSymbolicLink(&DosDeviceName);
|
||||
DPRINT("Status of symlink deletion is 0x%08x\n", Status);
|
||||
/*
|
||||
ASSERT(NT_SUCCESS(Status));
|
||||
*/
|
||||
|
||||
IoDeleteDevice(DeviceObject);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
DestroySoundDeviceWithDefaultName(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN UCHAR DeviceType,
|
||||
IN UCHAR Index)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PCWSTR WideDosDeviceName = NULL;
|
||||
|
||||
/* Check for NULL parameters */
|
||||
if ( ( ! DeviceObject ) )
|
||||
{
|
||||
DPRINT("Unexpected NULL parameter");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Range-check */
|
||||
if ( Index >= SOUND_MAX_DEVICES )
|
||||
{
|
||||
DPRINT("Device index %d exceeds maximum", Index);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Look-up the default name based on the device type */
|
||||
Status = GetDefaultSoundDeviceNameBodies(DeviceType,
|
||||
NULL,
|
||||
&WideDosDeviceName);
|
||||
|
||||
if ( ! NT_SUCCESS(Status) )
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
DPRINT("DOS device name at %p\n", WideDosDeviceName);
|
||||
|
||||
DPRINT("DOS device name is based on %ws\n", WideDosDeviceName);
|
||||
|
||||
return DestroySoundDevice(DeviceObject, WideDosDeviceName, Index);
|
||||
}
|
66
reactos/lib/drivers/sound/legacy/hardware.c
Normal file
66
reactos/lib/drivers/sound/legacy/hardware.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Hardware interaction helper
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
25 May 2008 - Created
|
||||
|
||||
Notes:
|
||||
This uses some obsolete calls (eg: HalGetInterruptVector).
|
||||
Might be worth updating this in future to use some of the
|
||||
recommended functions like IoReportDetectedDevice and
|
||||
IoReportResourceForDetection...
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <debug.h>
|
||||
|
||||
/* NOTE: Disconnect using IoDisconnectInterrupt */
|
||||
|
||||
NTSTATUS
|
||||
LegacyAttachInterrupt(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN UCHAR Irq,
|
||||
IN PKSERVICE_ROUTINE ServiceRoutine,
|
||||
OUT PKINTERRUPT* InterruptObject)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULONG Vector;
|
||||
KIRQL IrqLevel;
|
||||
KAFFINITY Affinity;
|
||||
|
||||
DPRINT("Obtaining interrupt vector");
|
||||
|
||||
Vector = HalGetInterruptVector(Isa,
|
||||
0,
|
||||
Irq,
|
||||
Irq,
|
||||
&IrqLevel,
|
||||
&Affinity);
|
||||
|
||||
DPRINT("Vector %d", Vector);
|
||||
DPRINT("Connecting IRQ %d", Irq);
|
||||
|
||||
Status = IoConnectInterrupt(InterruptObject,
|
||||
ServiceRoutine,
|
||||
DeviceObject,
|
||||
NULL,
|
||||
Vector,
|
||||
IrqLevel,
|
||||
IrqLevel,
|
||||
Latched,
|
||||
FALSE,
|
||||
Affinity,
|
||||
FALSE);
|
||||
|
||||
if ( Status == STATUS_INVALID_PARAMETER )
|
||||
{
|
||||
Status = STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
10
reactos/lib/drivers/sound/legacy/legacy.rbuild
Normal file
10
reactos/lib/drivers/sound/legacy/legacy.rbuild
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="audioleg" type="staticlibrary" allowwarnings="true">
|
||||
<define name="__NTDRIVER__"/>
|
||||
<define name="KERNEL"/>
|
||||
<include base="soundblaster">.</include>
|
||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||
<file>devname.c</file>
|
||||
<file>hardware.c</file>
|
||||
</module>
|
60
reactos/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/auxiliary/auxMessage.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/sound/mmebuddy/auxiliary/auxMessage.c
|
||||
*
|
||||
* PURPOSE: Provides the auxMessage exported function, as required by
|
||||
* the MME API, for auxiliary device support.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Standard MME driver entry-point for messages relating to auxiliary devices.
|
||||
*/
|
||||
APIENTRY DWORD
|
||||
auxMessage(
|
||||
DWORD DeviceId,
|
||||
DWORD Message,
|
||||
DWORD PrivateHandle,
|
||||
DWORD Parameter1,
|
||||
DWORD Parameter2)
|
||||
{
|
||||
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
AcquireEntrypointMutex(AUX_DEVICE_TYPE);
|
||||
|
||||
SND_TRACE(L"auxMessage - Message type %d\n", Message);
|
||||
|
||||
switch ( Message )
|
||||
{
|
||||
case AUXDM_GETNUMDEVS :
|
||||
{
|
||||
Result = GetSoundDeviceCount(AUX_DEVICE_TYPE);
|
||||
break;
|
||||
}
|
||||
|
||||
case AUXDM_GETDEVCAPS :
|
||||
{
|
||||
Result = MmeGetSoundDeviceCapabilities(AUX_DEVICE_TYPE,
|
||||
DeviceId,
|
||||
(PVOID) Parameter1,
|
||||
Parameter2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SND_TRACE(L"auxMessage returning MMRESULT %d\n", Result);
|
||||
|
||||
ReleaseEntrypointMutex(AUX_DEVICE_TYPE);
|
||||
|
||||
return Result;
|
||||
}
|
101
reactos/lib/drivers/sound/mmebuddy/capabilities.c
Normal file
101
reactos/lib/drivers/sound/mmebuddy/capabilities.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/capabilities.c
|
||||
*
|
||||
* PURPOSE: Queries sound devices for their capabilities.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Obtains the capabilities of a sound device. This routine ensures that the
|
||||
supplied CapabilitiesSize parameter at least meets the minimum size of the
|
||||
relevant capabilities structure.
|
||||
|
||||
Ultimately, it will call the GetCapabilities function specified in the
|
||||
sound device's function table. Note that there are several of these, in a
|
||||
union. This is simply to avoid manually typecasting when implementing the
|
||||
functions.
|
||||
*/
|
||||
MMRESULT
|
||||
GetSoundDeviceCapabilities(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
OUT PVOID Capabilities,
|
||||
IN DWORD CapabilitiesSize)
|
||||
{
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
PMMFUNCTION_TABLE FunctionTable;
|
||||
BOOLEAN GoodSize = FALSE;
|
||||
MMRESULT Result;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
||||
VALIDATE_MMSYS_PARAMETER( Capabilities );
|
||||
VALIDATE_MMSYS_PARAMETER( CapabilitiesSize > 0 );
|
||||
|
||||
/* Obtain the device type */
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
/* Obtain the function table */
|
||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
/* Check that the capabilities structure is of a valid size */
|
||||
switch ( DeviceType )
|
||||
{
|
||||
case WAVE_OUT_DEVICE_TYPE :
|
||||
{
|
||||
GoodSize = CapabilitiesSize >= sizeof(WAVEOUTCAPS);
|
||||
break;
|
||||
}
|
||||
case WAVE_IN_DEVICE_TYPE :
|
||||
{
|
||||
GoodSize = CapabilitiesSize >= sizeof(WAVEINCAPS);
|
||||
break;
|
||||
}
|
||||
case MIDI_OUT_DEVICE_TYPE :
|
||||
{
|
||||
GoodSize = CapabilitiesSize >= sizeof(MIDIOUTCAPS);
|
||||
break;
|
||||
}
|
||||
case MIDI_IN_DEVICE_TYPE :
|
||||
{
|
||||
GoodSize = CapabilitiesSize >= sizeof(MIDIINCAPS);
|
||||
break;
|
||||
}
|
||||
/* TODO: Others... */
|
||||
default :
|
||||
{
|
||||
SND_ASSERT(FALSE);
|
||||
}
|
||||
};
|
||||
|
||||
if ( ! GoodSize )
|
||||
{
|
||||
SND_ERR(L"Device capabilities structure too small\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
/* Call the "get capabilities" function within the function table */
|
||||
SND_ASSERT( FunctionTable->GetCapabilities );
|
||||
|
||||
if ( ! FunctionTable->GetCapabilities )
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
return FunctionTable->GetCapabilities(SoundDevice,
|
||||
Capabilities,
|
||||
CapabilitiesSize);
|
||||
}
|
317
reactos/lib/drivers/sound/mmebuddy/deviceinstance.c
Normal file
317
reactos/lib/drivers/sound/mmebuddy/deviceinstance.c
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* 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 <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
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;
|
||||
|
||||
/* Provide the caller with the new instance pointer */
|
||||
*SoundDeviceInstance = NewInstance;
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
VOID
|
||||
FreeSoundDeviceInstance(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
||||
{
|
||||
/* This won't work as the device is no longer valid by this point! */
|
||||
/*SND_ASSERT( IsValidSoundDeviceInstance(SoundDeviceInstance) );*/
|
||||
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) );
|
||||
|
||||
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;
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
/* Bad practice, really! If you can open, why not close?! */
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
/* Try and close the device */
|
||||
Result = FunctionTable->Close(SoundDeviceInstance, Handle);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
/* Drop it from the list */
|
||||
Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
FreeSoundDeviceInstance(SoundDeviceInstance);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
DestroyAllSoundDeviceInstances(
|
||||
IN PSOUND_DEVICE SoundDevice)
|
||||
{
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
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 ClientCallback,
|
||||
IN DWORD 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;
|
||||
}
|
360
reactos/lib/drivers/sound/mmebuddy/devicelist.c
Normal file
360
reactos/lib/drivers/sound/mmebuddy/devicelist.c
Normal file
|
@ -0,0 +1,360 @@
|
|||
/*
|
||||
* 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 <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.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;
|
||||
}
|
60
reactos/lib/drivers/sound/mmebuddy/functiontable.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/functiontable.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/functiontable.c
|
||||
*
|
||||
* PURPOSE: Routes function calls through a function table, calling
|
||||
* implementation-defined routines or a default function, depending
|
||||
* on configuration.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Attaches a function table to a sound device. Any NULL entries in this
|
||||
table are automatically set to point to a default routine to handle
|
||||
the appropriate function. If NULL is passed as the function table itself,
|
||||
the entire function table will use only the default routines.
|
||||
*/
|
||||
MMRESULT
|
||||
SetSoundDeviceFunctionTable(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
IN PMMFUNCTION_TABLE FunctionTable OPTIONAL)
|
||||
{
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
||||
|
||||
/* Zero out the existing function table (if present) */
|
||||
ZeroMemory(&SoundDevice->FunctionTable, sizeof(MMFUNCTION_TABLE));
|
||||
|
||||
if ( FunctionTable )
|
||||
{
|
||||
/* Fill in the client-supplied functions */
|
||||
CopyMemory(&SoundDevice->FunctionTable,
|
||||
FunctionTable,
|
||||
sizeof(MMFUNCTION_TABLE));
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
Retrieves the function table for a sound device, as previously set using
|
||||
SetSoundDeviceFunctionTable.
|
||||
*/
|
||||
MMRESULT
|
||||
GetSoundDeviceFunctionTable(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
OUT PMMFUNCTION_TABLE* FunctionTable)
|
||||
{
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
||||
VALIDATE_MMSYS_PARAMETER( FunctionTable );
|
||||
|
||||
*FunctionTable = &SoundDevice->FunctionTable;
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
134
reactos/lib/drivers/sound/mmebuddy/kernel.c
Normal file
134
reactos/lib/drivers/sound/mmebuddy/kernel.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/kernel.c
|
||||
*
|
||||
* PURPOSE: Routines assisting with device I/O between user-mode and
|
||||
* kernel-mode.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Wraps around CreateFile in order to provide a simpler interface tailored
|
||||
towards sound driver support code. This simply takes a device path and
|
||||
opens the device in either read-only mode, or read/write mode (depending on
|
||||
the ReadOnly parameter).
|
||||
|
||||
If the device is opened in read/write mode, it is opened for overlapped I/O.
|
||||
*/
|
||||
MMRESULT
|
||||
OpenKernelSoundDeviceByName(
|
||||
IN PWSTR DevicePath,
|
||||
IN BOOLEAN ReadOnly,
|
||||
OUT PHANDLE Handle)
|
||||
{
|
||||
DWORD AccessRights;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( DevicePath );
|
||||
VALIDATE_MMSYS_PARAMETER( Handle );
|
||||
|
||||
AccessRights = ReadOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE;
|
||||
|
||||
SND_TRACE(L"OpenKernelSoundDeviceByName: %wS\n", DevicePath);
|
||||
*Handle = CreateFile(DevicePath,
|
||||
AccessRights,
|
||||
FILE_SHARE_WRITE, /* FIXME? Should be read also? */
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
ReadOnly ? 0 : FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
|
||||
if ( *Handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
SND_ERR(L"CreateFile filed - winerror %d\n", GetLastError());
|
||||
return Win32ErrorToMmResult(GetLastError());
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Just a wrapped around CloseHandle.
|
||||
*/
|
||||
MMRESULT
|
||||
CloseKernelSoundDevice(
|
||||
IN HANDLE Handle)
|
||||
{
|
||||
VALIDATE_MMSYS_PARAMETER( Handle );
|
||||
|
||||
CloseHandle(Handle);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
This is a wrapper around DeviceIoControl which provides control over
|
||||
instantiated sound devices. It waits for I/O to complete (since an
|
||||
instantiated sound device is opened in overlapped mode, this is necessary).
|
||||
*/
|
||||
MMRESULT
|
||||
SyncOverlappedDeviceIoControl(
|
||||
IN HANDLE Handle,
|
||||
IN DWORD IoControlCode,
|
||||
IN LPVOID InBuffer,
|
||||
IN DWORD InBufferSize,
|
||||
OUT LPVOID OutBuffer,
|
||||
IN DWORD OutBufferSize,
|
||||
OUT LPDWORD BytesTransferred OPTIONAL)
|
||||
{
|
||||
OVERLAPPED Overlapped;
|
||||
BOOLEAN IoResult;
|
||||
DWORD Transferred;
|
||||
|
||||
/* Overlapped I/O is done here - this is used for waiting for completion */
|
||||
ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
|
||||
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
if ( ! Overlapped.hEvent )
|
||||
return Win32ErrorToMmResult(GetLastError());
|
||||
|
||||
/* Talk to the device */
|
||||
IoResult = DeviceIoControl(Handle,
|
||||
IoControlCode,
|
||||
InBuffer,
|
||||
InBufferSize,
|
||||
OutBuffer,
|
||||
OutBufferSize,
|
||||
NULL,
|
||||
&Overlapped);
|
||||
|
||||
/* If failure occurs, make sure it's not just due to the overlapped I/O */
|
||||
if ( ! IoResult )
|
||||
{
|
||||
if ( GetLastError() != ERROR_IO_PENDING )
|
||||
{
|
||||
CloseHandle(Overlapped.hEvent);
|
||||
return Win32ErrorToMmResult(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the I/O to complete */
|
||||
IoResult = GetOverlappedResult(Handle,
|
||||
&Overlapped,
|
||||
&Transferred,
|
||||
TRUE);
|
||||
|
||||
/* Don't need this any more */
|
||||
CloseHandle(Overlapped.hEvent);
|
||||
|
||||
if ( ! IoResult )
|
||||
return Win32ErrorToMmResult(GetLastError());
|
||||
|
||||
if ( BytesTransferred )
|
||||
*BytesTransferred = Transferred;
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
60
reactos/lib/drivers/sound/mmebuddy/midi/midMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/midi/midMessage.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/sound/mmebuddy/midi/midMessage.c
|
||||
*
|
||||
* PURPOSE: Provides the midMessage exported function, as required by
|
||||
* the MME API, for MIDI input device support.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Standard MME driver entry-point for messages relating to MIDI input.
|
||||
*/
|
||||
APIENTRY DWORD
|
||||
midMessage(
|
||||
DWORD DeviceId,
|
||||
DWORD Message,
|
||||
DWORD PrivateHandle,
|
||||
DWORD Parameter1,
|
||||
DWORD Parameter2)
|
||||
{
|
||||
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
AcquireEntrypointMutex(MIDI_IN_DEVICE_TYPE);
|
||||
|
||||
SND_TRACE(L"midMessage - Message type %d\n", Message);
|
||||
|
||||
switch ( Message )
|
||||
{
|
||||
case MIDM_GETNUMDEVS :
|
||||
{
|
||||
Result = GetSoundDeviceCount(MIDI_IN_DEVICE_TYPE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MIDM_GETDEVCAPS :
|
||||
{
|
||||
Result = MmeGetSoundDeviceCapabilities(MIDI_IN_DEVICE_TYPE,
|
||||
DeviceId,
|
||||
(PVOID) Parameter1,
|
||||
Parameter2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SND_TRACE(L"midMessage returning MMRESULT %d\n", Result);
|
||||
|
||||
ReleaseEntrypointMutex(MIDI_IN_DEVICE_TYPE);
|
||||
|
||||
return Result;
|
||||
}
|
60
reactos/lib/drivers/sound/mmebuddy/midi/modMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/midi/modMessage.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/sound/mmebuddy/midi/modMessage.c
|
||||
*
|
||||
* PURPOSE: Provides the modMessage exported function, as required by
|
||||
* the MME API, for MIDI output device support.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Standard MME driver entry-point for messages relating to MIDI output.
|
||||
*/
|
||||
APIENTRY DWORD
|
||||
modMessage(
|
||||
DWORD DeviceId,
|
||||
DWORD Message,
|
||||
DWORD PrivateHandle,
|
||||
DWORD Parameter1,
|
||||
DWORD Parameter2)
|
||||
{
|
||||
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
AcquireEntrypointMutex(MIDI_OUT_DEVICE_TYPE);
|
||||
|
||||
SND_TRACE(L"modMessage - Message type %d\n", Message);
|
||||
|
||||
switch ( Message )
|
||||
{
|
||||
case MODM_GETNUMDEVS :
|
||||
{
|
||||
Result = GetSoundDeviceCount(MIDI_OUT_DEVICE_TYPE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MODM_GETDEVCAPS :
|
||||
{
|
||||
Result = MmeGetSoundDeviceCapabilities(MIDI_OUT_DEVICE_TYPE,
|
||||
DeviceId,
|
||||
(PVOID) Parameter1,
|
||||
Parameter2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SND_TRACE(L"modMessage returning MMRESULT %d\n", Result);
|
||||
|
||||
ReleaseEntrypointMutex(MIDI_OUT_DEVICE_TYPE);
|
||||
|
||||
return Result;
|
||||
}
|
60
reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c
Normal file
60
reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/sound/mmebuddy/mixer/mxdMessage.c
|
||||
*
|
||||
* PURPOSE: Provides the mxdMessage exported function, as required by
|
||||
* the MME API, for mixer device support.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Standard MME driver entry-point for messages relating to mixers.
|
||||
*/
|
||||
APIENTRY DWORD
|
||||
mxdMessage(
|
||||
DWORD DeviceId,
|
||||
DWORD Message,
|
||||
DWORD PrivateHandle,
|
||||
DWORD Parameter1,
|
||||
DWORD Parameter2)
|
||||
{
|
||||
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
AcquireEntrypointMutex(MIXER_DEVICE_TYPE);
|
||||
|
||||
SND_TRACE(L"mxdMessage - Message type %d\n", Message);
|
||||
|
||||
switch ( Message )
|
||||
{
|
||||
case MXDM_GETNUMDEVS :
|
||||
{
|
||||
Result = GetSoundDeviceCount(MIXER_DEVICE_TYPE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_GETDEVCAPS :
|
||||
{
|
||||
Result = MmeGetSoundDeviceCapabilities(MIXER_DEVICE_TYPE,
|
||||
DeviceId,
|
||||
(PVOID) Parameter1,
|
||||
Parameter2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SND_TRACE(L"mxdMessage returning MMRESULT %d\n", Result);
|
||||
|
||||
ReleaseEntrypointMutex(MIXER_DEVICE_TYPE);
|
||||
|
||||
return Result;
|
||||
}
|
31
reactos/lib/drivers/sound/mmebuddy/mmebuddy.rbuild
Normal file
31
reactos/lib/drivers/sound/mmebuddy/mmebuddy.rbuild
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="mmebuddy" type="staticlibrary" allowwarnings="false" unicode="yes">
|
||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||
<define name="DEBUG_NT4">1</define>
|
||||
<file>capabilities.c</file>
|
||||
<file>devicelist.c</file>
|
||||
<file>deviceinstance.c</file>
|
||||
<file>functiontable.c</file>
|
||||
<file>mmewrap.c</file>
|
||||
<file>reentrancy.c</file>
|
||||
<file>utility.c</file>
|
||||
<file>kernel.c</file>
|
||||
<file>thread.c</file>
|
||||
<directory name="wave">
|
||||
<file>widMessage.c</file>
|
||||
<file>wodMessage.c</file>
|
||||
<file>format.c</file>
|
||||
<file>header.c</file>
|
||||
</directory>
|
||||
<directory name="midi">
|
||||
<file>midMessage.c</file>
|
||||
<file>modMessage.c</file>
|
||||
</directory>
|
||||
<directory name="mixer">
|
||||
<file>mxdMessage.c</file>
|
||||
</directory>
|
||||
<directory name="auxiliary">
|
||||
<file>auxMessage.c</file>
|
||||
</directory>
|
||||
</module>
|
183
reactos/lib/drivers/sound/mmebuddy/mmewrap.c
Normal file
183
reactos/lib/drivers/sound/mmebuddy/mmewrap.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/mmewrap.c
|
||||
*
|
||||
* PURPOSE: Interface between MME functions and MME Buddy's own.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Call the client application when something interesting happens (MME API
|
||||
defines "interesting things" as device open, close, and buffer
|
||||
completion.)
|
||||
*/
|
||||
VOID
|
||||
NotifyMmeClient(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN DWORD Message,
|
||||
IN DWORD Parameter)
|
||||
{
|
||||
SND_ASSERT( SoundDeviceInstance );
|
||||
|
||||
SND_TRACE(L"MME client callback - message %d, parameter %d\n",
|
||||
(int) Message,
|
||||
(int) Parameter);
|
||||
|
||||
if ( SoundDeviceInstance->WinMM.ClientCallback )
|
||||
{
|
||||
DriverCallback(SoundDeviceInstance->WinMM.ClientCallback,
|
||||
HIWORD(SoundDeviceInstance->WinMM.Flags),
|
||||
SoundDeviceInstance->WinMM.Handle,
|
||||
Message,
|
||||
SoundDeviceInstance->WinMM.ClientCallbackInstanceData,
|
||||
Parameter,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This is a helper function to alleviate some of the repetition involved with
|
||||
implementing the various MME message functions.
|
||||
*/
|
||||
MMRESULT
|
||||
MmeGetSoundDeviceCapabilities(
|
||||
IN MMDEVICE_TYPE DeviceType,
|
||||
IN DWORD DeviceId,
|
||||
IN PVOID Capabilities,
|
||||
IN DWORD CapabilitiesSize)
|
||||
{
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
MMRESULT Result;
|
||||
|
||||
SND_TRACE(L"MME *_GETCAPS for device %d of type %d\n", DeviceId, DeviceType);
|
||||
|
||||
/* FIXME: Validate device type and ID */
|
||||
VALIDATE_MMSYS_PARAMETER( Capabilities );
|
||||
VALIDATE_MMSYS_PARAMETER( CapabilitiesSize > 0 );
|
||||
|
||||
/* Our parameter checks are done elsewhere */
|
||||
Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return Result;
|
||||
|
||||
return GetSoundDeviceCapabilities(SoundDevice,
|
||||
Capabilities,
|
||||
CapabilitiesSize);
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
MmeOpenWaveDevice(
|
||||
IN MMDEVICE_TYPE DeviceType,
|
||||
IN DWORD DeviceId,
|
||||
IN LPWAVEOPENDESC OpenParameters,
|
||||
IN DWORD Flags,
|
||||
OUT DWORD* PrivateHandle)
|
||||
{
|
||||
MMRESULT Result;
|
||||
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
||||
LPWAVEFORMATEX Format;
|
||||
|
||||
SND_TRACE(L"Opening wave device (WIDM_OPEN / WODM_OPEN)");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) ); /* FIXME? wave in too? */
|
||||
VALIDATE_MMSYS_PARAMETER( OpenParameters );
|
||||
|
||||
Format = OpenParameters->lpFormat;
|
||||
|
||||
Result = GetSoundDevice(DeviceType, DeviceId, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
/* Does this device support the format? */
|
||||
Result = QueryWaveDeviceFormatSupport(SoundDevice, Format, sizeof(WAVEFORMATEX));
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Format not supported\n");
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
/* If the caller just wanted to know if a format is supported, end here */
|
||||
if ( Flags & WAVE_FORMAT_QUERY )
|
||||
return MMSYSERR_NOERROR;
|
||||
|
||||
/* Check that winmm gave us a private handle to fill */
|
||||
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
|
||||
|
||||
/* Create a sound device instance and open the sound device */
|
||||
Result = CreateSoundDeviceInstance(SoundDevice, &SoundDeviceInstance);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
Result = SetWaveDeviceFormat(SoundDeviceInstance, Format, sizeof(WAVEFORMATEX));
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
/* TODO: Destroy sound instance */
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
/* Store the device instance pointer in the private handle - is DWORD safe here? */
|
||||
*PrivateHandle = (DWORD) SoundDeviceInstance;
|
||||
|
||||
/* Store the additional information we were given - FIXME: Need flags! */
|
||||
SetSoundDeviceInstanceMmeData(SoundDeviceInstance,
|
||||
(HDRVR)OpenParameters->hWave,
|
||||
OpenParameters->dwCallback,
|
||||
OpenParameters->dwInstance,
|
||||
Flags);
|
||||
|
||||
/* Let the application know the device is open */
|
||||
ReleaseEntrypointMutex(DeviceType);
|
||||
NotifyMmeClient(SoundDeviceInstance,
|
||||
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_OPEN : WIM_OPEN,
|
||||
0);
|
||||
|
||||
AcquireEntrypointMutex(DeviceType);
|
||||
|
||||
SND_TRACE(L"Wave device now open\n");
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
MmeCloseDevice(
|
||||
IN DWORD PrivateHandle)
|
||||
{
|
||||
MMRESULT Result;
|
||||
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
|
||||
SND_TRACE(L"Closing wave device (WIDM_CLOSE / WODM_CLOSE)\n");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
|
||||
SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
ReleaseEntrypointMutex(DeviceType);
|
||||
NotifyMmeClient(SoundDeviceInstance,
|
||||
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE,
|
||||
0);
|
||||
AcquireEntrypointMutex(DeviceType);
|
||||
|
||||
Result = DestroySoundDeviceInstance(SoundDeviceInstance);
|
||||
|
||||
return Result;
|
||||
}
|
107
reactos/lib/drivers/sound/mmebuddy/reentrancy.c
Normal file
107
reactos/lib/drivers/sound/mmebuddy/reentrancy.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/sound/mmebuddy/reentrancy.c
|
||||
*
|
||||
* PURPOSE: Provides entry-point mutex guards.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
HANDLE EntrypointMutexes[SOUND_DEVICE_TYPES];
|
||||
|
||||
/*
|
||||
Creates a set of mutexes which are used for the purpose of guarding the
|
||||
device-type specific module entry-points. If any of these fail creation,
|
||||
all of them will be destroyed and the failure reported.
|
||||
*/
|
||||
MMRESULT
|
||||
InitEntrypointMutexes()
|
||||
{
|
||||
UCHAR i;
|
||||
MMRESULT Result = MMSYSERR_NOERROR;
|
||||
|
||||
/* Blank all entries ni the table first */
|
||||
for ( i = 0; i < SOUND_DEVICE_TYPES; ++ i )
|
||||
{
|
||||
EntrypointMutexes[i] = NULL;
|
||||
}
|
||||
|
||||
/* Now create the mutexes */
|
||||
for ( i = 0; i < SOUND_DEVICE_TYPES; ++ i )
|
||||
{
|
||||
EntrypointMutexes[i] = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
if ( ! EntrypointMutexes[i] )
|
||||
{
|
||||
Result = Win32ErrorToMmResult(GetLastError());
|
||||
|
||||
/* Clean up any mutexes we successfully created */
|
||||
CleanupEntrypointMutexes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/*
|
||||
Cleans up any of the entry-point guard mutexes. This will only close the
|
||||
handles of mutexes which have been created, making it safe for use as a
|
||||
cleanup routine even within the InitEntrypointMutexes routine above.
|
||||
*/
|
||||
VOID
|
||||
CleanupEntrypointMutexes()
|
||||
{
|
||||
UCHAR i;
|
||||
|
||||
/* Only clean up a mutex if it actually exists */
|
||||
for ( i = 0; i < SOUND_DEVICE_TYPES; ++ i )
|
||||
{
|
||||
if ( EntrypointMutexes[i] )
|
||||
{
|
||||
CloseHandle(EntrypointMutexes[i]);
|
||||
EntrypointMutexes[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Grabs an entry-point mutex.
|
||||
*/
|
||||
VOID
|
||||
AcquireEntrypointMutex(
|
||||
IN MMDEVICE_TYPE DeviceType)
|
||||
{
|
||||
UCHAR i;
|
||||
|
||||
SND_ASSERT( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
|
||||
i = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
|
||||
|
||||
SND_ASSERT( EntrypointMutexes[i] );
|
||||
|
||||
WaitForSingleObject(EntrypointMutexes[i], INFINITE);
|
||||
}
|
||||
|
||||
/*
|
||||
Releases an entry-point mutex.
|
||||
*/
|
||||
VOID
|
||||
ReleaseEntrypointMutex(
|
||||
IN MMDEVICE_TYPE DeviceType)
|
||||
{
|
||||
UCHAR i;
|
||||
|
||||
SND_ASSERT( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
|
||||
i = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
|
||||
|
||||
SND_ASSERT( EntrypointMutexes[i] );
|
||||
|
||||
ReleaseMutex(EntrypointMutexes[i]);
|
||||
}
|
227
reactos/lib/drivers/sound/mmebuddy/thread.c
Normal file
227
reactos/lib/drivers/sound/mmebuddy/thread.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/thread.c
|
||||
*
|
||||
* PURPOSE: Multimedia thread management
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
DWORD WINAPI
|
||||
SoundThreadMain(
|
||||
IN LPVOID lpParameter OPTIONAL)
|
||||
{
|
||||
PSOUND_THREAD Thread = (PSOUND_THREAD) lpParameter;
|
||||
|
||||
SND_TRACE(L"SoundThread running :)\n");
|
||||
|
||||
/* Callers will wait for us to be ready */
|
||||
Thread->Running = TRUE;
|
||||
SetEvent(Thread->Events.Ready);
|
||||
|
||||
while ( Thread->Running )
|
||||
{
|
||||
DWORD WaitResult;
|
||||
|
||||
/* Wait for a request, or an I/O completion */
|
||||
WaitResult = WaitForSingleObjectEx(Thread->Events.Request, INFINITE, TRUE);
|
||||
SND_TRACE(L"SoundThread - Came out of waiting\n");
|
||||
|
||||
if ( WaitResult == WAIT_OBJECT_0 )
|
||||
{
|
||||
SND_TRACE(L"SoundThread - Processing request\n");
|
||||
|
||||
if ( Thread->Request.Handler )
|
||||
{
|
||||
Thread->Request.Result = Thread->Request.Handler(Thread->Request.SoundDeviceInstance,
|
||||
Thread->Request.Parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread->Request.Result = MMSYSERR_ERROR;
|
||||
}
|
||||
|
||||
/* Announce completion of the request */
|
||||
SetEvent(Thread->Events.Done);
|
||||
/* Accept new requests */
|
||||
SetEvent(Thread->Events.Ready);
|
||||
}
|
||||
else if ( WaitResult == WAIT_IO_COMPLETION )
|
||||
{
|
||||
SND_TRACE(L"SoundThread - Processing IO completion\n");
|
||||
/* TODO */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This should not happen! */
|
||||
SND_ASSERT(FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
CreateSoundThreadEvents(
|
||||
OUT HANDLE* ReadyEvent,
|
||||
OUT HANDLE* RequestEvent,
|
||||
OUT HANDLE* DoneEvent)
|
||||
{
|
||||
BOOL ok;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( ReadyEvent );
|
||||
VALIDATE_MMSYS_PARAMETER( RequestEvent );
|
||||
VALIDATE_MMSYS_PARAMETER( DoneEvent );
|
||||
|
||||
SND_TRACE(L"Creating thread events\n");
|
||||
|
||||
/* Initialise these so we can identify them upon failure */
|
||||
*ReadyEvent = *RequestEvent = *DoneEvent = INVALID_HANDLE_VALUE;
|
||||
|
||||
ok = (*ReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
|
||||
ok &= (*RequestEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
|
||||
ok &= (*DoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) != INVALID_HANDLE_VALUE;
|
||||
|
||||
/* If something went wrong, clean up */
|
||||
if ( ! ok )
|
||||
{
|
||||
if ( *ReadyEvent != INVALID_HANDLE_VALUE )
|
||||
CloseHandle(*ReadyEvent);
|
||||
|
||||
if ( *RequestEvent != INVALID_HANDLE_VALUE )
|
||||
CloseHandle(*RequestEvent);
|
||||
|
||||
if ( *DoneEvent != INVALID_HANDLE_VALUE )
|
||||
CloseHandle(*DoneEvent);
|
||||
|
||||
return MMSYSERR_NOMEM;
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
DestroySoundThreadEvents(
|
||||
IN HANDLE ReadyEvent,
|
||||
IN HANDLE RequestEvent,
|
||||
IN HANDLE DoneEvent)
|
||||
{
|
||||
VALIDATE_MMSYS_PARAMETER( ReadyEvent != INVALID_HANDLE_VALUE );
|
||||
VALIDATE_MMSYS_PARAMETER( RequestEvent != INVALID_HANDLE_VALUE );
|
||||
VALIDATE_MMSYS_PARAMETER( DoneEvent != INVALID_HANDLE_VALUE );
|
||||
|
||||
SND_TRACE(L"Destroying thread events\n");
|
||||
|
||||
CloseHandle(ReadyEvent);
|
||||
CloseHandle(RequestEvent);
|
||||
CloseHandle(DoneEvent);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
CreateSoundThread(
|
||||
OUT PSOUND_THREAD* Thread)
|
||||
{
|
||||
MMRESULT Result;
|
||||
PSOUND_THREAD NewThread;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( Thread );
|
||||
|
||||
NewThread = AllocateStruct(SOUND_THREAD);
|
||||
if ( ! NewThread )
|
||||
return MMSYSERR_NOMEM;
|
||||
|
||||
/* Prepare the events we'll be using to sync. everything */
|
||||
Result = CreateSoundThreadEvents(&NewThread->Events.Ready,
|
||||
&NewThread->Events.Request,
|
||||
&NewThread->Events.Done);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
FreeMemory(NewThread);
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
SND_TRACE(L"Creating a sound thread\n");
|
||||
NewThread->Handle = CreateThread(NULL,
|
||||
0,
|
||||
&SoundThreadMain,
|
||||
(LPVOID) NewThread,
|
||||
CREATE_SUSPENDED,
|
||||
NULL);
|
||||
|
||||
/* Something went wrong, bail out! */
|
||||
if ( NewThread->Handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
SND_ERR(L"Sound thread creation failed!\n");
|
||||
DestroySoundThreadEvents(NewThread->Events.Ready,
|
||||
NewThread->Events.Request,
|
||||
NewThread->Events.Done);
|
||||
|
||||
FreeMemory(NewThread);
|
||||
|
||||
return Win32ErrorToMmResult(GetLastError());
|
||||
}
|
||||
|
||||
/* Wake the thread up */
|
||||
if ( ResumeThread(NewThread->Handle) == -1 )
|
||||
{
|
||||
CloseHandle(NewThread->Handle);
|
||||
DestroySoundThreadEvents(NewThread->Events.Ready,
|
||||
NewThread->Events.Request,
|
||||
NewThread->Events.Done);
|
||||
|
||||
FreeMemory(NewThread);
|
||||
return Win32ErrorToMmResult(GetLastError());
|
||||
}
|
||||
|
||||
/* If all is well we can now give the thread to the caller */
|
||||
*Thread = NewThread;
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
DestroySoundThread(
|
||||
IN PSOUND_THREAD Thread)
|
||||
{
|
||||
/* TODO: Implement me! */
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
CallSoundThread(
|
||||
IN PSOUND_THREAD Thread,
|
||||
IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance OPTIONAL,
|
||||
IN PVOID Parameter OPTIONAL)
|
||||
{
|
||||
VALIDATE_MMSYS_PARAMETER( Thread );
|
||||
VALIDATE_MMSYS_PARAMETER( RequestHandler );
|
||||
|
||||
SND_TRACE(L"Waiting for READY event\n");
|
||||
WaitForSingleObject(Thread->Events.Ready, INFINITE);
|
||||
|
||||
Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
|
||||
Thread->Request.Handler = RequestHandler;
|
||||
Thread->Request.SoundDeviceInstance = SoundDeviceInstance;
|
||||
Thread->Request.Parameter = Parameter;
|
||||
|
||||
/* Notify the thread it has work to do */
|
||||
SND_TRACE(L"Setting REQUEST event\n");
|
||||
SetEvent(Thread->Events.Request);
|
||||
|
||||
/* Wait for the work to be done */
|
||||
SND_TRACE(L"Waiting for DONE event\n");
|
||||
WaitForSingleObject(Thread->Events.Done, INFINITE);
|
||||
|
||||
return Thread->Request.Result;
|
||||
}
|
145
reactos/lib/drivers/sound/mmebuddy/utility.c
Normal file
145
reactos/lib/drivers/sound/mmebuddy/utility.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/sound/mmebuddy/utility.c
|
||||
*
|
||||
* PURPOSE: Provides utility functions used by the library.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
|
||||
static HANDLE ProcessHeapHandle = NULL;
|
||||
static UINT CurrentAllocations = 0;
|
||||
|
||||
/*
|
||||
Allocates memory, zeroes it, and increases the allocation count.
|
||||
*/
|
||||
PVOID
|
||||
AllocateMemory(
|
||||
IN UINT Size)
|
||||
{
|
||||
PVOID Pointer = NULL;
|
||||
|
||||
if ( ! ProcessHeapHandle )
|
||||
ProcessHeapHandle = GetProcessHeap();
|
||||
|
||||
Pointer = HeapAlloc(ProcessHeapHandle, HEAP_ZERO_MEMORY, Size);
|
||||
|
||||
if ( ! Pointer )
|
||||
return NULL;
|
||||
|
||||
++ CurrentAllocations;
|
||||
|
||||
return Pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
Frees memory and reduces the allocation count.
|
||||
*/
|
||||
VOID
|
||||
FreeMemory(
|
||||
IN PVOID Pointer)
|
||||
{
|
||||
SND_ASSERT( ProcessHeapHandle );
|
||||
SND_ASSERT( Pointer );
|
||||
|
||||
HeapFree(ProcessHeapHandle, 0, Pointer);
|
||||
|
||||
-- CurrentAllocations;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the current number of memory allocations outstanding. Useful for
|
||||
detecting/tracing memory leaks.
|
||||
*/
|
||||
UINT
|
||||
GetMemoryAllocationCount()
|
||||
{
|
||||
return CurrentAllocations;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Count the number of digits in a UINT
|
||||
*/
|
||||
UINT
|
||||
GetDigitCount(
|
||||
IN UINT Number)
|
||||
{
|
||||
UINT Value = Number;
|
||||
ULONG Digits = 1;
|
||||
|
||||
while ( Value > 9 )
|
||||
{
|
||||
Value /= 10;
|
||||
++ Digits;
|
||||
}
|
||||
|
||||
return Digits;
|
||||
}
|
||||
|
||||
/*
|
||||
Translate a Win32 error code into an MMRESULT code.
|
||||
*/
|
||||
MMRESULT
|
||||
Win32ErrorToMmResult(
|
||||
IN UINT ErrorCode)
|
||||
{
|
||||
switch ( ErrorCode )
|
||||
{
|
||||
case NO_ERROR :
|
||||
case ERROR_IO_PENDING :
|
||||
return MMSYSERR_NOERROR;
|
||||
|
||||
case ERROR_BUSY :
|
||||
return MMSYSERR_ALLOCATED;
|
||||
|
||||
case ERROR_NOT_SUPPORTED :
|
||||
case ERROR_INVALID_FUNCTION :
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
case ERROR_NOT_ENOUGH_MEMORY :
|
||||
return MMSYSERR_NOMEM;
|
||||
|
||||
case ERROR_ACCESS_DENIED :
|
||||
return MMSYSERR_BADDEVICEID;
|
||||
|
||||
case ERROR_INSUFFICIENT_BUFFER :
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
default :
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If a function invokes another function, this aids in translating the
|
||||
result code so that it is applicable in the context of the original caller.
|
||||
For example, specifying that an invalid parameter was passed probably does
|
||||
not make much sense if the parameter wasn't passed by the original caller!
|
||||
|
||||
This could potentially highlight internal logic problems.
|
||||
|
||||
However, things like MMSYSERR_NOMEM make sense to return to the caller.
|
||||
*/
|
||||
MMRESULT
|
||||
TranslateInternalMmResult(
|
||||
IN MMRESULT Result)
|
||||
{
|
||||
switch ( Result )
|
||||
{
|
||||
case MMSYSERR_INVALPARAM :
|
||||
case MMSYSERR_INVALFLAG :
|
||||
{
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
90
reactos/lib/drivers/sound/mmebuddy/wave/format.c
Normal file
90
reactos/lib/drivers/sound/mmebuddy/wave/format.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/wave/format.c
|
||||
*
|
||||
* PURPOSE: Queries and sets wave device format (sample rate, etc.)
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
MMRESULT
|
||||
QueryWaveDeviceFormatSupport(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
IN LPWAVEFORMATEX Format,
|
||||
IN DWORD FormatSize)
|
||||
{
|
||||
MMRESULT Result;
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
PMMFUNCTION_TABLE FunctionTable;
|
||||
|
||||
SND_TRACE(L"Querying wave format support\n");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
||||
VALIDATE_MMSYS_PARAMETER( Format );
|
||||
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
|
||||
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
/* Ensure we have a wave device (TODO: check if this applies to wavein as well) */
|
||||
VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) );
|
||||
|
||||
/* Obtain the function table */
|
||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
if ( ! FunctionTable->QueryWaveFormatSupport )
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
return FunctionTable->QueryWaveFormatSupport(SoundDevice, Format, FormatSize);
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
SetWaveDeviceFormat(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN LPWAVEFORMATEX Format,
|
||||
IN DWORD FormatSize)
|
||||
{
|
||||
MMRESULT Result;
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
PMMFUNCTION_TABLE FunctionTable;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
|
||||
SND_TRACE(L"Setting wave format\n");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||
VALIDATE_MMSYS_PARAMETER( Format );
|
||||
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
/* Ensure we have a wave device (TODO: check if this applies to wavein as well) */
|
||||
VALIDATE_MMSYS_PARAMETER( IS_WAVE_DEVICE_TYPE(DeviceType) );
|
||||
|
||||
/* Obtain the function table */
|
||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
if ( ! FunctionTable->SetWaveFormat )
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
return FunctionTable->SetWaveFormat(SoundDeviceInstance, Format, FormatSize);
|
||||
}
|
100
reactos/lib/drivers/sound/mmebuddy/wave/header.c
Normal file
100
reactos/lib/drivers/sound/mmebuddy/wave/header.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/header.c
|
||||
*
|
||||
* PURPOSE: Wave header preparation routines
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
MMRESULT
|
||||
PrepareWaveHeader(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN PWAVEHDR Header)
|
||||
{
|
||||
MMRESULT Result;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
PMMFUNCTION_TABLE FunctionTable;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||
VALIDATE_MMSYS_PARAMETER( Header );
|
||||
|
||||
SND_TRACE(L"Preparing wave header\n");
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
if ( ! FunctionTable->PrepareWaveHeader )
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
return FunctionTable->PrepareWaveHeader(SoundDeviceInstance, Header);
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
UnprepareWaveHeader(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN PWAVEHDR Header)
|
||||
{
|
||||
MMRESULT Result;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
PMMFUNCTION_TABLE FunctionTable;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||
VALIDATE_MMSYS_PARAMETER( Header );
|
||||
|
||||
SND_TRACE(L"Un-preparing wave header\n");
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
if ( ! FunctionTable->UnprepareWaveHeader )
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
return FunctionTable->UnprepareWaveHeader(SoundDeviceInstance, Header);
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
SubmitWaveHeader(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN PWAVEHDR Header)
|
||||
{
|
||||
MMRESULT Result;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
PMMFUNCTION_TABLE FunctionTable;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||
VALIDATE_MMSYS_PARAMETER( Header );
|
||||
|
||||
SND_TRACE(L"Submitting wave header\n");
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
if ( ! FunctionTable->SubmitWaveHeader )
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
return FunctionTable->SubmitWaveHeader(SoundDeviceInstance, Header);
|
||||
}
|
||||
|
61
reactos/lib/drivers/sound/mmebuddy/wave/widMessage.c
Normal file
61
reactos/lib/drivers/sound/mmebuddy/wave/widMessage.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/sound/mmebuddy/wave/widMessage.c
|
||||
*
|
||||
* PURPOSE: Provides the widMessage exported function, as required by
|
||||
* the MME API, for wave input device support.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
|
||||
/*
|
||||
Standard MME driver entry-point for messages relating to wave audio
|
||||
input.
|
||||
*/
|
||||
APIENTRY DWORD
|
||||
widMessage(
|
||||
DWORD DeviceId,
|
||||
DWORD Message,
|
||||
DWORD PrivateHandle,
|
||||
DWORD Parameter1,
|
||||
DWORD Parameter2)
|
||||
{
|
||||
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
AcquireEntrypointMutex(WAVE_IN_DEVICE_TYPE);
|
||||
|
||||
SND_TRACE(L"widMessage - Message type %d\n", Message);
|
||||
|
||||
switch ( Message )
|
||||
{
|
||||
case WIDM_GETNUMDEVS :
|
||||
{
|
||||
Result = GetSoundDeviceCount(WAVE_IN_DEVICE_TYPE);
|
||||
break;
|
||||
}
|
||||
|
||||
case WIDM_GETDEVCAPS :
|
||||
{
|
||||
Result = MmeGetSoundDeviceCapabilities(WAVE_IN_DEVICE_TYPE,
|
||||
DeviceId,
|
||||
(PVOID) Parameter1,
|
||||
Parameter2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SND_TRACE(L"widMessage returning MMRESULT %d\n", Result);
|
||||
|
||||
ReleaseEntrypointMutex(WAVE_IN_DEVICE_TYPE);
|
||||
|
||||
return Result;
|
||||
}
|
117
reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c
Normal file
117
reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mmebuddy/wave/wodMessage.c
|
||||
*
|
||||
* PURPOSE: Provides the wodMessage exported function, as required by
|
||||
* the MME API, for wave output device support.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
|
||||
#if 0
|
||||
MMRESULT HelloWorld(PSOUND_DEVICE_INSTANCE Instance, PVOID String)
|
||||
{
|
||||
PWSTR WString = (PWSTR) String;
|
||||
SND_TRACE(WString);
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Standard MME driver entry-point for messages relating to wave audio
|
||||
output.
|
||||
*/
|
||||
APIENTRY DWORD
|
||||
wodMessage(
|
||||
DWORD DeviceId,
|
||||
DWORD Message,
|
||||
DWORD PrivateHandle,
|
||||
DWORD Parameter1,
|
||||
DWORD Parameter2)
|
||||
{
|
||||
MMRESULT Result = MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
AcquireEntrypointMutex(WAVE_OUT_DEVICE_TYPE);
|
||||
|
||||
SND_TRACE(L"wodMessage - Message type %d\n", Message);
|
||||
|
||||
switch ( Message )
|
||||
{
|
||||
case WODM_GETNUMDEVS :
|
||||
{
|
||||
Result = GetSoundDeviceCount(WAVE_OUT_DEVICE_TYPE);
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_GETDEVCAPS :
|
||||
{
|
||||
Result = MmeGetSoundDeviceCapabilities(WAVE_OUT_DEVICE_TYPE,
|
||||
DeviceId,
|
||||
(PVOID) Parameter1,
|
||||
Parameter2);
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_OPEN :
|
||||
{
|
||||
Result = MmeOpenWaveDevice(WAVE_OUT_DEVICE_TYPE,
|
||||
DeviceId,
|
||||
(LPWAVEOPENDESC) Parameter1,
|
||||
Parameter2,
|
||||
(DWORD*) PrivateHandle);
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_CLOSE :
|
||||
{
|
||||
Result = MmeCloseDevice(PrivateHandle);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_PREPARE :
|
||||
{
|
||||
/* TODO: Do we need to pass 2nd parameter? */
|
||||
Result = MmePrepareWaveHeader(PrivateHandle, Parameter1);
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_UNPREPARE :
|
||||
{
|
||||
Result = MmeUnprepareWaveHeader(PrivateHandle, Parameter1);
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_WRITE :
|
||||
{
|
||||
Result = MmeSubmitWaveHeader(PrivateHandle, Parameter1);
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_GETPOS :
|
||||
{
|
||||
#if 0
|
||||
/* Hacky code to test the threading */
|
||||
PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)PrivateHandle;
|
||||
CallSoundThread(Instance->Thread, HelloWorld, Instance, L"Hello World!");
|
||||
CallSoundThread(Instance->Thread, HelloWorld, Instance, L"Hello Universe!");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SND_TRACE(L"wodMessage returning MMRESULT %d\n", Result);
|
||||
|
||||
ReleaseEntrypointMutex(WAVE_OUT_DEVICE_TYPE);
|
||||
|
||||
return Result;
|
||||
}
|
230
reactos/lib/drivers/sound/mment4/control.c
Normal file
230
reactos/lib/drivers/sound/mment4/control.c
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" NT4 Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mment4/control.c
|
||||
*
|
||||
* PURPOSE: Device control for NT4 audio devices
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
#include <mmebuddy.h>
|
||||
#include <mment4.h>
|
||||
|
||||
/*
|
||||
Convenience routine for getting the path of a device and opening it.
|
||||
*/
|
||||
MMRESULT
|
||||
OpenNt4KernelSoundDevice(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
IN BOOLEAN ReadOnly,
|
||||
OUT PHANDLE Handle)
|
||||
{
|
||||
PWSTR Path;
|
||||
MMRESULT Result;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
||||
VALIDATE_MMSYS_PARAMETER( Handle );
|
||||
|
||||
Result = GetSoundDeviceIdentifier(SoundDevice, (PVOID*) &Path);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Unable to get sound device path");
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
SND_ASSERT( Path );
|
||||
|
||||
return OpenKernelSoundDeviceByName(Path, ReadOnly, Handle);
|
||||
}
|
||||
|
||||
/*
|
||||
Device open/close. These are basically wrappers for the MME-Buddy
|
||||
open and close routines, which provide a Windows device handle.
|
||||
These may seem simple but as you can return pretty much anything
|
||||
as the handle, we could just as easily return a structure etc.
|
||||
*/
|
||||
MMRESULT
|
||||
OpenNt4SoundDevice(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
OUT PVOID* Handle)
|
||||
{
|
||||
SND_TRACE(L"Opening NT4 style sound device\n");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
||||
VALIDATE_MMSYS_PARAMETER( Handle );
|
||||
|
||||
return OpenNt4KernelSoundDevice(SoundDevice, FALSE, Handle);
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
CloseNt4SoundDevice(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN PVOID Handle)
|
||||
{
|
||||
SND_TRACE(L"Closing NT4 style sound device\n");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||
return CloseKernelSoundDevice((HANDLE) Handle);
|
||||
}
|
||||
|
||||
/*
|
||||
Provides an implementation for the "get capabilities" request,
|
||||
using the standard IOCTLs used by NT4 sound drivers.
|
||||
*/
|
||||
MMRESULT
|
||||
GetNt4SoundDeviceCapabilities(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
OUT PVOID Capabilities,
|
||||
IN DWORD CapabilitiesSize)
|
||||
{
|
||||
MMRESULT Result;
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
DWORD IoCtl;
|
||||
HANDLE DeviceHandle;
|
||||
|
||||
/* If these are bad there's an internal error with MME-Buddy! */
|
||||
SND_ASSERT( SoundDevice );
|
||||
SND_ASSERT( Capabilities );
|
||||
SND_ASSERT( CapabilitiesSize > 0 );
|
||||
|
||||
SND_TRACE(L"NT4 get-capabilities routine called\n");
|
||||
|
||||
/* Get the device type */
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
if ( ! MMSUCCESS(Result) );
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
/* Choose the appropriate IOCTL */
|
||||
if ( IS_WAVE_DEVICE_TYPE(DeviceType) )
|
||||
{
|
||||
IoCtl = IOCTL_WAVE_GET_CAPABILITIES;
|
||||
}
|
||||
else if ( IS_MIDI_DEVICE_TYPE(DeviceType) )
|
||||
{
|
||||
IoCtl = IOCTL_MIDI_GET_CAPABILITIES;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME - need to support AUX and mixer devices */
|
||||
SND_ASSERT( FALSE );
|
||||
}
|
||||
|
||||
/* Get the capabilities information from the driver */
|
||||
Result = OpenNt4KernelSoundDevice(SoundDevice, TRUE, &DeviceHandle);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Failed to open device");
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
Result = SyncOverlappedDeviceIoControl(DeviceHandle,
|
||||
IoCtl,
|
||||
Capabilities,
|
||||
CapabilitiesSize,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
CloseKernelSoundDevice(DeviceHandle);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Retrieval of capabilities information failed\n");
|
||||
Result = TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/*
|
||||
Querying/setting the format of a wave device. Querying format support
|
||||
requires us to first open the device, whereas setting format is done
|
||||
on an already opened device.
|
||||
*/
|
||||
MMRESULT
|
||||
QueryNt4WaveDeviceFormatSupport(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
IN LPWAVEFORMATEX Format,
|
||||
IN DWORD FormatSize)
|
||||
{
|
||||
MMRESULT Result;
|
||||
HANDLE Handle;
|
||||
|
||||
SND_TRACE(L"NT4 wave format support querying routine called\n");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
|
||||
VALIDATE_MMSYS_PARAMETER( Format );
|
||||
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
|
||||
|
||||
/* Get the device path */
|
||||
Result = OpenNt4KernelSoundDevice(SoundDevice,
|
||||
FALSE,
|
||||
&Handle);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Unable to open kernel sound device\n");
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
Result = SyncOverlappedDeviceIoControl(Handle,
|
||||
IOCTL_WAVE_QUERY_FORMAT,
|
||||
(LPVOID) Format,
|
||||
FormatSize,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Sync overlapped I/O failed - MMSYS_ERROR %d\n", Result);
|
||||
Result = TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
CloseKernelSoundDevice(Handle);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
SetNt4WaveDeviceFormat(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN LPWAVEFORMATEX Format,
|
||||
IN DWORD FormatSize)
|
||||
{
|
||||
MMRESULT Result;
|
||||
HANDLE Handle;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||
VALIDATE_MMSYS_PARAMETER( Format );
|
||||
VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );
|
||||
|
||||
Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
SND_TRACE(L"Setting wave device format on handle %x\n", Handle);
|
||||
|
||||
Result = SyncOverlappedDeviceIoControl(Handle,
|
||||
IOCTL_WAVE_SET_FORMAT,
|
||||
(LPVOID) Format,
|
||||
FormatSize,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
205
reactos/lib/drivers/sound/mment4/detect.c
Normal file
205
reactos/lib/drivers/sound/mment4/detect.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" NT4 Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mment4/detect.c
|
||||
*
|
||||
* PURPOSE: Assists in locating Windows NT4 compatible sound devices,
|
||||
* which mostly use the same device naming convention and/or
|
||||
* store their created device names within their service key
|
||||
* within the registry.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
#include <mment4.h>
|
||||
|
||||
/*
|
||||
This is the "nice" way to discover audio devices in NT4 - go into the
|
||||
service registry key and enumerate the Parameters\Device*\Devices
|
||||
values. The value names represent the device name, whereas the data
|
||||
assigned to them identifies the type of device.
|
||||
*/
|
||||
MMRESULT
|
||||
EnumerateNt4ServiceSoundDevices(
|
||||
IN LPWSTR ServiceName,
|
||||
IN MMDEVICE_TYPE DeviceType,
|
||||
IN SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)
|
||||
{
|
||||
HKEY Key;
|
||||
DWORD KeyIndex = 0;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( ServiceName );
|
||||
|
||||
/* Device type zero means "all" */
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) ||
|
||||
DeviceType == 0 );
|
||||
|
||||
while ( OpenSoundDeviceRegKey(ServiceName, KeyIndex, &Key) == MMSYSERR_NOERROR )
|
||||
{
|
||||
HKEY DevicesKey;
|
||||
DWORD ValueType = REG_NONE, ValueIndex = 0;
|
||||
DWORD MaxNameLength = 0, ValueNameLength = 0;
|
||||
PWSTR DevicePath = NULL, ValueName = NULL;
|
||||
DWORD ValueDataLength = sizeof(DWORD);
|
||||
DWORD ValueData;
|
||||
|
||||
if ( RegOpenKeyEx(Key,
|
||||
REG_DEVICES_KEY_NAME_U,
|
||||
0,
|
||||
KEY_READ,
|
||||
&DevicesKey) == ERROR_SUCCESS )
|
||||
{
|
||||
/* Find out how much memory is needed for the key name */
|
||||
if ( RegQueryInfoKey(DevicesKey,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
&MaxNameLength,
|
||||
NULL, NULL, NULL) != ERROR_SUCCESS )
|
||||
{
|
||||
SND_ERR(L"Failed to query registry key information\n");
|
||||
RegCloseKey(DevicesKey);
|
||||
RegCloseKey(Key);
|
||||
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
|
||||
DevicePath = AllocateWideString(MaxNameLength +
|
||||
strlen("\\\\.\\"));
|
||||
|
||||
/* Check that the memory allocation was successful */
|
||||
if ( ! DevicePath )
|
||||
{
|
||||
/* There's no point in going further */
|
||||
RegCloseKey(DevicesKey);
|
||||
RegCloseKey(Key);
|
||||
|
||||
return MMSYSERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Insert the device path prefix */
|
||||
wsprintf(DevicePath, L"\\\\.\\");
|
||||
|
||||
/* The offset of the string following this prefix */
|
||||
ValueName = DevicePath + strlen("\\\\.\\");
|
||||
|
||||
/* Copy this so that it may be overwritten - include NULL */
|
||||
ValueNameLength = MaxNameLength + sizeof(WCHAR);
|
||||
|
||||
SND_TRACE(L"Interested in devices beginning with %wS\n", DevicePath);
|
||||
|
||||
while ( RegEnumValue(DevicesKey,
|
||||
ValueIndex,
|
||||
ValueName,
|
||||
&ValueNameLength,
|
||||
NULL,
|
||||
&ValueType,
|
||||
(LPBYTE) &ValueData,
|
||||
&ValueDataLength) == ERROR_SUCCESS )
|
||||
{
|
||||
/* Device types are stored as DWORDs */
|
||||
if ( ( ValueType == REG_DWORD ) &&
|
||||
( ValueDataLength == sizeof(DWORD) ) )
|
||||
{
|
||||
if ( ( DeviceType == 0 ) ||
|
||||
( DeviceType == ValueData ) )
|
||||
{
|
||||
SND_TRACE(L"Found device: %wS\n", DevicePath);
|
||||
SoundDeviceDetectedProc(ValueData, DevicePath);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset variables for the next iteration */
|
||||
ValueNameLength = MaxNameLength + sizeof(WCHAR);
|
||||
ZeroMemory(ValueName, (MaxNameLength+1)*sizeof(WCHAR));
|
||||
/*ZeroWideString(ValueName);*/
|
||||
ValueDataLength = sizeof(DWORD);
|
||||
ValueData = 0;
|
||||
ValueType = REG_NONE;
|
||||
|
||||
++ ValueIndex;
|
||||
}
|
||||
|
||||
FreeMemory(DevicePath);
|
||||
|
||||
RegCloseKey(DevicesKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
SND_WARN(L"Unable to open the Devices key!\n");
|
||||
}
|
||||
|
||||
++ KeyIndex;
|
||||
|
||||
RegCloseKey(Key);
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
Brute-force device detection, using a base device name (eg: \\.\WaveOut).
|
||||
|
||||
This will add the device number as a suffix to the end of the string and
|
||||
attempt to open the device based on that name. On success, it will
|
||||
increment the device number and repeat this process.
|
||||
|
||||
When it runs out of devices, it will give up.
|
||||
*/
|
||||
MMRESULT
|
||||
DetectNt4SoundDevices(
|
||||
IN MMDEVICE_TYPE DeviceType,
|
||||
IN PWSTR BaseDeviceName,
|
||||
IN SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc)
|
||||
{
|
||||
ULONG DeviceNameLength = 0;
|
||||
PWSTR DeviceName = NULL;
|
||||
ULONG Index = 0;
|
||||
HANDLE DeviceHandle;
|
||||
BOOLEAN DoSearch = TRUE;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
|
||||
|
||||
DeviceNameLength = wcslen(BaseDeviceName);
|
||||
/* Consider the length of the number */
|
||||
DeviceNameLength += GetDigitCount(Index);
|
||||
|
||||
DeviceName = AllocateWideString(DeviceNameLength);
|
||||
|
||||
if ( ! DeviceName )
|
||||
{
|
||||
return MMSYSERR_NOMEM;
|
||||
}
|
||||
|
||||
while ( DoSearch )
|
||||
{
|
||||
/* Nothing like a nice clean device name */
|
||||
ZeroWideString(DeviceName);
|
||||
wsprintf(DeviceName, L"%ls%d", BaseDeviceName, Index);
|
||||
|
||||
if ( OpenKernelSoundDeviceByName(DeviceName,
|
||||
TRUE,
|
||||
&DeviceHandle) == MMSYSERR_NOERROR )
|
||||
{
|
||||
/* Notify the callback function */
|
||||
SND_TRACE(L"Found device: %wS\n", DeviceName);
|
||||
SoundDeviceDetectedProc(DeviceType, DeviceName);
|
||||
|
||||
CloseHandle(DeviceHandle);
|
||||
|
||||
++ Index;
|
||||
}
|
||||
else
|
||||
{
|
||||
DoSearch = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
FreeMemory(DeviceName);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
9
reactos/lib/drivers/sound/mment4/mment4.rbuild
Normal file
9
reactos/lib/drivers/sound/mment4/mment4.rbuild
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="mment4" type="staticlibrary" allowwarnings="false" unicode="yes">
|
||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||
<define name="DEBUG_NT4">1</define>
|
||||
<file>detect.c</file>
|
||||
<file>registry.c</file>
|
||||
<file>control.c</file>
|
||||
</module>
|
137
reactos/lib/drivers/sound/mment4/registry.c
Normal file
137
reactos/lib/drivers/sound/mment4/registry.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Sound System "MME Buddy" NT4 Library
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: lib/drivers/sound/mment4/registry.c
|
||||
*
|
||||
* PURPOSE: Registry operation helper for audio device drivers.
|
||||
*
|
||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <mmddk.h>
|
||||
#include <ntddsnd.h>
|
||||
|
||||
#include <mmebuddy.h>
|
||||
#include <mment4.h>
|
||||
|
||||
/*
|
||||
Open the parameters key of a sound driver.
|
||||
NT4 only.
|
||||
*/
|
||||
MMRESULT
|
||||
OpenSoundDriverParametersRegKey(
|
||||
IN LPWSTR ServiceName,
|
||||
OUT PHKEY KeyHandle)
|
||||
{
|
||||
ULONG KeyLength;
|
||||
PWCHAR ParametersKeyName;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( ServiceName );
|
||||
VALIDATE_MMSYS_PARAMETER( KeyHandle );
|
||||
|
||||
/* Work out how long the string will be */
|
||||
KeyLength = wcslen(REG_SERVICES_KEY_NAME_U) + 1
|
||||
+ wcslen(ServiceName) + 1
|
||||
+ wcslen(REG_PARAMETERS_KEY_NAME_U);
|
||||
|
||||
/* Allocate memory for the string */
|
||||
ParametersKeyName = AllocateWideString(KeyLength);
|
||||
|
||||
if ( ! ParametersKeyName )
|
||||
return MMSYSERR_NOMEM;
|
||||
|
||||
/* Construct the registry path */
|
||||
wsprintf(ParametersKeyName,
|
||||
L"%s\\%s\\%s",
|
||||
REG_SERVICES_KEY_NAME_U,
|
||||
ServiceName,
|
||||
REG_PARAMETERS_KEY_NAME_U);
|
||||
|
||||
SND_TRACE(L"Opening reg key: %wS\n", ParametersKeyName);
|
||||
|
||||
/* Perform the open */
|
||||
if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
ParametersKeyName,
|
||||
0,
|
||||
KEY_READ,
|
||||
KeyHandle) != ERROR_SUCCESS )
|
||||
{
|
||||
/* Couldn't open the key */
|
||||
SND_ERR(L"Failed to open reg key: %wS\n", ParametersKeyName);
|
||||
FreeMemory(ParametersKeyName);
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
|
||||
FreeMemory(ParametersKeyName);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
Open one of the Device sub-keys belonging to the sound driver.
|
||||
NT4 only.
|
||||
*/
|
||||
MMRESULT
|
||||
OpenSoundDeviceRegKey(
|
||||
IN LPWSTR ServiceName,
|
||||
IN DWORD DeviceIndex,
|
||||
OUT PHKEY KeyHandle)
|
||||
{
|
||||
DWORD PathLength;
|
||||
PWCHAR RegPath;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( ServiceName );
|
||||
VALIDATE_MMSYS_PARAMETER( KeyHandle );
|
||||
|
||||
/*
|
||||
Work out the space required to hold the path:
|
||||
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\
|
||||
sndblst\
|
||||
Parameters\
|
||||
Device123\
|
||||
*/
|
||||
PathLength = wcslen(REG_SERVICES_KEY_NAME_U) + 1
|
||||
+ wcslen(ServiceName) + 1
|
||||
+ wcslen(REG_PARAMETERS_KEY_NAME_U) + 1
|
||||
+ wcslen(REG_DEVICE_KEY_NAME_U)
|
||||
+ GetDigitCount(DeviceIndex);
|
||||
|
||||
/* Allocate storage for the string */
|
||||
RegPath = AllocateWideString(PathLength);
|
||||
|
||||
if ( ! RegPath )
|
||||
{
|
||||
return MMSYSERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Write the path */
|
||||
wsprintf(RegPath,
|
||||
L"%ls\\%ls\\%ls\\%ls%d",
|
||||
REG_SERVICES_KEY_NAME_U,
|
||||
ServiceName,
|
||||
REG_PARAMETERS_KEY_NAME_U,
|
||||
REG_DEVICE_KEY_NAME_U,
|
||||
DeviceIndex);
|
||||
|
||||
SND_TRACE(L"Opening reg key: %wS\n", RegPath);
|
||||
|
||||
/* Perform the open */
|
||||
if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
RegPath,
|
||||
0,
|
||||
KEY_READ,
|
||||
KeyHandle) != ERROR_SUCCESS )
|
||||
{
|
||||
/* Couldn't open the key */
|
||||
SND_ERR(L"Failed to open reg key: %wS\n", RegPath);
|
||||
FreeMemory(RegPath);
|
||||
return MMSYSERR_ERROR;
|
||||
}
|
||||
|
||||
FreeMemory(RegPath);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
9
reactos/lib/drivers/sound/shared/shared.rbuild
Normal file
9
reactos/lib/drivers/sound/shared/shared.rbuild
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="audio" type="staticlibrary" allowwarnings="true">
|
||||
<define name="__NTDRIVER__"/>
|
||||
<define name="KERNEL"/>
|
||||
<include base="soundblaster">.</include>
|
||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||
<file>time.c</file>
|
||||
</module>
|
49
reactos/lib/drivers/sound/shared/time.c
Normal file
49
reactos/lib/drivers/sound/shared/time.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Timing helper
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
31 May 2008 - Created
|
||||
|
||||
Notes:
|
||||
Have checked timing in DebugView. A 10,000ms delay covered a period
|
||||
of 124.305 sec to 134.308 sec. Not 100% accurate but likely down to
|
||||
the delays in submitting the debug strings?
|
||||
*/
|
||||
|
||||
/*
|
||||
Nanoseconds are fun! You must try some!
|
||||
1 ns = .000000001 seconds = .0000001 ms
|
||||
100 ns = .0000001 seconds = .00001 ms
|
||||
10000 ns = .00001 seconds = .001 ms
|
||||
1000000 ns = .001 seconds = 1 ms
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
|
||||
VOID
|
||||
SleepMs(ULONG Milliseconds)
|
||||
{
|
||||
LARGE_INTEGER Period;
|
||||
|
||||
Period.QuadPart = -Milliseconds;
|
||||
Period.QuadPart *= 10000;
|
||||
|
||||
KeDelayExecutionThread(KernelMode, FALSE, &Period);
|
||||
}
|
||||
|
||||
ULONG
|
||||
QuerySystemTimeMs()
|
||||
{
|
||||
LARGE_INTEGER Time;
|
||||
|
||||
KeQuerySystemTime(&Time);
|
||||
|
||||
Time.QuadPart /= 10000;
|
||||
|
||||
return (ULONG) Time.QuadPart;
|
||||
}
|
||||
|
22
reactos/lib/drivers/sound/sound.rbuild
Normal file
22
reactos/lib/drivers/sound/sound.rbuild
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE group SYSTEM "../../../tools/rbuild/project.dtd">
|
||||
<group xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<directory name="legacy">
|
||||
<xi:include href="legacy/legacy.rbuild" />
|
||||
</directory>
|
||||
<directory name="shared">
|
||||
<xi:include href="shared/shared.rbuild" />
|
||||
</directory>
|
||||
<directory name="soundblaster">
|
||||
<xi:include href="soundblaster/soundblaster.rbuild" />
|
||||
</directory>
|
||||
<directory name="uartmidi">
|
||||
<xi:include href="uartmidi/uartmidi.rbuild" />
|
||||
</directory>
|
||||
<directory name="mmebuddy">
|
||||
<xi:include href="mmebuddy/mmebuddy.rbuild" />
|
||||
</directory>
|
||||
<directory name="mment4">
|
||||
<xi:include href="mment4/mment4.rbuild" />
|
||||
</directory>
|
||||
</group>
|
148
reactos/lib/drivers/sound/soundblaster/dsp_io.c
Normal file
148
reactos/lib/drivers/sound/soundblaster/dsp_io.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Sound Blaster DSP support
|
||||
General I/O
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
2 July 2008 - Created (split from sbdsp.c)
|
||||
|
||||
Notes:
|
||||
Functions documented in sbdsp.h
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sbdsp.h>
|
||||
|
||||
NTSTATUS
|
||||
SbDspReset(
|
||||
IN PUCHAR BasePort,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
ULONG Expiry;
|
||||
KIRQL CurrentIrqLevel = KeGetCurrentIrql();
|
||||
BOOLEAN DataAvailable = FALSE;
|
||||
|
||||
/* Should be called from DriverEntry with this IRQL */
|
||||
ASSERT(CurrentIrqLevel == PASSIVE_LEVEL);
|
||||
|
||||
WRITE_SB_DSP_RESET(BasePort, 0x01);
|
||||
SleepMs(50); /* Should be enough */
|
||||
WRITE_SB_DSP_RESET(BasePort, 0x00);
|
||||
|
||||
Expiry = QuerySystemTimeMs() + Timeout;
|
||||
|
||||
/* Wait for data to be available */
|
||||
while ( (QuerySystemTimeMs() < Expiry) || ( Timeout == 0) )
|
||||
{
|
||||
if ( SB_DSP_DATA_AVAILABLE(BasePort) )
|
||||
{
|
||||
DataAvailable = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! DataAvailable )
|
||||
{
|
||||
return STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Data is available - wait for the "DSP ready" code */
|
||||
while ( (QuerySystemTimeMs() < Expiry) || ( Timeout == 0) )
|
||||
{
|
||||
if ( READ_SB_DSP_DATA(BasePort) == SB_DSP_READY )
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbDspWaitToWrite(
|
||||
IN PUCHAR BasePort,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
ULONG Expiry = QuerySystemTimeMs() + Timeout;
|
||||
|
||||
while ( (QuerySystemTimeMs() < Expiry) || (Timeout == 0) )
|
||||
{
|
||||
if ( SB_DSP_CLEAR_TO_SEND(BasePort) )
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbDspWaitToRead(
|
||||
IN PUCHAR BasePort,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
ULONG Expiry = QuerySystemTimeMs() + Timeout;
|
||||
|
||||
while ( (QuerySystemTimeMs() < Expiry) || (Timeout == 0) )
|
||||
{
|
||||
if ( SB_DSP_DATA_AVAILABLE(BasePort) )
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbDspWrite(
|
||||
IN PUCHAR BasePort,
|
||||
IN UCHAR DataByte,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = SbDspWaitToWrite(BasePort, Timeout);
|
||||
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
DbgPrint("SBDSP - Writing %02x\n", DataByte);
|
||||
WRITE_SB_DSP_DATA(BasePort, DataByte);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbDspRead(
|
||||
IN PUCHAR BasePort,
|
||||
OUT PUCHAR DataByte,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
if ( ! DataByte )
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
}
|
||||
|
||||
Status = SbDspWaitToRead(BasePort, Timeout);
|
||||
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
*DataByte = READ_SB_DSP_DATA(BasePort);
|
||||
DbgPrint("SBDSP - Read %02x\n", *DataByte);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
246
reactos/lib/drivers/sound/soundblaster/mixer.c
Normal file
246
reactos/lib/drivers/sound/soundblaster/mixer.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Sound Blaster DSP support
|
||||
Mixer routines
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
2 July 2008 - Created
|
||||
|
||||
Notes:
|
||||
Functions documented in sbdsp.h
|
||||
|
||||
Currently, input/output switches and PC speaker volume
|
||||
level are not supported.
|
||||
|
||||
The I/O switches are used for muting/unmuting mic, etc.
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <sbdsp.h>
|
||||
|
||||
VOID
|
||||
SbMixerReset(IN PUCHAR BasePort)
|
||||
{
|
||||
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_RESET);
|
||||
/* Are we meant to send anything else? */
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbMixerPackLevelData(
|
||||
IN UCHAR Line,
|
||||
IN UCHAR Level,
|
||||
OUT PUCHAR PackedLevel)
|
||||
{
|
||||
if ( ! PackedLevel )
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
switch ( Line )
|
||||
{
|
||||
case SB_MIX_MASTER_LEFT_LEVEL :
|
||||
case SB_MIX_MASTER_RIGHT_LEVEL :
|
||||
case SB_MIX_VOC_LEFT_LEVEL :
|
||||
case SB_MIX_VOC_RIGHT_LEVEL :
|
||||
case SB_MIX_MIDI_LEFT_LEVEL :
|
||||
case SB_MIX_MIDI_RIGHT_LEVEL :
|
||||
case SB_MIX_CD_LEFT_LEVEL :
|
||||
case SB_MIX_CD_RIGHT_LEVEL :
|
||||
case SB_MIX_LINE_LEFT_LEVEL :
|
||||
case SB_MIX_LINE_RIGHT_LEVEL :
|
||||
case SB_MIX_MIC_LEVEL :
|
||||
case SB_MIX_LEGACY_MIC_LEVEL : /* is this correct? */
|
||||
{
|
||||
if ( Level >= 0x20 )
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
|
||||
*PackedLevel = Level << 3;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case SB_MIX_INPUT_LEFT_GAIN :
|
||||
case SB_MIX_INPUT_RIGHT_GAIN :
|
||||
case SB_MIX_OUTPUT_LEFT_GAIN :
|
||||
case SB_MIX_OUTPUT_RIGHT_GAIN :
|
||||
{
|
||||
if ( Level >= 0x04 )
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
|
||||
*PackedLevel = Level << 6;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case SB_MIX_VOC_LEVEL : /* legacy */
|
||||
case SB_MIX_MASTER_LEVEL :
|
||||
case SB_MIX_FM_LEVEL :
|
||||
case SB_MIX_CD_LEVEL :
|
||||
case SB_MIX_LINE_LEVEL :
|
||||
case SB_MIX_TREBLE_LEFT_LEVEL : /* bass/treble */
|
||||
case SB_MIX_TREBLE_RIGHT_LEVEL :
|
||||
case SB_MIX_BASS_LEFT_LEVEL :
|
||||
case SB_MIX_BASS_RIGHT_LEVEL :
|
||||
{
|
||||
if ( Level >= 0x10 )
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
|
||||
*PackedLevel = Level << 4;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
default :
|
||||
return STATUS_INVALID_PARAMETER_1;
|
||||
};
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbMixerUnpackLevelData(
|
||||
IN UCHAR Line,
|
||||
IN UCHAR PackedLevel,
|
||||
OUT PUCHAR Level)
|
||||
{
|
||||
if ( ! Level )
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
switch ( Line )
|
||||
{
|
||||
case SB_MIX_MASTER_LEFT_LEVEL :
|
||||
case SB_MIX_MASTER_RIGHT_LEVEL :
|
||||
case SB_MIX_VOC_LEFT_LEVEL :
|
||||
case SB_MIX_VOC_RIGHT_LEVEL :
|
||||
case SB_MIX_MIDI_LEFT_LEVEL :
|
||||
case SB_MIX_MIDI_RIGHT_LEVEL :
|
||||
case SB_MIX_CD_LEFT_LEVEL :
|
||||
case SB_MIX_CD_RIGHT_LEVEL :
|
||||
case SB_MIX_LINE_LEFT_LEVEL :
|
||||
case SB_MIX_LINE_RIGHT_LEVEL :
|
||||
case SB_MIX_MIC_LEVEL :
|
||||
{
|
||||
*Level = PackedLevel >> 3;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case SB_MIX_INPUT_LEFT_GAIN :
|
||||
case SB_MIX_INPUT_RIGHT_GAIN :
|
||||
case SB_MIX_OUTPUT_LEFT_GAIN :
|
||||
case SB_MIX_OUTPUT_RIGHT_GAIN :
|
||||
{
|
||||
*Level = PackedLevel >> 6;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case SB_MIX_VOC_LEVEL : /* legacy */
|
||||
case SB_MIX_MASTER_LEVEL :
|
||||
case SB_MIX_FM_LEVEL :
|
||||
case SB_MIX_CD_LEVEL :
|
||||
case SB_MIX_LINE_LEVEL :
|
||||
case SB_MIX_TREBLE_LEFT_LEVEL : /* bass/treble */
|
||||
case SB_MIX_TREBLE_RIGHT_LEVEL :
|
||||
case SB_MIX_BASS_LEFT_LEVEL :
|
||||
case SB_MIX_BASS_RIGHT_LEVEL :
|
||||
{
|
||||
*Level = PackedLevel >> 4;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
default :
|
||||
return STATUS_INVALID_PARAMETER_1;
|
||||
};
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbMixerSetLevel(
|
||||
IN PUCHAR BasePort,
|
||||
IN UCHAR Line,
|
||||
IN UCHAR Level)
|
||||
{
|
||||
UCHAR PackedLevel = 0;
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = SbMixerPackLevelData(Line, Level, &PackedLevel);
|
||||
|
||||
switch ( Status )
|
||||
{
|
||||
case STATUS_SUCCESS :
|
||||
break;
|
||||
|
||||
case STATUS_INVALID_PARAMETER_1 :
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
|
||||
case STATUS_INVALID_PARAMETER_2 :
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
default :
|
||||
return Status;
|
||||
};
|
||||
|
||||
DbgPrint("SbMixerSetLevel: Line 0x%x, raw level 0x%x, packed 0x%x\n", Line, Level, PackedLevel);
|
||||
|
||||
WRITE_SB_MIXER_REGISTER(BasePort, Line);
|
||||
WRITE_SB_MIXER_DATA(BasePort, PackedLevel);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbMixerGetLevel(
|
||||
IN PUCHAR BasePort,
|
||||
IN UCHAR Line,
|
||||
OUT PUCHAR Level)
|
||||
{
|
||||
UCHAR PackedLevel = 0;
|
||||
NTSTATUS Status;
|
||||
|
||||
if ( ! Level )
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
WRITE_SB_MIXER_REGISTER(BasePort, Line);
|
||||
PackedLevel = READ_SB_MIXER_DATA(BasePort);
|
||||
|
||||
Status = SbMixerUnpackLevelData(Line, PackedLevel, Level);
|
||||
|
||||
switch ( Status )
|
||||
{
|
||||
case STATUS_SUCCESS :
|
||||
break;
|
||||
|
||||
case STATUS_INVALID_PARAMETER_1 :
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
|
||||
case STATUS_INVALID_PARAMETER_2 :
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
default :
|
||||
return Status;
|
||||
};
|
||||
|
||||
DbgPrint("SbMixerGetLevel: Line 0x%x, raw level 0x%x, packed 0x%x\n", Line, Level, PackedLevel);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
SbMixerEnableAGC(IN PUCHAR BasePort)
|
||||
{
|
||||
/* Untested... */
|
||||
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
|
||||
WRITE_SB_MIXER_DATA(BasePort, 1);
|
||||
}
|
||||
|
||||
VOID
|
||||
SbMixerDisableAGC(IN PUCHAR BasePort)
|
||||
{
|
||||
/* Untested... */
|
||||
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
|
||||
WRITE_SB_MIXER_DATA(BasePort, 0);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
SbMixerIsAGCEnabled(IN PUCHAR BasePort)
|
||||
{
|
||||
/* Untested... */
|
||||
WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
|
||||
return (READ_SB_MIXER_DATA(BasePort) != 0);
|
||||
}
|
154
reactos/lib/drivers/sound/soundblaster/rate.c
Normal file
154
reactos/lib/drivers/sound/soundblaster/rate.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Sound Blaster DSP support
|
||||
Sample rate routines
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
2 July 2008 - Created (split from sbdsp.c)
|
||||
|
||||
Notes:
|
||||
Functions documented in sbdsp.h
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <sbdsp.h>
|
||||
|
||||
BOOLEAN
|
||||
SbDspIsValidInputRate(
|
||||
IN UCHAR MajorVersion,
|
||||
IN UCHAR MinorVersion,
|
||||
IN USHORT Rate,
|
||||
IN BOOLEAN Stereo)
|
||||
{
|
||||
if ( MajorVersion == 1 )
|
||||
{
|
||||
if ( Stereo )
|
||||
return FALSE;
|
||||
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 13000 ) );
|
||||
}
|
||||
else if ( MajorVersion == 2 )
|
||||
{
|
||||
if ( Stereo )
|
||||
return FALSE;
|
||||
|
||||
if ( MinorVersion == 0 )
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 15000 ) );
|
||||
else
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 44100 ) );
|
||||
}
|
||||
else if ( MajorVersion == 3 )
|
||||
{
|
||||
if ( Stereo )
|
||||
return FALSE;
|
||||
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 13000 ) );
|
||||
}
|
||||
else /* 4.00 and above */
|
||||
{
|
||||
return ( ( Rate >= 5000 ) && ( Rate <= 44100 ) );
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
SbDspIsValidOutputRate(
|
||||
IN UCHAR MajorVersion,
|
||||
IN UCHAR MinorVersion,
|
||||
IN USHORT Rate,
|
||||
IN BOOLEAN Stereo)
|
||||
{
|
||||
if ( MajorVersion == 1 )
|
||||
{
|
||||
if ( Stereo )
|
||||
return FALSE;
|
||||
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 23000 ) );
|
||||
}
|
||||
else if ( MajorVersion == 2 )
|
||||
{
|
||||
if ( Stereo )
|
||||
return FALSE;
|
||||
|
||||
if ( MinorVersion == 0 )
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 23000 ) );
|
||||
else
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 44100 ) );
|
||||
}
|
||||
else if ( MajorVersion == 3 )
|
||||
{
|
||||
if ( ! Stereo )
|
||||
return ( ( Rate >= 4000 ) && ( Rate <= 44100 ) );
|
||||
else
|
||||
return ( ( Rate >= 11025 ) && ( Rate <= 22050 ) );
|
||||
}
|
||||
else /* 4.00 and above */
|
||||
{
|
||||
return ( ( Rate >= 5000 ) && ( Rate <= 44100 ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Internal routine - call only after submitting one of the rate commands */
|
||||
NTSTATUS
|
||||
SbDsp4WriteRate(
|
||||
IN PUCHAR BasePort,
|
||||
IN USHORT Rate,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
/* NOTE - No check for validity of rate! */
|
||||
|
||||
/* Write high byte */
|
||||
Status = SbDspWrite(BasePort, (Rate & 0xff00) >> 8, Timeout);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return Status;
|
||||
|
||||
/* Write low byte */
|
||||
Status = SbDspWrite(BasePort, Rate & 0xff, Timeout);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return Status;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbDsp4SetOutputRate(
|
||||
IN PUCHAR BasePort,
|
||||
IN USHORT Rate,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
/* NOTE - No check for validity of rate! */
|
||||
|
||||
/* Prepare to write the output rate */
|
||||
Status = SbDspWrite(BasePort, SB_DSP_OUTPUT_RATE, (Rate & 0xff00) >> 8);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return Status;
|
||||
|
||||
return SbDsp4WriteRate(BasePort, Rate, Timeout);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbDsp4SetInputRate(
|
||||
IN PUCHAR BasePort,
|
||||
IN USHORT Rate,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
/* NOTE - No check for validity of rate! */
|
||||
|
||||
/* Prepare to write the input rate */
|
||||
Status = SbDspWrite(BasePort, SB_DSP_OUTPUT_RATE, (Rate & 0xff00) >> 8);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return Status;
|
||||
|
||||
return SbDsp4WriteRate(BasePort, Rate, Timeout);
|
||||
}
|
||||
|
13
reactos/lib/drivers/sound/soundblaster/soundblaster.rbuild
Normal file
13
reactos/lib/drivers/sound/soundblaster/soundblaster.rbuild
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="soundblaster" type="staticlibrary" allowwarnings="true">
|
||||
<define name="__NTDRIVER__"/>
|
||||
<define name="KERNEL"/>
|
||||
<include base="soundblaster">.</include>
|
||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||
<file>dsp_io.c</file>
|
||||
<file>version.c</file>
|
||||
<file>speaker.c</file>
|
||||
<file>rate.c</file>
|
||||
<file>mixer.c</file>
|
||||
</module>
|
66
reactos/lib/drivers/sound/soundblaster/speaker.c
Normal file
66
reactos/lib/drivers/sound/soundblaster/speaker.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Sound Blaster DSP support
|
||||
Speaker commands
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
2 July 2008 - Created (split from sbdsp.c)
|
||||
|
||||
Notes:
|
||||
Functions documented in sbdsp.h
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <sbdsp.h>
|
||||
|
||||
NTSTATUS
|
||||
SbDspEnableSpeaker(
|
||||
IN PUCHAR BasePort,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
return SbDspWrite(BasePort, SB_DSP_SPEAKER_ON, Timeout);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SbDspDisableSpeaker(
|
||||
IN PUCHAR BasePort,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
return SbDspWrite(BasePort, SB_DSP_SPEAKER_OFF, Timeout);
|
||||
}
|
||||
|
||||
/*
|
||||
VirtualBox doesn't seem to support this.
|
||||
*/
|
||||
NTSTATUS
|
||||
SbDspIsSpeakerEnabled(
|
||||
IN PUCHAR BasePort,
|
||||
OUT PBOOLEAN IsEnabled,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
UCHAR SpeakerStatus = 0;
|
||||
|
||||
if ( ! IsEnabled )
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
|
||||
/* Request the speaker status */
|
||||
Status = SbDspWrite(BasePort, SB_DSP_SPEAKER_STATUS, Timeout);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return Status;
|
||||
|
||||
/* Obtain the status */
|
||||
Status = SbDspRead(BasePort, &SpeakerStatus, Timeout);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return Status;
|
||||
|
||||
DbgPrint("SBDSP - SpeakerStatus is %02x\n", SpeakerStatus);
|
||||
*IsEnabled = (SpeakerStatus == 0xFF);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
50
reactos/lib/drivers/sound/soundblaster/version.c
Normal file
50
reactos/lib/drivers/sound/soundblaster/version.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
Sound Blaster DSP support
|
||||
Version routine
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
2 July 2008 - Created (split from sbdsp.c)
|
||||
|
||||
Notes:
|
||||
Functions documented in sbdsp.h
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <sbdsp.h>
|
||||
|
||||
NTSTATUS
|
||||
SbDspGetVersion(
|
||||
IN PUCHAR BasePort,
|
||||
OUT PUCHAR MajorVersion,
|
||||
OUT PUCHAR MinorVersion,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Make sure our parameters are sane */
|
||||
if ( ! MajorVersion )
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
|
||||
if ( ! MinorVersion )
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
|
||||
/* Send version request */
|
||||
Status = SbDspWrite(BasePort, SB_DSP_VERSION, Timeout);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return Status;
|
||||
|
||||
/* Get the major version */
|
||||
Status = SbDspRead(BasePort, MajorVersion, Timeout);
|
||||
if ( Status != STATUS_SUCCESS )
|
||||
return FALSE;
|
||||
|
||||
/* Get the minor version */
|
||||
Status = SbDspRead(BasePort, MinorVersion, Timeout);
|
||||
return Status;
|
||||
}
|
93
reactos/lib/drivers/sound/uartmidi/midiuart.c
Normal file
93
reactos/lib/drivers/sound/uartmidi/midiuart.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
ReactOS Sound System
|
||||
MIDI UART support
|
||||
|
||||
Author:
|
||||
Andrew Greenwood (silverblade@reactos.org)
|
||||
|
||||
History:
|
||||
26 May 2008 - Created
|
||||
|
||||
Notes:
|
||||
Functions documented in midiuart.h
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include "midiuart.h"
|
||||
|
||||
BOOLEAN
|
||||
WaitForMidiUartStatus(
|
||||
IN PUCHAR UartBasePort,
|
||||
IN UCHAR StatusFlags,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
ULONG RemainingTime = Timeout;
|
||||
|
||||
while ( RemainingTime -- )
|
||||
{
|
||||
if ( READ_MIDIUART_STATUS(UartBasePort) & StatusFlags )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
WriteMidiUartByte(
|
||||
IN PUCHAR UartBasePort,
|
||||
IN UCHAR Data,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
if ( ! WaitForMidiUartCTS(UartBasePort, Timeout) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WRITE_MIDIUART_DATA(UartBasePort, Data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
WriteMidiUartMulti(
|
||||
IN PUCHAR UartBasePort,
|
||||
IN PUCHAR Data,
|
||||
IN ULONG DataLength,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
ULONG DataIndex;
|
||||
|
||||
for ( DataIndex = 0; DataIndex < DataLength; ++ DataIndex )
|
||||
{
|
||||
if ( ! WriteMidiUartByte(UartBasePort, Data[DataIndex], Timeout) )
|
||||
{
|
||||
/* We failed - don't try writing any more */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
ReadMidiUartByte(
|
||||
IN PUCHAR UartBasePort,
|
||||
OUT UCHAR* Data,
|
||||
IN ULONG Timeout)
|
||||
{
|
||||
if ( ! Data )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ! WaitForMidiUartDTR(UartBasePort, Timeout) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*Data = READ_MIDIUART_DATA(UartBasePort);
|
||||
|
||||
return TRUE;
|
||||
}
|
9
reactos/lib/drivers/sound/uartmidi/uartmidi.rbuild
Normal file
9
reactos/lib/drivers/sound/uartmidi/uartmidi.rbuild
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module SYSTEM "../../../../tools/rbuild/project.dtd">
|
||||
<module name="uartmidi" type="staticlibrary" allowwarnings="true">
|
||||
<define name="__NTDRIVER__"/>
|
||||
<define name="KERNEL"/>
|
||||
<include base="soundblaster">.</include>
|
||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||
<file>midiuart.c</file>
|
||||
</module>
|
Loading…
Reference in a new issue