You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1125 lines
35 KiB
1125 lines
35 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: sysaudio.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
#include "redbook.h"
|
|
#include "proto.h"
|
|
#include <wdmguid.h>
|
|
#include <ksmedia.h>
|
|
|
|
#ifdef _USE_ETW
|
|
#include "sysaudio.tmh"
|
|
#endif // _USE_ETW
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, AttachVirtualSource)
|
|
#pragma alloc_text(PAGE, CloseSysAudio)
|
|
#pragma alloc_text(PAGE, GetPinProperty)
|
|
#pragma alloc_text(PAGE, GetVolumeNodeId)
|
|
#pragma alloc_text(PAGE, InitializeVirtualSource)
|
|
#pragma alloc_text(PAGE, OpenInterfaceByGuid)
|
|
#pragma alloc_text(PAGE, OpenSysAudio)
|
|
#pragma alloc_text(PAGE, RedBookKsSetVolume)
|
|
#pragma alloc_text(PAGE, SetNextDeviceState)
|
|
#pragma alloc_text(PAGE, SysAudioPnpNotification)
|
|
#pragma alloc_text(PAGE, UninitializeVirtualSource)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
OpenSysAudio(
|
|
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is a wrapper around all the work that must be done
|
|
just to open sysaudio for playback. the code was swiped from
|
|
Win98, and then translated into CSN (Cutler Standard Notation)
|
|
|
|
Arguments:
|
|
|
|
DeviceExtensionPinConnect - if successful, this will be the pin to send data to
|
|
|
|
PinFileObject - if successful, the file object this pin is associated
|
|
with is returned in this structure
|
|
|
|
PinDeviceObject - if successful, the device object this pin is
|
|
associated with is returned in this structure
|
|
|
|
VolumeNodeId - ?? No idea what this is... yet.
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
PFILE_OBJECT guidFileObject;
|
|
PFILE_OBJECT pinFileObject;
|
|
HANDLE deviceHandle;
|
|
NTSTATUS status;
|
|
HANDLE pinHandle;
|
|
ULONG volumeNodeId;
|
|
ULONG mixerPinId;
|
|
|
|
ULONG pins, pinId;
|
|
|
|
PAGED_CODE();
|
|
VerifyCalledByThread(DeviceExtension);
|
|
|
|
guidFileObject = NULL;
|
|
pinFileObject = NULL;
|
|
deviceHandle = NULL;
|
|
status = STATUS_SUCCESS;
|
|
pinHandle = NULL;
|
|
volumeNodeId = -1;
|
|
mixerPinId = DeviceExtension->Stream.MixerPinId;
|
|
|
|
|
|
TRY {
|
|
ASSERT( mixerPinId != MAXULONG );
|
|
|
|
//
|
|
// Note dependency on IoRegisterPlugPlayNotification() in pnp.c
|
|
//
|
|
|
|
status = OpenInterfaceByGuid(
|
|
//&KSCATEGORY_SYSAUDIO,
|
|
&KSCATEGORY_PREFERRED_WAVEOUT_DEVICE,
|
|
&deviceHandle,
|
|
&guidFileObject);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
LEAVE;
|
|
}
|
|
|
|
//
|
|
// Get the number of pins
|
|
//
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SysAudio => Getting Pin Property PIN_CTYPES\n"));
|
|
|
|
status = GetPinProperty(guidFileObject,
|
|
KSPROPERTY_PIN_CTYPES,
|
|
0, // doesn't matter for ctypes
|
|
sizeof(pins),
|
|
&pins);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"SysAudio !! Unable to get number of pins %lx\n",
|
|
status));
|
|
RedBookLogError(DeviceExtension,
|
|
REDBOOK_ERR_CANNOT_GET_NUMBER_OF_PINS,
|
|
status);
|
|
LEAVE;
|
|
}
|
|
|
|
//
|
|
// Try to get a matching pin -- brute force method
|
|
//
|
|
|
|
for( pinId = 0; pinId < pins; pinId++) {
|
|
|
|
KSPIN_COMMUNICATION communication;
|
|
KSPIN_DATAFLOW dataFlow;
|
|
|
|
//
|
|
// check communication of the pin. accept either
|
|
// a sink or a pin that is both a source and sink
|
|
//
|
|
|
|
status = GetPinProperty(guidFileObject,
|
|
KSPROPERTY_PIN_COMMUNICATION,
|
|
pinId,
|
|
sizeof(communication),
|
|
&communication);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"SysAudio !! Pin %d communication query "
|
|
"failed %lx\n", pinId, status ));
|
|
continue;
|
|
}
|
|
|
|
if ( communication != KSPIN_COMMUNICATION_SINK &&
|
|
communication != KSPIN_COMMUNICATION_BOTH ) continue;
|
|
|
|
//
|
|
// only use this pin if it accepts incoming data
|
|
//
|
|
|
|
status = GetPinProperty(guidFileObject,
|
|
KSPROPERTY_PIN_DATAFLOW,
|
|
pinId,
|
|
sizeof(dataFlow),
|
|
&dataFlow);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"SysAudio !! Pin %d dataflow query failed %lx\n",
|
|
pinId, status));
|
|
continue;
|
|
}
|
|
|
|
if (dataFlow != KSPIN_DATAFLOW_IN) continue;
|
|
|
|
//
|
|
// we have found a matching pin, so attempt to connect
|
|
//
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SysAudio => Attempt to connect to pin %d\n", pinId));
|
|
|
|
DeviceExtension->Stream.Connect.PinId = pinId;
|
|
DeviceExtension->Stream.Connect.PinToHandle = NULL;
|
|
|
|
status = KsCreatePin(deviceHandle,
|
|
&DeviceExtension->Stream.Connect,
|
|
GENERIC_WRITE, // FILE_WRITE_ACCESS
|
|
&pinHandle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"SysAudio => Cannot create a writable pin %d\n",
|
|
pinId));
|
|
continue;
|
|
}
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SysAudio => Connected to pin %d\n", pinId ));
|
|
|
|
//
|
|
// get the object associated with the pinHandle just created
|
|
// so we can then get other information about the pin
|
|
//
|
|
|
|
status = ObReferenceObjectByHandle(pinHandle,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
NULL,
|
|
KernelMode,
|
|
&pinFileObject,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"SysAudio !! Object from handle for pin "
|
|
"failed %lx\n", status));
|
|
LEAVE;
|
|
}
|
|
|
|
//
|
|
// this allows us to change our output volume
|
|
// this just sends a ks ioctl, no referencing done here
|
|
//
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SysAudio => Getting VolumeNodeId\n"));
|
|
|
|
status = GetVolumeNodeId(pinFileObject,
|
|
&volumeNodeId);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"SysAudio !! Unable to get volume node "
|
|
"id %lx\n", status));
|
|
LEAVE;
|
|
}
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SysAudio => Attaching PinFileObject %p "
|
|
"to MixerPinId %d\n", pinFileObject,
|
|
mixerPinId));
|
|
|
|
//
|
|
// this just sends a ks ioctl, no referencing done here
|
|
//
|
|
|
|
status = AttachVirtualSource(pinFileObject, mixerPinId);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"SysAudio !! Unable to attach virtual "
|
|
"source %lx\n", status));
|
|
LEAVE;
|
|
}
|
|
|
|
//
|
|
// successful completion
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
LEAVE;
|
|
}
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"Sysaudio !! Unable to connect to any pins\n"));
|
|
RedBookLogError(DeviceExtension,
|
|
REDBOOK_ERR_CANNOT_CONNECT_TO_PLAYBACK_PINS,
|
|
status);
|
|
|
|
//
|
|
// no pin succeeded, so set status to failure
|
|
//
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
LEAVE;
|
|
|
|
|
|
} FINALLY {
|
|
|
|
//
|
|
// the pin handle is not required, as we've referenced
|
|
// the pin in pinFileObject. close it here.
|
|
//
|
|
|
|
if (pinHandle != NULL) {
|
|
ZwClose(pinHandle);
|
|
pinHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// the device handle is only required to create
|
|
// the actual pin. close it here.
|
|
//
|
|
|
|
if (deviceHandle != NULL) {
|
|
ZwClose(deviceHandle);
|
|
deviceHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// the guidFileObject is also only required to query
|
|
// and create the pins. close it here.
|
|
//
|
|
// (pinFileObject is still important)
|
|
//
|
|
|
|
if (guidFileObject != NULL) {
|
|
ObDereferenceObject(guidFileObject);
|
|
guidFileObject = NULL;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
if (pinFileObject != NULL) {
|
|
ObDereferenceObject(pinFileObject);
|
|
pinFileObject = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// the MixerPinId should not have changed in this function
|
|
//
|
|
|
|
ASSERT(mixerPinId == DeviceExtension->Stream.MixerPinId);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DeviceExtension->Stream.PinFileObject = pinFileObject;
|
|
DeviceExtension->Stream.PinDeviceObject =
|
|
IoGetRelatedDeviceObject(pinFileObject);
|
|
DeviceExtension->Stream.VolumeNodeId = volumeNodeId;
|
|
|
|
} else {
|
|
|
|
DeviceExtension->Stream.PinFileObject = NULL;
|
|
DeviceExtension->Stream.PinDeviceObject = NULL;
|
|
DeviceExtension->Stream.VolumeNodeId = -1;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
CloseSysAudio(
|
|
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
VerifyCalledByThread(DeviceExtension);
|
|
|
|
ASSERT(DeviceExtension->Stream.PinFileObject);
|
|
ASSERT(DeviceExtension->Stream.PinDeviceObject);
|
|
|
|
ObDereferenceObject(DeviceExtension->Stream.PinFileObject);
|
|
DeviceExtension->Stream.PinDeviceObject = NULL;
|
|
DeviceExtension->Stream.PinFileObject = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetPinProperty(
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG PropertyId,
|
|
IN ULONG PinId,
|
|
IN ULONG PropertySize,
|
|
OUT PVOID Property
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
another wrapper to hide getting pin properties
|
|
|
|
Arguments:
|
|
|
|
FileObject - file object to query
|
|
|
|
PropertyId - what property to query
|
|
|
|
PinId - which pin to query
|
|
|
|
PropertySize - size of output buffer
|
|
|
|
Property - output buffer for property
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
ULONG bytesReturned;
|
|
KSP_PIN prop = {0};
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
prop.Property.Set = KSPROPSETID_Pin;
|
|
prop.Property.Id = PropertyId;
|
|
prop.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
prop.PinId = PinId;
|
|
prop.Reserved = 0;
|
|
|
|
status = KsSynchronousIoControlDevice( FileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&prop,
|
|
sizeof(prop),
|
|
Property,
|
|
PropertySize,
|
|
&bytesReturned
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"GetPinProperty !! fileobj %p property %p "
|
|
"pin %d status %lx\n",
|
|
FileObject, Property, PinId, status));
|
|
return status;
|
|
}
|
|
|
|
ASSERT( bytesReturned == PropertySize );
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetVolumeNodeId(
|
|
IN PFILE_OBJECT FileObject,
|
|
OUT PULONG VolumeNodeId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the pin to set the volume for playback
|
|
|
|
Arguments:
|
|
|
|
FileObject - The fileobject which contains the pin
|
|
|
|
VolumeNodeId - id of the volume node
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
KSPROPERTY property = {0};
|
|
ULONG bytesReturned;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
property.Set = KSPROPSETID_Sysaudio_Pin;
|
|
property.Id = KSPROPERTY_SYSAUDIO_PIN_VOLUME_NODE;
|
|
property.Flags = KSPROPERTY_TYPE_GET;
|
|
|
|
status = KsSynchronousIoControlDevice( FileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&property,
|
|
sizeof(property),
|
|
VolumeNodeId,
|
|
sizeof(ULONG),
|
|
&bytesReturned
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"GetVolumeNodeId !! fileobj %p status %lx\n",
|
|
FileObject, status));
|
|
return status;
|
|
}
|
|
|
|
ASSERT(bytesReturned == sizeof(ULONG));
|
|
return(status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
UninitializeVirtualSource(
|
|
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
ULONG state;
|
|
|
|
PAGED_CODE();
|
|
VerifyCalledByThread(DeviceExtension);
|
|
|
|
ASSERT(DeviceExtension->Stream.MixerPinId != -1);
|
|
ASSERT(DeviceExtension->Stream.MixerFileObject != NULL);
|
|
|
|
state = GetCdromState(DeviceExtension);
|
|
ASSERT(state == CD_STOPPED);
|
|
|
|
DeviceExtension->Stream.MixerPinId = -1;
|
|
ObDereferenceObject(DeviceExtension->Stream.MixerFileObject);
|
|
DeviceExtension->Stream.MixerFileObject = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
InitializeVirtualSource(
|
|
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
MixerPinId - initialized to the correct pin id of mixer
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
SYSAUDIO_CREATE_VIRTUAL_SOURCE createVirtualSource = {0};
|
|
PFILE_OBJECT fileObject;
|
|
NTSTATUS status;
|
|
HANDLE deviceHandle;
|
|
ULONG bytesReturned;
|
|
ULONG mixerPinId;
|
|
ULONG state;
|
|
|
|
PAGED_CODE();
|
|
VerifyCalledByThread(DeviceExtension);
|
|
|
|
ASSERT(DeviceExtension->Stream.MixerPinId == -1);
|
|
ASSERT(DeviceExtension->Stream.MixerFileObject == NULL);
|
|
|
|
state = GetCdromState(DeviceExtension);
|
|
ASSERT(state == CD_STOPPED);
|
|
|
|
fileObject = NULL;
|
|
status = STATUS_SUCCESS;
|
|
deviceHandle = NULL;
|
|
mixerPinId = -1;
|
|
|
|
//
|
|
// use IoGetDeviceInterfaces()
|
|
//
|
|
status = OpenInterfaceByGuid(&KSCATEGORY_SYSAUDIO,
|
|
&deviceHandle,
|
|
&fileObject);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
RedBookLogError(DeviceExtension,
|
|
REDBOOK_ERR_CANNOT_OPEN_SYSAUDIO_MIXER,
|
|
status);
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"CreateVirtSource !! Unable to open sysaudio\\mixer %lx\n",
|
|
status));
|
|
goto exit;
|
|
}
|
|
|
|
createVirtualSource.Property.Set = KSPROPSETID_Sysaudio;
|
|
createVirtualSource.Property.Id = KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE;
|
|
createVirtualSource.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
createVirtualSource.PinCategory = KSNODETYPE_CD_PLAYER;
|
|
createVirtualSource.PinName = KSNODETYPE_CD_PLAYER;
|
|
|
|
status = KsSynchronousIoControlDevice(fileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&createVirtualSource,
|
|
sizeof(createVirtualSource),
|
|
&mixerPinId,
|
|
sizeof(ULONG), // MixerPinId
|
|
&bytesReturned
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
RedBookLogError(DeviceExtension,
|
|
REDBOOK_ERR_CANNOT_CREATE_VIRTUAL_SOURCE,
|
|
status);
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
|
"CreateVirtSource !! creating virtual source "
|
|
"failed %lx\n", status));
|
|
goto exit;
|
|
}
|
|
|
|
ASSERT( bytesReturned == sizeof(ULONG) );
|
|
|
|
exit:
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
DeviceExtension->Stream.MixerPinId = mixerPinId;
|
|
DeviceExtension->Stream.MixerFileObject = fileObject;
|
|
|
|
} else if (fileObject != NULL) {
|
|
|
|
//
|
|
// failed to open, so deref object if non-null
|
|
//
|
|
|
|
ObDereferenceObject(fileObject);
|
|
fileObject = NULL;
|
|
|
|
}
|
|
|
|
if (deviceHandle != NULL) {
|
|
ZwClose(deviceHandle);
|
|
deviceHandle = NULL;
|
|
}
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
AttachVirtualSource(
|
|
IN PFILE_OBJECT PinFileObject,
|
|
IN ULONG MixerPinId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
FileObject - ??
|
|
|
|
MixerPinId - ??
|
|
|
|
Return Value:
|
|
|
|
status
|
|
|
|
--*/
|
|
{
|
|
SYSAUDIO_ATTACH_VIRTUAL_SOURCE attachVirtualSource = {0};
|
|
NTSTATUS status;
|
|
ULONG bytesReturned;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// if the source hasn't been initialized, reject this
|
|
// request as invalid
|
|
//
|
|
|
|
if(MixerPinId == MAXULONG) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
|
"AttatchVirtSource !! Mixer Pin uninitialized\n"));
|
|
ASSERT(!"Mixer Pin Uninitialized");
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
|
|
attachVirtualSource.Property.Set = KSPROPSETID_Sysaudio_Pin;
|
|
attachVirtualSource.Property.Id = KSPROPERTY_SYSAUDIO_ATTACH_VIRTUAL_SOURCE;
|
|
attachVirtualSource.Property.Flags = KSPROPERTY_TYPE_SET;
|
|
attachVirtualSource.MixerPinId = MixerPinId;
|
|
|
|
status = KsSynchronousIoControlDevice(PinFileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&attachVirtualSource,
|
|
sizeof(attachVirtualSource),
|
|
NULL,
|
|
0,
|
|
&bytesReturned
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"AttachVirtSource !! Couldn't attatch %lx\n", status));
|
|
return status;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
SetNextDeviceState(
|
|
PREDBOOK_DEVICE_EXTENSION DeviceExtension,
|
|
KSSTATE State
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KSIDENTIFIER stateProperty = {0};
|
|
NTSTATUS status;
|
|
ULONG bytesReturned;
|
|
KSSTATE acquireState;
|
|
PFILE_OBJECT fileObject;
|
|
|
|
PAGED_CODE();
|
|
VerifyCalledByThread(DeviceExtension);
|
|
|
|
fileObject = DeviceExtension->Stream.PinFileObject;
|
|
|
|
acquireState = KSSTATE_ACQUIRE;
|
|
|
|
stateProperty.Set = KSPROPSETID_Connection;
|
|
stateProperty.Id = KSPROPERTY_CONNECTION_STATE;
|
|
stateProperty.Flags = KSPROPERTY_TYPE_SET;
|
|
|
|
ASSERT(fileObject);
|
|
status = KsSynchronousIoControlDevice(fileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&stateProperty,
|
|
sizeof(stateProperty),
|
|
&acquireState,
|
|
sizeof(acquireState),
|
|
&bytesReturned
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
|
"SetDeviceState => (1) Audio device error %x. need to "
|
|
"stop playback AND change audio devices\n", status));
|
|
}
|
|
|
|
//
|
|
// now that it's acquired, set the new state
|
|
//
|
|
|
|
stateProperty.Set = KSPROPSETID_Connection;
|
|
stateProperty.Id = KSPROPERTY_CONNECTION_STATE;
|
|
stateProperty.Flags = KSPROPERTY_TYPE_SET;
|
|
|
|
status = KsSynchronousIoControlDevice(fileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&stateProperty,
|
|
sizeof(stateProperty),
|
|
&State,
|
|
sizeof(State),
|
|
&bytesReturned
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
|
|
"SetDeviceState => (2) Audio device error %x. need to "
|
|
"stop playback AND change audio devices\n", status));
|
|
}
|
|
return;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// this table is in 1/65536 decibles for a UCHAR setting: //
|
|
// 20 * log10( Level / 256 ) * 65536 //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
AttenuationTable[] = {
|
|
0x7fffffff, 0xffcfd5d0, 0xffd5db16, 0xffd960ad, // 0- 3
|
|
0xffdbe05c, 0xffddd08a, 0xffdf65f3, 0xffe0bcb7, // 4- 7
|
|
0xffe1e5a2, 0xffe2eb89, 0xffe3d5d0, 0xffe4a9be, // 8- b
|
|
0xffe56b39, 0xffe61d34, 0xffe6c1fd, 0xffe75b67, // c- f
|
|
0xffe7eae8, 0xffe871b6, 0xffe8f0cf, 0xffe96908, // 10-13
|
|
0xffe9db16, 0xffea4793, 0xffeaaf04, 0xffeb11dc, // 14-17
|
|
0xffeb707f, 0xffebcb44, 0xffec227a, 0xffec7665, // 18-1b
|
|
0xffecc743, 0xffed154b, 0xffed60ad, 0xffeda996, // 1c-1f
|
|
0xffedf02e, 0xffee349b, 0xffee76fc, 0xffeeb771, // 20-23
|
|
0xffeef615, 0xffef3302, 0xffef6e4e, 0xffefa810, // 24-27
|
|
0xffefe05c, 0xfff01744, 0xfff04cda, 0xfff0812c, // 28-2b
|
|
0xfff0b44b, 0xfff0e643, 0xfff11722, 0xfff146f4, // 2c-2f
|
|
0xfff175c5, 0xfff1a39e, 0xfff1d08a, 0xfff1fc93, // 30-33
|
|
0xfff227c0, 0xfff2521b, 0xfff27bab, 0xfff2a478, // 34-37
|
|
0xfff2cc89, 0xfff2f3e5, 0xfff31a91, 0xfff34093, // 38-3b
|
|
0xfff365f3, 0xfff38ab4, 0xfff3aedc, 0xfff3d270, // 3c-3f
|
|
0xfff3f574, 0xfff417ee, 0xfff439e1, 0xfff45b51, // 40-43
|
|
0xfff47c42, 0xfff49cb8, 0xfff4bcb7, 0xfff4dc42, // 44-47
|
|
0xfff4fb5b, 0xfff51a07, 0xfff53848, 0xfff55621, // 48-4b
|
|
0xfff57394, 0xfff590a5, 0xfff5ad56, 0xfff5c9aa, // 4c-4f
|
|
0xfff5e5a2, 0xfff60142, 0xfff61c8a, 0xfff6377e, // 50-53
|
|
0xfff65220, 0xfff66c70, 0xfff68672, 0xfff6a027, // 54-57
|
|
0xfff6b991, 0xfff6d2b1, 0xfff6eb89, 0xfff7041b, // 58-5b
|
|
0xfff71c68, 0xfff73472, 0xfff74c3a, 0xfff763c2, // 5c-5f
|
|
0xfff77b0b, 0xfff79216, 0xfff7a8e4, 0xfff7bf77, // 60-63
|
|
0xfff7d5d0, 0xfff7ebf0, 0xfff801d9, 0xfff8178a, // 64-67
|
|
0xfff82d06, 0xfff8424d, 0xfff85761, 0xfff86c42, // 68-6b
|
|
0xfff880f1, 0xfff89570, 0xfff8a9be, 0xfff8bdde, // 6c-6f
|
|
0xfff8d1cf, 0xfff8e593, 0xfff8f92b, 0xfff90c96, // 70-73
|
|
0xfff91fd7, 0xfff932ed, 0xfff945d9, 0xfff9589d, // 74-77
|
|
0xfff96b39, 0xfff97dad, 0xfff98ffa, 0xfff9a221, // 78-7b
|
|
0xfff9b422, 0xfff9c5fe, 0xfff9d7b6, 0xfff9e94a, // 7c-7f
|
|
0xfff9faba, 0xfffa0c08, 0xfffa1d34, 0xfffa2e3e, // 80-83
|
|
0xfffa3f27, 0xfffa4fef, 0xfffa6097, 0xfffa711f, // 84-87
|
|
0xfffa8188, 0xfffa91d3, 0xfffaa1ff, 0xfffab20d, // 88-8b
|
|
0xfffac1fd, 0xfffad1d1, 0xfffae188, 0xfffaf122, // 8c-8f
|
|
0xfffb00a1, 0xfffb1004, 0xfffb1f4d, 0xfffb2e7a, // 90-93
|
|
0xfffb3d8e, 0xfffb4c87, 0xfffb5b67, 0xfffb6a2d, // 94-97
|
|
0xfffb78da, 0xfffb876f, 0xfffb95eb, 0xfffba450, // 98-9b
|
|
0xfffbb29c, 0xfffbc0d2, 0xfffbcef0, 0xfffbdcf7, // 9c-9f
|
|
0xfffbeae8, 0xfffbf8c3, 0xfffc0688, 0xfffc1437, // a0-a3
|
|
0xfffc21d0, 0xfffc2f55, 0xfffc3cc4, 0xfffc4a1f, // a4-a7
|
|
0xfffc5766, 0xfffc6498, 0xfffc71b6, 0xfffc7ec1, // a8-ab
|
|
0xfffc8bb8, 0xfffc989c, 0xfffca56d, 0xfffcb22b, // ac-af
|
|
0xfffcbed7, 0xfffccb70, 0xfffcd7f7, 0xfffce46c, // b0-b3
|
|
0xfffcf0cf, 0xfffcfd21, 0xfffd0961, 0xfffd1590, // b4-b7
|
|
0xfffd21ae, 0xfffd2dbc, 0xfffd39b8, 0xfffd45a4, // b8-bb
|
|
0xfffd5180, 0xfffd5d4c, 0xfffd6908, 0xfffd74b4, // bc-bf
|
|
0xfffd8051, 0xfffd8bde, 0xfffd975c, 0xfffda2ca, // c0-c3
|
|
0xfffdae2a, 0xfffdb97b, 0xfffdc4bd, 0xfffdcff1, // c4-c7
|
|
0xfffddb16, 0xfffde62d, 0xfffdf136, 0xfffdfc31, // c8-cb
|
|
0xfffe071f, 0xfffe11fe, 0xfffe1cd0, 0xfffe2795, // cc-cf
|
|
0xfffe324c, 0xfffe3cf6, 0xfffe4793, 0xfffe5224, // d0-d3
|
|
0xfffe5ca7, 0xfffe671e, 0xfffe7188, 0xfffe7be6, // d4-d7
|
|
0xfffe8637, 0xfffe907d, 0xfffe9ab6, 0xfffea4e3, // d8-db
|
|
0xfffeaf04, 0xfffeb91a, 0xfffec324, 0xfffecd22, // dc-df
|
|
0xfffed715, 0xfffee0fd, 0xfffeead9, 0xfffef4aa, // e0-e3
|
|
0xfffefe71, 0xffff082c, 0xffff11dc, 0xffff1b82, // e4-e7
|
|
0xffff251d, 0xffff2ead, 0xffff3833, 0xffff41ae, // e8-eb
|
|
0xffff4b1f, 0xffff5486, 0xffff5de3, 0xffff6736, // ec-ef
|
|
0xffff707f, 0xffff79be, 0xffff82f3, 0xffff8c1e, // f0-f3
|
|
0xffff9540, 0xffff9e58, 0xffffa767, 0xffffb06c, // f4-f7
|
|
0xffffb968, 0xffffc25b, 0xffffcb44, 0xffffd425, // f8-fb
|
|
0xffffdcfc, 0xffffe5ca, 0xffffee90, 0x00000000, // fc-ff
|
|
};
|
|
|
|
#define DA_CHANNEL_LEFT 0
|
|
#define DA_CHANNEL_RIGHT 1
|
|
#define DA_CHANNEL_MAX 2
|
|
|
|
VOID
|
|
RedBookKsSetVolume(
|
|
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
|
|
KSNODEPROPERTY_AUDIO_CHANNEL volumeProperty = {0};
|
|
VOLUME_CONTROL volume = {0};
|
|
NTSTATUS status;
|
|
ULONG32 channel;
|
|
ULONG32 bytesReturned = 0;
|
|
BOOLEAN mute;
|
|
|
|
PAGED_CODE();
|
|
VerifyCalledByThread(DeviceExtension);
|
|
|
|
volume = DeviceExtension->CDRom.Volume;
|
|
|
|
//
|
|
// These settings are common for all the sets
|
|
//
|
|
|
|
volumeProperty.NodeProperty.Property.Set = KSPROPSETID_Audio;
|
|
volumeProperty.NodeProperty.Property.Flags = KSPROPERTY_TYPE_SET |
|
|
KSPROPERTY_TYPE_TOPOLOGY;
|
|
volumeProperty.NodeProperty.NodeId = DeviceExtension->Stream.VolumeNodeId;
|
|
|
|
//
|
|
// Do both Left and right channels
|
|
//
|
|
|
|
for ( channel = 0; channel < DA_CHANNEL_MAX; channel++ ) {
|
|
|
|
//
|
|
// handle the correct channel
|
|
//
|
|
|
|
volumeProperty.Channel = channel;
|
|
|
|
//
|
|
// if not muting the channel, set the volume
|
|
//
|
|
|
|
if ( volume.PortVolume[channel] != 0 ) {
|
|
ULONG32 level;
|
|
ULONG32 index;
|
|
|
|
volumeProperty.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
|
|
|
|
level = AttenuationTable[ volume.PortVolume[channel] ];
|
|
|
|
ASSERT(DeviceExtension->Stream.PinFileObject);
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SetVolume => Setting channel %d to %lx\n",
|
|
channel, level ));
|
|
status = KsSynchronousIoControlDevice(DeviceExtension->Stream.PinFileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&volumeProperty,
|
|
sizeof(volumeProperty),
|
|
&level,
|
|
sizeof(level),
|
|
&bytesReturned
|
|
);
|
|
// ASSERT( NT_SUCCESS(status) );
|
|
mute = FALSE;
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SetVolume => Un-Muting channel %d\n", channel));
|
|
} else {
|
|
mute = TRUE;
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"SetVolume => Muting channel %d\n", channel));
|
|
}
|
|
volumeProperty.NodeProperty.Property.Id = KSPROPERTY_AUDIO_MUTE;
|
|
|
|
status = KsSynchronousIoControlDevice(DeviceExtension->Stream.PinFileObject,
|
|
KernelMode,
|
|
IOCTL_KS_PROPERTY,
|
|
&volumeProperty,
|
|
sizeof(volumeProperty),
|
|
&mute,
|
|
sizeof(mute),
|
|
&bytesReturned
|
|
);
|
|
// ASSERT( NT_SUCCESS(status) );
|
|
|
|
}
|
|
|
|
//
|
|
// End of all channels
|
|
//
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
OpenInterfaceByGuid(
|
|
IN CONST GUID * InterfaceClassGuid,
|
|
OUT HANDLE * Handle,
|
|
OUT PFILE_OBJECT * FileObject
|
|
)
|
|
{
|
|
PWSTR tempString;
|
|
PWSTR symbolicLinkList;
|
|
HANDLE localHandle;
|
|
PFILE_OBJECT localFileObject;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
localHandle = NULL;
|
|
tempString = NULL;
|
|
symbolicLinkList = NULL;
|
|
*Handle = NULL;
|
|
*FileObject = NULL;
|
|
|
|
status = IoGetDeviceInterfaces(InterfaceClassGuid,
|
|
// currently, the GUID is one of
|
|
// KSCATEGORY_PREFERRED_WAVEOUT_DEVICE
|
|
// or KSCATEGORY_SYSAUDIO
|
|
NULL, // no preferred device object
|
|
0,
|
|
&symbolicLinkList);
|
|
if (!NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"OpenDevice !! IoGetDeviceInterfaces failed %x\n",
|
|
status));
|
|
return status;
|
|
}
|
|
|
|
#if DBG
|
|
tempString = symbolicLinkList;
|
|
while (*tempString != UNICODE_NULL) {
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"OpenDevice => Possible Device: %ws\n", tempString));
|
|
|
|
//
|
|
// get the next symbolic link
|
|
//
|
|
|
|
while(*tempString++ != UNICODE_NULL) {
|
|
NOTHING;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// this code is proudly propogated from wdmaud.sys
|
|
//
|
|
|
|
tempString = symbolicLinkList;
|
|
while (*tempString != UNICODE_NULL) {
|
|
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
UNICODE_STRING deviceString;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
RtlInitUnicodeString( &deviceString, tempString);
|
|
|
|
InitializeObjectAttributes(&objectAttributes,
|
|
&deviceString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// could use IoCreateFile(), based on
|
|
// ntos\dd\wdm\audio\legacy\wdmaud.sys\sysaudio.c:OpenDevice()
|
|
//
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"OpenDevice => Opening %ws\n", tempString));
|
|
status = ZwCreateFile(&localHandle,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
&objectAttributes,
|
|
&ioStatusBlock,
|
|
NULL, // ignored on non-create
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0, // no share access
|
|
FILE_OPEN, // open the existing file
|
|
0, NULL, 0 // options
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
ASSERT(localHandle != NULL);
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"OpenDevice => Opened %ws\n", tempString));
|
|
break; // out of the while loop
|
|
|
|
}
|
|
|
|
ASSERT(localHandle == NULL);
|
|
|
|
//
|
|
// get the next symbolic link
|
|
//
|
|
|
|
while(*tempString++ != UNICODE_NULL) {
|
|
NOTHING;
|
|
}
|
|
|
|
}
|
|
|
|
if (symbolicLinkList != NULL) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"OpenDevice => Freeing list from IoGetDevInt...\n"));
|
|
ExFreePool(symbolicLinkList);
|
|
symbolicLinkList = NULL;
|
|
tempString = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// if succeeded to open the file, try to get
|
|
// the FileObject that is related to this handle.
|
|
//
|
|
|
|
if (localHandle != NULL) {
|
|
|
|
status = ObReferenceObjectByHandle(localHandle,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
NULL,
|
|
KernelMode,
|
|
&localFileObject, // double pointer
|
|
NULL);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
|
|
"OpenDevice => Succeeded\n"));
|
|
|
|
*Handle = localHandle;
|
|
*FileObject = localFileObject;
|
|
|
|
return status; // Exit point for success
|
|
}
|
|
|
|
ZwClose(localHandle);
|
|
localHandle = NULL;
|
|
|
|
}
|
|
|
|
KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
|
|
"OpenDevice => unable to open any audio devices\n"));
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
return status;
|
|
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SysAudioPnpNotification(
|
|
PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification,
|
|
PREDBOOK_DEVICE_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PAGED_CODE();
|
|
|
|
InterlockedExchange(&DeviceExtension->Stream.UpdateMixerPin, 1);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|