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 對齊。

EvtAcxStreamAllocateRtPackets 會在 EvtAcxStreamPrepareHardware 之前呼叫,以允許在 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

另請參閱