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 |