EVT_ACX_STREAM_ALLOCATE_RTPACKETS fonction de rappel (acxstreams.h)

L’événement EvtAcxStreamAllocateRtPackets indique au pilote d’allouer des RtPackets pour la diffusion en continu.

Syntaxe

EVT_ACX_STREAM_ALLOCATE_RTPACKETS EvtAcxStreamAllocateRtpackets;

NTSTATUS EvtAcxStreamAllocateRtpackets(
  ACXSTREAM Stream,
  ULONG PacketCount,
  ULONG PacketSize,
  PACX_RTPACKET *Packets
)
{...}

Paramètres

Stream

Un objet ACXSTREAM représente un flux audio créé par un circuit. Le flux est composé d’une liste d’éléments créés en fonction des éléments du circuit parent. Pour plus d’informations, consultez ACX - Résumé des objets ACX.

PacketCount

Spécifie le nombre de paquets à allouer. Les valeurs valides sont 1 ou 2. Les flux pilotés par les événements utilisent deux paquets, tandis que les flux pilotés par le minuteur utilisent un paquet.

PacketSize

Taille du paquet, mesurée en octets.

Packets

Pointeur qui reçoit un pointeur vers un tableau de structures ACX_RTPACKET qui décrit l’emplacement et la taille des paquets.

La version initiale d’ACX prend uniquement en charge les mémoires tampons WdfMemoryDescriptorTypeMdl pour le membre ACX_RTPACKET RtPacketBuffer. RtPacketBuffer doit être aligné sur la page et avoir un nombre d’octets alignés sur la page.

Valeur retournée

Retourne STATUS_SUCCESS si l’appel a réussi. Sinon, elle retourne un code d’erreur approprié. Pour plus d’informations, consultez Utilisation de valeurs NTSTATUS.

Remarques

La version initiale d’ACX appelle avec PacketCount = 1 ou PacketCount = 2 lorsque StreamModel est AcxStreamModelRtPacket. Avec PacketCount = 2, le pilote peut allouer une mémoire tampon unique partagée entre les deux paquets ou le pilote peut allouer deux mémoires tampons distinctes.

Si le pilote alloue une seule mémoire tampon à partager entre deux paquets, la deuxième structure ACX_RTPACKET doit avoir un WDF_MEMORY_DESCRIPTOR_TYPE = WdfMemoryDescriptorTypeInvalid. Le RtPacketOffset de la deuxième structure ACX_RTPACKET doit être un décalage valide dans le RtPacketBuffer de la première structure ACX_RTPACKET et doit s’aligner sur rtPacketOffset + RtPacketSize de la première structure ACX_RTPACKET structure.

EvtAcxStreamAllocateRtPackets est appelé avant EvtAcxStreamPrepareHardware pour permettre l’allocation de paquets RT avant EvtAcxStreamPrepareHardware.

L’allocation de mémoire tampon implique généralement uniquement l’allocation de mémoire système de telle sorte qu’elle puisse être utilisée avec le matériel DMA. En règle générale, l’allocation de mémoire tampon n’a aucun effet sur le matériel de streaming. La phase de préparation du matériel est utilisée lorsque le pilote prépare le flux à s’exécuter, en effectuant des tâches telles que la réservation de bande passante, la programmation DMA et la préparation de la demande d’exécution du flux. En règle générale, le code matériel de préparation utilise les mémoires tampons allouées pour préparer l’assistant DMA et les activités associées afin d’être prêt à démarrer le flux.

Exemple

L’exemple d’utilisation est illustré ci-dessous.

    //
    // 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;
}

Configuration requise pour ACX

Version ACX minimale : 1.0

Pour plus d’informations sur les versions d’ACX, consultez Vue d’ensemble des versions d’ACX.

Configuration requise

Condition requise Valeur
En-tête acxstreams.h
IRQL PASSIVE_LEVEL

Voir aussi