EVT_ACX_STREAM_ALLOCATE_RTPACKETS funzione di callback (acxstreams.h)
L'evento EvtAcxStreamAllocateRtPackets indica al driver di allocare RtPackets per lo streaming.
Sintassi
EVT_ACX_STREAM_ALLOCATE_RTPACKETS EvtAcxStreamAllocateRtpackets;
NTSTATUS EvtAcxStreamAllocateRtpackets(
ACXSTREAM Stream,
ULONG PacketCount,
ULONG PacketSize,
PACX_RTPACKET *Packets
)
{...}
Parametri
Stream
Un oggetto ACXSTREAM rappresenta un flusso audio creato da un circuito. Il flusso è costituito da un elenco di elementi creati in base agli elementi del circuito padre. Per altre informazioni, vedere ACX - Riepilogo degli oggetti ACX.
PacketCount
Specifica il numero di pacchetti da allocare. I valori validi sono 1 o 2. I flussi basati su eventi useranno due pacchetti mentre i flussi basati su timer useranno un pacchetto.
PacketSize
Dimensioni dei pacchetti, misurate in byte.
Packets
Puntatore che riceve un puntatore a una matrice di strutture ACX_RTPACKET che descrive la posizione e le dimensioni dei pacchetti.
La versione iniziale di ACX supporta solo i buffer WdfMemoryDescriptorTypeMdl per il membro rtPacketBuffer ACX_RTPACKET. RtPacketBuffer deve essere allineato a pagina e avere un conteggio di byte allineato alla pagina.
Valore restituito
Restituisce STATUS_SUCCESS
se la chiamata ha avuto esito positivo. In caso contrario, restituisce un codice di errore appropriato. Per altre informazioni, vedere Uso dei valori NTSTATUS.
Commenti
La versione iniziale di ACX chiamerà con PacketCount = 1 o PacketCount = 2 quando StreamModel è AcxStreamModelRtPacket. Con PacketCount = 2, il driver può allocare un singolo buffer condiviso tra i due pacchetti o il driver può allocare due buffer separati.
Se il driver alloca un singolo buffer da condividere tra due pacchetti, la seconda struttura ACX_RTPACKET deve avere un WDF_MEMORY_DESCRIPTOR_TYPE = WdfMemoryDescriptorTypeInvalid. La struttura RtPacketOffset per la seconda struttura ACX_RTPACKET deve essere un offset valido nella struttura RtPacketBuffer della prima struttura ACX_RTPACKET e deve essere allineata alla prima struttura di ACX_RTPACKET RtPacketOffset + RtPacketSize.
EvtAcxStreamAllocateRtPackets viene chiamato prima di EvtAcxStreamPrepareHardware per consentire l'allocazione dei pacchetti RT prima di EvtAcxStreamPrepareHardware .
L'allocazione del buffer comporta in genere l'allocazione della memoria di sistema in modo che possa essere usata con l'hardware DMA. In genere, l'allocazione del buffer non avrà alcun effetto sull'hardware di streaming. La fase di preparazione dell'hardware viene usata come driver per l'esecuzione del flusso, completando attività come la prenotazione della larghezza di banda, la programmazione DMA e il completamento della preparazione della richiesta per l'esecuzione del flusso. In genere, il codice hardware di preparazione userà i buffer allocati per preparare la DMA e le attività correlate per essere pronti per avviare il flusso.
Esempio
Di seguito è riportato l'esempio di utilizzo.
//
// 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;
}
Requisiti ACX
Versione minima DI ACX: 1.0
Per altre informazioni sulle versioni ACX, vedere Panoramica della versione di ACX.
Requisiti
Requisito | Valore |
---|---|
Intestazione | acxstreams.h |
IRQL | PASSIVE_LEVEL |