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 |