summaryrefslogtreecommitdiff
path: root/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/device.cpp
diff options
context:
space:
mode:
authorDaniel Rugerio <[email protected]>2025-11-25 11:00:04 -0800
committerDaniel Rugerio <[email protected]>2025-12-15 14:00:37 -0800
commit6fa87d3bef7972f7fac034adb68cd856f69c8607 (patch)
tree90ddf9e506b651c81dd803e0a9cc04af5db24a79 /audio/SoundWire/Samples/SdcaVad/SdcaVCodec/device.cpp
parent1d89a1513f519f62226f84a3131916ab2fd0c3ef (diff)
New SDCAVAD sample.
Diffstat (limited to 'audio/SoundWire/Samples/SdcaVad/SdcaVCodec/device.cpp')
-rw-r--r--audio/SoundWire/Samples/SdcaVad/SdcaVCodec/device.cpp808
1 files changed, 808 insertions, 0 deletions
diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/device.cpp b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/device.cpp
new file mode 100644
index 00000000..e4805669
--- /dev/null
+++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/device.cpp
@@ -0,0 +1,808 @@
+/*++
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Device.cpp
+
+Abstract:
+
+ Plug and Play module. This file contains routines to handle pnp requests.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "private.h"
+#include <devguid.h>
+#include "stdunk.h"
+#include <ks.h>
+#include <mmsystem.h>
+#include <ksmedia.h>
+#include "streamengine.h"
+#include "CircuitHelper.h"
+
+#ifndef __INTELLISENSE__
+#include "device.tmh"
+#endif
+
+UNICODE_STRING g_RegistryPath = {0}; // This is used to store the registry settings path for the driver
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+PAGED_CODE_SEG
+NTSTATUS CopyRegistrySettingsPath
+(
+ _In_ PUNICODE_STRING RegistryPath
+)
+/*++
+
+Routine Description:
+
+Copies the following registry path to a global variable.
+
+\REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\<driver>\Parameters
+
+Arguments:
+
+RegistryPath - Registry path passed to DriverEntry
+
+Returns:
+
+NTSTATUS - SUCCESS if able to configure the framework
+
+--*/
+
+{
+ PAGED_CODE();
+
+ // Initializing the unicode string, so that if it is not allocated it will not be deallocated too.
+ RtlInitUnicodeString(&g_RegistryPath, NULL);
+
+ g_RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
+
+ g_RegistryPath.Buffer = (PWCH)ExAllocatePool2(POOL_FLAG_PAGED, g_RegistryPath.MaximumLength, DRIVER_TAG);
+
+ if (g_RegistryPath.Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // ExAllocatePool2 zeros memory.
+
+ RtlAppendUnicodeToString(&g_RegistryPath, RegistryPath->Buffer);
+
+ return STATUS_SUCCESS;
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtBusDeviceAdd(
+ _In_ WDFDRIVER Driver,
+ _Inout_ PWDFDEVICE_INIT DeviceInit
+ )
+/*++
+Routine Description:
+
+ EvtDeviceAdd is called by the framework in response to AddDevice
+ call from the PnP manager. We create and initialize a device object to
+ represent a new instance of the device. All the software resources
+ should be allocated in this callback.
+
+Arguments:
+
+ Driver - Handle to a framework driver object created in DriverEntry
+
+ DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ //
+ // Allow ACX to add any pre-requirement it needs on this device.
+ //
+ ACX_DEVICEINIT_CONFIG devInitCfg;
+ ACX_DEVICEINIT_CONFIG_INIT(&devInitCfg);
+ RETURN_NTSTATUS_IF_FAILED(AcxDeviceInitInitialize(DeviceInit, &devInitCfg));
+
+ //
+ // Initialize the pnpPowerCallbacks structure. Callback events for PNP
+ // and Power are specified here. If you don't supply any callbacks,
+ // the Framework will take appropriate default actions based on whether
+ // DeviceInit is initialized to be an FDO, a PDO or a filter device
+ // object.
+ //
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+ pnpPowerCallbacks.EvtDevicePrepareHardware = Codec_EvtDevicePrepareHardware;
+ pnpPowerCallbacks.EvtDeviceReleaseHardware = Codec_EvtDeviceReleaseHardware;
+ WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
+
+ //
+ // Specify the type of context needed.
+ // Use default locking, i.e., none.
+ //
+ WDF_OBJECT_ATTRIBUTES attributes;
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_DEVICE_CONTEXT);
+ attributes.EvtCleanupCallback = Codec_EvtDeviceContextCleanup;
+
+ //
+ // Create the device.
+ //
+ WDFDEVICE device = NULL;
+ RETURN_NTSTATUS_IF_FAILED(WdfDeviceCreate(&DeviceInit, &attributes, &device));
+
+ //
+ // Init Codec's device context.
+ //
+ PCODEC_DEVICE_CONTEXT devCtx;
+ devCtx = GetCodecDeviceContext(device);
+ ASSERT(devCtx != NULL);
+ devCtx->Render = NULL;
+ devCtx->Capture = NULL;
+
+ //
+ // Assume XU lower filter driver is not present
+ //
+ devCtx->SdcaXuData.bSdcaXu = FALSE;
+
+ //
+ // Allow ACX to add any post-requirement it needs on this device.
+ //
+ ACX_DEVICE_CONFIG devCfg;
+ ACX_DEVICE_CONFIG_INIT(&devCfg);
+ RETURN_NTSTATUS_IF_FAILED(AcxDeviceInitialize(device, &devCfg));
+
+ //
+ // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so
+ // that you don't get the popup in usermode (on Win2K) when you surprise
+ // remove the device.
+ //
+ WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
+ WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);
+ pnpCaps.SurpriseRemovalOK = WdfTrue;
+ WdfDeviceSetPnpCapabilities(device, &pnpCaps);
+
+ //
+ // Get SDCA XU filter interface
+ //
+ RETURN_NTSTATUS_IF_FAILED_UNLESS_ALLOWED(Codec_GetSdcaXu(device), STATUS_NOT_SUPPORTED);
+
+ if (devCtx->SdcaXuData.bSdcaXu)
+ {
+ RETURN_NTSTATUS_IF_FAILED(Codec_SetSdcaXuHwConfig(device));
+ }
+
+ RETURN_NTSTATUS_IF_FAILED(Codec_AddRenderComposites(device));
+
+ RETURN_NTSTATUS_IF_FAILED(Codec_AddCaptureComposites(device));
+
+ //
+ // Add a render device and a capture device.
+ //
+ RETURN_NTSTATUS_IF_FAILED(CodecR_AddRenders(Driver, device));
+
+ //
+ // Add a render device and a capture device.
+ //
+ RETURN_NTSTATUS_IF_FAILED(CodecC_AddCaptures(Driver, device));
+
+ return status;
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtDevicePrepareHardware(
+ _In_ WDFDEVICE Device,
+ _In_ WDFCMRESLIST ResourceList,
+ _In_ WDFCMRESLIST ResourceListTranslated
+)
+/*++
+
+Routine Description:
+
+ In this callback, the driver does whatever is necessary to make the
+ hardware ready to use.
+
+Arguments:
+
+ Device - handle to a device
+
+Return Value:
+
+ NT status value
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(ResourceList);
+ UNREFERENCED_PARAMETER(ResourceListTranslated);
+
+ PAGED_CODE();
+
+ DrvLogEnter(g_SDCAVCodecLog);
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PCODEC_DEVICE_CONTEXT devCtx;
+ devCtx = GetCodecDeviceContext(Device);
+ ASSERT(devCtx != NULL);
+
+
+ RETURN_NTSTATUS_IF_FAILED(Codec_SetPowerPolicy(Device));
+
+ //
+ // Add static circuit to device's list.
+ //
+ ASSERT(devCtx->Render);
+ RETURN_NTSTATUS_IF_FAILED(AcxDeviceAddCircuit(Device, devCtx->Render));
+
+ ASSERT(devCtx->Capture);
+ RETURN_NTSTATUS_IF_FAILED(AcxDeviceAddCircuit(Device, devCtx->Capture));
+
+ return status;
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtDeviceReleaseHardware(
+ _In_ WDFDEVICE Device,
+ _In_ WDFCMRESLIST ResourceListTranslated
+)
+/*++
+
+Routine Description:
+
+ In this callback, the driver releases the h/w resources allocated in the
+ prepare h/w callback.
+
+Arguments:
+
+ Device - handle to a device
+
+Return Value:
+
+ NT status value
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Device);
+ UNREFERENCED_PARAMETER(ResourceListTranslated);
+
+ PCODEC_DEVICE_CONTEXT devCtx;
+ devCtx = GetCodecDeviceContext(Device);
+ ASSERT(devCtx != NULL);
+
+
+ return status;
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_SetPowerPolicy(
+ _In_ WDFDEVICE Device
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DrvLogEnter(g_SDCAVCodecLog);
+
+ WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
+ //WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;
+
+ //
+ // Init the idle policy structure.
+ //
+ //WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCanWakeFromS0);
+ WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCannotWakeFromS0);
+ idleSettings.IdleTimeout = 10000; // 10-sec
+
+ RETURN_NTSTATUS_IF_FAILED(WdfDeviceAssignS0IdleSettings(Device, &idleSettings));
+
+ return status;
+}
+
+#pragma code_seg()
+
+DEFINE_GUID(CODEC_CIRCUIT_RENDER_GUID,
+0xfd4b6e78, 0x51e0, 0x4aa6, 0x90, 0x98, 0xbb, 0xcb, 0x70, 0x89, 0xcb, 0x6a);
+
+DEFINE_GUID(EXTENSION_CIRCUIT_RENDER_GUID,
+0x656ab905, 0x55fb, 0x4b08, 0xb6, 0x01, 0xd7, 0xf0, 0xc1, 0xce, 0x36, 0x2c);
+
+// {17F5B19F-C2C7-4B53-AFB9-49A0283D0DCE}
+DEFINE_GUID(DSP_CIRCUIT_SPEAKER_GUID,
+ 0x17f5b19f, 0xc2c7, 0x4b53, 0xaf, 0xb9, 0x49, 0xa0, 0x28, 0x3d, 0xd, 0xce);
+
+DEFINE_GUID(CODEC_CIRCUIT_CAPTURE_GUID,
+0x67ec5936, 0xa395, 0x4e93, 0xbe, 0x8a, 0xfc, 0xed, 0xe3, 0x1b, 0xad, 0x40);
+
+DEFINE_GUID(EXTENSION_CIRCUIT_CAPTURE_GUID,
+0x44c69385, 0xa012, 0x405f, 0x8a, 0x9a, 0x7b, 0x44, 0x29, 0x71, 0xc8, 0x50);
+
+// {6F9EACF7-CD2D-4030-9E49-7CC4ADEFF192}
+DEFINE_GUID(DSP_CIRCUIT_MICROPHONE_GUID,
+ 0x6f9eacf7, 0xcd2d, 0x4030, 0x9e, 0x49, 0x7c, 0xc4, 0xad, 0xef, 0xf1, 0x92);
+
+DEFINE_GUID(SYSTEM_CONTAINER_GUID,
+0x00000000, 0x0000, 0x0000, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
+
+
+#define DSP_FACTORY_URI L"acpi:obj-path:\\_SB.PC00.HDAS"
+
+#define RENDER_CIRCUIT_UNIQUE_ID L"{613fd364-64bb-4b69-99bc-5b075ea9756b}"
+#define RENDER_CIRCUIT_FRIENDLY_NAME L"Speaker-360"
+#define RENDER_CIRCUIT_NAME L"Speaker"
+#define CAPTURE_CIRCUIT_UNIQUE_ID L"{3A509246-5902-4AA2-9E06-C7C8D10461C3}"
+#define CAPTURE_CIRCUIT_FRIENDLY_NAME L"Microphone-360"
+#define CAPTURE_CIRCUIT_NAME L"Microphone"
+
+#define CIRCUIT_RENDER_VENDOR_BLOB "Streaming_Speaker"
+#define CIRCUIT_CAPTURE_VENDOR_BLOB "Streaming_MicrophoneArray"
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+PAGED_CODE_SEG
+NTSTATUS
+Codec_AddRenderComposites(_In_ WDFDEVICE Device)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Device);
+
+ PAGED_CODE();
+
+ RETURN_NTSTATUS_IF_FAILED(Codec_AddComposites(Device, CompositeType_RENDER));
+
+ return status;
+}
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+PAGED_CODE_SEG
+NTSTATUS
+Codec_AddCaptureComposites(_In_ WDFDEVICE Device)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Device);
+
+ PAGED_CODE();
+
+ RETURN_NTSTATUS_IF_FAILED(Codec_AddComposites(Device, CompositeType_CAPTURE));
+
+ return status;
+}
+
+__drv_requiresIRQL(PASSIVE_LEVEL)
+PAGED_CODE_SEG
+NTSTATUS
+Codec_AddComposites(_In_ WDFDEVICE Device, _In_ CompositeType compositeType)
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DrvLogEnter(g_SDCAVCodecLog);
+
+ UNICODE_STRING circuit_IDs[] = {
+ { sizeof(RENDER_CIRCUIT_UNIQUE_ID) - sizeof(WCHAR), sizeof(RENDER_CIRCUIT_UNIQUE_ID), RENDER_CIRCUIT_UNIQUE_ID },
+ { sizeof(CAPTURE_CIRCUIT_UNIQUE_ID) - sizeof(WCHAR), sizeof(CAPTURE_CIRCUIT_UNIQUE_ID), CAPTURE_CIRCUIT_UNIQUE_ID}
+ };
+
+ UNICODE_STRING circuit_friendly_names[] = {
+ { sizeof(RENDER_CIRCUIT_FRIENDLY_NAME) - sizeof(WCHAR), sizeof(RENDER_CIRCUIT_FRIENDLY_NAME), RENDER_CIRCUIT_FRIENDLY_NAME },
+ { sizeof(CAPTURE_CIRCUIT_FRIENDLY_NAME) - sizeof(WCHAR), sizeof(CAPTURE_CIRCUIT_FRIENDLY_NAME), CAPTURE_CIRCUIT_FRIENDLY_NAME}
+ };
+
+ UNICODE_STRING circuit_names[] = {
+ { sizeof(RENDER_CIRCUIT_NAME) - sizeof(WCHAR), sizeof(RENDER_CIRCUIT_NAME), RENDER_CIRCUIT_NAME },
+ { sizeof(CAPTURE_CIRCUIT_NAME) - sizeof(WCHAR), sizeof(CAPTURE_CIRCUIT_NAME), CAPTURE_CIRCUIT_NAME}
+ };
+
+ UNICODE_STRING codec_circuit_uris[] = {
+ { sizeof(RENDER_CIRCUIT_URI) - sizeof(WCHAR), sizeof(RENDER_CIRCUIT_URI), RENDER_CIRCUIT_URI },
+ { sizeof(CAPTURE_CIRCUIT_URI) - sizeof(WCHAR), sizeof(CAPTURE_CIRCUIT_URI), CAPTURE_CIRCUIT_URI}
+ };
+
+ UNICODE_STRING extension_circuit_uris[] = {
+ { sizeof(EXT_RENDER_CIRCUIT_URI) - sizeof(WCHAR), sizeof(EXT_RENDER_CIRCUIT_URI), EXT_RENDER_CIRCUIT_URI },
+ { sizeof(EXT_CAPTURE_CIRCUIT_URI) - sizeof(WCHAR), sizeof(EXT_CAPTURE_CIRCUIT_URI), EXT_CAPTURE_CIRCUIT_URI}
+ };
+
+ GUID dsp_circuit_guids[] = {
+ DSP_CIRCUIT_SPEAKER_GUID,
+ DSP_CIRCUIT_MICROPHONE_GUID
+ };
+
+ UNICODE_STRING dsp_factory_uris[] = {
+ { sizeof(DSP_FACTORY_URI) - sizeof(WCHAR), sizeof(DSP_FACTORY_URI), DSP_FACTORY_URI },
+ { sizeof(DSP_FACTORY_URI) - sizeof(WCHAR), sizeof(DSP_FACTORY_URI), DSP_FACTORY_URI}
+ };
+
+ const char* dsp_factory_vendor_blobs[] = {
+ CIRCUIT_RENDER_VENDOR_BLOB,
+ CIRCUIT_CAPTURE_VENDOR_BLOB
+ };
+
+ PCODEC_DEVICE_CONTEXT deviceCtx = NULL;
+ deviceCtx = GetCodecDeviceContext(Device);
+ ASSERT(deviceCtx);
+
+ //
+ // May be called again for rebalance
+ // Add composites only once
+ //
+ RETURN_NTSTATUS_IF_TRUE(0 != deviceCtx->refComposite[compositeType], STATUS_SUCCESS);
+
+ //
+ // Object bag
+ //
+ // This obj-bag config setting is shared by all composite/circuit templates.
+ ACX_OBJECTBAG_CONFIG objBagCfg;
+ ACX_OBJECTBAG_CONFIG_INIT(&objBagCfg);
+
+ WDF_OBJECT_ATTRIBUTES attributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = AcxGetManager(NULL);
+
+ ACXOBJECTBAG objBag = NULL;
+ RETURN_NTSTATUS_IF_FAILED(AcxObjectBagCreate(&attributes, &objBagCfg, &objBag));
+ auto objBag_scope = scope_exit([&objBag]() {
+ if (objBag != NULL)
+ {
+ WdfObjectDelete(objBag);
+ }
+ });
+
+ //
+ // Add a test unsigned int 4 bytes to the object bag
+ //
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddTestUI4(objBag, 0));
+
+ //
+ // Add unique circuit ID to the object bag
+ // This unique Id will be picked up by DSP circuit
+ //
+ DECLARE_CONST_ACXOBJECTBAG_SYSTEM_PROPERTY_NAME(UniqueID);
+ GUID uniqueID = { 0 };
+ RETURN_NTSTATUS_IF_FAILED(RtlGUIDFromString(&circuit_IDs[compositeType], &uniqueID));
+
+ RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddGuid(objBag, &UniqueID, uniqueID));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddUnicodeStrings(objBag, circuit_friendly_names[compositeType], circuit_names[compositeType]));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddEndpointId(objBag, 9));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddDataPortNumber(objBag, 9));
+
+ //
+ // Composite template.
+ //
+ ULONG circuitsInTemplate = 0;
+ ACXCIRCUITTEMPLATE circuits[3] = { 0 };
+ ACX_COMPOSITE_TEMPLATE_CONFIG compositeCfg;
+ ACX_COMPOSITE_TEMPLATE_CONFIG_INIT(&compositeCfg);
+ compositeCfg.Properties = objBag;
+ compositeCfg.Flags |= AcxCompositeTemplateConfigSingleton;
+
+ ACXCOMPOSITETEMPLATE composite = NULL;
+ RETURN_NTSTATUS_IF_FAILED(AcxCompositeTemplateCreate(WdfGetDriver(),
+ &attributes,
+ &compositeCfg,
+ &composite));
+
+ auto composite_scope = scope_exit([&composite]() {
+ WdfObjectDelete(composite);
+ composite = NULL;
+ });
+
+ objBag = NULL;
+
+ // This attribute setting is shared by all the circuit templates.
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = composite;
+
+ // Codec template.
+ RETURN_NTSTATUS_IF_FAILED(AcxObjectBagCreate(&attributes, &objBagCfg, &objBag));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddTestUI4(objBag, 2));
+
+ ACX_CIRCUIT_TEMPLATE_CONFIG circuitCfg1;
+ ACX_CIRCUIT_TEMPLATE_CONFIG_INIT(&circuitCfg1);
+ circuitCfg1.CircuitProperties = objBag;
+ circuitCfg1.CircuitUri = &codec_circuit_uris[compositeType];
+
+ ULONG codecIndex = circuitsInTemplate;
+ RETURN_NTSTATUS_IF_FAILED(AcxCircuitTemplateCreate(WdfGetDriver(),
+ &attributes,
+ &circuitCfg1,
+ &circuits[circuitsInTemplate++]));
+
+ objBag = NULL;
+
+ // XU template.
+ //
+ // Check if XU is present
+ // and compose with Xu circuit
+ //
+ if (deviceCtx->SdcaXuData.bSdcaXu)
+ {
+ RETURN_NTSTATUS_IF_FAILED(AcxObjectBagCreate(&attributes, &objBagCfg, &objBag));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddTestUI4(objBag, 2));
+
+ ACX_CIRCUIT_TEMPLATE_CONFIG circuitCfg2;
+ ACX_CIRCUIT_TEMPLATE_CONFIG_INIT(&circuitCfg2);
+ circuitCfg2.CircuitProperties = objBag;
+ circuitCfg2.CircuitUri = &extension_circuit_uris[compositeType];
+
+ RETURN_NTSTATUS_IF_FAILED(AcxCircuitTemplateCreate(WdfGetDriver(),
+ &attributes,
+ &circuitCfg2,
+ &circuits[circuitsInTemplate++]));
+
+ objBag = NULL;
+ }
+
+ // Dsp template.
+ RETURN_NTSTATUS_IF_FAILED(AcxObjectBagCreate(&attributes, &objBagCfg, &objBag));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddTestUI4(objBag, 3));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddCircuitId(objBag, dsp_circuit_guids[compositeType]));
+
+ RETURN_NTSTATUS_IF_FAILED(ObjBagAddBlob(objBag, dsp_factory_vendor_blobs[compositeType]));
+
+ ACX_CIRCUIT_TEMPLATE_CONFIG circuitCfg3;
+ ACX_CIRCUIT_TEMPLATE_CONFIG_INIT(&circuitCfg3);
+ circuitCfg3.CircuitProperties = objBag;
+ circuitCfg3.FactoryUri = &dsp_factory_uris[compositeType];
+ circuitCfg3.Flags |= AcxCircuitTemplateCircuitOnDemand;
+
+ RETURN_NTSTATUS_IF_FAILED(AcxCircuitTemplateCreate(WdfGetDriver(),
+ &attributes,
+ &circuitCfg3,
+ &circuits[circuitsInTemplate++]));
+
+ objBag = NULL;
+ objBag_scope.release();
+
+ RETURN_NTSTATUS_IF_FAILED(AcxCompositeTemplateAssignCircuits(composite, circuits, circuitsInTemplate));
+
+ // Select the core circuit.
+ AcxCompositeTemplateSetCoreCircuit(composite, circuits[codecIndex]);
+
+ // Final step.
+ RETURN_NTSTATUS_IF_FAILED(AcxManagerAddCompositeTemplate(AcxGetManager(NULL), composite));
+
+ deviceCtx->Composite[compositeType] = composite;
+ composite_scope.release();
+
+ deviceCtx->refComposite[compositeType]++;
+
+ return status;
+}
+
+#pragma code_seg()
+NTSTATUS
+Codec_RemoveComposites(_In_ WDFDEVICE Device)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PCODEC_DEVICE_CONTEXT deviceCtx = NULL;
+ deviceCtx = GetCodecDeviceContext(Device);
+ ASSERT(deviceCtx);
+
+ for (ULONG compositeType = CompositeType_RENDER; compositeType <= CompositeType_CAPTURE; )
+ {
+ if (deviceCtx->refComposite[compositeType])
+ {
+ deviceCtx->refComposite[compositeType]--;
+ if (deviceCtx->refComposite[compositeType] == 0)
+ {
+ if (deviceCtx->Composite[compositeType] != NULL)
+ {
+ RETURN_NTSTATUS_IF_FAILED(AcxManagerRemoveCompositeTemplate(AcxGetManager(NULL), deviceCtx->Composite[compositeType]));
+
+ WdfObjectDelete(deviceCtx->Composite[compositeType]);
+ deviceCtx->Composite[compositeType] = NULL;
+ }
+ }
+ }
+
+ compositeType++;
+ }
+
+ return status;
+}
+
+#pragma code_seg()
+VOID
+Codec_EvtDeviceContextCleanup(
+ _In_ WDFOBJECT WdfDevice
+ )
+/*++
+
+Routine Description:
+
+ In this callback, it cleans up device context.
+
+Arguments:
+
+ WdfDevice - WDF device object
+
+Return Value:
+
+ NULL
+
+--*/
+{
+ WDFDEVICE device;
+ PCODEC_DEVICE_CONTEXT devCtx;
+
+
+ device = (WDFDEVICE)WdfDevice;
+ devCtx = GetCodecDeviceContext(device);
+ ASSERT(devCtx != NULL);
+
+ Codec_RemoveComposites(device);
+
+ if (devCtx->SdcaXuData.XUEntities)
+ {
+ ExFreePoolWithTag(devCtx->SdcaXuData.XUEntities, DRIVER_TAG);
+ devCtx->SdcaXuData.numXUEntities = 0;
+ }
+ if (devCtx->SdcaXuData.InterruptInfo)
+ {
+ ExFreePoolWithTag(devCtx->SdcaXuData.InterruptInfo, DRIVER_TAG);
+ devCtx->SdcaXuData.InterruptInfo = NULL;
+ }
+}
+
+#pragma code_seg()
+VOID
+Codec_EvtStreamDestroy(
+ _In_ WDFOBJECT Object
+ )
+{
+ PCODEC_STREAM_CONTEXT ctx;
+ CStreamEngine * streamEngine = NULL;
+
+ ctx = GetCodecStreamContext((ACXSTREAM)Object);
+
+ streamEngine = (CStreamEngine*)ctx->StreamEngine;
+ ctx->StreamEngine = NULL;
+ delete streamEngine;
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtStreamGetHwLatency(
+ _In_ ACXSTREAM Stream,
+ _Out_ ULONG * FifoSize,
+ _Out_ ULONG * Delay
+)
+{
+ PCODEC_STREAM_CONTEXT ctx;
+ CStreamEngine * streamEngine = NULL;
+
+ PAGED_CODE();
+
+ ctx = GetCodecStreamContext(Stream);
+
+ streamEngine = (CStreamEngine*)ctx->StreamEngine;
+
+ return streamEngine->GetHWLatency(FifoSize, Delay);
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtStreamPrepareHardware(
+ _In_ ACXSTREAM Stream
+ )
+{
+ PCODEC_STREAM_CONTEXT ctx;
+ CStreamEngine * streamEngine = NULL;
+
+ PAGED_CODE();
+
+ ctx = GetCodecStreamContext(Stream);
+
+ streamEngine = (CStreamEngine*)ctx->StreamEngine;
+
+ return streamEngine->PrepareHardware();
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtStreamReleaseHardware(
+ _In_ ACXSTREAM Stream
+ )
+{
+ PCODEC_STREAM_CONTEXT ctx;
+ CStreamEngine * streamEngine = NULL;
+
+ PAGED_CODE();
+
+ ctx = GetCodecStreamContext(Stream);
+
+ streamEngine = (CStreamEngine*)ctx->StreamEngine;
+
+ return streamEngine->ReleaseHardware();
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtStreamRun(
+ _In_ ACXSTREAM Stream
+ )
+{
+ PCODEC_STREAM_CONTEXT ctx;
+ CStreamEngine * streamEngine = NULL;
+
+ PAGED_CODE();
+
+ ctx = GetCodecStreamContext(Stream);
+
+ streamEngine = (CStreamEngine*)ctx->StreamEngine;
+
+ return streamEngine->Run();
+}
+
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtStreamPause(
+ _In_ ACXSTREAM Stream
+ )
+{
+ PCODEC_STREAM_CONTEXT ctx;
+ CStreamEngine * streamEngine = NULL;
+
+ PAGED_CODE();
+
+ ctx = GetCodecStreamContext(Stream);
+
+ streamEngine = (CStreamEngine*)ctx->StreamEngine;
+
+ return streamEngine->Pause();
+}
+
+PAGED_CODE_SEG
+NTSTATUS
+Codec_EvtStreamAssignDrmContentId(
+ _In_ ACXSTREAM Stream,
+ _In_ ULONG DrmContentId,
+ _In_ PACXDRMRIGHTS DrmRights
+ )
+{
+ PCODEC_STREAM_CONTEXT ctx;
+ CStreamEngine * streamEngine = NULL;
+
+ PAGED_CODE();
+
+ ctx = GetCodecStreamContext(Stream);
+
+ streamEngine = (CStreamEngine*)ctx->StreamEngine;
+
+ return streamEngine->AssignDrmContentId(DrmContentId, DrmRights);
+}
+
+