Share via


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

Confira também