EVT_ACX_STREAM_ALLOCATE_RTPACKETS Rückruffunktion (acxstreams.h)
Das EvtAcxStreamAllocateRtPackets-Ereignis weist den Treiber an, RtPackets für das Streaming zuzuweisen.
Syntax
EVT_ACX_STREAM_ALLOCATE_RTPACKETS EvtAcxStreamAllocateRtpackets;
NTSTATUS EvtAcxStreamAllocateRtpackets(
ACXSTREAM Stream,
ULONG PacketCount,
ULONG PacketSize,
PACX_RTPACKET *Packets
)
{...}
Parameter
Stream
Ein ACXSTREAM-Objekt stellt einen audiostream dar, der von einer Verbindung erstellt wird. Der Stream besteht aus einer Liste von Elementen, die basierend auf den Elementen der übergeordneten Verbindung erstellt wurden. Weitere Informationen finden Sie unter ACX – Zusammenfassung von ACX-Objekten.
PacketCount
Gibt die Anzahl der pakete an, die zugeordnet werden sollen. Gültige Werte sind 1 oder 2. Ereignisgesteuerte Streams verwenden zwei Pakete, während timergesteuerte Streams ein Paket verwenden.
PacketSize
Die Paketgröße, gemessen in Bytes.
Packets
Ein Zeiger, der einen Zeiger auf ein Array von ACX_RTPACKET Strukturen empfängt, der den Speicherort und die Größe der Pakete beschreibt.
Die anfängliche ACX-Version unterstützt nur WdfMemoryDescriptorTypeMdl-Puffer für den ACX_RTPACKET RtPacketBuffer-Member. Der RtPacketBuffer muss seitenbündig sein und über eine seitenbündige Byteanzahl verfügen.
Rückgabewert
Gibt zurück STATUS_SUCCESS
, wenn der Aufruf erfolgreich war. Andernfalls wird ein geeigneter Fehlercode zurückgegeben. Weitere Informationen finden Sie unter Verwenden von NTSTATUS-Werten.
Hinweise
Die anfängliche ACX-Version ruft mit PacketCount = 1 oder PacketCount = 2 auf, wenn streamModel AcxStreamModelRtPacket ist. Mit PacketCount = 2 kann der Treiber einen einzelnen Puffer zuordnen, der zwischen den beiden Paketen gemeinsam genutzt wird, oder der Treiber kann zwei separate Puffer zuordnen.
Wenn der Treiber einen einzelnen Puffer zuordnet, der für zwei Pakete freigegeben werden soll, sollte die zweite ACX_RTPACKET-Struktur einen WDF_MEMORY_DESCRIPTOR_TYPE = WdfMemoryDescriptorTypeInvalid aufweisen. Das RtPacketOffset für die zweite ACX_RTPACKET-Struktur sollte ein gültiger Offset im RtPacketBuffer der ersten ACX_RTPACKET-Struktur sein und am RtPacketOffset + RtPacketSize der ersten ACX_RTPACKET Struktur ausgerichtet sein.
EvtAcxStreamAllocateRtPackets wird vor EvtAcxStreamPrepareHardware aufgerufen, damit die RT-Paketzuordnung vor EvtAcxStreamPrepareHardware erfolgen kann.
Die Pufferzuordnung umfasst in der Regel nur die Zuweisung des Systemspeichers, sodass er mit der DMA-Hardware verwendet werden kann. In der Regel hat die Pufferzuweisung keine Auswirkungen auf die Streaminghardware. Die Vorbereiten der Hardwarephase wird verwendet, wenn der Treiber den Stream für die Ausführung vorbereitet, indem Aufgaben wie das Reservieren von Bandbreite, das Programmieren von DMA und die Vorbereitung der Anforderung zum Ausführen des Streams abgeschlossen werden. In der Regel verwendet der Hardwarevorbereitungscode die zugeordneten Puffer, um den DMA und die zugehörigen Aktivitäten vorzubereiten, damit der Datenstrom gestartet werden kann.
Beispiel
Das Beispiel für die Verwendung ist unten dargestellt.
//
// 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-Anforderungen
ACX-Mindestversion: 1.0
Weitere Informationen zu ACX-Versionen finden Sie unter ACX-Versionsübersicht.
Anforderungen
Anforderung | Wert |
---|---|
Header | acxstreams.h |
IRQL | PASSIVE_LEVEL |