EVT_ACX_STREAM_ALLOCATE_RTPACKETS回调函数 (acxstreams.h)

EvtAcxStreamAllocateRtPackets 事件告知驱动程序为流式传输分配 RtPacket。

语法

EVT_ACX_STREAM_ALLOCATE_RTPACKETS EvtAcxStreamAllocateRtpackets;

NTSTATUS EvtAcxStreamAllocateRtpackets(
  ACXSTREAM Stream,
  ULONG PacketCount,
  ULONG PacketSize,
  PACX_RTPACKET *Packets
)
{...}

参数

Stream

ACXSTREAM 对象表示线路创建的音频流。 该流由基于父线路的元素创建的元素列表组成。 有关详细信息,请参阅 ACX - ACX 对象的摘要

PacketCount

指定要分配的数据包数。 有效值为 1 或 2。 事件驱动的流将使用两个数据包,而计时器驱动的流将使用一个数据包。

PacketSize

数据包大小(以字节为单位)。

Packets

一个指针,用于接收指向 ACX_RTPACKET 结构的数组的指针, 描述数据包的位置和大小。

初始 ACX 版本仅支持 ACX_RTPACKET RtPacketBuffer 成员的 WdfMemoryDescriptorTypeMdl 缓冲区。 RtPacketBuffer 必须是页面对齐且具有页面对齐字节计数。

返回值

如果调用成功,则返回 STATUS_SUCCESS。 否则,它将返回适当的错误代码。 有关详细信息,请参阅 使用 NTSTATUS 值

言论

当 StreamModel 为 AcxStreamModelRtPacket 时,初始 ACX 版本将使用 PacketCount = 1 或 PacketCount = 2 进行调用。 使用 PacketCount = 2,驱动程序可以分配在两个数据包之间共享的单个缓冲区,或者驱动程序可以分配两个单独的缓冲区。

如果驱动程序分配单个缓冲区以在两个数据包之间共享,则第二个ACX_RTPACKET结构应具有 WDF_MEMORY_DESCRIPTOR_TYPE = WdfMemoryDescriptorTypeInvalid。 第二个ACX_RTPACKET结构的 RtPacketOffset 应该是第一个ACX_RTPACKET结构的 RtPacketBuffer 的有效偏移量,应与第一个ACX_RTPACKET结构的 RtPacketOffset + RtPacketSize 对齐。

EvtAcxStreamPrepareHardware 之前调用 EvtAcxStreamAllocateRtPackets,以允许在 EvtAcxStreamPrepareHardware 之前进行 RT 数据包分配。

缓冲区分配通常只涉及分配系统内存的方式,以便可用于 DMA 硬件。 通常,缓冲区分配不会对流式处理硬件产生任何影响。 准备硬件阶段用作驱动程序,通过完成保留带宽、编程 DMA 等任务,并完成请求运行流的准备,从而准备好运行流。 通常,准备硬件代码将使用分配的缓冲区来准备 DMA 和相关活动,以便启动流。

示例用法如下所示。

    //
    // Init RT streaming callbacks.
    //
    ACX_RT_STREAM_CALLBACKS_INIT(&rtCallbacks);
    rtCallbacks.EvtAcxStreamAllocateRtPackets       = Codec_EvtStreamAllocateRtPackets;

...

#pragma code_seg("PAGE")
NTSTATUS
Codec_EvtStreamAllocateRtPackets(
    _In_ ACXSTREAM Stream,
    _In_ ULONG PacketCount,
    _In_ ULONG PacketSize,
    _Out_ PACX_RTPACKET *Packets
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PCODEC_STREAM_CONTEXT ctx;
    PACX_RTPACKET packets = NULL;
    PVOID packetBuffer = NULL;
    ULONG i;
    ULONG packetAllocSizeInPages = 0;
    ULONG packetAllocSizeInBytes = 0;
    ULONG firstPacketOffset = 0;
    size_t packetsSize = 0;

    PAGED_CODE();

    ctx = GetCodecStreamContext(Stream);

    if (PacketCount > 2)
    {
        status = STATUS_INVALID_PARAMETER;
        goto exit;
    }

    status = RtlSizeTMult(PacketCount, sizeof(ACX_RTPACKET), &packetsSize);
    if (!NT_SUCCESS(status)) {
        goto exit;
    }

    packets = (PACX_RTPACKET)ExAllocatePool2(POOL_FLAG_NON_PAGED, packetsSize, DRIVER_TAG);
    if (!packets) {
        status = STATUS_NO_MEMORY;
        goto exit;
    }

    // We need to allocate page-aligned buffers, to ensure no kernel memory leaks
    // to user space. Round up the packet size to page aligned, then calculate
    // the first packet's buffer offset so packet 0 ends on a page boundary and
    // packet 1 begins on a page boundary.
    status = RtlULongAdd(PacketSize, PAGE_SIZE - 1, &packetAllocSizeInPages);
    if (!NT_SUCCESS(status)) {
        goto exit;
    }
    packetAllocSizeInPages = packetAllocSizeInPages / PAGE_SIZE;
    packetAllocSizeInBytes = PAGE_SIZE * packetAllocSizeInPages;
    firstPacketOffset = packetAllocSizeInBytes - PacketSize;

    for (i = 0; i < PacketCount; ++i)
    {
        PMDL pMdl = NULL;

        ACX_RTPACKET_INIT(&packets[i]);

        packetBuffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, packetAllocSizeInBytes, DRIVER_TAG);
        if (packetBuffer == NULL) {
            status = STATUS_NO_MEMORY;
            goto exit;
        }

        pMdl = IoAllocateMdl(packetBuffer, packetAllocSizeInBytes, FALSE, TRUE, NULL);
        if (pMdl == NULL) {
            status = STATUS_NO_MEMORY;
            goto exit;
        }

        MmBuildMdlForNonPagedPool(pMdl);

        WDF_MEMORY_DESCRIPTOR_INIT_MDL(
            &((packets)[i].RtPacketBuffer),
            pMdl,
            packetAllocSizeInBytes);

        packets[i].RtPacketSize = PacketSize;
        if (i == 0)
        {
            packets[i].RtPacketOffset = firstPacketOffset;
        }
        else
        {
            packets[i].RtPacketOffset = 0;
        }
        m_Packets[i] = packetBuffer;

        packetBuffer = NULL;
    }

    *Packets = packets;
    packets = NULL;
    ctx->PacketsCount = PacketCount;
    ctx->PacketSize = PacketSize;
    ctx->FirstPacketOffset = firstPacketOffset;

exit:
    if (packetBuffer)
    {
        ExFreePoolWithTag(packetBuffer, DRIVER_TAG);
    }
    if (packets)
    {
        FreeRtPackets(packets, PacketCount);
    }
    return status;
}

ACX 要求

最低 ACX 版本: 1.0

有关 ACX 版本的详细信息,请参阅 ACX 版本概述

要求

要求 价值
标头 acxstreams.h
IRQL PASSIVE_LEVEL

另请参阅