mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
[WDMAUD_KERNEL]
- Implement kernel side of notifying clients of volume / mute control changes svn path=/trunk/; revision=44122
This commit is contained in:
parent
a8286c3821
commit
61887111ab
6 changed files with 296 additions and 41 deletions
|
@ -372,6 +372,8 @@ WdmAudDeviceControl(
|
|||
return WdmAudGetControlDetails(DeviceObject, Irp, DeviceInfo, ClientInfo);
|
||||
case IOCTL_QUERYDEVICEINTERFACESTRING:
|
||||
return WdmAudGetDeviceInterface(DeviceObject, Irp, DeviceInfo);
|
||||
case IOCTL_GET_MIXER_EVENT:
|
||||
return WdmAudGetMixerEvent(DeviceObject, Irp, DeviceInfo, ClientInfo);
|
||||
case IOCTL_GETPOS:
|
||||
case IOCTL_GETDEVID:
|
||||
case IOCTL_GETVOLUME:
|
||||
|
|
|
@ -205,22 +205,41 @@ WdmAudOpenSysaudio(
|
|||
PWDMAUD_CLIENT Client;
|
||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
if (!DeviceExtension->NumSysAudioDevices)
|
||||
{
|
||||
/* wdmaud failed to open sysaudio */
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
ASSERT(!IsListEmpty(&DeviceExtension->SysAudioDeviceList));
|
||||
|
||||
/* allocate client context struct */
|
||||
Client = ExAllocatePool(NonPagedPool, sizeof(WDMAUD_CLIENT));
|
||||
|
||||
/* check for allocation failure */
|
||||
if (!Client)
|
||||
{
|
||||
/* not enough memory */
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* zero client context struct */
|
||||
RtlZeroMemory(Client, sizeof(WDMAUD_CLIENT));
|
||||
|
||||
/* initialize mixer event list */
|
||||
InitializeListHead(&Client->MixerEventList);
|
||||
|
||||
/* store result */
|
||||
*pClient = Client;
|
||||
|
||||
/* insert client into list */
|
||||
ExInterlockedInsertTailList(&DeviceExtension->WdmAudClientList, &Client->Entry, &DeviceExtension->Lock);
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ WdmAudInstallDevice(
|
|||
/* initialize sysaudio device list */
|
||||
InitializeListHead(&DeviceExtension->SysAudioDeviceList);
|
||||
|
||||
/* initialize client context device list */
|
||||
InitializeListHead(&DeviceExtension->WdmAudClientList);
|
||||
|
||||
/* initialize spinlock */
|
||||
KeInitializeSpinLock(&DeviceExtension->Lock);
|
||||
|
||||
|
@ -123,14 +126,11 @@ WdmAudCreate(
|
|||
IN PIRP Irp)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
PWDMAUD_CLIENT pClient;
|
||||
|
||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||
|
||||
DPRINT("WdmAudCreate\n");
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
#if KS_IMPLEMENTED
|
||||
|
@ -146,8 +146,12 @@ WdmAudCreate(
|
|||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to open sysaudio!\n");
|
||||
if (pClient)
|
||||
ExFreePool(pClient);
|
||||
|
||||
/* complete and forget */
|
||||
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
/* done */
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
@ -170,8 +174,7 @@ WdmAudClose(
|
|||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp)
|
||||
{
|
||||
DPRINT("WdmAudClose\n");
|
||||
|
||||
/* nothing to do complete request */
|
||||
#if KS_IMPLEMENTED
|
||||
Status = KsDereferenceSoftwareBusObject(DeviceExtension->DeviceHeader);
|
||||
|
||||
|
@ -186,6 +189,7 @@ WdmAudClose(
|
|||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -196,45 +200,67 @@ WdmAudCleanup(
|
|||
IN PIRP Irp)
|
||||
{
|
||||
PIO_STACK_LOCATION IoStack;
|
||||
WDMAUD_CLIENT *pClient;
|
||||
PWDMAUD_CLIENT pClient;
|
||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||
ULONG Index;
|
||||
KIRQL OldIrql;
|
||||
|
||||
DPRINT("WdmAudCleanup\n");
|
||||
/* get device extension */
|
||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* get current irp stack location */
|
||||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
pClient = (WDMAUD_CLIENT*)IoStack->FileObject->FsContext;
|
||||
/* sanity check */
|
||||
ASSERT(IoStack->FileObject);
|
||||
|
||||
if (pClient)
|
||||
/* get client context struct */
|
||||
pClient = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
|
||||
|
||||
/* sanity check */
|
||||
ASSERT(pClient);
|
||||
|
||||
/* acquire client context list lock */
|
||||
KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
|
||||
|
||||
/* remove entry */
|
||||
RemoveEntryList(&pClient->Entry);
|
||||
|
||||
/* release lock */
|
||||
KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
|
||||
|
||||
/* check if all audio pins have been closed */
|
||||
for (Index = 0; Index < pClient->NumPins; Index++)
|
||||
{
|
||||
for (Index = 0; Index < pClient->NumPins; Index++)
|
||||
{
|
||||
DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type);
|
||||
if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE)
|
||||
{
|
||||
ZwClose(pClient->hPins[Index].Handle);
|
||||
}
|
||||
}
|
||||
|
||||
if (pClient->hPins)
|
||||
{
|
||||
ExFreePool(pClient->hPins);
|
||||
}
|
||||
|
||||
ExFreePool(pClient);
|
||||
IoStack->FileObject->FsContext = NULL;
|
||||
DPRINT("Index %u Pin %p Type %x\n", Index, pClient->hPins[Index].Handle, pClient->hPins[Index].Type);
|
||||
if (pClient->hPins[Index].Handle && pClient->hPins[Index].Type != MIXER_DEVICE_TYPE)
|
||||
{
|
||||
/* found an still open audio pin */
|
||||
ZwClose(pClient->hPins[Index].Handle);
|
||||
}
|
||||
}
|
||||
|
||||
/* free pin array */
|
||||
if (pClient->hPins)
|
||||
ExFreePool(pClient->hPins);
|
||||
|
||||
/* free client context struct */
|
||||
ExFreePool(pClient);
|
||||
|
||||
/* clear old client pointer */
|
||||
IoStack->FileObject->FsContext = NULL;
|
||||
|
||||
/* complete request */
|
||||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
DPRINT("WdmAudCleanup complete\n");
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS NTAPI
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
DriverEntry(
|
||||
IN PDRIVER_OBJECT Driver,
|
||||
IN PUNICODE_STRING Registry_path
|
||||
|
|
|
@ -49,9 +49,17 @@ typedef struct
|
|||
LPWSTR DeviceInterfaceString;
|
||||
ULONG DeviceInterfaceStringSize;
|
||||
}Interface;
|
||||
|
||||
struct
|
||||
{
|
||||
HANDLE hMixer;
|
||||
ULONG NotificationType;
|
||||
ULONG Value;
|
||||
}MixerEvent;
|
||||
KSSTATE State;
|
||||
ULONG Volume;
|
||||
ULONG FrameSize;
|
||||
HANDLE hNotifyEvent;
|
||||
}u;
|
||||
|
||||
}WDMAUD_DEVICE_INFO, *PWDMAUD_DEVICE_INFO;
|
||||
|
@ -336,4 +344,21 @@ typedef struct
|
|||
METHOD_BUFFERED, \
|
||||
FILE_CREATE_TREE_CONNECTION | FILE_ANY_ACCESS)
|
||||
|
||||
/// IOCTL_GET_MIXER_EVENT
|
||||
///
|
||||
/// Description: This IOCTL queries for
|
||||
///
|
||||
/// Arguments: InputBuffer is a pointer to a WDMAUD_DEVICE_INFO structure,
|
||||
/// InputBufferSize is size of WDMAUD_DEVICE_INFO structure
|
||||
/// Note: The hDevice member must be set
|
||||
/// Result: The result is returned in the struct MixerInfo
|
||||
/// ReturnCode: STATUS_SUCCESS indicates success
|
||||
|
||||
#define IOCTL_GET_MIXER_EVENT \
|
||||
CTL_CODE(FILE_DEVICE_SOUND, \
|
||||
16, \
|
||||
METHOD_BUFFERED, \
|
||||
FILE_CREATE_TREE_CONNECTION | FILE_ANY_ACCESS)
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1770,6 +1770,7 @@ WdmAudControlOpenMixer(
|
|||
{
|
||||
/* re-use pseudo handle */
|
||||
DeviceInfo->hDevice = (HANDLE)DeviceInfo->DeviceIndex;
|
||||
ClientInfo->hPins[Index].hNotifyEvent = DeviceInfo->u.hNotifyEvent;
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
||||
}
|
||||
}
|
||||
|
@ -1787,6 +1788,7 @@ WdmAudControlOpenMixer(
|
|||
ClientInfo->hPins = Handels;
|
||||
ClientInfo->hPins[ClientInfo->NumPins].Handle = (HANDLE)DeviceInfo->DeviceIndex;
|
||||
ClientInfo->hPins[ClientInfo->NumPins].Type = MIXER_DEVICE_TYPE;
|
||||
ClientInfo->hPins[ClientInfo->NumPins].hNotifyEvent = DeviceInfo->u.hNotifyEvent;
|
||||
ClientInfo->NumPins++;
|
||||
}
|
||||
else
|
||||
|
@ -2049,11 +2051,95 @@ SetGetControlDetails(
|
|||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NotifyWdmAudClients(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG NotificationType,
|
||||
IN HANDLE hMixer,
|
||||
IN ULONG Value)
|
||||
{
|
||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||
PLIST_ENTRY Entry;
|
||||
PWDMAUD_CLIENT CurClient;
|
||||
PKEVENT EventObject;
|
||||
PMIXER_EVENT Event;
|
||||
KIRQL OldIrql;
|
||||
ULONG Index;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* acquire client context lock */
|
||||
KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
|
||||
|
||||
/* point to first entry */
|
||||
Entry = DeviceExtension->WdmAudClientList.Flink;
|
||||
|
||||
/* iterate through all clients */
|
||||
while(Entry != &DeviceExtension->WdmAudClientList)
|
||||
{
|
||||
/* get client context */
|
||||
CurClient = (PWDMAUD_CLIENT)CONTAINING_RECORD(Entry, WDMAUD_CLIENT, Entry);
|
||||
|
||||
/* now iterate through all pins and try to find an matching handle */
|
||||
for(Index = 0; Index < CurClient->NumPins; Index++)
|
||||
{
|
||||
if (CurClient->hPins[Index].Handle == hMixer && CurClient->hPins[Index].Type == MIXER_DEVICE_TYPE && CurClient->hPins[Index].hNotifyEvent)
|
||||
{
|
||||
/* found a matching mixer handle and a valid notify event */
|
||||
Status = ObReferenceObjectByHandle(CurClient->hPins[Index].hNotifyEvent, EVENT_MODIFY_STATE, ExEventObjectType, UserMode, (LPVOID*)&EventObject, NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Invalid notify event passed %p from client %p\n", CurClient->hPins[Index].hNotifyEvent, CurClient);
|
||||
break;
|
||||
}
|
||||
|
||||
/* allocate event entry */
|
||||
Event = (PMIXER_EVENT)ExAllocatePool(NonPagedPool, sizeof(MIXER_EVENT));
|
||||
if (!Event)
|
||||
{
|
||||
/* no memory */
|
||||
ObDereferenceObject(EventObject);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* initialize event entry */
|
||||
Event->hMixer = hMixer;
|
||||
Event->NotificationType = NotificationType;
|
||||
Event->Value = Value;
|
||||
|
||||
/* insert event entry */
|
||||
InsertTailList(&CurClient->MixerEventList, &Event->Entry);
|
||||
|
||||
/* now signal the event */
|
||||
KeSetEvent(EventObject, 0, FALSE);
|
||||
|
||||
/* dereference event */
|
||||
ObDereferenceObject(EventObject);
|
||||
|
||||
/* search next client */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* move to next client */
|
||||
Entry = Entry->Flink;
|
||||
}
|
||||
|
||||
/* release client context lock */
|
||||
KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
|
||||
|
||||
/* done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SetGetMuteControlDetails(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN ULONG DeviceId,
|
||||
IN ULONG NodeId,
|
||||
IN ULONG dwLineID,
|
||||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||
IN ULONG bSet)
|
||||
{
|
||||
|
@ -2074,9 +2160,21 @@ SetGetMuteControlDetails(
|
|||
/* set control details */
|
||||
Status = SetGetControlDetails(DeviceObject, DeviceId, NodeId, DeviceInfo, bSet, KSPROPERTY_AUDIO_MUTE, MAXULONG, &Value);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
/* FIXME SEH */
|
||||
if (!bSet)
|
||||
{
|
||||
Input->fValue = Value;
|
||||
return Status;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* notify clients of a line change */
|
||||
NotifyWdmAudClients(DeviceObject, MM_MIXM_LINE_CHANGE, DeviceInfo->hDevice, dwLineID);
|
||||
}
|
||||
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -2147,10 +2245,76 @@ SetGetVolumeControlDetails(
|
|||
}
|
||||
Input->dwValue = VolumeData->InputSteppingDelta * (VolumeData->ValuesCount-1);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* notify clients of a line change */
|
||||
NotifyWdmAudClients(DeviceObject, MM_MIXM_CONTROL_CHANGE, DeviceInfo->hDevice, MixerControl->dwControlID);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
WdmAudGetMixerEvent(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||
IN PWDMAUD_CLIENT ClientInfo)
|
||||
{
|
||||
PWDMAUD_DEVICE_EXTENSION DeviceExtension;
|
||||
PMIXER_EVENT Event = NULL;
|
||||
PLIST_ENTRY Entry;
|
||||
KIRQL OldIrql;
|
||||
|
||||
/* get device extension */
|
||||
DeviceExtension = (PWDMAUD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||||
|
||||
/* acquire client context lock */
|
||||
KeAcquireSpinLock(&DeviceExtension->Lock, &OldIrql);
|
||||
|
||||
/* point to first entry */
|
||||
Entry = ClientInfo->MixerEventList.Flink;
|
||||
|
||||
while(Entry != &ClientInfo->MixerEventList)
|
||||
{
|
||||
/* get mixer event */
|
||||
Event = (PMIXER_EVENT)CONTAINING_RECORD(Entry, MIXER_EVENT, Entry);
|
||||
|
||||
if (Event->hMixer == DeviceInfo->hDevice)
|
||||
{
|
||||
/* found an event for that particular device */
|
||||
break;
|
||||
}
|
||||
|
||||
/* no match found */
|
||||
Event = NULL;
|
||||
|
||||
/* move to next entry */
|
||||
Entry = Entry->Flink;
|
||||
}
|
||||
|
||||
|
||||
/* release client context lock */
|
||||
KeReleaseSpinLock(&DeviceExtension->Lock, OldIrql);
|
||||
|
||||
if (!Event)
|
||||
{
|
||||
/* no events available */
|
||||
return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
|
||||
}
|
||||
|
||||
/* store event result */
|
||||
DeviceInfo->u.MixerEvent.hMixer = Event->hMixer;
|
||||
DeviceInfo->u.MixerEvent.NotificationType = Event->NotificationType;
|
||||
DeviceInfo->u.MixerEvent.Value = Event->Value;
|
||||
|
||||
/* free event info */
|
||||
ExFreePool(Event);
|
||||
|
||||
/* done */
|
||||
return SetIrpIoStatus(Irp, STATUS_SUCCESS, sizeof(WDMAUD_DEVICE_INFO));
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
WdmAudSetControlDetails(
|
||||
|
@ -2193,7 +2357,7 @@ WdmAudSetControlDetails(
|
|||
if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
|
||||
{
|
||||
/* send the request */
|
||||
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, TRUE);
|
||||
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, MixerLine->Line.dwLineID, DeviceInfo, TRUE);
|
||||
}
|
||||
else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
|
||||
{
|
||||
|
@ -2245,7 +2409,7 @@ WdmAudGetControlDetails(
|
|||
if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
|
||||
{
|
||||
/* send the request */
|
||||
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, DeviceInfo, FALSE);
|
||||
Status = SetGetMuteControlDetails(DeviceObject, MixerLine->DeviceIndex, NodeId, MixerLine->Line.dwLineID, DeviceInfo, FALSE);
|
||||
}
|
||||
else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
|
||||
{
|
||||
|
|
|
@ -18,19 +18,30 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE Handle;
|
||||
SOUND_DEVICE_TYPE Type;
|
||||
ULONG FilterId;
|
||||
ULONG PinId;
|
||||
}WDMAUD_HANDLE, *PWDMAUD_HANDLE;
|
||||
LIST_ENTRY Entry;
|
||||
HANDLE hMixer;
|
||||
ULONG NotificationType;
|
||||
ULONG Value;
|
||||
}MIXER_EVENT, *PMIXER_EVENT;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE Handle;
|
||||
SOUND_DEVICE_TYPE Type;
|
||||
ULONG FilterId;
|
||||
ULONG PinId;
|
||||
HANDLE hNotifyEvent;
|
||||
}WDMAUD_HANDLE, *PWDMAUD_HANDLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
HANDLE hProcess;
|
||||
ULONG NumPins;
|
||||
WDMAUD_HANDLE * hPins;
|
||||
|
||||
LIST_ENTRY MixerEventList;
|
||||
}WDMAUD_CLIENT, *PWDMAUD_CLIENT;
|
||||
|
||||
typedef struct
|
||||
|
@ -115,7 +126,7 @@ typedef struct
|
|||
ULONG WaveOutDeviceCount;
|
||||
LIST_ENTRY WaveOutList;
|
||||
|
||||
|
||||
LIST_ENTRY WdmAudClientList;
|
||||
}WDMAUD_DEVICE_EXTENSION, *PWDMAUD_DEVICE_EXTENSION;
|
||||
|
||||
NTSTATUS
|
||||
|
@ -243,6 +254,14 @@ WdmAudSetControlDetails(
|
|||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||
IN PWDMAUD_CLIENT ClientInfo);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
WdmAudGetMixerEvent(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN PIRP Irp,
|
||||
IN PWDMAUD_DEVICE_INFO DeviceInfo,
|
||||
IN PWDMAUD_CLIENT ClientInfo);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
WdmAudGetControlDetails(
|
||||
|
|
Loading…
Reference in a new issue