From 7d5c202eddde517fe5546452d83c36cf42381f8a Mon Sep 17 00:00:00 2001 From: Julia D'Zmura <78620953+judzmura@users.noreply.github.com> Date: Tue, 7 Mar 2023 11:32:48 -0800 Subject: Adding the AudioCodec ACX sample driver to Github. (#882) * Adding the AudioCodec acx sample driver to Github. * Fix to make AudioCodec driver all build in one solution file. Builds in ARM64 now. --- audio/Acx/Samples/Common/CaptureCircuit.cpp | 799 ++++++++++++++++++++++++++++ 1 file changed, 799 insertions(+) create mode 100644 audio/Acx/Samples/Common/CaptureCircuit.cpp (limited to 'audio/Acx/Samples/Common/CaptureCircuit.cpp') diff --git a/audio/Acx/Samples/Common/CaptureCircuit.cpp b/audio/Acx/Samples/Common/CaptureCircuit.cpp new file mode 100644 index 00000000..ba205a90 --- /dev/null +++ b/audio/Acx/Samples/Common/CaptureCircuit.cpp @@ -0,0 +1,799 @@ +/*++ + +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: + + CaptureCircuit.cpp + +Abstract: + + Capture Circuit. This file contains routines to create and handle + capture circuit. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "public.h" +#include +#include +#include +#include "AudioFormats.h" +#include "streamengine.h" +#include "cpp_utils.h" +#include "circuithelper.h" + +#ifndef __INTELLISENSE__ +#include "captureCircuit.tmh" +#endif + +// +// Controls how the custom name of the bridge pin is read. +// +BOOL g_UseCustomInfName = TRUE; + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtAcxPinSetDataFormat( + _In_ ACXPIN Pin, + _In_ ACXDATAFORMAT DataFormat +) +/*++ + +Routine Description: + + This ACX pin callback sets the device/mixed format. + +Return Value: + + NTSTATUS + +--*/ +{ + UNREFERENCED_PARAMETER(Pin); + UNREFERENCED_PARAMETER(DataFormat); + + PAGED_CODE(); + + // NOTE: update device/mixed format here. + + return STATUS_NOT_SUPPORTED; +} + +/////////////////////////////////////////////////////////// +// +// For more information on volume element see: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/ksnodetype-volume +// +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtVolumeAssignLevelCallback( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _In_ LONG VolumeLevel +) +{ + PAGED_CODE(); + + ASSERT(Volume); + PVOLUME_ELEMENT_CONTEXT volumeCtx = GetVolumeElementContext(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; +} + +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtVolumeRetrieveLevelCallback( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _Out_ LONG * VolumeLevel +) +{ + PAGED_CODE(); + + ASSERT(Volume); + PVOLUME_ELEMENT_CONTEXT volumeCtx = GetVolumeElementContext(Volume); + ASSERT(volumeCtx); + + if (Channel == ALL_CHANNELS_ID) + { + Channel = 0; + } + + *VolumeLevel = volumeCtx->VolumeLevel[Channel]; + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_CreateVolumeElement( + _In_ ACXCIRCUIT Circuit, + _Out_ ACXVOLUME* Element +) +/*++ + +Routine Description: + + This routine creates a volume element. + +Return Value: + + NT status value +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + ACX_VOLUME_CALLBACKS volumeCallbacks; + ACX_VOLUME_CONFIG volumeCfg; + VOLUME_ELEMENT_CONTEXT * volumeCtx; + + PAGED_CODE(); + + // + // The driver uses this DDI to assign its volume element callbacks. + // + ACX_VOLUME_CALLBACKS_INIT(&volumeCallbacks); + volumeCallbacks.EvtAcxVolumeAssignLevel = CodecC_EvtVolumeAssignLevelCallback; + volumeCallbacks.EvtAcxVolumeRetrieveLevel = CodecC_EvtVolumeRetrieveLevelCallback; + + // + // Create Volume element + // + 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, VOLUME_ELEMENT_CONTEXT); + attributes.ParentObject = Circuit; + + RETURN_NTSTATUS_IF_FAILED(AcxVolumeCreate(Circuit, &attributes, &volumeCfg, Element)); + + ASSERT(*Element != nullptr); + volumeCtx = GetVolumeElementContext(*Element); + ASSERT(volumeCtx); + + // + // (max + min)/2 puts it in the middle of the valid range, divide that by the stepping to get the nearest + // valid step, multiply that by stepping to put it back at a level value. + // + 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; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtAcxPinRetrieveName( + _In_ ACXPIN Pin, + _Out_ PUNICODE_STRING Name +) +/*++ + +Routine Description: + + If g_UseCustomInfName is false then the ACX + pin callback EvtAcxPinRetrieveName calls this + function in order to retrieve the pin name. + +Return Value: + + NTSTATUS + +--*/ +{ + UNREFERENCED_PARAMETER(Pin); + + PAGED_CODE(); + + return RtlUnicodeStringPrintf(Name, L"CustomName2"); +} + +VOID +CodecC_EvtPinContextCleanup( + _In_ WDFOBJECT WdfPin +) +/*++ + +Routine Description: + + In this callback, it cleans up pin context. + +Arguments: + + WdfDevice - WDF device object + +Return Value: + + nullptr + +--*/ +{ + UNREFERENCED_PARAMETER(WdfPin); +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_CircuitCleanup( + _In_ ACXCIRCUIT Circuit +) +{ + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + + PAGED_CODE(); + + // + // Remove the static capture circuit. + // + circuitCtx = GetCaptureCircuitContext(Circuit); + ASSERT(circuitCtx != nullptr); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_AddStaticCapture( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName +) +/*++ + +Routine Description: + + Creates the static capture circuit (pictured below) + and adds it to the device context. This is called + when a new device is detected and the AddDevice + call is made by the pnp manager. + + ****************************************************** + * Capture Circuit * + * * + * +-----------------------+ * + * | | * + * | +-------------+ | * + * Host ------>| | Volume Node | |---> Bridge * + * Pin | +-------------+ | Pin * + * | | * + * +-----------------------+ * + * * + ****************************************************** + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCODEC_DEVICE_CONTEXT devCtx; + PCAPTURE_DEVICE_CONTEXT captureDevCtx; + ACXCIRCUIT captureCircuit = nullptr; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // + // Alloc audio context to current device. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CAPTURE_DEVICE_CONTEXT); + RETURN_NTSTATUS_IF_FAILED(WdfObjectAllocateContext(Device, &attributes, (PVOID*)&captureDevCtx)); + ASSERT(captureDevCtx); + + // + // Create a capture circuit associated with this child device. + // + RETURN_NTSTATUS_IF_FAILED(CodecC_CreateCaptureCircuit(Device, ComponentGuid, MicCustomName, CircuitName, &captureCircuit)); + + devCtx->Capture = captureCircuit; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Capture_AllocateSupportedFormats( + _In_ WDFDEVICE Device, + _In_reads_bytes_(CodecCapturePinCount) ACXPIN Pin[], + _In_ ACXCIRCUIT Circuit, + _In_ size_t CodecCapturePinCount +) +{ + UNREFERENCED_PARAMETER(CodecCapturePinCount); + + NTSTATUS status = STATUS_SUCCESS; + ACXDATAFORMAT formatPcm44100c1; + ACXDATAFORMAT formatPcm48000c1; + ACXDATAFORMATLIST formatList; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + /////////////////////////////////////////////////////////// + // + // Allocate the formats this circuit supports. + // + + RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm44100c1, Circuit, Device, &formatPcm44100c1)); + RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm48000c1, Circuit, Device, &formatPcm48000c1)); + + /////////////////////////////////////////////////////////// + // + // Define supported formats for the host pin. + // + + // + // The raw processing mode list is associated with each single circuit + // by ACX. A driver uses this DDI to retrieve the built-in raw + // data-format list. + // + RETURN_NTSTATUS_IF_TRUE(CodecCaptureHostPin >= CodecCapturePinCount, STATUS_INVALID_PARAMETER); + formatList = AcxPinGetRawDataFormatList(Pin[CodecCaptureHostPin]); + RETURN_NTSTATUS_IF_TRUE(formatList == nullptr, STATUS_INSUFFICIENT_RESOURCES); + + // + // The driver uses this DDI to add data formats to the raw + // processing mode list associated with the current circuit. + // + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm44100c1)); + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm48000c1)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName, + _Out_ ACXCIRCUIT* Circuit +) +/*++ + +Routine Description: + + This routine builds the CODEC capture circuit. + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + ACXCIRCUIT circuit; + CODEC_CAPTURE_CIRCUIT_CONTEXT* circuitCtx; + ACXPIN pin[CodecCapturePinCount]; + + PAGED_CODE(); + + // + // Init output value. + // + *Circuit = nullptr; + + /////////////////////////////////////////////////////////// + // + // Create a circuit. + // + { + PACXCIRCUIT_INIT circuitInit = nullptr; + ACX_CIRCUIT_PNPPOWER_CALLBACKS powerCallbacks; + + // + // The driver uses this DDI to allocate an ACXCIRCUIT_INIT + // structure. This opaque structure is used when creating + // a standalone audio circuit representing an audio device. + // + circuitInit = AcxCircuitInitAllocate(Device); + + // + // A driver uses this DDI to free the allocated + // ACXCIRCUIT_INIT structure when an error is detected. + // Normally the structures is deleted/cleared by ACX when + // an ACX circuit is created successfully. + // + auto circuitInitScope = scope_exit([&circuitInit]() { + if (circuitInit) { + AcxCircuitInitFree(circuitInit); + } + }); + + // + // The driver uses this DDI to specify the Component ID + // of the ACX circuit. This ID is a guid that uniquely + // identifies the circuit instance (vendor specific). + // + AcxCircuitInitSetComponentId(circuitInit, ComponentGuid); + + // + // The driver uses this DDI to specify the circuit name. + // For standalone circuits, this is the audio device name + // which is used by clients to open handles to the audio devices. + // + (VOID)AcxCircuitInitAssignName(circuitInit, CircuitName); + + // + // The driver uses this DDI to specify the circuit type. The + // circuit type can be AcxCircuitTypeRender, AcxCircuitTypeCapture, + // AcxCircuitTypeOther, or AcxCircuitTypeMaximum (for validation). + // + AcxCircuitInitSetCircuitType(circuitInit, AcxCircuitTypeCapture); + + // + // The driver uses this DDI to assign its (if any) power callbacks. + // + ACX_CIRCUIT_PNPPOWER_CALLBACKS_INIT(&powerCallbacks); + powerCallbacks.EvtAcxCircuitPowerUp = CodecC_EvtCircuitPowerUp; + powerCallbacks.EvtAcxCircuitPowerDown = CodecC_EvtCircuitPowerDown; + AcxCircuitInitSetAcxCircuitPnpPowerCallbacks(circuitInit, &powerCallbacks); + + // + // The driver uses this DDI to register for a stream-create callback. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignAcxCreateStreamCallback(circuitInit, CodecC_EvtCircuitCreateStream)); + + // + // The driver uses this DDI to create a new ACX circuit. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_CAPTURE_CIRCUIT_CONTEXT); + RETURN_NTSTATUS_IF_FAILED(AcxCircuitCreate(Device, &attributes, &circuitInit, &circuit)); + + circuitInitScope.release(); + + circuitCtx = GetCaptureCircuitContext(circuit); + ASSERT(circuitCtx); + } + + // + // Post circuit creation initialization. + // + + /////////////////////////////////////////////////////////// + // + // Create volume element. + // + { + ACXELEMENT elements[CaptureElementCount] = { 0 }; + + RETURN_NTSTATUS_IF_FAILED(CodecC_CreateVolumeElement(circuit, (ACXVOLUME*)&elements[CaptureVolumeIndex])); + + // + // Saving the volume element in the circuit context. + // + circuitCtx->VolumeElement = (ACXVOLUME)elements[CaptureVolumeIndex]; + + // + // The driver uses this DDI post circuit creation to add ACXELEMENTs. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddElements(circuit, elements, SIZEOF_ARRAY(elements))); + } + + /////////////////////////////////////////////////////////// + // + // Create the pins for the circuit. + // + { + ACX_PIN_CALLBACKS pinCallbacks; + ACX_PIN_CONFIG pinCfg; + CODEC_PIN_CONTEXT* pinCtx; + + /////////////////////////////////////////////////////////// + // + // Create capture streaming pin. + // + ACX_PIN_CALLBACKS_INIT(&pinCallbacks); + pinCallbacks.EvtAcxPinSetDataFormat = CodecC_EvtAcxPinSetDataFormat; + + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSource; + pinCfg.Communication = AcxPinCommunicationSink; + pinCfg.Category = &KSCATEGORY_AUDIO; + pinCfg.PinCallbacks = &pinCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecC_EvtPinContextCleanup; + attributes.ParentObject = circuit; + + // + // The driver uses this DDI to create one or more pins on the circuits. + // + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &(pin[CodecCaptureHostPin]))); + + ASSERT(pin[CodecCaptureHostPin] != nullptr); + pinCtx = GetCodecPinContext(pin[CodecCaptureHostPin]); + ASSERT(pinCtx); + pinCtx->CodecPinType = CodecPinTypeHost; + + /////////////////////////////////////////////////////////// + // + // Create capture endpoint pin. + // + ACX_PIN_CALLBACKS_INIT(&pinCallbacks); + ACX_PIN_CONFIG_INIT(&pinCfg); + + pinCfg.Type = AcxPinTypeSink; + pinCfg.Communication = AcxPinCommunicationNone; + pinCfg.Category = &KSNODETYPE_MICROPHONE; + pinCfg.PinCallbacks = &pinCallbacks; + + // Specify how to read the custom name. + if (g_UseCustomInfName) + { + pinCfg.Name = MicCustomName; + } + else + { + pinCallbacks.EvtAcxPinRetrieveName = CodecC_EvtAcxPinRetrieveName; + } + g_UseCustomInfName = !g_UseCustomInfName; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = circuit; + + // + // The driver uses this DDI to create one or more pins on the circuits. + // + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &(pin[CodecCaptureBridgePin]))); + + ASSERT(pin[CodecCaptureBridgePin] != nullptr); + } + + /////////////////////////////////////////////////////////// + // + // Add audio jack to bridge pin. + // For more information on audio jack see: https://docs.microsoft.com/en-us/windows/win32/api/devicetopology/ns-devicetopology-ksjack_description + // + { + ACX_JACK_CONFIG jackCfg; + ACXJACK jack; + PJACK_CONTEXT jackCtx; + + ACX_JACK_CONFIG_INIT(&jackCfg); + jackCfg.Description.ChannelMapping = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + jackCfg.Description.Color = RGB(0, 0, 0); + jackCfg.Description.ConnectionType = AcxConnTypeAtapiInternal; + jackCfg.Description.GeoLocation = AcxGeoLocFront; + jackCfg.Description.GenLocation = AcxGenLocPrimaryBox; + jackCfg.Description.PortConnection = AcxPortConnIntegratedDevice; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, JACK_CONTEXT); + attributes.ParentObject = pin[CodecCaptureBridgePin]; + + RETURN_NTSTATUS_IF_FAILED(AcxJackCreate(pin[CodecCaptureBridgePin], &attributes, &jackCfg, &jack)); + + ASSERT(jack != nullptr); + + jackCtx = GetJackContext(jack); + ASSERT(jackCtx); + jackCtx->Dummy = 0; + + RETURN_NTSTATUS_IF_FAILED(AcxPinAddJacks(pin[CodecCaptureBridgePin], &jack, 1)); + } + + RETURN_NTSTATUS_IF_FAILED(Capture_AllocateSupportedFormats(Device, pin, circuit, CodecCapturePinCount)); + + /////////////////////////////////////////////////////////// + // + // The driver uses this DDI post circuit creation to add ACXPINs. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddPins(circuit, pin, CodecCapturePinCount)); + + // + // Set output value. + // + *Circuit = circuit; + + // + // Done. + // + status = STATUS_SUCCESS; + + return status; +} + +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtCircuitPowerUp( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE PreviousState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(PreviousState); + + PAGED_CODE(); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtCircuitPowerDown( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE TargetState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(TargetState); + + PAGED_CODE(); + + 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 creates a stream for the specified circuit. + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PCAPTURE_DEVICE_CONTEXT devCtx; + WDF_OBJECT_ATTRIBUTES attributes; + ACXSTREAM stream; + STREAMENGINE_CONTEXT * streamCtx; + ACX_STREAM_CALLBACKS streamCallbacks; + ACX_RT_STREAM_CALLBACKS rtCallbacks; + CCaptureStreamEngine * streamEngine = nullptr; + CODEC_CAPTURE_CIRCUIT_CONTEXT * circuitCtx; + CODEC_PIN_CONTEXT * pinCtx; + + auto streamEngineScope = scope_exit([&streamEngine]() { + + if (streamEngine) + { + delete streamEngine; + } + + }); + + PAGED_CODE(); + UNREFERENCED_PARAMETER(SignalProcessingMode); + UNREFERENCED_PARAMETER(VarArguments); + + ASSERT(IsEqualGUID(*SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW)); + + devCtx = GetCaptureDeviceContext(Device); + ASSERT(devCtx != nullptr); + + circuitCtx = GetCaptureCircuitContext(Circuit); + ASSERT(circuitCtx != nullptr); + + pinCtx = GetCodecPinContext(Pin); + ASSERT(pinCtx != nullptr); + + // + // Init streaming callbacks. + // + ACX_STREAM_CALLBACKS_INIT(&streamCallbacks); + streamCallbacks.EvtAcxStreamPrepareHardware = EvtStreamPrepareHardware; + streamCallbacks.EvtAcxStreamReleaseHardware = EvtStreamReleaseHardware; + streamCallbacks.EvtAcxStreamRun = EvtStreamRun; + streamCallbacks.EvtAcxStreamPause = EvtStreamPause; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxStreamCallbacks(StreamInit, &streamCallbacks)); + + // + // Init RT streaming callbacks. + // + ACX_RT_STREAM_CALLBACKS_INIT(&rtCallbacks); + rtCallbacks.EvtAcxStreamGetHwLatency = EvtStreamGetHwLatency; + rtCallbacks.EvtAcxStreamAllocateRtPackets = EvtStreamAllocateRtPackets; + rtCallbacks.EvtAcxStreamFreeRtPackets = EvtStreamFreeRtPackets; + rtCallbacks.EvtAcxStreamGetCapturePacket = CodecC_EvtStreamGetCapturePacket; + rtCallbacks.EvtAcxStreamGetCurrentPacket = EvtStreamGetCurrentPacket; + rtCallbacks.EvtAcxStreamGetPresentationPosition = EvtStreamGetPresentationPosition; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxRtStreamCallbacks(StreamInit, &rtCallbacks)); + + // + // Buffer notifications are supported. + // + AcxStreamInitSetAcxRtStreamSupportsNotifications(StreamInit); + + // + // Create the stream. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, STREAMENGINE_CONTEXT); + attributes.EvtDestroyCallback = EvtStreamDestroy; + RETURN_NTSTATUS_IF_FAILED(AcxRtStreamCreate(Device, Circuit, &attributes, &StreamInit, &stream)); + + streamCtx = GetStreamEngineContext(stream); + ASSERT(streamCtx); + + // + // Create the virtual streaming engine which will control + // streaming logic for the capture circuit. + // + streamEngine = new (POOL_FLAG_NON_PAGED, DeviceDriverTag) CCaptureStreamEngine(stream, StreamFormat); + RETURN_NTSTATUS_IF_TRUE(streamEngine == nullptr, STATUS_INSUFFICIENT_RESOURCES); + + streamCtx->StreamEngine = (PVOID)streamEngine; + + streamEngine = nullptr; + + // + // Done. + // + status = STATUS_SUCCESS; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtStreamGetCapturePacket( + _In_ ACXSTREAM Stream, + _Out_ ULONG * LastCapturePacket, + _Out_ ULONGLONG * QPCPacketStart, + _Out_ BOOLEAN * MoreData +) +{ + PSTREAMENGINE_CONTEXT ctx; + CCaptureStreamEngine* streamEngine = nullptr; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = static_cast(ctx->StreamEngine); + + return streamEngine->GetCapturePacket(LastCapturePacket, QPCPacketStart, MoreData); +} + + -- cgit v1.3.1