diff options
Diffstat (limited to 'audio/SoundWire/Samples/SdcaVad/SdcaVCodec')
15 files changed, 5618 insertions, 0 deletions
diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/CircuitHelper.cpp b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/CircuitHelper.cpp new file mode 100644 index 00000000..e7b36b1f --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/CircuitHelper.cpp @@ -0,0 +1,286 @@ +/*++ + + 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: + + CircuitHelper.cpp + +Abstract: + + This module contains helper functions for device.cpp and render.cpp files. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "CircuitHelper.h" + +#ifndef __INTELLISENSE__ +#include "CircuitHelper.tmh" +#endif + +PAGED_CODE_SEG +NTSTATUS CreateRenderCircuit( + _In_ PACXCIRCUIT_INIT CircuitInit, + _In_ UNICODE_STRING CircuitName, + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT* Circuit +) +{ + + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_RENDER_CIRCUIT_CONTEXT); + + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignName(CircuitInit, &CircuitName)); + + // + // Add circuit type. + // + AcxCircuitInitSetCircuitType(CircuitInit, AcxCircuitTypeRender); + + // + // Assign the circuit's pnp-power callbacks. + // + { + ACX_CIRCUIT_PNPPOWER_CALLBACKS powerCallbacks; + ACX_CIRCUIT_PNPPOWER_CALLBACKS_INIT(&powerCallbacks); + powerCallbacks.EvtAcxCircuitPowerUp = CodecR_EvtCircuitPowerUp; + powerCallbacks.EvtAcxCircuitPowerDown = CodecR_EvtCircuitPowerDown; + AcxCircuitInitSetAcxCircuitPnpPowerCallbacks(CircuitInit, &powerCallbacks); + } + + // + // Assign the circuit's composite callbacks. + // + { + ACX_CIRCUIT_COMPOSITE_CALLBACKS compositeCallbacks; + ACX_CIRCUIT_COMPOSITE_CALLBACKS_INIT(&compositeCallbacks); + compositeCallbacks.EvtAcxCircuitCompositeCircuitInitialize = CodecR_EvtCircuitCompositeCircuitInitialize; + compositeCallbacks.EvtAcxCircuitCompositeInitialize = CodecR_EvtCircuitCompositeInitialize; + AcxCircuitInitSetAcxCircuitCompositeCallbacks(CircuitInit, &compositeCallbacks); + } + + // + // Set circuit-callbacks. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignAcxRequestPreprocessCallback( + CircuitInit, + CodecR_EvtCircuitRequestPreprocess, + (ACXCONTEXT)AcxRequestTypeAny, // dbg only + AcxRequestTypeAny, + NULL, + AcxItemIdNone)); + + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignAcxCreateStreamCallback( + CircuitInit, + CodecR_EvtCircuitCreateStream)); + + // + // Create the circuit. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_RENDER_CIRCUIT_CONTEXT); + RETURN_NTSTATUS_IF_FAILED(AcxCircuitCreate(Device, &attributes, &CircuitInit, Circuit)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS ConnectRenderCircuitElements( + _In_ ULONG ElementCount, + _In_reads_(ElementCount) ACXELEMENT* Elements, + _In_ ACXCIRCUIT Circuit +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + // + // Explicitly connect the circuit/elements. Note that driver doens't + // need to perform this step when circuit/elements are connected in the + // same order as they were added to the circuit. By default ACX connects + // the elements starting from the sink circuit pin and ending with the + // source circuit pin for both render and capture devices. + // + // circuit.pin[default_sink] -> 1st element.pin[default_in] + // 1st element.pin[default_out] -> 2nd element.pin[default_in] + // 2nd element.pin[default_out] -> circuit.pin[default_source] + // + const int numElements = 2; + const int numConnections = numElements + 1; + + ACX_CONNECTION connections[numConnections]; + ACX_CONNECTION_INIT(&connections[0], Circuit, Elements[ElementCount - 2]); + ACX_CONNECTION_INIT(&connections[1], Elements[ElementCount - 2], Elements[ElementCount - 1]); + ACX_CONNECTION_INIT(&connections[2], Elements[ElementCount - 1], Circuit); + + // + // Add the connections linking circuit to elements. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddConnections(Circuit, connections, SIZEOF_ARRAY(connections))); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS ObjBagAddBlob( + _In_ ACXOBJECTBAG ObjBag, + _In_z_ const char* Blob +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DECLARE_CONST_ACXOBJECTBAG_SYSTEM_PROPERTY_NAME(VendorPropertiesBlock); + STRING vendorBlob; + RtlInitString(&vendorBlob, Blob); + WDFMEMORY vendorBlobMem; + RETURN_NTSTATUS_IF_FAILED(WdfMemoryCreatePreallocated(NULL, vendorBlob.Buffer, vendorBlob.MaximumLength, &vendorBlobMem)); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddBlob(ObjBag, &VendorPropertiesBlock, vendorBlobMem)); + WdfObjectDelete(vendorBlobMem); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS ObjBagAddEndpointId( + _In_ ACXOBJECTBAG ObjBag, + _In_ UINT Value +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DECLARE_CONST_ACXOBJECTBAG_SOUNDWIRE_PROPERTY_NAME(EndpointId); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUI4(ObjBag, &EndpointId, Value)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS ObjBagAddDataPortNumber( + _In_ ACXOBJECTBAG ObjBag, + _In_ UINT Value +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DECLARE_CONST_ACXOBJECTBAG_SOUNDWIRE_PROPERTY_NAME(DataPortNumber); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUI4(ObjBag, &DataPortNumber, Value)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS ObjBagAddTestUI4( + _In_ ACXOBJECTBAG ObjBag, + _In_ UINT Value +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DECLARE_CONST_ACXOBJECTBAG_DRIVER_PROPERTY_NAME(msft, TestUI4); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUI4(ObjBag, &TestUI4, Value)); + + return status; +} + + +PAGED_CODE_SEG +NTSTATUS ObjBagAddCircuitId( + _In_ ACXOBJECTBAG ObjBag, + _In_ GUID Guid +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DECLARE_CONST_ACXOBJECTBAG_DRIVER_PROPERTY_NAME(msft, CircuitId); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddGuid(ObjBag, &CircuitId, Guid)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS ObjBagAddUnicodeStrings( + _In_ ACXOBJECTBAG ObjBag, + _In_ UNICODE_STRING FriendlyNameStr, + _In_ UNICODE_STRING NameStr +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DECLARE_CONST_ACXOBJECTBAG_SYSTEM_PROPERTY_NAME(FriendlyName); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUnicodeString(ObjBag, &FriendlyName, &FriendlyNameStr)); + + DECLARE_CONST_ACXOBJECTBAG_SYSTEM_PROPERTY_NAME(Name); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUnicodeString(ObjBag, &Name, &NameStr)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS AddJack( + _In_ WDF_OBJECT_ATTRIBUTES Attributes, + _In_ ACXPIN Pin, + _In_ ULONG ChannelMapping, + _In_ ULONG Color, + _In_ ACX_JACK_CONNECTION_TYPE ConnectionType, + _In_ ACX_JACK_GEO_LOCATION GeoLocation, + _In_ ACX_JACK_GEN_LOCATION GenLocation, + _In_ ACX_JACK_PORT_CONNECTION PortConnection +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + ACX_JACK_CONFIG jackCfg; + ACX_JACK_CONFIG_INIT(&jackCfg); + jackCfg.Description.ChannelMapping = ChannelMapping; + jackCfg.Description.Color = Color; + jackCfg.Description.ConnectionType = ConnectionType; + jackCfg.Description.GeoLocation = GeoLocation; + jackCfg.Description.GenLocation = GenLocation; + jackCfg.Description.PortConnection = PortConnection; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, CODEC_JACK_CONTEXT); + Attributes.ParentObject = Pin; + + ACXJACK jack; + RETURN_NTSTATUS_IF_FAILED(AcxJackCreate(Pin, &Attributes, &jackCfg, &jack)); + + ASSERT(jack != NULL); + + PCODEC_JACK_CONTEXT jackCtx; + jackCtx = GetCodecJackContext(jack); + ASSERT(jackCtx); + jackCtx->Dummy = 0; + + RETURN_NTSTATUS_IF_FAILED(AcxPinAddJacks(Pin, &jack, 1)); + + return status; +} + + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/CircuitHelper.h b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/CircuitHelper.h new file mode 100644 index 00000000..c3776c1c --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/CircuitHelper.h @@ -0,0 +1,84 @@ +/*++ + + 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: + + CircuitHelper.h + +Abstract: + + This module contains helper functions for device.cpp and render.cpp files. + +Environment: + + Kernel mode + +--*/ + +PAGED_CODE_SEG +NTSTATUS CreateRenderCircuit( + _In_ PACXCIRCUIT_INIT CircuitInit, + _In_ UNICODE_STRING CircuitName, + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT* Circuit +); + +PAGED_CODE_SEG +NTSTATUS ConnectRenderCircuitElements( + _In_ ULONG ElementCount, + _In_reads_(ElementCount) ACXELEMENT* Elements, + _In_ ACXCIRCUIT Circuit +); + +PAGED_CODE_SEG +NTSTATUS ObjBagAddBlob( + _In_ ACXOBJECTBAG ObjBag, + _In_z_ const char* Blob +); + +PAGED_CODE_SEG +NTSTATUS ObjBagAddEndpointId( + _In_ ACXOBJECTBAG ObjBag, + _In_ UINT Value +); + +PAGED_CODE_SEG +NTSTATUS ObjBagAddDataPortNumber( + _In_ ACXOBJECTBAG ObjBag, + _In_ UINT Value +); + +PAGED_CODE_SEG +NTSTATUS ObjBagAddTestUI4( + _In_ ACXOBJECTBAG ObjBag, + _In_ UINT Value +); + +PAGED_CODE_SEG +NTSTATUS ObjBagAddCircuitId( + _In_ ACXOBJECTBAG ObjBag, + _In_ GUID Guid +); + +PAGED_CODE_SEG +NTSTATUS ObjBagAddUnicodeStrings( + _In_ ACXOBJECTBAG ObjBag, + _In_ UNICODE_STRING FriendlyNameStr, + _In_ UNICODE_STRING NameStr +); + +PAGED_CODE_SEG +NTSTATUS AddJack( + _In_ WDF_OBJECT_ATTRIBUTES Attributes, + _In_ ACXPIN Pin, + _In_ ULONG ChannelMapping, + _In_ ULONG Color, + _In_ ACX_JACK_CONNECTION_TYPE ConnectionType, + _In_ ACX_JACK_GEO_LOCATION GeoLocation, + _In_ ACX_JACK_GEN_LOCATION GenLocation, + _In_ ACX_JACK_PORT_CONNECTION PortConnection +); diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/Extension.cpp b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/Extension.cpp new file mode 100644 index 00000000..d56a172b --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/Extension.cpp @@ -0,0 +1,262 @@ +/*++ + + 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: + + Extension.cpp + +Abstract: + + SDCA XU functions + +Environment: + + Kernel mode + +--*/ + +#include "private.h" + +#ifndef __INTELLISENSE__ +#include "Extension.tmh" +#endif + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetJackOverride +( + _In_ PVOID Context, // SDCA Context + _In_ BOOLEAN Override // TRUE: Override + // FALSE: Default SDCA behavior +) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(Context); + UNREFERENCED_PARAMETER(Override); + NTSTATUS status = STATUS_SUCCESS; + + PCODEC_DEVICE_CONTEXT devCtx; + + devCtx = GetCodecDeviceContext(Context); + ASSERT(devCtx != NULL); + + devCtx->SdcaXuData.bExtensionJackOVerride = Override; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetJackSelectedMode +( + _In_ PVOID Context, // SDCA Context + _In_ ULONG GroupEntityId, // SDCA Group Entity ID for Jack(s) + _In_ ULONG SelectedMode // Type of jack type overriden by XU +) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(Context); + UNREFERENCED_PARAMETER(GroupEntityId); + UNREFERENCED_PARAMETER(SelectedMode); + NTSTATUS status = STATUS_SUCCESS; + + return status; +} + +#pragma code_seg() +NTSTATUS Codec_SdcaXuPDEPowerReferenceAcquire +( + _In_ PVOID Context, // SDCA Context + _In_ ULONG PowerDomainEntityId, // SDCA Entity ID for entity + _In_ SDCAXU_POWER_STATE RequiredState // Power state the PowerDomain needs to be in +) +{ + UNREFERENCED_PARAMETER(Context); + UNREFERENCED_PARAMETER(PowerDomainEntityId); + UNREFERENCED_PARAMETER(RequiredState); + NTSTATUS status = STATUS_SUCCESS; + + return status; +} + +#pragma code_seg() +NTSTATUS Codec_SdcaXuPDEPowerReferenceRelease +( + _In_ PVOID Context, // SDCA Context + _In_ ULONG PowerDomainEntityId, // SDCA Entity ID for entity + _In_ SDCAXU_POWER_STATE ReleasedState // Power state the PowerDomain no longer needs to be in +) +{ + UNREFERENCED_PARAMETER(Context); + UNREFERENCED_PARAMETER(PowerDomainEntityId); + UNREFERENCED_PARAMETER(ReleasedState); + NTSTATUS status = STATUS_SUCCESS; + + return status; +} + +#pragma code_seg() +NTSTATUS Codec_SdcaXuReadDeferredAudioControls +( + _In_ PVOID Context, // SDCA Context + _Inout_ PSDCA_AUDIO_CONTROLS Controls // Array of SDCA Audio Controls +) +{ + UNREFERENCED_PARAMETER(Context); + UNREFERENCED_PARAMETER(Controls); + NTSTATUS status = STATUS_SUCCESS; + + return status; +} + +#pragma code_seg() +NTSTATUS Codec_SdcaXuWriteDeferredAudioControls +( + _In_ PVOID Context, // SDCA Context + _Inout_ PSDCA_AUDIO_CONTROLS Controls // Array of SDCA Audio Controls +) +{ + UNREFERENCED_PARAMETER(Context); + UNREFERENCED_PARAMETER(Controls); + NTSTATUS status = STATUS_SUCCESS; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetXUEntities +( + _In_ PVOID Context, + _In_ ULONG NumEntities, + _In_reads_(NumEntities) + ULONG EntityIDs[] + ) +{ + PAGED_CODE(); + + DrvLogEnter(g_SDCAVCodecLog); + + NTSTATUS status = STATUS_SUCCESS; + + PCODEC_DEVICE_CONTEXT devCtx; + devCtx = GetCodecDeviceContext((WDFDEVICE)Context); + + if (NumEntities) + { + PULONG pXUEntities = (PULONG)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(ULONG) * NumEntities, DRIVER_TAG); + RETURN_NTSTATUS_IF_TRUE(NULL == pXUEntities, STATUS_INSUFFICIENT_RESOURCES); + + for (ULONG i = 0; i < NumEntities; i++) + { + pXUEntities[i] = EntityIDs[i]; + } + + devCtx->SdcaXuData.numXUEntities = NumEntities; + devCtx->SdcaXuData.XUEntities = pXUEntities; + } + + return status; +} + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuRegisterForInterrupts +( + _In_ PVOID Context, + _In_ PSDCAXU_INTERRUPT_INFO InterruptInfo +) +{ + PAGED_CODE(); + + DrvLogEnter(g_SDCAVCodecLog); + + NTSTATUS status = STATUS_SUCCESS; + + PCODEC_DEVICE_CONTEXT devCtx; + devCtx = GetCodecDeviceContext((WDFDEVICE)Context); + + RETURN_NTSTATUS_IF_TRUE(InterruptInfo->Size != sizeof(SDCAXU_INTERRUPT_INFO), STATUS_INVALID_PARAMETER_1); + + PSDCAXU_INTERRUPT_INFO pInterruptInfo = (PSDCAXU_INTERRUPT_INFO)ExAllocatePool2( + POOL_FLAG_NON_PAGED, + InterruptInfo->Size, + DRIVER_TAG); + RETURN_NTSTATUS_IF_TRUE(NULL == pInterruptInfo, STATUS_MEMORY_NOT_ALLOCATED); + + RtlCopyMemory(pInterruptInfo, InterruptInfo, InterruptInfo->Size); + + devCtx->SdcaXuData.InterruptInfo = pInterruptInfo; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS Codec_GetSdcaXu(_In_ WDFDEVICE Device) +{ + PAGED_CODE(); + NTSTATUS status = STATUS_SUCCESS; + PCODEC_DEVICE_CONTEXT devCtx; + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != NULL); + + RtlZeroMemory(&devCtx->SdcaXuData, sizeof(devCtx->SdcaXuData)); + + // Initialize Interface for requesting correct version + devCtx->SdcaXuData.ExtensionInterface.InterfaceHeader.Size = sizeof(SDCAXU_INTERFACE_V0101); + devCtx->SdcaXuData.ExtensionInterface.InterfaceHeader.Version = SDCAXU_INTERFACE_VERSION_0101; + + // + // Provide SDCA Interface that XU driver can call into + // XU driver will copy these function addresses while + // handling Query Interface + // + devCtx->SdcaXuData.ExtensionInterface.EvtSetXUEntities = Codec_SdcaXuSetXUEntities; + devCtx->SdcaXuData.ExtensionInterface.EvtRegisterForInterrupts = Codec_SdcaXuRegisterForInterrupts; + devCtx->SdcaXuData.ExtensionInterface.EvtSetJackOverride = Codec_SdcaXuSetJackOverride; + devCtx->SdcaXuData.ExtensionInterface.EvtSetJackSelectedMode = Codec_SdcaXuSetJackSelectedMode; + devCtx->SdcaXuData.ExtensionInterface.EvtPDEPowerReferenceAcquire = Codec_SdcaXuPDEPowerReferenceAcquire; + devCtx->SdcaXuData.ExtensionInterface.EvtPDEPowerReferenceRelease = Codec_SdcaXuPDEPowerReferenceRelease; + devCtx->SdcaXuData.ExtensionInterface.EvtReadDeferredAudioControls = Codec_SdcaXuReadDeferredAudioControls; + devCtx->SdcaXuData.ExtensionInterface.EvtWriteDeferredAudioControls = Codec_SdcaXuWriteDeferredAudioControls; + + status = WdfFdoQueryForInterface( + Device, + &SDCAXU_INTERFACE, + (PINTERFACE)&(devCtx->SdcaXuData.ExtensionInterface), + sizeof(SDCAXU_INTERFACE_V0101), + SDCAXU_INTERFACE_VERSION_0101, + Device + ); + + if (NT_SUCCESS(status)) + { + devCtx->SdcaXuData.bSdcaXu = TRUE; + } + + return status; +} + +PAGED_CODE_SEG +NTSTATUS Codec_SetSdcaXuHwConfig(_In_ WDFDEVICE Device) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DrvLogEnter(g_SDCAVCodecLog); + + PCODEC_DEVICE_CONTEXT devCtx; + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != NULL); + PSDCAXU_INTERFACE_V0101 exInterface = &devCtx->SdcaXuData.ExtensionInterface; + PVOID exContext = devCtx->SdcaXuData.ExtensionInterface.InterfaceHeader.Context; + + SdcaXuAcpiBlob acpiBlob; + acpiBlob.NumEndpoints = 2; + RETURN_NTSTATUS_IF_FAILED(exInterface->EvtSetHwConfig(exContext, SdcaXuHwConfigTypeAcpiBlob, &acpiBlob, sizeof(acpiBlob))); + + return status; +} + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SDCAVCodec.vcxproj b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SDCAVCodec.vcxproj new file mode 100644 index 00000000..c855cfc0 --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SDCAVCodec.vcxproj @@ -0,0 +1,364 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|ARM64"> + <Configuration>Debug</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM64"> + <Configuration>Release</Configuration> + <Platform>ARM64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{98C9E1FB-3F06-4B5C-BA88-545AD0A80F94}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <KMDF_VERSION_MINOR>31</KMDF_VERSION_MINOR> + <ACX_VERSION_MAJOR>1</ACX_VERSION_MAJOR> + <ACX_VERSION_MINOR>0</ACX_VERSION_MINOR> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion> + <SupportsPackaging>false</SupportsPackaging> + <RequiresPackageProject>true</RequiresPackageProject> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + <DriverType>KMDF</DriverType> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;..\common\.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;..\common\.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;..\common\.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;..\common\.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;..\common\.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;..\common\.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;$(DDK_LIB_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib</AdditionalDependencies> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\inc;..\common\.</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <PreprocessorDefinitions>%(PreprocessorDefinitions);ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=0;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions> + <WppEnabled>true</WppEnabled> + <WppRecorderEnabled>true</WppRecorderEnabled> + <WppTraceFunction> + </WppTraceFunction> + <WppScanConfigurationData>..\inc\trace_macros.h</WppScanConfigurationData> + <WppAdditionalOptions>-km \ +-DENABLE_WPP_RECORDER=1 \ +-DENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER=1 \ +-func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...) \ +-p:SDCAVCodec</WppAdditionalOptions> + </ClCompile> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> + </ItemDefinitionGroup> + <ItemGroup> + <FilesToPackage Include="$(TargetPath)" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inx)" Include="*.inx" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\inc\NewDelete.h" /> + <ClInclude Include="CircuitHelper.h" /> + <ClInclude Include="private.h" /> + <ClInclude Include="streamengine.h" /> + <ClInclude Include="Trace.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="capture.cpp" /> + <ClCompile Include="CircuitHelper.cpp" /> + <ClCompile Include="device.cpp" /> + <ClCompile Include="driver.cpp" /> + <ClCompile Include="Extension.cpp" /> + <ClCompile Include="..\common\NewDelete.cpp" /> + <ClCompile Include="render.cpp" /> + <ClCompile Include="streamengine.cpp" /> + <ResourceCompile Include="resources.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SDCAVCodec.vcxproj.Filters b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SDCAVCodec.vcxproj.Filters new file mode 100644 index 00000000..44bc3f92 --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SDCAVCodec.vcxproj.Filters @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Driver Files"> + <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + </Filter> + </ItemGroup> +</Project> diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SdcaVCodec.inx b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SdcaVCodec.inx new file mode 100644 index 00000000..88c9eba4 --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/SdcaVCodec.inx @@ -0,0 +1,146 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +;Module Name: +; +; SDCAVCodec.INF +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=SYSTEM +ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} +Provider=%ProviderName% +DriverVer=06/13/2016, 1.0.0.1 +CatalogFile=SDCAVad.cat +PnpLockdown=1 + +[DestinationDirs] +DefaultDestDir = 13 + +;***************************************** +; Audio Device Install Section +;***************************************** +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$.10.0...19041 + +[Standard.NT$ARCH$.10.0...19041] +%WdfCodecDevice.DeviceDesc%=Audio_Device, ROOT\SDCAVCodec + +[Audio_Device.NT] +CopyFiles=Audio_Device.NT.Copy + +[Audio_Device.NT.Copy] +SDCAVCodec.sys + + +[Audio_Device.NT.HW] +AddReg=FilterLevelReg + +;**************************************************** +; SDCAXu filters are installed in filter level +; SDCAXu +;**************************************************** +[FilterLevelReg] +HKR,,LowerFilterLevels,%REG_MULTI_SZ%,"SDCAXu","DefaultLowerFilter" +HKR,,LowerFilterDefaultLevel,,"DefaultLowerFilter" + +;-------------- Service installation + +[Audio_Device.NT.Services] +AddService = SDCAVCodec, %SPSVCINST_ASSOCSERVICE%, Audio_Service_Inst + +[Audio_Service_Inst] +DisplayName = %WdfCodecDevice.DeviceDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %13%\SDCAVCodec.sys + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +SDCAVCodec.sys = 1,, + + +[Audio_Device.NT.Wdf] +KmdfService = SDCAVCodec, Audio_wdfsect +[Audio_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + +; +; render interfaces: speaker +; +[Audio_Device.I.Speaker] +AddReg=Audio_Device.I.Speaker.AddReg +[Audio_Device.I.Speaker.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%Audio_Device.Speaker.szPname% +; The following lines opt-in to pull mode. +HKR,EP\0,%PKEY_AudioEndpoint_Association%,,%KSNODETYPE_ANY% +HKR,EP\0,%PKEY_AudioEndpoint_Supports_EventDriven_Mode%,0x00010001,0x1 + +; +; capture interfaces: microphone +; +[Audio_Device.I.Microphone] +AddReg=Audio_Device.I.Microphone.AddReg +[Audio_Device.I.Microphone.AddReg] +HKR,,CLSID,,%Proxy.CLSID% +HKR,,FriendlyName,,%Audio_Device.Microphone.szPname% +; The following lines opt-in to pull mode. +HKR,EP\0,%PKEY_AudioEndpoint_Association%,,%KSNODETYPE_ANY% +HKR,EP\0,%PKEY_AudioEndpoint_Supports_EventDriven_Mode%,0x00010001,0x1 + +; +; PnP add interface directives for static enumerated audio endpoints. +; +[Audio_Device.NT.Interfaces] +; Interfaces for render endpoint. +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_Speaker%, Audio_Device.I.Speaker +AddInterface=%KSCATEGORY_TOPOLOGY%, %KSNAME_Speaker%, Audio_Device.I.Speaker + +; Interfaces for mic capture endpoint +AddInterface=%KSCATEGORY_AUDIO%, %KSNAME_Microphone%, Audio_Device.I.Microphone +AddInterface=%KSCATEGORY_TOPOLOGY%, %KSNAME_Microphone%, Audio_Device.I.Microphone + +[Strings] +; +;Non-localizable +; +KSNAME_Speaker="Speaker0" +KSNAME_Microphone="Microphone0" + +SPSVCINST_ASSOCSERVICE = 0x00000002 +ProviderName = "VS_Microsoft" + +Proxy.CLSID = "{17CCA71B-ECD7-11D0-B908-00A0C9223196}" +KSCATEGORY_AUDIO = "{6994AD04-93EF-11D0-A3CC-00A0C9223196}" +KSCATEGORY_RENDER = "{65E8773E-8F56-11D0-A3B9-00A0C9223196}" +KSCATEGORY_CAPTURE = "{65E8773D-8F56-11D0-A3B9-00A0C9223196}" +KSCATEGORY_REALTIME = "{EB115FFC-10C8-4964-831D-6DCB02E6F23F}" +KSCATEGORY_TOPOLOGY = "{DDA54A40-1E4C-11D1-A050-405705C10000}" + +MediaCategories="SYSTEM\CurrentControlSet\Control\MediaCategories" +KSNODETYPE_ANY = "{00000000-0000-0000-0000-000000000000}" + +PKEY_AudioEndpoint_ControlPanelPageProvider = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E},1" +PKEY_AudioEndpoint_Association = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E},2" +PKEY_AudioEndpoint_Supports_EventDriven_Mode = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E},7" +PKEY_AudioEndpoint_Default_VolumeInDb = "{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E},9" +REG_MULTI_SZ = 0x00010000 +; +;Localizable +; +StdMfg = "SDCA Virtual Codec Audio Device" +DiskId1 = "SDCA Virtual Codec Audio Driver Installation Disk" +WdfCodecDevice.DeviceDesc = "SDCA Virtual Codec Audio Driver" + +;; friendly names +Audio_Device.Speaker.szPname="SDCA Virtual Codec Speaker" +Audio_Device.Microphone.szPname="SDCA Virtual Codec Microphone" + + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/Trace.h b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/Trace.h new file mode 100644 index 00000000..4b292930 --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/Trace.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + +Trace.h + +--*/ + +#pragma once + +#include <WppRecorder.h> +#include <evntrace.h> // For TRACE_LEVEL definitions + +#define WPP_TOTAL_BUFFER_SIZE (PAGE_SIZE) +#define WPP_ERROR_PARTITION_SIZE (WPP_TOTAL_BUFFER_SIZE/4) + +// {C456FD64-2AC1-4A72-8280-B4163555CD03} +#define WPP_CONTROL_GUIDS \ +WPP_DEFINE_CONTROL_GUID(DrvLogger,(c456fd64,2ac1,4a72,8280,b4163555cd03), \ + WPP_DEFINE_BIT(FLAG_DEVICE_ALL) /* bit 0 = 0x00000001 */ \ + WPP_DEFINE_BIT(FLAG_FUNCTION) /* bit 1 = 0x00000002 */ \ + WPP_DEFINE_BIT(FLAG_INFO) /* bit 2 = 0x00000004 */ \ + WPP_DEFINE_BIT(FLAG_PNP) /* bit 3 = 0x00000008 */ \ + WPP_DEFINE_BIT(FLAG_POWER) /* bit 4 = 0x00000010 */ \ + WPP_DEFINE_BIT(FLAG_STREAM) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(FLAG_INIT) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(FLAG_DDI) /* bit 7 = 0x00000080 */ \ + WPP_DEFINE_BIT(FLAG_GENERIC) /* bit 8 = 0x00000100 */ \ + ) + +#include "trace_macros.h" + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/capture.cpp b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/capture.cpp new file mode 100644 index 00000000..df6de34c --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/capture.cpp @@ -0,0 +1,1150 @@ +/*++ + + 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: + + Capture.cpp + +Abstract: + + Contains ACX Capture factory and circuit + +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 "soundwirecontroller.h" +#include "sdcastreaming.h" +#include "CircuitHelper.h" + +#include "AudioFormats.h" + +#ifndef __INTELLISENSE__ +#include "capture.tmh" +#endif + +ACX_PROPERTY_ITEM KwsProperties[] = +{ + { + &KSPROPERTYSETID_SdcaKws, + KSPROPERTY_SDCAKWS_DEVICE_CAPABILITY, + ACX_PROPERTY_ITEM_FLAG_GET, + &CodecC_EvtCircuitDeviceKwsCapability, // Event to call + NULL, // Reserved + 0, // ControlCb + sizeof(DEVICE_KWS_CAPABILITY_DESCRIPTOR) // ValueCb + }, + { + &KSPROPERTYSETID_SdcaKws, + KSPROPERTY_SDCAKWS_VAD_CAPABILITY, + ACX_PROPERTY_ITEM_FLAG_GET, + &CodecC_EvtCircuitVadCapability, // Event to call + NULL, // Reserved + 0, // ControlCb + sizeof(VAD_DESCRIPTOR) // ValueCb + }, + { + &KSPROPERTYSETID_SdcaKws, + KSPROPERTY_SDCAKWS_VAD_ENTITIES, + ACX_PROPERTY_ITEM_FLAG_GET, + &CodecC_EvtCircuitVadEntities, // Event to call + NULL, // Reserved + 0, // ControlCb + sizeof(VAD_ENTITIES) // ValueCb + }, + { + &KSPROPERTYSETID_SdcaKws, + KSPROPERTY_SDCAKWS_ACCESS_EVENTS, + ACX_PROPERTY_ITEM_FLAG_SET, + &CodecC_EvtCircuitSetKwsAccessEvents, // Event to call + NULL, // Reserved + 0, // ControlCb + sizeof(SDCA_KWS_NOTIFICATIONS) // ValueCb + }, + { + &KSPROPERTYSETID_SdcaKws, + KSPROPERTY_SDCAKWS_CONFIGURE_VAD_PORT, + ACX_PROPERTY_ITEM_FLAG_SET, + &CodecC_EvtCircuitConfigureVadPort, // Event to call + NULL, // Reserved + 0, // ControlCb + sizeof(SDCA_KWS_PREPARE_PARAMS) // ValueCb + }, + { + &KSPROPERTYSETID_SdcaKws, + KSPROPERTY_SDCAKWS_CLEANUP_VAD_PORT, + ACX_PROPERTY_ITEM_FLAG_SET, + &CodecC_EvtCircuitCleanupVadPort, // Event to call + // No parameters - can only have one + }, +}; + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +CodecC_EvtCircuitVadCapability( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + ACX_REQUEST_PARAMETERS params; + ULONG_PTR outDataCb = 0; + PVAD_DESCRIPTOR value; + ULONG valueCb; + ULONG_PTR minSize; + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + ULONG formatCount = 0; + + PAGED_CODE(); + + circuitCtx = GetCaptureCircuitContext((ACXCIRCUIT)Object); + + ACX_REQUEST_PARAMETERS_INIT(¶ms); + AcxRequestGetParameters(Request, ¶ms); + + ASSERT(params.Type == AcxRequestTypeProperty); + ASSERT(params.Parameters.Property.Verb == AcxPropertyVerbGet); + + value = (PVAD_DESCRIPTOR)params.Parameters.Property.Value; + valueCb = params.Parameters.Property.ValueCb; + + // + // Compute min size. + // + minSize = sizeof(VAD_DESCRIPTOR); + + // + // Sample only supports 1 format + // + formatCount = 1; + + // Note the VAD_DESCRIPTOR already has room for 1, hence subtracting that here + minSize += (formatCount - ANYSIZE_ARRAY) * sizeof(WAVEFORMATEXTENSIBLE); + + if (valueCb == 0) + { + outDataCb = minSize; + status = STATUS_BUFFER_OVERFLOW; + } + else if (valueCb < minSize) + { + outDataCb = 0; + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + // + // Reset buffer. + // + RtlZeroMemory(value, valueCb); + + // It's safe for us to use the KwsDataFormat directly in AcxDataFormatGetWaveFormatExtensible + // because we control it and know it will have a proper WAVEFORMATEXTENSIBLE value. + RtlCopyMemory(value->Format, AcxDataFormatGetWaveFormatExtensible(circuitCtx->KwsDataFormat), sizeof(WAVEFORMATEXTENSIBLE)); + + value->FormatCount = formatCount; + + // + // All done. + // + outDataCb = minSize; + status = STATUS_SUCCESS; + } + + WdfRequestCompleteWithInformation(Request, status, outDataCb); +} + + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +CodecC_EvtCircuitVadEntities( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + ACX_REQUEST_PARAMETERS params; + ULONG_PTR outDataCb = 0; + PVAD_DESCRIPTOR value; + ULONG valueCb; + ULONG_PTR minSize; + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + + PAGED_CODE(); + + circuitCtx = GetCaptureCircuitContext((ACXCIRCUIT)Object); + + ACX_REQUEST_PARAMETERS_INIT(¶ms); + AcxRequestGetParameters(Request, ¶ms); + + ASSERT(params.Type == AcxRequestTypeProperty); + ASSERT(params.Parameters.Property.Verb == AcxPropertyVerbGet); + + value = (PVAD_DESCRIPTOR)params.Parameters.Property.Value; + valueCb = params.Parameters.Property.ValueCb; + + // we're going to return 0 entities, so only the base structure + // is needed. + minSize = sizeof(VAD_ENTITIES); + + if (valueCb == 0) + { + outDataCb = minSize; + status = STATUS_BUFFER_OVERFLOW; + } + else if (valueCb < minSize) + { + outDataCb = 0; + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + // + // Reset buffer. + // + RtlZeroMemory(value, valueCb); + + // we do not have disco info for this sample driver, so + // we have no entities to copy, but an empty list is sufficient + // for testing. + + outDataCb = minSize; + status = STATUS_SUCCESS; + } + + WdfRequestCompleteWithInformation(Request, status, outDataCb); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +CodecC_EvtCircuitDeviceKwsCapability( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + ACX_REQUEST_PARAMETERS params; + ULONG_PTR outDataCb = 0; + PDEVICE_KWS_CAPABILITY_DESCRIPTOR value; + ULONG valueCb; + ULONG_PTR minSize; + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + + PAGED_CODE(); + + circuitCtx = GetCaptureCircuitContext((ACXCIRCUIT)Object); + + ACX_REQUEST_PARAMETERS_INIT(¶ms); + AcxRequestGetParameters(Request, ¶ms); + + ASSERT(params.Type == AcxRequestTypeProperty); + ASSERT(params.Parameters.Property.Verb == AcxPropertyVerbGet); + + value = (PDEVICE_KWS_CAPABILITY_DESCRIPTOR)params.Parameters.Property.Value; + valueCb = params.Parameters.Property.ValueCb; + + // + // Compute min size. + // + + minSize = sizeof(DEVICE_KWS_CAPABILITY_DESCRIPTOR); + + if (valueCb == 0) + { + outDataCb = minSize; + status = STATUS_BUFFER_OVERFLOW; + } + else if (valueCb < minSize) + { + outDataCb = 0; + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + // + // Reset buffer. + // + RtlZeroMemory(value, valueCb); + + // Get the Device KWS Capabilities + // In this sample, just return that Buffered is supported + value->DataPathsSupported = SupportedDataPathsBufferedRaw; + + // + // All done. + // + outDataCb = minSize; + status = STATUS_SUCCESS; + } + + WdfRequestCompleteWithInformation(Request, status, outDataCb); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +CodecC_EvtCircuitSetKwsAccessEvents( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + ACX_REQUEST_PARAMETERS params; + ULONG_PTR outDataCb = 0; // default no size info + PSDCA_KWS_NOTIFICATIONS value; + ULONG valueCb; + ULONG minSize; + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + + PAGED_CODE(); + + circuitCtx = GetCaptureCircuitContext((ACXCIRCUIT)Object); + + ACX_REQUEST_PARAMETERS_INIT(¶ms); + AcxRequestGetParameters(Request, ¶ms); + + ASSERT(params.Type == AcxRequestTypeProperty); + ASSERT(params.Parameters.Property.Verb == AcxPropertyVerbSet); + + minSize = sizeof(SDCA_KWS_NOTIFICATIONS); + + value = (PSDCA_KWS_NOTIFICATIONS)params.Parameters.Property.Value; + valueCb = params.Parameters.Property.ValueCb; + + if (valueCb == 0) + { + outDataCb = minSize; + status = STATUS_BUFFER_OVERFLOW; + goto exit; + } + + if (valueCb < minSize) + { + status = STATUS_BUFFER_TOO_SMALL; + goto exit; + } + + circuitCtx->KwsSuspendEvent = value->Suspend; + circuitCtx->KwsResumeEvent = value->Resume; + + status = STATUS_SUCCESS; + +exit: + + WdfRequestCompleteWithInformation(Request, status, outDataCb); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +CodecC_EvtCircuitConfigureVadPort( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + ACX_REQUEST_PARAMETERS params; + ULONG_PTR outDataCb = 0; // default no size info + PSDCA_KWS_PREPARE_PARAMS value; + ULONG valueCb; + ULONG minSize; + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + + PAGED_CODE(); + + circuitCtx = GetCaptureCircuitContext((ACXCIRCUIT)Object); + + ACX_REQUEST_PARAMETERS_INIT(¶ms); + AcxRequestGetParameters(Request, ¶ms); + + ASSERT(params.Type == AcxRequestTypeProperty); + ASSERT(params.Parameters.Property.Verb == AcxPropertyVerbSet); + + if (circuitCtx->KwsActiveVadStream) + { + status = STATUS_INVALID_DEVICE_REQUEST; + goto exit; + } + + minSize = sizeof(SDCA_KWS_PREPARE_PARAMS); + + value = (PSDCA_KWS_PREPARE_PARAMS)params.Parameters.Property.Value; + valueCb = params.Parameters.Property.ValueCb; + + if (valueCb == 0) + { + outDataCb = minSize; + status = STATUS_BUFFER_OVERFLOW; + goto exit; + } + + if (valueCb < minSize) + { + status = STATUS_BUFFER_TOO_SMALL; + goto exit; + } + + if (value->DetectionFormat.Format.cbSize > sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + + // Set up the hardware for KWS + circuitCtx->KwsActiveVadStream = TRUE; + status = STATUS_SUCCESS; + +exit: + + WdfRequestCompleteWithInformation(Request, status, outDataCb); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +CodecC_EvtCircuitCleanupVadPort( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + NTSTATUS status = STATUS_NOT_SUPPORTED; + ACX_REQUEST_PARAMETERS params; + ULONG_PTR outDataCb = 0; // default no size info + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + + PAGED_CODE(); + + circuitCtx = GetCaptureCircuitContext((ACXCIRCUIT)Object); + + ACX_REQUEST_PARAMETERS_INIT(¶ms); + AcxRequestGetParameters(Request, ¶ms); + + ASSERT(params.Type == AcxRequestTypeProperty); + ASSERT(params.Parameters.Property.Verb == AcxPropertyVerbSet); + + if (!circuitCtx->KwsActiveVadStream) + { + status = STATUS_INVALID_DEVICE_REQUEST; + goto exit; + } + + // Deconfigure hardware + circuitCtx->KwsActiveVadStream = FALSE; + status = STATUS_SUCCESS; + +exit: + + WdfRequestCompleteWithInformation(Request, status, outDataCb); +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtAcxPinSetDataFormat( + _In_ ACXPIN Pin, + _In_ ACXDATAFORMAT DataFormat +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Pin); + UNREFERENCED_PARAMETER(DataFormat); + + + return STATUS_NOT_SUPPORTED; +} + +#pragma code_seg() +VOID +CodecC_EvtPinContextCleanup( + _In_ WDFOBJECT WdfPin +) +/*++ + +Routine Description: + + In this callback, it cleans up pin context. + +Arguments: + + WdfDevice - WDF device object + +Return Value: + + NULL + +--*/ +{ + UNREFERENCED_PARAMETER(WdfPin); +} + +PAGED_CODE_SEG +VOID +CodecC_EvtCircuitRequestPreprocess( + _In_ ACXOBJECT Object, + _In_ ACXCONTEXT DriverContext, + _In_ WDFREQUEST Request +) +/*++ + +Routine Description: + + This function is an example of a preprocess routine. + +--*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DriverContext); + + ASSERT(Object != NULL); + ASSERT(DriverContext); + ASSERT(Request); + + + // + // Just give the request back to ACX. + // + (VOID)AcxCircuitDispatchAcxRequest((ACXCIRCUIT)Object, Request); +} + +PAGED_CODE_SEG +VOID +CodecC_EvtStreamRequestPreprocess( + _In_ ACXOBJECT Object, + _In_ ACXCONTEXT DriverContext, + _In_ WDFREQUEST Request +) +/*++ + +Routine Description: + + This function is an example of a preprocess routine. + +--*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DriverContext); + + ASSERT(Object != NULL); + ASSERT(DriverContext); + ASSERT(Request); + + + // + // Just give the request back to ACX. + // + (VOID)AcxStreamDispatchAcxRequest((ACXSTREAM)Object, Request); +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_AddCaptures( + _In_ WDFDRIVER Driver, + _In_ WDFDEVICE Device +) +{ + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + // + // Add a static capture device. + // + RETURN_NTSTATUS_IF_FAILED(CodecC_AddStaticCapture(Device)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_AddStaticCapture( + _In_ WDFDEVICE Device +) +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + PCODEC_DEVICE_CONTEXT devCtx; + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != NULL); + + // + // Alloc audio context to current device. + // + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_CAPTURE_DEVICE_CONTEXT); + PCODEC_CAPTURE_DEVICE_CONTEXT captureDevCtx; + RETURN_NTSTATUS_IF_FAILED(WdfObjectAllocateContext(Device, &attributes, (PVOID*)&captureDevCtx)); + + ASSERT(captureDevCtx); + + // + // Create a capture circuit associated with this device. + // + ACXCIRCUIT captureCircuit = NULL; + RETURN_NTSTATUS_IF_FAILED(CodecC_CreateCaptureCircuit(Device, &captureCircuit)); + + RETURN_NTSTATUS_IF_FAILED(Codec_SdcaXuSetCaptureEndpointConfig(Device, captureCircuit)); + + devCtx->Capture = captureCircuit; + + return status; +} + +EXTERN_C const GUID DECLSPEC_SELECTANY CODEC_CIRCUIT_CAPTURE_GUID; +EXTERN_C const GUID DECLSPEC_SELECTANY EXTENSION_CIRCUIT_CAPTURE_GUID; +EXTERN_C const GUID DECLSPEC_SELECTANY SYSTEM_CONTAINER_GUID; + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetCaptureEndpointConfig( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit +) +{ + PAGED_CODE(); + + DrvLogEnter(g_SDCAVCodecLog); + + NTSTATUS status = STATUS_SUCCESS; + + PCODEC_DEVICE_CONTEXT devCtx; + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != NULL); + + DECLARE_CONST_UNICODE_STRING(circuitName, L"ExtensionMicrophone0"); + DECLARE_CONST_UNICODE_STRING(circuitUri, EXT_CAPTURE_CIRCUIT_URI); + +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "memory is freed by scope_exit") + PSDCAXU_ACX_CIRCUIT_CONFIG exCircuitConfig = (PSDCAXU_ACX_CIRCUIT_CONFIG)ExAllocatePool2( + POOL_FLAG_NON_PAGED, + sizeof(SDCAXU_ACX_CIRCUIT_CONFIG) + circuitName.MaximumLength, + DRIVER_TAG); + RETURN_NTSTATUS_IF_TRUE(NULL == exCircuitConfig, STATUS_INSUFFICIENT_RESOURCES); + auto exConfigFree = scope_exit([&exCircuitConfig]() { + ExFreePoolWithTag(exCircuitConfig, DRIVER_TAG); + }); + + // + // Provide circuit configuration to SDCA XU driver + // SDCA XU driver will generate circuits to match this configuration + // + if (devCtx->SdcaXuData.bSdcaXu) + { + exCircuitConfig->cbSize = sizeof(SDCAXU_ACX_CIRCUIT_CONFIG) + circuitName.MaximumLength; + + exCircuitConfig->CircuitName = circuitName; + exCircuitConfig->CircuitName.Buffer = (PWCH)(exCircuitConfig + 1); + RtlCopyMemory(exCircuitConfig->CircuitName.Buffer, circuitName.Buffer, circuitName.MaximumLength); + + exCircuitConfig->CircuitContext = Circuit; + exCircuitConfig->CircuitType = AcxCircuitTypeCapture; + exCircuitConfig->ContainerID = SYSTEM_CONTAINER_GUID; + exCircuitConfig->ComponentID = EXTENSION_CIRCUIT_CAPTURE_GUID; + exCircuitConfig->ComponentUri = circuitUri; + + PSDCAXU_INTERFACE_V0101 exInterface = &devCtx->SdcaXuData.ExtensionInterface; + PVOID exContext = devCtx->SdcaXuData.ExtensionInterface.InterfaceHeader.Context; + + RETURN_NTSTATUS_IF_FAILED(exInterface->EvtSetEndpointConfig(exContext, SdcaXuEndpointConfigTypeAcxCircuitConfig, exCircuitConfig, exCircuitConfig->cbSize)); + } + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT * Circuit +) +/*++ + +Routine Description: + + This routine builds the CODEC capture circuit. + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + // + // Init output value. + // + *Circuit = NULL; + + /////////////////////////////////////////////////////////// + // + // Create a circuit. + // + + // + // Get a CircuitInit structure. + // + PACXCIRCUIT_INIT circuitInit = NULL; + circuitInit = AcxCircuitInitAllocate(Device); + RETURN_NTSTATUS_IF_TRUE(NULL == circuitInit, STATUS_NO_MEMORY); + auto circuitInitScope = scope_exit([&circuitInit]() { + AcxCircuitInitFree(circuitInit); + }); + + // + // Add circuit identifiers. + // + AcxCircuitInitSetComponentId(circuitInit, &CODEC_CIRCUIT_CAPTURE_GUID); + + DECLARE_CONST_UNICODE_STRING(circuitUri, CAPTURE_CIRCUIT_URI); + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignComponentUri(circuitInit, &circuitUri)); + + DECLARE_CONST_UNICODE_STRING(circuitName, L"Microphone0"); + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignName(circuitInit, &circuitName)); + + // + // Add circuit type. + // + AcxCircuitInitSetCircuitType(circuitInit, AcxCircuitTypeCapture); + + // + // Assign the circuit's pnp-power callbacks. + // + ACX_CIRCUIT_PNPPOWER_CALLBACKS powerCallbacks; + ACX_CIRCUIT_PNPPOWER_CALLBACKS_INIT(&powerCallbacks); + powerCallbacks.EvtAcxCircuitPowerUp = CodecC_EvtCircuitPowerUp; + powerCallbacks.EvtAcxCircuitPowerDown = CodecC_EvtCircuitPowerDown; + AcxCircuitInitSetAcxCircuitPnpPowerCallbacks(circuitInit, &powerCallbacks); + + // + // Set circuit-callbacks. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignAcxRequestPreprocessCallback( + circuitInit, + CodecC_EvtCircuitRequestPreprocess, + (ACXCONTEXT)AcxRequestTypeAny, // dbg only + AcxRequestTypeAny, + NULL, + AcxItemIdNone)); + + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignAcxCreateStreamCallback( + circuitInit, + CodecC_EvtCircuitCreateStream)); + + // + // Add properties, events and methods. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignProperties(circuitInit, + KwsProperties, + ARRAYSIZE(KwsProperties))); + + // + // Create the circuit. + // + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_CAPTURE_CIRCUIT_CONTEXT); + ACXCIRCUIT circuit; + RETURN_NTSTATUS_IF_FAILED(AcxCircuitCreate(Device, &attributes, &circuitInit, &circuit)); + circuitInitScope.release(); + + ASSERT(circuit != NULL); + CODEC_CAPTURE_CIRCUIT_CONTEXT *circuitCtx; + circuitCtx = GetCaptureCircuitContext(circuit); + ASSERT(circuitCtx); + + // + // Post circuit creation initialization. + // + + /////////////////////////////////////////////////////////// + // + // Add two custom circuit elements. Note that driver doesn't need to + // perform this step if it doesn't want to expose any circuit elements. + // + + // + // Create 1st custom circuit-element. + // + ACX_ELEMENT_CONFIG elementCfg; + ACX_ELEMENT_CONFIG_INIT(&elementCfg); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_ELEMENT_CONTEXT); + attributes.ParentObject = circuit; + + const int numElements = 2; + ACXELEMENT elements[numElements] = {0}; + RETURN_NTSTATUS_IF_FAILED(AcxElementCreate(circuit, &attributes, &elementCfg, &elements[0])); + + ASSERT(elements[0] != NULL); + CODEC_ELEMENT_CONTEXT *elementCtx; + elementCtx = GetCodecElementContext(elements[0]); + ASSERT(elementCtx); + UNREFERENCED_PARAMETER(elementCtx); + + // + // Create 2nd custom circuit-element. + // + ACX_ELEMENT_CONFIG_INIT(&elementCfg); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_ELEMENT_CONTEXT); + attributes.ParentObject = circuit; + + RETURN_NTSTATUS_IF_FAILED(AcxElementCreate(circuit, &attributes, &elementCfg, &elements[1])); + + ASSERT(elements[1] != NULL); + elementCtx = GetCodecElementContext(elements[1]); + ASSERT(elementCtx); + UNREFERENCED_PARAMETER(elementCtx); + + // + // Add the circuit elements + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddElements(circuit, elements, SIZEOF_ARRAY(elements))); + + /////////////////////////////////////////////////////////// + // Create Capture Pin, using default pin id. + // Acx Circuit will create other pin by default. + // + // Allocate the formats this circuit supports. Use formats without + // channel mask for capture. + // + // PCM:44100 channel:2 24in32 + ACX_DATAFORMAT_CONFIG formatCfg; + ACX_DATAFORMAT_CONFIG_INIT_KS(&formatCfg, &Pcm44100c2_24in32_nomask); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_FORMAT_CONTEXT); + attributes.ParentObject = circuit; + + ACXDATAFORMAT formatPcm44100c2_24in32nomask; + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatCreate(Device, &attributes, &formatCfg, &formatPcm44100c2_24in32nomask)); + + CODEC_FORMAT_CONTEXT *formatCtx; + formatCtx = GetCodecFormatContext(formatPcm44100c2_24in32nomask); + ASSERT(formatCtx); + UNREFERENCED_PARAMETER(formatCtx); + + // PCM:48000 channel:2 24in32 + ACX_DATAFORMAT_CONFIG_INIT_KS(&formatCfg, &Pcm48000c2_24in32_nomask); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_FORMAT_CONTEXT); + attributes.ParentObject = circuit; + + ACXDATAFORMAT formatPcm48000c2_24in32nomask; + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatCreate(Device, &attributes, &formatCfg, &formatPcm48000c2_24in32nomask)); + + formatCtx = GetCodecFormatContext(formatPcm48000c2_24in32nomask); + ASSERT(formatCtx); + UNREFERENCED_PARAMETER(formatCtx); + + // This is the format we'll report support for with KWS. Note that DSP uses 4ch; that includes + // 2ch from the hardware + 2ch reference + ACX_DATAFORMAT_CONFIG_INIT_KS(&formatCfg, &Pcm16000c2nomask); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_FORMAT_CONTEXT); + attributes.ParentObject = circuit; + + ACXDATAFORMAT formatPcm16000c2nomask; + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatCreate(Device, &attributes, &formatCfg, &formatPcm16000c2nomask)); + + formatCtx = GetCodecFormatContext(formatPcm16000c2nomask); + ASSERT(formatCtx); + UNREFERENCED_PARAMETER(formatCtx); + + /////////////////////////////////////////////////////////// + // + // Create Capture Pin. AcxCircuit creates the other pin by default. + // + + ACX_PIN_CALLBACKS pinCallbacks; + ACX_PIN_CALLBACKS_INIT(&pinCallbacks); + pinCallbacks.EvtAcxPinSetDataFormat = CodecC_EvtAcxPinSetDataFormat; + + ACX_PIN_CONFIG pinCfg; + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSource; + pinCfg.Communication = AcxPinCommunicationNone; + pinCfg.Category = &KSCATEGORY_AUDIO; + pinCfg.PinCallbacks = &pinCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecC_EvtPinContextCleanup; + attributes.ParentObject = circuit; + + ACXPIN pin; + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &pin)); + + ASSERT(pin != NULL); + CODEC_PIN_CONTEXT *pinCtx; + pinCtx = GetCodecPinContext(pin); + ASSERT(pinCtx); + UNREFERENCED_PARAMETER(pinCtx); + + // + // Add our supported formats to the Default mode for the circuit + // + ACXDATAFORMATLIST formatList; + formatList = AcxPinGetRawDataFormatList(pin); + RETURN_NTSTATUS_IF_TRUE(NULL == formatList, STATUS_INSUFFICIENT_RESOURCES); + + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm44100c2_24in32nomask)); + + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm48000c2_24in32nomask)); + + circuitCtx->KwsDataFormat = formatPcm16000c2nomask; + + // Add Capture Pin, using default pin id. + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddPins(circuit, &pin, 1)); + + /////////////////////////////////////////////////////////// + // + // Create Bridge Pin. + // + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSink; + pinCfg.Communication = AcxPinCommunicationNone; + pinCfg.Category = &KSNODETYPE_MICROPHONE; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecR_EvtPinContextCleanup; + attributes.ParentObject = circuit; + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &pin)); + + ASSERT(pin != NULL); + + RETURN_NTSTATUS_IF_FAILED(AddJack(attributes, pin, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, RGB(0, 0, 0), AcxConnTypeAtapiInternal, AcxGeoLocFront, AcxGenLocPrimaryBox, AcxPortConnIntegratedDevice)); + + // Add capture bridge pin + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddPins(circuit, &pin, 1)); + + + + // + // Explicitly connect the circuit/elements. Note that driver doens't + // need to perform this step when circuit/elements are connected in the + // same order as they were added to the circuit. By default ACX connects + // the elements starting from the sink circuit pin and ending on the + // source circuit pin on both render and capture devices. + // + // circuit.pin[default_sink] -> 1st element.pin[default_in] + // 1st element.pin[default_out] -> 2nd element.pin[default_in] + // 2nd element.pin[default_out] -> circuit.pin[default_source] + // + const int numConnections = numElements + 1; + ACX_CONNECTION connections[numConnections]; + ACX_CONNECTION_INIT(&connections[0], circuit, elements[0]); + ACX_CONNECTION_INIT(&connections[1], elements[0], elements[1]); + ACX_CONNECTION_INIT(&connections[2], elements[1], circuit); + + // + // Add the connections linking circuit to elements. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddConnections(circuit, connections, SIZEOF_ARRAY(connections))); + + // + // Set output value. + // + *Circuit = circuit; + + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtCircuitPowerUp( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE PreviousState +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(PreviousState); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtCircuitPowerDown( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE TargetState +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(TargetState); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtCircuitCreateStream( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ ACXPIN Pin, + _In_ PACXSTREAM_INIT StreamInit, + _In_ ACXDATAFORMAT StreamFormat, + _In_ const GUID * SignalProcessingMode, + _In_ ACXOBJECTBAG VarArguments +) +/*++ + +Routine Description: + + This routine create a stream for the specified circuit. + +Return Value: + + NT status value + +--*/ +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(Pin); + UNREFERENCED_PARAMETER(SignalProcessingMode); + UNREFERENCED_PARAMETER(VarArguments); + + ASSERT(IsEqualGUID(*SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW)); + + PCODEC_CAPTURE_DEVICE_CONTEXT devCtx; + devCtx = GetCaptureDeviceContext(Device); + ASSERT(devCtx != NULL); + + DECLARE_CONST_ACXOBJECTBAG_DRIVER_PROPERTY_NAME(msft, TestUI4); + if (VarArguments) + { + // Get the variable arguments parameter and retrive the values set by the DSP object. + ULONG ui4Value = 0; + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagRetrieveUI4(VarArguments, &TestUI4, &ui4Value)); + + RETURN_NTSTATUS_IF_TRUE(ui4Value == 0, STATUS_UNSUCCESSFUL); + + ui4Value++; + + // Add the modified value back to object bag. + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUI4(VarArguments, &TestUI4, ui4Value)); + } + + // + // Set circuit-callbacks. + // + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxRequestPreprocessCallback( + StreamInit, + CodecC_EvtStreamRequestPreprocess, + (ACXCONTEXT)AcxRequestTypeAny, // dbg only + AcxRequestTypeAny, + NULL, + AcxItemIdNone)); + + /* + // + // Add properties, events and methods. + // + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignProperties(StreamInit, + StreamProperties, + StreamPropertiesCount)); + */ + + // + // Init streaming callbacks. + // + ACX_STREAM_CALLBACKS streamCallbacks; + ACX_STREAM_CALLBACKS_INIT(&streamCallbacks); + streamCallbacks.EvtAcxStreamPrepareHardware = Codec_EvtStreamPrepareHardware; + streamCallbacks.EvtAcxStreamReleaseHardware = Codec_EvtStreamReleaseHardware; + streamCallbacks.EvtAcxStreamRun = Codec_EvtStreamRun; + streamCallbacks.EvtAcxStreamPause = Codec_EvtStreamPause; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxStreamCallbacks(StreamInit, &streamCallbacks)); + + // + // Create the stream. + // + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_STREAM_CONTEXT); + attributes.EvtDestroyCallback = Codec_EvtStreamDestroy; + ACXSTREAM stream; + RETURN_NTSTATUS_IF_FAILED(AcxStreamCreate(Device, Circuit, &attributes, &StreamInit, &stream)); + + CCaptureStreamEngine *streamEngine = NULL; + streamEngine = new(POOL_FLAG_NON_PAGED, DRIVER_TAG) CCaptureStreamEngine(stream, StreamFormat); + RETURN_NTSTATUS_IF_TRUE(NULL == streamEngine, STATUS_INSUFFICIENT_RESOURCES); + + CODEC_STREAM_CONTEXT *streamCtx; + streamCtx = GetCodecStreamContext(stream); + ASSERT(streamCtx); + streamCtx->StreamEngine = (PVOID)streamEngine; + streamEngine = NULL; + + // + // Post stream creation initialization. + // + + // + // Create 1st custom stream-elements. + // + ACX_ELEMENT_CONFIG elementCfg; + ACX_ELEMENT_CONFIG_INIT(&elementCfg); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_ELEMENT_CONTEXT); + attributes.ParentObject = stream; + + ACXELEMENT elements[2] = {0}; + RETURN_NTSTATUS_IF_FAILED(AcxElementCreate(stream, &attributes, &elementCfg, &elements[0])); + + ASSERT(elements[0] != NULL); + CODEC_ELEMENT_CONTEXT *elementCtx; + elementCtx = GetCodecElementContext(elements[0]); + ASSERT(elementCtx); + UNREFERENCED_PARAMETER(elementCtx); + + // + // Create 2nd custom stream-elements. + // + ACX_ELEMENT_CONFIG_INIT(&elementCfg); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_ELEMENT_CONTEXT); + attributes.ParentObject = stream; + + RETURN_NTSTATUS_IF_FAILED(AcxElementCreate(stream, &attributes, &elementCfg, &elements[1])); + + ASSERT(elements[1] != NULL); + elementCtx = GetCodecElementContext(elements[1]); + ASSERT(elementCtx); + UNREFERENCED_PARAMETER(elementCtx); + + // + // Add stream elements + // + RETURN_NTSTATUS_IF_FAILED(AcxStreamAddElements(stream, elements, SIZEOF_ARRAY(elements))); + + return status; +} + + 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); +} + + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/driver.cpp b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/driver.cpp new file mode 100644 index 00000000..4c9f937e --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/driver.cpp @@ -0,0 +1,218 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Driver.cpp + +Abstract: + + Sample soundwire Codec driver + +Environment: + + Kernel mode only + +--*/ + +#include "private.h" + +#ifndef __INTELLISENSE__ +#include "driver.tmh" +#endif + +RECORDER_LOG g_SDCAVCodecLog{ nullptr }; + +INIT_CODE_SEG +void +Test_ClientVersionHigherThanFramework() +{ + PAGED_CODE(); + + // example on how to check if a function is available. + /* + if (ACX_IS_FUNCTION_AVAILABLE(AcxCircuitCreate)) { + DbgPrint("Available: AcxCircuitCreate\n"); + } + else + { + DbgPrint("Not available: AcxCircuitCreate\n"); + ASSERT(FALSE); + } + */ + + if (ACX_IS_FIELD_AVAILABLE(ACX_DEVICEINIT_CONFIG, SynchronizationScope)) { + ACX_DEVICEINIT_CONFIG config; + ACX_DEVICEINIT_CONFIG_INIT(&config); + DbgPrint("Available: ACX_DEVICEINIT_CONFIG.SynchronizationScope\n"); + } + else + { + DbgPrint("Not available: ACX_DEVICEINIT_CONFIG.SynchronizationScope\n"); + ASSERT(FALSE); + } +} + +PAGED_CODE_SEG +VOID Codec_DriverUnload(_In_ WDFDRIVER Driver) +{ + PAGED_CODE(); + + if (!Driver) + { + ASSERT(FALSE); + return; + } + + WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver)); + + if (g_RegistryPath.Buffer != NULL) + { + ExFreePool(g_RegistryPath.Buffer); + RtlZeroMemory(&g_RegistryPath, sizeof(g_RegistryPath)); + } + + return; +} + +INIT_CODE_SEG +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + WPP_INIT_TRACING(DriverObject, RegistryPath); + + auto exit = scope_exit([&status, &DriverObject]() { + if (!NT_SUCCESS(status)) + { + if (g_RegistryPath.Buffer != NULL) + { + ExFreePool(g_RegistryPath.Buffer); + RtlZeroMemory(&g_RegistryPath, sizeof(g_RegistryPath)); + } + + WPP_CLEANUP(DriverObject); + } + else + { + DrvLogInfo(g_SDCAVCodecLog, FLAG_INIT, "ACX SDCA Virtual Codec Driver Init complete, %!STATUS!", status); + } + }); + + RETURN_NTSTATUS_IF_FAILED(CopyRegistrySettingsPath(RegistryPath)); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG wdfCfg; + WDF_DRIVER_CONFIG_INIT(&wdfCfg, Codec_EvtBusDeviceAdd); + wdfCfg.EvtDriverUnload = Codec_DriverUnload; + + // + // Add a driver context. (for illustration purposes only). + // + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_DRIVER_CONTEXT); + + // + // Create a framework driver object to represent our driver. + // + WDFDRIVER driver; + RETURN_NTSTATUS_IF_FAILED(WdfDriverCreate( + DriverObject, + RegistryPath, + &attributes, // Driver Attributes + &wdfCfg, // Driver Config Info + &driver // hDriver + )); + + RECORDER_CONFIGURE_PARAMS recorderConfig; + RECORDER_CONFIGURE_PARAMS_INIT(&recorderConfig); + recorderConfig.CreateDefaultLog = FALSE; + WppRecorderConfigure(&recorderConfig); + + RECORDER_LOG_CREATE_PARAMS recorderLogCreateParams; + RECORDER_LOG_CREATE_PARAMS_INIT(&recorderLogCreateParams, NULL); + recorderLogCreateParams.TotalBufferSize = WPP_TOTAL_BUFFER_SIZE; + recorderLogCreateParams.ErrorPartitionSize = WPP_ERROR_PARTITION_SIZE; + + RtlStringCbPrintfA(recorderLogCreateParams.LogIdentifier, + RECORDER_LOG_IDENTIFIER_MAX_CHARS, + "SDCAVCodec"); + + RECORDER_LOG logHandle = NULL; + status = WppRecorderLogCreate(&recorderLogCreateParams, &logHandle); + if (!NT_SUCCESS(status)) + { + logHandle = NULL; + + // Non fatal failure + status = STATUS_SUCCESS; + } + + g_SDCAVCodecLog = logHandle; + + // + // Post init. + // + ACX_DRIVER_CONFIG acxCfg; + ACX_DRIVER_CONFIG_INIT(&acxCfg); + + RETURN_NTSTATUS_IF_FAILED(AcxDriverInitialize(driver, &acxCfg)); + + // + // Test ACX bindings. + // + ACX_DRIVER_VERSION_AVAILABLE_PARAMS ver; + ACX_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0); + if (!AcxDriverIsVersionAvailable(driver, &ver)) { + status = STATUS_DRIVER_INTERNAL_ERROR; + DbgPrint("Unexpected ACX library version.\n"); + ASSERT(FALSE); + } + RETURN_NTSTATUS_IF_FAILED(status); + + Test_ClientVersionHigherThanFramework(); + + return status; +} + + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/private.h b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/private.h new file mode 100644 index 00000000..602133ba --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/private.h @@ -0,0 +1,522 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + 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: + + private.h + +Abstract: + + Contains structure definitions and function prototypes private to + the driver. + +Environment: + + Kernel mode + +--*/ + +#ifndef _PRIVATE_H_ +#define _PRIVATE_H_ + +#include "cpp_utils.h" + +#include "NewDelete.h" + +/* make prototypes usable from C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma warning(disable:4200) // +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int + +#include <initguid.h> +#include <ntddk.h> +#include <ntstrsafe.h> +#include <ntintsafe.h> + +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +#include <wdf.h> +#include <acx.h> + +#include "SoundWireController.h" +#include "SdcaXu.h" + +#include "trace.h" + +#include <TestProperties.h> + +#define PAGED_CODE_SEG __declspec(code_seg("PAGE")) +#define INIT_CODE_SEG __declspec(code_seg("INIT")) + +extern RECORDER_LOG g_SDCAVCodecLog; + +// Simple ACX driver +#define DRIVER_TAG (ULONG) 'Ccds' + +// Number of millisecs per sec. +#define MS_PER_SEC 1000 + +// Number of hundred nanosecs per sec. +#define HNS_PER_SEC 10000000 + +// Compatible ID for render/capture +#define ACX_CODEC_TEST_COMPATIBLE_ID L"{99a0ee05-7167-4b63-843d-19d6d285942e}" + +// Container ID for render/capture +#define ACX_CODEC_TEST_CONTAINER_ID L"{00000000-0000-0000-ffff-ffffffffffff}" + +#define RENDER_CIRCUIT_URI L"test:obj-path:\\SDCAVCODEC\\RENDER" +#define EXT_RENDER_CIRCUIT_URI L"test:obj-path:\\SDCAVCODEC\\RENDER_xu" +#define CAPTURE_CIRCUIT_URI L"test:obj-path:\\SDCAVCODEC\\CAPTURE" +#define EXT_CAPTURE_CIRCUIT_URI L"test:obj-path:\\SDCAVCODEC\\CAPTURE_xu" + +#undef MIN +#undef MAX +#define MIN(a,b) ((a) > (b) ? (b) : (a)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#ifndef BOOL +typedef int BOOL; +#endif + +#ifndef SIZEOF_ARRAY +#define SIZEOF_ARRAY(ar) (sizeof(ar)/sizeof((ar)[0])) +#endif // !defined(SIZEOF_ARRAY) + +#ifndef RGB +#define RGB(r, g, b) (DWORD)(r << 16 | g << 8 | b) +#endif + + +// +// Example Acpi blob for Hardware configuration +// +typedef struct _SdcaXuAcpiBlob +{ + // Number of endpoints + ULONG NumEndpoints; + +}SdcaXuAcpiBlob, *PSdcaXuAcpiBlob; + +#define ALL_CHANNELS_ID UINT32_MAX +#define MAX_CHANNELS 2 + +// +// Ks support. +// +#define KSPROPERTY_TYPE_ALL KSPROPERTY_TYPE_BASICSUPPORT | \ + KSPROPERTY_TYPE_GET | \ + KSPROPERTY_TYPE_SET + +// +// Define CODEC driver context. +// +typedef struct _CODEC_DRIVER_CONTEXT { + ULONG reserved; +} CODEC_DRIVER_CONTEXT, *PCODEC_DRIVER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_DRIVER_CONTEXT, GetCodecDriverContext) + +// +// Extension Unit specific data +// +typedef struct _SDCAXU_DATA +{ + BOOLEAN bSdcaXu; + BOOLEAN bExtensionJackOVerride; + SDCAXU_INTERFACE_V0101 ExtensionInterface; + ULONG numXUEntities; + ULONG *XUEntities; + PSDCAXU_INTERRUPT_INFO InterruptInfo; +}SDCAXU_DATA, *PSDCAXU_DATA; + +// +// Define CODEC device context. +// +typedef struct _CODEC_DEVICE_CONTEXT { + ACXCIRCUIT Render; + ACXCIRCUIT Capture; + ACXCOMPOSITETEMPLATE Composite[2]; + ULONG refComposite[2]; + SDCAXU_DATA SdcaXuData; + +} CODEC_DEVICE_CONTEXT, *PCODEC_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_DEVICE_CONTEXT, GetCodecDeviceContext) + +// +// Define RENDER device context. +// +typedef struct _CODEC_RENDER_DEVICE_CONTEXT { + ACXCIRCUIT Circuit; + BOOLEAN FirstTimePrepareHardware; +} CODEC_RENDER_DEVICE_CONTEXT, *PCODEC_RENDER_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_RENDER_DEVICE_CONTEXT, GetRenderDeviceContext) + +// +// Define RENDER circuit context. +// +typedef struct _CODEC_RENDER_CIRCUIT_CONTEXT { + ACXMUTE MuteElement; + ACXVOLUME VolumeElement; +} CODEC_RENDER_CIRCUIT_CONTEXT, *PCODEC_RENDER_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_RENDER_CIRCUIT_CONTEXT, GetRenderCircuitContext) + +// +// Define CAPTURE device context. +// +typedef struct _CODEC_CAPTURE_DEVICE_CONTEXT { + ACXCIRCUIT Circuit; + BOOLEAN FirstTimePrepareHardware; +} CODEC_CAPTURE_DEVICE_CONTEXT, *PCODEC_CAPTURE_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_CAPTURE_DEVICE_CONTEXT, GetCaptureDeviceContext) + +// +// Define CAPTURE circuit context. +// +typedef struct _CODEC_CAPTURE_CIRCUIT_CONTEXT { + BOOLEAN KwsActiveVadStream; + KEVENT KwsSuspendEvent; + KEVENT KwsResumeEvent; + ACXDATAFORMAT KwsDataFormat; +} CODEC_CAPTURE_CIRCUIT_CONTEXT, *PCODEC_CAPTURE_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_CAPTURE_CIRCUIT_CONTEXT, GetCaptureCircuitContext) + +// +// Define CODEC render/capture stream context. +// +typedef struct _CODEC_STREAM_CONTEXT { + PVOID StreamEngine; +} CODEC_STREAM_CONTEXT, *PCODEC_STREAM_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_STREAM_CONTEXT, GetCodecStreamContext) + +// +// Define CODEC circuit/stream element context. +// +typedef struct _CODEC_ELEMENT_CONTEXT { + BOOLEAN Dummy; +} CODEC_ELEMENT_CONTEXT, *PCODEC_ELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_ELEMENT_CONTEXT, GetCodecElementContext) + +// +// Define CODEC circuit/stream element context. +// +typedef struct _CODEC_MUTE_ELEMENT_CONTEXT { + BOOL MuteState[MAX_CHANNELS]; + WDFTIMER Timer; // for testing only. +} CODEC_MUTE_ELEMENT_CONTEXT, *PCODEC_MUTE_ELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_MUTE_ELEMENT_CONTEXT, GetCodecMuteElementContext) + +// +// Define CODEC mute timer context. +// +typedef struct _CODEC_MUTE_TIMER_CONTEXT { + ACXMUTE MuteElement; +} CODEC_MUTE_TIMER_CONTEXT, *PCODEC_MUTE_TIMER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_MUTE_TIMER_CONTEXT, GetCodecMuteTimerContext) + +// +// Define CODEC circuit/stream element context. +// +typedef struct _CODEC_VOLUME_ELEMENT_CONTEXT { + LONG VolumeLevel[MAX_CHANNELS]; + WDFTIMER Timer; // for testing only. +} CODEC_VOLUME_ELEMENT_CONTEXT, *PCODEC_VOLUME_ELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_VOLUME_ELEMENT_CONTEXT, GetCodecVolumeElementContext) + + +#define VOLUME_STEPPING 0x8000 +#define VOLUME_LEVEL_MAXIMUM 0x00000000 +#define VOLUME_LEVEL_MINIMUM (-96 * 0x10000) + +// +// Define CODEC mute timer context. +// +typedef struct _CODEC_VOLUME_TIMER_CONTEXT { + ACXVOLUME VolumeElement; +} CODEC_VOLUME_TIMER_CONTEXT, *PCODEC_VOLUME_TIMER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_VOLUME_TIMER_CONTEXT, GetCodecVolumeTimerContext) + + +// +// Define CODEC format context. +// +typedef struct _CODEC_FORMAT_CONTEXT { + BOOLEAN Dummy; +} CODEC_FORMAT_CONTEXT, *PCODEC_FORMAT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_FORMAT_CONTEXT, GetCodecFormatContext) + +typedef struct _CODEC_PIN_CONTEXT { + BOOLEAN Dummy; +} CODEC_PIN_CONTEXT, *PCODEC_PIN_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_PIN_CONTEXT, GetCodecPinContext) + +typedef struct _CODEC_JACK_CONTEXT +{ + ULONG Dummy; +} CODEC_JACK_CONTEXT, *PCODEC_JACK_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_JACK_CONTEXT, GetCodecJackContext) + +typedef enum { + CompositeType_RENDER, + CompositeType_CAPTURE +}CompositeType; + +// +// Driver prototypes. +// +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_UNLOAD Codec_DriverUnload; +EVT_WDF_DRIVER_DEVICE_ADD Codec_EvtBusDeviceAdd; + +// Device callbacks. + +EVT_WDF_DEVICE_PREPARE_HARDWARE Codec_EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE Codec_EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_CONTEXT_CLEANUP Codec_EvtDeviceContextCleanup; + +// Stream callbacks shared between Capture and Render + +EVT_WDF_OBJECT_CONTEXT_DESTROY Codec_EvtStreamDestroy; +EVT_ACX_STREAM_GET_HW_LATENCY Codec_EvtStreamGetHwLatency; +EVT_ACX_STREAM_PREPARE_HARDWARE Codec_EvtStreamPrepareHardware; +EVT_ACX_STREAM_RELEASE_HARDWARE Codec_EvtStreamReleaseHardware; +EVT_ACX_STREAM_RUN Codec_EvtStreamRun; +EVT_ACX_STREAM_PAUSE Codec_EvtStreamPause; +EVT_ACX_STREAM_ASSIGN_DRM_CONTENT_ID Codec_EvtStreamAssignDrmContentId; + +// Render callbacks. + +EVT_ACX_OBJECT_PREPROCESS_REQUEST CodecR_EvtCircuitRequestPreprocess; +EVT_ACX_CIRCUIT_CREATE_STREAM CodecR_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP CodecR_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN CodecR_EvtCircuitPowerDown; +EVT_ACX_STREAM_SET_RENDER_PACKET CodecR_EvtStreamSetRenderPacket; +EVT_ACX_PIN_SET_DATAFORMAT CodecR_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CodecR_EvtPinContextCleanup; + +EVT_ACX_CIRCUIT_COMPOSITE_CIRCUIT_INITIALIZE CodecR_EvtCircuitCompositeCircuitInitialize; +EVT_ACX_CIRCUIT_COMPOSITE_INITIALIZE CodecR_EvtCircuitCompositeInitialize; + +// Capture callbacks. + +EVT_ACX_OBJECT_PREPROCESS_REQUEST CodecC_EvtCircuitRequestPreprocess; +EVT_ACX_CIRCUIT_CREATE_STREAM CodecC_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP CodecC_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN CodecC_EvtCircuitPowerDown; +EVT_ACX_STREAM_GET_CAPTURE_PACKET CodecC_EvtStreamGetCapturePacket; +EVT_ACX_PIN_SET_DATAFORMAT CodecC_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CodecC_EvtPinContextCleanup; + +EVT_ACX_OBJECT_PREPROCESS_REQUEST CodecC_EvtStreamRequestPreprocess; + +EVT_ACX_OBJECT_PROCESS_REQUEST CodecC_EvtCircuitDeviceKwsCapability; +EVT_ACX_OBJECT_PROCESS_REQUEST CodecC_EvtCircuitVadCapability; +EVT_ACX_OBJECT_PROCESS_REQUEST CodecC_EvtCircuitVadEntities; +EVT_ACX_OBJECT_PROCESS_REQUEST CodecC_EvtCircuitSetKwsAccessEvents; +EVT_ACX_OBJECT_PROCESS_REQUEST CodecC_EvtCircuitConfigureVadPort; +EVT_ACX_OBJECT_PROCESS_REQUEST CodecC_EvtCircuitCleanupVadPort; + +EVT_ACX_MUTE_ASSIGN_STATE CodecR_EvtMuteAssignStateCallback; +EVT_ACX_MUTE_RETRIEVE_STATE CodecR_EvtMuteRetrieveStateCallback; +EVT_WDF_TIMER CodecR_EvtMuteTimerFunc; +EVT_ACX_VOLUME_ASSIGN_LEVEL CodecR_EvtVolumeAssignLevelCallback; +EVT_ACX_VOLUME_RETRIEVE_LEVEL CodecR_EvtVolumeRetrieveLevelCallback; +EVT_WDF_TIMER CodecR_EvtVolumeTimerFunc; +EVT_ACX_OBJECT_PREPROCESS_REQUEST CodecR_EvtStreamRequestPreprocess; + +/* make internal prototypes usable from C++ */ +#ifdef __cplusplus +} +#endif + +// +// Used to store the registry settings path for the driver +// +extern UNICODE_STRING g_RegistryPath; + +__drv_requiresIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +NTSTATUS +CopyRegistrySettingsPath( + _In_ PUNICODE_STRING RegistryPath + ); + +__drv_requiresIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +NTSTATUS +Codec_AddComposites(_In_ WDFDEVICE Device, _In_ CompositeType compositeType); + +__drv_requiresIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +NTSTATUS +Codec_AddRenderComposites(_In_ WDFDEVICE Device); + +__drv_requiresIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +NTSTATUS +Codec_AddCaptureComposites(_In_ WDFDEVICE Device); + +#pragma code_seg() +NTSTATUS +Codec_RemoveComposites(_In_ WDFDEVICE Device); + +PAGED_CODE_SEG +NTSTATUS +Codec_SetPowerPolicy( + _In_ WDFDEVICE Device + ); + +PAGED_CODE_SEG +NTSTATUS +CodecR_AddRenders( + _In_ WDFDRIVER Driver, + _In_ WDFDEVICE Device + ); + +PAGED_CODE_SEG +NTSTATUS +CodecR_AddStaticRender( + _In_ WDFDEVICE Device + ); + +PAGED_CODE_SEG +NTSTATUS +CodecR_CreateRenderCircuit( + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT * Circuit + ); + +PAGED_CODE_SEG +NTSTATUS +CodecC_AddCaptures( + _In_ WDFDRIVER Driver, + _In_ WDFDEVICE Device + ); + +PAGED_CODE_SEG +NTSTATUS +CodecC_AddStaticCapture( + _In_ WDFDEVICE Device + ); + +PAGED_CODE_SEG +NTSTATUS +CodecC_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT * Circuit + ); + +// +// Extension Unit +// +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetJackOverride +( + _In_ PVOID Context, // SDCA Context + _In_ BOOLEAN Override // TRUE: Override + // FALSE: Default SDCA behavior +); + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetJackSelectedMode +( + _In_ PVOID Context, // SDCA Context + _In_ ULONG GroupEntityId, // SDCA Group Entity ID for Jack(s) + _In_ ULONG SelectedMode // Type of jack type overriden by XU +); + +#pragma code_seg() +NTSTATUS Codec_SdcaXuPDEPowerReferenceAcquire +( + _In_ PVOID Context, + _In_ ULONG PowerDomainEntityId, + _In_ SDCAXU_POWER_STATE RequiredState +); + +#pragma code_seg() +NTSTATUS Codec_SdcaXuPDEPowerReferenceRelease +( + _In_ PVOID Context, + _In_ ULONG PowerDomainEntityId, + _In_ SDCAXU_POWER_STATE ReleasedState +); + +#pragma code_seg() +NTSTATUS Codec_SdcaXuReadDeferredAudioControls +( + _In_ PVOID Context, + _Inout_ PSDCA_AUDIO_CONTROLS Controls +); + +#pragma code_seg() +NTSTATUS Codec_SdcaXuWriteDeferredAudioControls +( + _In_ PVOID Context, + _Inout_ PSDCA_AUDIO_CONTROLS Controls +); + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetXUEntities +( + _In_ PVOID Context, + _In_ ULONG NumEntities, + _In_reads_(NumEntities) + ULONG EntityIDs[] +); + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuRegisterForInterrupts +( + _In_ PVOID Context, + _In_ PSDCAXU_INTERRUPT_INFO InterruptInfo +); + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetRenderEndpointConfig +( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit +); + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetCaptureEndpointConfig +( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit +); + +PAGED_CODE_SEG +NTSTATUS Codec_GetSdcaXu(_In_ WDFDEVICE Device); + +PAGED_CODE_SEG +NTSTATUS Codec_SetSdcaXuHwConfig(_In_ WDFDEVICE Device); + +#pragma code_seg() + +#endif // _PRIVATE_H_ diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/render.cpp b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/render.cpp new file mode 100644 index 00000000..901398dc --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/render.cpp @@ -0,0 +1,1310 @@ +/*++ + + 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: + + Render.cpp + +Abstract: + + Contains ACX Capture factory and circuit + +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 "soundwirecontroller.h" +#include "sdcastreaming.h" +#include "CircuitHelper.h" + +#include "AudioFormats.h" + +#ifndef __INTELLISENSE__ +#include "render.tmh" +#endif + +//#define CODEC_NEXT_CIRCUIT_STR L"\\??\\ROOT#AcxAmpTestDriver#0000#{2c6bb644-e1ae-47f8-9a2b-1d1fa750f2fa}\\Speaker0" +//#define CODEC_NEXT_CIRCUIT_STR L"\\??\\ROOT#AcxAmpTestDriver#0000#{6994AD04-93EF-11D0-A3CC-00A0C9223196}\\Speaker0" + +//#define CODEC_PREVIOUS_CIRCUIT_STR L"\\??\\AcxDspTestDriver#DynamicEnumSpeaker0#1&6244bc4&d&00#{2c6bb644-e1ae-47f8-9a2b-1d1fa750f2fa}\\Speaker0" +//#define CODEC_PREVIOUS_CIRCUIT_STR L"\\??\\AcxDspTestDriver#DynamicEnumSpeaker0#1&6244bc4&0&00#{6994AD04-93EF-11D0-A3CC-00A0C9223196}\\Speaker0" + +PAGED_CODE_SEG +VOID +CodecR_EvtPinCInstancesCallback( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request + ) +{ + PAGED_CODE(); + + // TEMP: for testing only. + UNREFERENCED_PARAMETER(Object); + WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); +} + +PAGED_CODE_SEG +VOID +CodecR_EvtPinCTypesCallback( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request + ) +{ + PAGED_CODE(); + + // TEMP: for testing only. + UNREFERENCED_PARAMETER(Object); + WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); +} + +PAGED_CODE_SEG +VOID +CodecR_EvtPinDataFlowCallback( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request + ) +{ + PAGED_CODE(); + + // TEMP: for testing only. + UNREFERENCED_PARAMETER(Object); + WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); +} + +PAGED_CODE_SEG +VOID +CodecR_EvtPinDataRangesCallback( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request + ) +{ + PAGED_CODE(); + + // TEMP: for testing only. + UNREFERENCED_PARAMETER(Object); + WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); +} + +PAGED_CODE_SEG +VOID +CodecR_EvtPinDataIntersectionCallback( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request + ) +{ + PAGED_CODE(); + + // TEMP: for testing only. + UNREFERENCED_PARAMETER(Object); + WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtAcxPinSetDataFormat ( + _In_ ACXPIN Pin, + _In_ ACXDATAFORMAT DataFormat + ) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Pin); + UNREFERENCED_PARAMETER(DataFormat); + + + return STATUS_NOT_SUPPORTED; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtMuteAssignStateCallback( + _In_ ACXMUTE Mute, + _In_ ULONG Channel, + _In_ ULONG State + ) +{ + PAGED_CODE(); + + ASSERT(Mute); + PCODEC_MUTE_ELEMENT_CONTEXT muteCtx = GetCodecMuteElementContext(Mute); + ASSERT(muteCtx); + + if (Channel != ALL_CHANNELS_ID) + { + muteCtx->MuteState[Channel] = State; + } + else + { + for (ULONG i = 0; i < MAX_CHANNELS; ++i) + { + muteCtx->MuteState[i] = State; + } + } + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +NTAPI +CodecR_EvtMuteRetrieveStateCallback( + _In_ ACXMUTE Mute, + _In_ ULONG Channel, + _Out_ ULONG *State + ) +{ + PAGED_CODE(); + + ASSERT(Mute); + PCODEC_MUTE_ELEMENT_CONTEXT muteCtx = GetCodecMuteElementContext(Mute); + ASSERT(muteCtx); + + if (Channel == ALL_CHANNELS_ID) + { + Channel = 0; + } + + *State = muteCtx->MuteState[Channel]; + + return STATUS_SUCCESS; +} + +// +// Testing mute element. +// +#pragma code_seg() +VOID +CodecR_EvtMuteTimerFunc( + _In_ WDFTIMER Timer + ) +{ + PCODEC_MUTE_TIMER_CONTEXT timerCtx = GetCodecMuteTimerContext(Timer); + + ASSERT(timerCtx != NULL); + ASSERT(timerCtx->MuteElement != NULL); + + PCODEC_MUTE_ELEMENT_CONTEXT muteCtx = GetCodecMuteElementContext(timerCtx->MuteElement); + ASSERT(muteCtx != NULL); + + // update settings 0 <-> 1 + for (ULONG i = 0; i < MAX_CHANNELS; ++i) + { + muteCtx->MuteState[i] = !muteCtx->MuteState[i]; + } + + AcxMuteChangeStateNotification(timerCtx->MuteElement); +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtVolumeAssignLevelCallback( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _In_ LONG VolumeLevel + ) +{ + PAGED_CODE(); + + ASSERT(Volume); + PCODEC_VOLUME_ELEMENT_CONTEXT volumeCtx = GetCodecVolumeElementContext(Volume); + ASSERT(volumeCtx); + + if (Channel != ALL_CHANNELS_ID) + { + volumeCtx->VolumeLevel[Channel] = VolumeLevel; + } + else + { + for (ULONG i = 0; i < MAX_CHANNELS; ++i) + { + volumeCtx->VolumeLevel[i] = VolumeLevel; + } + } + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +NTAPI +CodecR_EvtVolumeRetrieveLevelCallback( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _Out_ LONG *VolumeLevel + ) +{ + PAGED_CODE(); + + ASSERT(Volume); + PCODEC_VOLUME_ELEMENT_CONTEXT volumeCtx = GetCodecVolumeElementContext(Volume); + ASSERT(volumeCtx); + + if (Channel == ALL_CHANNELS_ID) + { + Channel = 0; + } + + *VolumeLevel = volumeCtx->VolumeLevel[Channel]; + + return STATUS_SUCCESS; +} + +// +// Testing volume element. +// +#pragma code_seg() +VOID +CodecR_EvtVolumeTimerFunc( + _In_ WDFTIMER Timer + ) +{ + PCODEC_VOLUME_TIMER_CONTEXT timerCtx = GetCodecVolumeTimerContext(Timer); + + ASSERT(timerCtx != NULL); + ASSERT(timerCtx->VolumeElement != NULL); + + PCODEC_VOLUME_ELEMENT_CONTEXT volumeCtx = GetCodecVolumeElementContext(timerCtx->VolumeElement); + ASSERT(volumeCtx != NULL); + + // Toggle volume between max and min + for (ULONG i = 0; i < MAX_CHANNELS; ++i) + { + volumeCtx->VolumeLevel[i] = volumeCtx->VolumeLevel[i] == VOLUME_LEVEL_MAXIMUM ? VOLUME_LEVEL_MINIMUM : VOLUME_LEVEL_MAXIMUM; + } + + AcxVolumeChangeLevelNotification(timerCtx->VolumeElement); +} + +#pragma code_seg() +VOID +CodecR_EvtPinContextCleanup( + _In_ WDFOBJECT WdfPin + ) +/*++ + +Routine Description: + + In this callback, it cleans up pin context. + +Arguments: + + WdfDevice - WDF device object + +Return Value: + + NULL + +--*/ +{ + UNREFERENCED_PARAMETER(WdfPin); +} + +PAGED_CODE_SEG +VOID +CodecR_EvtCircuitRequestPreprocess( + _In_ ACXOBJECT Object, + _In_ ACXCONTEXT DriverContext, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + This function is an example of a preprocess routine. + +--*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DriverContext); + + ASSERT(Object != NULL); + ASSERT(DriverContext); + ASSERT(Request); + + + // + // Just give the request back to ACX. + // + (VOID)AcxCircuitDispatchAcxRequest((ACXCIRCUIT)Object, Request); +} + +PAGED_CODE_SEG +VOID +CodecR_EvtStreamRequestPreprocess( + _In_ ACXOBJECT Object, + _In_ ACXCONTEXT DriverContext, + _In_ WDFREQUEST Request + ) +/*++ + +Routine Description: + + This function is an example of a preprocess routine. + +--*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DriverContext); + + ASSERT(Object != NULL); + ASSERT(DriverContext); + ASSERT(Request); + + + // + // Just give the request back to ACX. + // + (VOID)AcxStreamDispatchAcxRequest((ACXSTREAM)Object, Request); +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_AddRenders( + _In_ WDFDRIVER Driver, + _In_ WDFDEVICE Device + ) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Driver); + + NTSTATUS status = STATUS_SUCCESS; + + // + // Add a static render device. + // + status = CodecR_AddStaticRender(Device); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_AddStaticRender( + _In_ WDFDEVICE Device +) +{ + PAGED_CODE(); + + DrvLogEnter(g_SDCAVCodecLog); + + NTSTATUS status = STATUS_SUCCESS; + + PCODEC_DEVICE_CONTEXT devCtx; + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != NULL); + + // + // Alloc audio context to current device. + // + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_RENDER_DEVICE_CONTEXT); + PCODEC_RENDER_DEVICE_CONTEXT renderDevCtx; + RETURN_NTSTATUS_IF_FAILED(WdfObjectAllocateContext(Device, &attributes, (PVOID*)&renderDevCtx)); + ASSERT(renderDevCtx); + + // + // Create a render circuit associated with this device. + // + ACXCIRCUIT renderCircuit = NULL; + RETURN_NTSTATUS_IF_FAILED(CodecR_CreateRenderCircuit(Device, &renderCircuit)); + + RETURN_NTSTATUS_IF_FAILED(Codec_SdcaXuSetRenderEndpointConfig(Device, renderCircuit)); + + devCtx->Render = renderCircuit; + + return status; +} + +EXTERN_C const GUID DECLSPEC_SELECTANY CODEC_CIRCUIT_RENDER_GUID; +EXTERN_C const GUID DECLSPEC_SELECTANY EXTENSION_CIRCUIT_RENDER_GUID; +EXTERN_C const GUID DECLSPEC_SELECTANY SYSTEM_CONTAINER_GUID; + +PAGED_CODE_SEG +NTSTATUS Codec_SdcaXuSetRenderEndpointConfig +( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit +) +{ + PAGED_CODE(); + + DrvLogEnter(g_SDCAVCodecLog); + + NTSTATUS status = STATUS_SUCCESS; + + PCODEC_DEVICE_CONTEXT devCtx; + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != NULL); + + DECLARE_CONST_UNICODE_STRING(circuitName, L"ExtensionSpeaker0"); + DECLARE_CONST_UNICODE_STRING(circuitUri, EXT_RENDER_CIRCUIT_URI); + +#pragma prefast(suppress:__WARNING_ALIASED_MEMORY_LEAK, "memory is freed by scope_exit") + PSDCAXU_ACX_CIRCUIT_CONFIG exCircuitConfig = (PSDCAXU_ACX_CIRCUIT_CONFIG)ExAllocatePool2( + POOL_FLAG_NON_PAGED, + sizeof(SDCAXU_ACX_CIRCUIT_CONFIG) + circuitName.MaximumLength, + DRIVER_TAG); + RETURN_NTSTATUS_IF_TRUE(NULL == exCircuitConfig, STATUS_INSUFFICIENT_RESOURCES); + auto exConfigFree = scope_exit([&exCircuitConfig]() { + ExFreePoolWithTag(exCircuitConfig, DRIVER_TAG); + }); + + // + // Provide circuit configuration to SDCA XU driver + // SDCA XU driver will generate circuits to match this configuration + // + if (devCtx->SdcaXuData.bSdcaXu) + { + exCircuitConfig->cbSize = sizeof(SDCAXU_ACX_CIRCUIT_CONFIG) + circuitName.MaximumLength; + + exCircuitConfig->CircuitName = circuitName; + exCircuitConfig->CircuitName.Buffer = (PWCH)(exCircuitConfig + 1); + RtlCopyMemory(exCircuitConfig->CircuitName.Buffer, circuitName.Buffer, circuitName.MaximumLength); + + exCircuitConfig->CircuitContext = Circuit; + exCircuitConfig->CircuitType = AcxCircuitTypeRender; + exCircuitConfig->ContainerID = SYSTEM_CONTAINER_GUID; + exCircuitConfig->ComponentID = EXTENSION_CIRCUIT_RENDER_GUID; + exCircuitConfig->ComponentUri = circuitUri; + + PSDCAXU_INTERFACE_V0101 exInterface = &devCtx->SdcaXuData.ExtensionInterface; + PVOID exContext = devCtx->SdcaXuData.ExtensionInterface.InterfaceHeader.Context; + + RETURN_NTSTATUS_IF_FAILED(exInterface->EvtSetEndpointConfig(exContext, SdcaXuEndpointConfigTypeAcxCircuitConfig, exCircuitConfig, exCircuitConfig->cbSize)); + } + + return status; +} + +// {3CE41646-9BF2-4A9E-B851-D711CAE9AEA8} +DEFINE_GUID(SDCAVADPropsetId, + 0x3ce41646, 0x9bf2, 0x4a9e, 0xb8, 0x51, 0xd7, 0x11, 0xca, 0xe9, 0xae, 0xa8); + +typedef enum { + SDCAVAD_PROPERTY_TEST1, + SDCAVAD_PROPERTY_TEST2, + SDCAVAD_PROPERTY_TEST3, + SDCAVAD_PROPERTY_TEST4, + SDCAVAD_PROPERTY_TEST5, + SDCAVAD_PROPERTY_TEST6, +} SDCAVAD_Properties; + +PAGED_CODE_SEG +NTSTATUS +CodecR_SDCAVADPropertyTest1( + _Inout_ PVOID pValue, + _In_ ULONG ValueCb, + _Out_ PULONG ValueCbOut +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(pValue); + UNREFERENCED_PARAMETER(ValueCb); + + NTSTATUS status = STATUS_SUCCESS; + + DrvLogInfo(g_SDCAVCodecLog, FLAG_STREAM, L"SDCAVCodec: SDCAVAD_PROPERTY_TEST1"); + + *ValueCbOut = 0; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_SDCAVADPropertyTest2( + _Inout_ PVOID pValue, + _In_ ULONG ValueCb, + _Out_ PULONG ValueCbOut +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(ValueCb); + + NTSTATUS status = STATUS_SUCCESS; + + DrvLogInfo(g_SDCAVCodecLog, FLAG_STREAM, L"SDCAVCodec: SDCAVAD_PROPERTY_TEST2"); + + *((PULONG)pValue) = 10; + *ValueCbOut = sizeof(ULONG); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_SDCAVADPropertyTest5( + _Inout_ PVOID pValue, + _In_ ULONG ValueCb, + _Out_ PULONG ValueCbOut +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(pValue); + UNREFERENCED_PARAMETER(ValueCb); + + NTSTATUS status = STATUS_SUCCESS; + + DrvLogInfo(g_SDCAVCodecLog, FLAG_STREAM, L"SDCAVCodec: SDCAVAD_PROPERTY_TEST5"); + + *ValueCbOut = 0; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_SDCAVADPropertyTest6( + _Inout_ PVOID pValue, + _In_ ULONG ValueCb, + _Out_ PULONG ValueCbOut +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(ValueCb); + + NTSTATUS status = STATUS_SUCCESS; + + DrvLogInfo(g_SDCAVCodecLog, FLAG_STREAM, L"SDCAVCodec: SDCAVAD_PROPERTY_TEST6"); + + *((PULONG)pValue) = 12; + *ValueCbOut = sizeof(ULONG); + + return status; +} + +PAGED_CODE_SEG +VOID +CodecR_EvtPropertyCallback( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Object); + + ACX_REQUEST_PARAMETERS params; + ACX_REQUEST_PARAMETERS_INIT(¶ms); + + AcxRequestGetParameters(Request, ¶ms); + + NTSTATUS status = STATUS_SUCCESS; + PVOID Value = params.Parameters.Property.Value; + ULONG ValueCb = params.Parameters.Property.ValueCb; + ULONG ValueCbOut = 0; + + switch (params.Parameters.Property.Id) + { + case SDCAVAD_PROPERTY_TEST1: + status = CodecR_SDCAVADPropertyTest1(Value, ValueCb, &ValueCbOut); + break; + case SDCAVAD_PROPERTY_TEST2: + status = CodecR_SDCAVADPropertyTest2(Value, ValueCb, &ValueCbOut); + break; + case SDCAVAD_PROPERTY_TEST5: + status = CodecR_SDCAVADPropertyTest5(Value, ValueCb, &ValueCbOut); + break; + case SDCAVAD_PROPERTY_TEST6: + status = CodecR_SDCAVADPropertyTest6(Value, ValueCb, &ValueCbOut); + break; + default: + break; + } + + WdfRequestCompleteWithInformation(Request, status, ValueCbOut); +} + +PAGED_CODE_SEG +VOID +CodecR_EvtPropertyVendorSpecificCallback( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Object); + + ACX_REQUEST_PARAMETERS params; + ACX_REQUEST_PARAMETERS_INIT(¶ms); + + AcxRequestGetParameters(Request, ¶ms); + + NTSTATUS status = STATUS_SUCCESS; + + // The Class Driver will send IOCTL_SOUNDWIRE_VENDOR_SPECIFIC with Control/Value to the SoundWire Controller. + + PVIRTUAL_STACK_VENDOR_SPECIFIC_CONTROL control = (PVIRTUAL_STACK_VENDOR_SPECIFIC_CONTROL)params.Parameters.Property.Control; + ULONG controlCb = params.Parameters.Property.ControlCb; + + PVIRTUAL_STACK_VENDOR_SPECIFIC_VALUE_TEST_DATA value = (PVIRTUAL_STACK_VENDOR_SPECIFIC_VALUE_TEST_DATA)params.Parameters.Property.Value; + ULONG valueCb = params.Parameters.Property.ValueCb; + + ULONG_PTR information = 0; + + // Validate we have enough control data + if (controlCb < sizeof(VIRTUAL_STACK_VENDOR_SPECIFIC_CONTROL)) + { + status = STATUS_INVALID_PARAMETER; + } + else if (control->VendorSpecificSize != sizeof(VIRTUAL_STACK_VENDOR_SPECIFIC_CONTROL)) + { + status = STATUS_INVALID_PARAMETER; + } + else if (control->VendorSpecificId == VirtualStackVendorSpecificRequestGetTestData) + { + if (valueCb == 0 && value == nullptr) + { + status = STATUS_BUFFER_OVERFLOW; + information = sizeof(VIRTUAL_STACK_VENDOR_SPECIFIC_VALUE_TEST_DATA); + } + else if (valueCb < sizeof(VIRTUAL_STACK_VENDOR_SPECIFIC_VALUE_TEST_DATA)) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + value->Test1 = 0x12345678; + value->Test2 = 0x87654321; + information = sizeof(VIRTUAL_STACK_VENDOR_SPECIFIC_VALUE_TEST_DATA); + } + } + else if (control->VendorSpecificId == VirtualStackVendorSpecificRequestSetTestConfig) + { + DrvLogInfo(g_SDCAVCodecLog, FLAG_STREAM, L"SDCAVCodec: VENDOR SPECIFIC Set Test Config %d", control->Config.IsScatterGather); + } + else + { + status = STATUS_INVALID_PARAMETER; + } + + WdfRequestCompleteWithInformation(Request, status, information); +} + +static ACX_PROPERTY_ITEM g_CircuitProperties[] = +{ + { + &SDCAVADPropsetId, + SDCAVAD_PROPERTY_TEST1, + ACX_PROPERTY_ITEM_FLAG_SET, + CodecR_EvtPropertyCallback + }, + { + &SDCAVADPropsetId, + SDCAVAD_PROPERTY_TEST2, + ACX_PROPERTY_ITEM_FLAG_GET, + CodecR_EvtPropertyCallback + }, + { + &SDCAVADPropsetId, + SDCAVAD_PROPERTY_TEST5, + ACX_PROPERTY_ITEM_FLAG_SET, + CodecR_EvtPropertyCallback + }, + { + &SDCAVADPropsetId, + SDCAVAD_PROPERTY_TEST6, + ACX_PROPERTY_ITEM_FLAG_GET, + CodecR_EvtPropertyCallback + }, + { + &KSPROPERTYSETID_Sdca, + KSPROPERTY_SDCA_VENDOR_SPECIFIC, + ACX_PROPERTY_ITEM_FLAG_GET | ACX_PROPERTY_ITEM_FLAG_SET, + CodecR_EvtPropertyVendorSpecificCallback + }, +}; + +PAGED_CODE_SEG +NTSTATUS +CodecR_CreateRenderCircuit( + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT * Circuit +) +/*++ + +Routine Description: + + This routine builds the CODEC render circuit. + +Return Value: + + NT status value + +--*/ +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DrvLogEnter(g_SDCAVCodecLog); + + // + // Get a CircuitInit structure. + // + PACXCIRCUIT_INIT circuitInit = NULL; + circuitInit = AcxCircuitInitAllocate(Device); + RETURN_NTSTATUS_IF_TRUE(NULL == circuitInit, STATUS_NO_MEMORY); + auto circuitInitScope = scope_exit([&circuitInit]() { + AcxCircuitInitFree(circuitInit); + }); + + // + // Init output value. + // + *Circuit = NULL; + + /////////////////////////////////////////////////////////// + // + // Create a circuit. + // + + // + // Add circuit identifiers. + // + AcxCircuitInitSetComponentId(circuitInit, &CODEC_CIRCUIT_RENDER_GUID); + + DECLARE_CONST_UNICODE_STRING(circuitUri, RENDER_CIRCUIT_URI); + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignComponentUri(circuitInit, &circuitUri)); + + WDF_OBJECT_ATTRIBUTES attributes; + ACXCIRCUIT circuit; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_RENDER_CIRCUIT_CONTEXT); + DECLARE_CONST_UNICODE_STRING(circuitName, L"Speaker0"); + + // + // Add properties, events and methods. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignProperties(circuitInit, + g_CircuitProperties, + SIZEOF_ARRAY(g_CircuitProperties))); + + + RETURN_NTSTATUS_IF_FAILED(CreateRenderCircuit(circuitInit, circuitName, Device, &circuit)); + circuitInitScope.release(); + + CODEC_RENDER_CIRCUIT_CONTEXT *circuitCtx; + ASSERT(circuit != NULL); + circuitCtx = GetRenderCircuitContext(circuit); + ASSERT(circuitCtx); + + // + // Post circuit creation initialization. + // + + /////////////////////////////////////////////////////////// + // + // Add two custom circuit elements. Note that driver doesn't need to + // perform this step if it doesn't want to expose any circuit elements. + // + + // + // Create 1st custom circuit-element (mute element). + // + ACX_MUTE_CALLBACKS muteCallbacks; + ACX_MUTE_CALLBACKS_INIT(&muteCallbacks); + muteCallbacks.EvtAcxMuteAssignState = CodecR_EvtMuteAssignStateCallback; + muteCallbacks.EvtAcxMuteRetrieveState = CodecR_EvtMuteRetrieveStateCallback; + + ACX_MUTE_CONFIG muteCfg; + ACX_MUTE_CONFIG_INIT(&muteCfg); + muteCfg.ChannelsCount = MAX_CHANNELS; + muteCfg.Callbacks = &muteCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_MUTE_ELEMENT_CONTEXT); + attributes.ParentObject = circuit; + + const int numElements = 2; + ACXELEMENT elements[numElements] = {0}; + RETURN_NTSTATUS_IF_FAILED(AcxMuteCreate(circuit, &attributes, &muteCfg, (ACXMUTE *)&elements[0])); + + ASSERT(elements[0] != NULL); + CODEC_MUTE_ELEMENT_CONTEXT *muteCtx; + muteCtx = GetCodecMuteElementContext(elements[0]); + ASSERT(muteCtx); + UNREFERENCED_PARAMETER(muteCtx); + + circuitCtx->MuteElement = (ACXMUTE)elements[0]; + + // + // Testing async mute state change. + // + { + WDF_TIMER_CONFIG timerCfg; + PCODEC_MUTE_TIMER_CONTEXT timerCtx; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_MUTE_TIMER_CONTEXT); + attributes.ParentObject = circuitCtx->MuteElement; + + WDF_TIMER_CONFIG_INIT_PERIODIC(&timerCfg, CodecR_EvtMuteTimerFunc, 4000 /* 4sec in msec */); + + RETURN_NTSTATUS_IF_FAILED(WdfTimerCreate(&timerCfg, &attributes, &muteCtx->Timer)); + + ASSERT(muteCtx->Timer); + + timerCtx = GetCodecMuteTimerContext(muteCtx->Timer); + ASSERT(timerCtx); + + timerCtx->MuteElement = circuitCtx->MuteElement; + } + + // + // Create 2nd custom circuit-element (volume element). + // + ACX_VOLUME_CALLBACKS volumeCallbacks; + ACX_VOLUME_CALLBACKS_INIT(&volumeCallbacks); + volumeCallbacks.EvtAcxVolumeAssignLevel = CodecR_EvtVolumeAssignLevelCallback; + volumeCallbacks.EvtAcxVolumeRetrieveLevel = CodecR_EvtVolumeRetrieveLevelCallback; + + ACX_VOLUME_CONFIG volumeCfg; + ACX_VOLUME_CONFIG_INIT(&volumeCfg); + volumeCfg.ChannelsCount = MAX_CHANNELS; + volumeCfg.Minimum = VOLUME_LEVEL_MINIMUM; + volumeCfg.Maximum = VOLUME_LEVEL_MAXIMUM; + volumeCfg.SteppingDelta = VOLUME_STEPPING; + volumeCfg.Callbacks = &volumeCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_VOLUME_ELEMENT_CONTEXT); + attributes.ParentObject = circuit; + + RETURN_NTSTATUS_IF_FAILED(AcxVolumeCreate(circuit, &attributes, &volumeCfg, (ACXVOLUME *)&elements[1])); + + ASSERT(elements[1] != NULL); + CODEC_VOLUME_ELEMENT_CONTEXT *volumeCtx; + volumeCtx = GetCodecVolumeElementContext(elements[1]); + ASSERT(volumeCtx); + volumeCtx->VolumeLevel[0] = (VOLUME_LEVEL_MAXIMUM + VOLUME_LEVEL_MINIMUM) / 2 / VOLUME_STEPPING * VOLUME_STEPPING; + volumeCtx->VolumeLevel[1] = (VOLUME_LEVEL_MAXIMUM + VOLUME_LEVEL_MINIMUM) / 2 / VOLUME_STEPPING * VOLUME_STEPPING; + + circuitCtx->VolumeElement = (ACXVOLUME)elements[1]; + + // + // Testing async volume state change. + // + { + WDF_TIMER_CONFIG timerCfg; + PCODEC_VOLUME_TIMER_CONTEXT timerCtx; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_VOLUME_TIMER_CONTEXT); + attributes.ParentObject = circuitCtx->VolumeElement; + + WDF_TIMER_CONFIG_INIT_PERIODIC(&timerCfg, CodecR_EvtVolumeTimerFunc, 4500 /* 4.5sec in msec */); + + RETURN_NTSTATUS_IF_FAILED(WdfTimerCreate(&timerCfg, &attributes, &volumeCtx->Timer)); + + ASSERT(volumeCtx->Timer); + + timerCtx = GetCodecVolumeTimerContext(volumeCtx->Timer); + ASSERT(timerCtx); + + timerCtx->VolumeElement = circuitCtx->VolumeElement; + } + + // + // Add the circuit elements + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddElements(circuit, elements, SIZEOF_ARRAY(elements))); + + /////////////////////////////////////////////////////////// + // + // Allocate the formats this circuit supports. + // + // PCM:44100 channel:2 24in32 + ACX_DATAFORMAT_CONFIG formatCfg; + ACX_DATAFORMAT_CONFIG_INIT_KS(&formatCfg, &Pcm44100c2_24in32); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_FORMAT_CONTEXT); + attributes.ParentObject = circuit; + + ACXDATAFORMAT formatPcm44100c2_24in32; + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatCreate(Device, &attributes, &formatCfg, &formatPcm44100c2_24in32)); + + CODEC_FORMAT_CONTEXT *formatCtx; + formatCtx = GetCodecFormatContext(formatPcm44100c2_24in32); + ASSERT(formatCtx); + + UNREFERENCED_PARAMETER(formatCtx); + + // PCM:48000 channel:2 24in32 + ACX_DATAFORMAT_CONFIG_INIT_KS(&formatCfg, &Pcm48000c2_24in32); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_FORMAT_CONTEXT); + attributes.ParentObject = circuit; + + ACXDATAFORMAT formatPcm48000c2_24in32; + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatCreate(Device, &attributes, &formatCfg, &formatPcm48000c2_24in32)); + + formatCtx = GetCodecFormatContext(formatPcm48000c2_24in32); + ASSERT(formatCtx); + UNREFERENCED_PARAMETER(formatCtx); + + /////////////////////////////////////////////////////////// + // + // Create render pin. AcxCircuit creates the other pin by default. + // + + ACX_PIN_CALLBACKS pinCallbacks; + ACX_PIN_CALLBACKS_INIT(&pinCallbacks); + pinCallbacks.EvtAcxPinSetDataFormat = CodecR_EvtAcxPinSetDataFormat; + + ACX_PIN_CONFIG pinCfg; + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSink; + pinCfg.Communication = AcxPinCommunicationNone; + pinCfg.Category = &KSCATEGORY_AUDIO; + pinCfg.PinCallbacks = &pinCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecR_EvtPinContextCleanup; + attributes.ParentObject = circuit; + + ACXPIN pin; + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &pin)); + + ASSERT(pin != NULL); + CODEC_PIN_CONTEXT *pinCtx; + pinCtx = GetCodecPinContext(pin); + ASSERT(pinCtx); + + // + // Add our supported formats to the Default mode for the circuit + // + ACXDATAFORMATLIST formatList; + formatList = AcxPinGetRawDataFormatList(pin); + if (formatList == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + RETURN_NTSTATUS_IF_FAILED(status); + + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAssignDefaultDataFormat(formatList, formatPcm48000c2_24in32)); + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm44100c2_24in32)); + + // Add render pin, using default pin id (0) + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddPins(circuit, &pin, 1)); + + /////////////////////////////////////////////////////////// + // + // Create Bridge Pin. + // + + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSource; + pinCfg.Communication = AcxPinCommunicationNone; + pinCfg.Category = &KSNODETYPE_SPEAKER; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecR_EvtPinContextCleanup; + attributes.ParentObject = circuit; + + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &pin)); + + ASSERT(pin != NULL); + pinCtx = GetCodecPinContext(pin); + ASSERT(pinCtx); + + RETURN_NTSTATUS_IF_FAILED(AddJack(attributes, pin, SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, RGB(0, 0, 0), AcxConnTypeAtapiInternal, AcxGeoLocFront, AcxGenLocPrimaryBox, AcxPortConnIntegratedDevice)); + + // Add render bridge pin + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddPins(circuit, &pin, 1)); + + ConnectRenderCircuitElements(numElements, elements, circuit); + + // + // Set output value. + // + *Circuit = circuit; + + // + // Done. + // + status = STATUS_SUCCESS; + + + return status; +} + +_Use_decl_annotations_ +#pragma code_seg() +NTSTATUS +CodecR_EvtCircuitPowerUp ( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE PreviousState + ) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(PreviousState); + + CODEC_RENDER_CIRCUIT_CONTEXT * circuitCtx; + CODEC_MUTE_ELEMENT_CONTEXT * muteCtx; + CODEC_VOLUME_ELEMENT_CONTEXT * volumeCtx; + + // for testing. + circuitCtx = GetRenderCircuitContext(Circuit); + ASSERT(circuitCtx); + + ASSERT(circuitCtx->MuteElement); + muteCtx = GetCodecMuteElementContext(circuitCtx->MuteElement); + ASSERT(muteCtx); + + ASSERT(circuitCtx->VolumeElement); + volumeCtx = GetCodecVolumeElementContext(circuitCtx->VolumeElement); + ASSERT(volumeCtx); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtCircuitPowerDown ( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE TargetState + ) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(TargetState); + + CODEC_RENDER_CIRCUIT_CONTEXT * circuitCtx; + CODEC_MUTE_ELEMENT_CONTEXT * muteCtx; + CODEC_VOLUME_ELEMENT_CONTEXT * volumeCtx; + + PAGED_CODE(); + + // for testing. + circuitCtx = GetRenderCircuitContext(Circuit); + ASSERT(circuitCtx); + + ASSERT(circuitCtx->MuteElement); + muteCtx = GetCodecMuteElementContext(circuitCtx->MuteElement); + ASSERT(muteCtx); + + ASSERT(circuitCtx->VolumeElement); + volumeCtx = GetCodecVolumeElementContext(circuitCtx->VolumeElement); + ASSERT(volumeCtx); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtCircuitCompositeCircuitInitialize( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_opt_ ACXOBJECTBAG CircuitProperties +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + + NTSTATUS status = STATUS_SUCCESS; + + if (CircuitProperties != NULL) + { + DECLARE_CONST_ACXOBJECTBAG_DRIVER_PROPERTY_NAME(msft, TestUI4); + ULONG testUI4 = 0; + + status = AcxObjectBagRetrieveUI4(CircuitProperties, &TestUI4, &testUI4); + } + + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtCircuitCompositeInitialize( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ ACXOBJECTBAG CompositeProperties + ) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + + ASSERT(CompositeProperties); + + DECLARE_CONST_ACXOBJECTBAG_SYSTEM_PROPERTY_NAME(UniqueID); + GUID uniqueId = {0}; + status = AcxObjectBagRetrieveGuid(CompositeProperties, &UniqueID, &uniqueId); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtCircuitCreateStream( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ ACXPIN Pin, + _In_ PACXSTREAM_INIT StreamInit, + _In_ ACXDATAFORMAT StreamFormat, + _In_ const GUID * SignalProcessingMode, + _In_ ACXOBJECTBAG VarArguments +) +/*++ + +Routine Description: + + This routine create a stream for the specified circuit. + +Return Value: + + NT status value + +--*/ +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + DrvLogEnter(g_SDCAVCodecLog); + + UNREFERENCED_PARAMETER(Pin); + UNREFERENCED_PARAMETER(SignalProcessingMode); + + ASSERT(IsEqualGUID(*SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW)); + + PCODEC_RENDER_DEVICE_CONTEXT devCtx; + devCtx = GetRenderDeviceContext(Device); + ASSERT(devCtx != NULL); + + DECLARE_CONST_ACXOBJECTBAG_DRIVER_PROPERTY_NAME(msft, TestUI4); + if (VarArguments) + { + // Get the variable arguments parameter and retrive the values set by the DSP object. + ULONG ui4Value = 0; + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagRetrieveUI4(VarArguments, &TestUI4, &ui4Value)); + + RETURN_NTSTATUS_IF_TRUE(ui4Value == 0, STATUS_UNSUCCESSFUL); + + ui4Value++; + + // Add the modified value back to object bag. + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUI4(VarArguments, &TestUI4, ui4Value)); + } + + // + // Set circuit-callbacks. + // + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxRequestPreprocessCallback( + StreamInit, + CodecR_EvtStreamRequestPreprocess, + (ACXCONTEXT)AcxRequestTypeAny, // dbg only + AcxRequestTypeAny, + NULL, + AcxItemIdNone)); + + /* + // + // Add properties, events and methods. + // + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignProperties(StreamInit, + StreamProperties, + StreamPropertiesCount)); + */ + + // + // Init streaming callbacks. + // + ACX_STREAM_CALLBACKS streamCallbacks; + ACX_STREAM_CALLBACKS_INIT(&streamCallbacks); + streamCallbacks.EvtAcxStreamPrepareHardware = Codec_EvtStreamPrepareHardware; + streamCallbacks.EvtAcxStreamReleaseHardware = Codec_EvtStreamReleaseHardware; + streamCallbacks.EvtAcxStreamRun = Codec_EvtStreamRun; + streamCallbacks.EvtAcxStreamPause = Codec_EvtStreamPause; + streamCallbacks.EvtAcxStreamAssignDrmContentId = Codec_EvtStreamAssignDrmContentId; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxStreamCallbacks(StreamInit, &streamCallbacks)); + + // + // Create the stream. + // + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_STREAM_CONTEXT); + attributes.EvtDestroyCallback = Codec_EvtStreamDestroy; + ACXSTREAM stream; + RETURN_NTSTATUS_IF_FAILED(AcxStreamCreate(Device, Circuit, &attributes, &StreamInit, &stream)); + + CRenderStreamEngine *streamEngine = NULL; + streamEngine = new(POOL_FLAG_NON_PAGED, DRIVER_TAG) CRenderStreamEngine(stream, StreamFormat); + RETURN_NTSTATUS_IF_TRUE(NULL == streamEngine, STATUS_INSUFFICIENT_RESOURCES); + + CODEC_STREAM_CONTEXT *streamCtx; + streamCtx = GetCodecStreamContext(stream); + ASSERT(streamCtx); + streamCtx->StreamEngine = (PVOID)streamEngine; + streamEngine = NULL; + + // + // Post stream creation initialization. + // + + // + // Create 1st custom stream-elements. + // + ACX_ELEMENT_CONFIG elementCfg; + ACX_ELEMENT_CONFIG_INIT(&elementCfg); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_ELEMENT_CONTEXT); + attributes.ParentObject = stream; + + ACXELEMENT elements[2] = {0}; + RETURN_NTSTATUS_IF_FAILED(AcxElementCreate(stream, &attributes, &elementCfg, &elements[0])); + + ASSERT(elements[0] != NULL); + CODEC_ELEMENT_CONTEXT *elementCtx; + elementCtx = GetCodecElementContext(elements[0]); + ASSERT(elementCtx); + UNREFERENCED_PARAMETER(elementCtx); + + // + // Create 2nd custom stream-elements. + // + ACX_ELEMENT_CONFIG_INIT(&elementCfg); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_ELEMENT_CONTEXT); + attributes.ParentObject = stream; + + RETURN_NTSTATUS_IF_FAILED(AcxElementCreate(stream, &attributes, &elementCfg, &elements[1])); + + ASSERT(elements[1] != NULL); + elementCtx = GetCodecElementContext(elements[1]); + ASSERT(elementCtx); + UNREFERENCED_PARAMETER(elementCtx); + + // + // Add stream elements + // + RETURN_NTSTATUS_IF_FAILED(AcxStreamAddElements(stream, elements, SIZEOF_ARRAY(elements))); + + return status; +} + + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/resources.rc b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/resources.rc new file mode 100644 index 00000000..0b1f9749 --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/resources.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "ACX v1.0 Codec Audio Driver" +#define VER_INTERNALNAME_STR "SDCAVCodec.sys" +#define VER_ORIGINALFILENAME_STR "SDCAVCodec.sys" + +#include "common.ver" + diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/streamengine.cpp b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/streamengine.cpp new file mode 100644 index 00000000..730f0553 --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/streamengine.cpp @@ -0,0 +1,270 @@ +/*++ + + 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: + + StreamEngine.cpp + +Abstract: + + Virtual Streaming Engine - this module controls streaming logic for + the device. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include <devguid.h> +#include "stdunk.h" +#include <ks.h> +#include <mmsystem.h> +#include <ksmedia.h> +#include "streamengine.h" + +#ifndef __INTELLISENSE__ +#include "streamengine.tmh" +#endif + +_Use_decl_annotations_ +PAGED_CODE_SEG +CStreamEngine::CStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat + ) + : m_CurrentState(AcxStreamStateStop), + m_Stream(Stream), + m_StreamFormat(StreamFormat) +{ + PAGED_CODE(); + + KeQueryPerformanceCounter(&m_PerformanceCounterFrequency); +} + +#pragma code_seg() +CStreamEngine::~CStreamEngine() +{ +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::PrepareHardware() +{ + PAGED_CODE(); + + m_CurrentState = AcxStreamStatePause; + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::ReleaseHardware() +{ + PAGED_CODE(); + + m_CurrentState = AcxStreamStateStop; + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::Pause() +{ + PAGED_CODE(); + + m_CurrentState = AcxStreamStatePause; + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::Run() +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + if (m_CurrentState != AcxStreamStatePause) + { + status = STATUS_INVALID_STATE_TRANSITION; + return status; + } + + m_CurrentState = AcxStreamStateRun; + + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::AssignDrmContentId( + _In_ ULONG DrmContentId, + _In_ PACXDRMRIGHTS DrmRights +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DrmContentId); + UNREFERENCED_PARAMETER(DrmRights); + + // + // At this point the driver should enforce the new DrmRights. + // + // HDMI render: if DigitalOutputDisable or CopyProtect is true, enable HDCP. + // + // From MSDN: + // + // This sample doesn't forward protected content, but if your driver uses + // lower layer drivers or a different stack to properly work, please see the + // following info from MSDN: + // + // "Before allowing protected content to flow through a data path, the system + // verifies that the data path is secure. To do so, the system authenticates + // each module in the data path beginning at the upstream end of the data path + // and moving downstream. As each module is authenticated, that module gives + // the system information about the next module in the data path so that it + // can also be authenticated. To be successfully authenticated, a module's + // binary file must be signed as DRM-compliant. + // + // Two adjacent modules in the data path can communicate with each other in + // one of several ways. If the upstream module calls the downstream module + // through IoCallDriver, the downstream module is part of a WDM driver. In + // this case, the upstream module calls the AcxDrmForwardContentToDeviceObject + // function to provide the system with the device object representing the + // downstream module. (If the two modules communicate through the downstream + // module's content handlers, the upstream module calls AcxDrmAddContentHandlers + // instead.) + // + // For more information, see MSDN's DRM Functions and Interfaces. + // + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::GetHWLatency( + _Out_ ULONG * FifoSize, + _Out_ ULONG * Delay +) +{ + PAGED_CODE(); + + *FifoSize = 128; + *Delay = 0; + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CRenderStreamEngine::CRenderStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat +) + : CStreamEngine(Stream, StreamFormat) +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CRenderStreamEngine::~CRenderStreamEngine() +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CRenderStreamEngine::PrepareHardware() +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + status = CStreamEngine::PrepareHardware(); + + // Add other init here. + + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CRenderStreamEngine::ReleaseHardware() +{ + PAGED_CODE(); + + return CStreamEngine::ReleaseHardware(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CCaptureStreamEngine::CCaptureStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat +) + : CStreamEngine(Stream, StreamFormat) +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CCaptureStreamEngine::~CCaptureStreamEngine() +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CCaptureStreamEngine::PrepareHardware() +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + RETURN_NTSTATUS_IF_FAILED(CStreamEngine::PrepareHardware()); + + RETURN_NTSTATUS_IF_FAILED(ReadRegistrySettings()); + + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CCaptureStreamEngine::ReleaseHardware() +{ + PAGED_CODE(); + + return CStreamEngine::ReleaseHardware(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CCaptureStreamEngine::ReadRegistrySettings() +{ + PAGED_CODE(); + + return STATUS_SUCCESS; +} diff --git a/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/streamengine.h b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/streamengine.h new file mode 100644 index 00000000..906e21f3 --- /dev/null +++ b/audio/SoundWire/Samples/SdcaVad/SdcaVCodec/streamengine.h @@ -0,0 +1,131 @@ +#pragma once + +#define HNSTIME_PER_MILLISECOND 10000 + +class CStreamEngine +{ +public: + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReleaseHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Run(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Pause(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + AssignDrmContentId( + _In_ ULONG DrmContentId, + _In_ PACXDRMRIGHTS DrmRights + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + GetHWLatency( + _Out_ ULONG * FifoSize, + _Out_ ULONG * Delay + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + virtual + #pragma code_seg() + ~CStreamEngine(); + +protected: + ACX_STREAM_STATE m_CurrentState; + ACXSTREAM m_Stream; + ACXDATAFORMAT m_StreamFormat; + LARGE_INTEGER m_PerformanceCounterFrequency; +}; + +class CRenderStreamEngine : public CStreamEngine +{ +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CRenderStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CRenderStreamEngine(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReleaseHardware(); + +protected: + // data section. +}; + +class CCaptureStreamEngine : public CStreamEngine +{ +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CCaptureStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CCaptureStreamEngine(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReleaseHardware(); + +protected: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReadRegistrySettings(); +}; + |
