EVT_ACX_STREAM_ALLOCATE_RTPACKETS função de retorno de chamada (acxstreams.h)
O evento EvtAcxStreamAllocateRtPackets informa ao driver para alocar RtPackets para streaming.
Sintaxe
EVT_ACX_STREAM_ALLOCATE_RTPACKETS EvtAcxStreamAllocateRtpackets;
NTSTATUS EvtAcxStreamAllocateRtpackets(
ACXSTREAM Stream,
ULONG PacketCount,
ULONG PacketSize,
PACX_RTPACKET *Packets
)
{...}
Parâmetros
Stream
Um objeto ACXSTREAM representa um fluxo de áudio criado por um circuito. O fluxo é composto por uma lista de elementos criados com base nos elementos do circuito pai. Para obter mais informações, consulte ACX – Resumo de objetos ACX.
PacketCount
Especifica o número de pacotes a serem alocados. Os valores válidos são 1 ou 2. Os fluxos controlados por eventos usarão dois pacotes, enquanto os fluxos controlados por temporizador usarão um pacote.
PacketSize
O tamanho do pacote, medido em bytes.
Packets
Um ponteiro que recebe um ponteiro para uma matriz de estruturas ACX_RTPACKET que descreve o local e o tamanho dos pacotes.
A versão inicial do ACX dá suporte apenas a buffers WdfMemoryDescriptorTypeMdl para o ACX_RTPACKET membro RtPacketBuffer. O RtPacketBuffer deve ser alinhado à página e ter uma contagem de bytes alinhada à página.
Retornar valor
Retorna STATUS_SUCCESS
se a chamada foi bem-sucedida. Caso contrário, ele retornará um código de erro apropriado. Para obter mais informações, consulte Usando valores NTSTATUS.
Comentários
A versão inicial do ACX chamará com PacketCount = 1 ou PacketCount = 2 quando StreamModel for AcxStreamModelRtPacket. Com PacketCount = 2, o driver pode alocar um único buffer compartilhado entre os dois pacotes ou o driver pode alocar dois buffers separados.
Se o driver alocar um único buffer a ser compartilhado entre dois pacotes, a segunda estrutura ACX_RTPACKET deverá ter um WDF_MEMORY_DESCRIPTOR_TYPE = WdfMemoryDescriptorTypeInvalid. O RtPacketOffset para a segunda estrutura ACX_RTPACKET deve ser um deslocamento válido para o RtPacketBuffer da primeira estrutura ACX_RTPACKET e deve se alinhar com o rtpacketOffset + RtPacketSize da primeira estrutura ACX_RTPACKET.
EvtAcxStreamAllocateRtPackets é chamado antes de EvtAcxStreamPrepareHardware para permitir que a alocação de pacotes RT ocorra antes de EvtAcxStreamPrepareHardware.
Normalmente, a alocação de buffer envolve apenas a alocação de memória do sistema de forma que possa ser usada com o hardware de DMA. Normalmente, a alocação de buffer não terá nenhum efeito no hardware de streaming. A fase de preparação do hardware é usada porque o driver está preparando o fluxo para execução, concluindo tarefas como reservar largura de banda, programar DMA e concluir a preparação para a solicitação executar o fluxo. Normalmente, o código de hardware de preparação usará os buffers alocados para preparar o DMA e as atividades relacionadas para estar pronto para iniciar o fluxo.
Exemplo
O uso de exemplo é mostrado abaixo.
//
// 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;
}
Requisitos do ACX
Versão mínima do ACX: 1.0
Para obter mais informações sobre as versões do ACX, consulte Visão geral da versão do ACX.
Requisitos
Requisito | Valor |
---|---|
Cabeçalho | acxstreams.h |
IRQL | PASSIVE_LEVEL |