EVT_ACX_STREAM_ALLOCATE_RTPACKETS回调函数 (acxstreams.h)

EvtAcxStreamAllocateRtPackets 事件告知驱动程序分配 RtPackets 进行流式处理。

语法

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 保持一致。

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

缓冲区分配通常只涉及以可与 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 版本概述

要求

要求
Header acxstreams.h
IRQL PASSIVE_LEVEL

另请参阅