Поделиться через


функция обратного вызова EVT_ACX_STREAM_ALLOCATE_RTPACKETS (acxstreams.h)

Событие EvtAcxStreamAllocateRtPackets указывает драйверу выделить RtPackets для потоковой передачи.

Синтаксис

EVT_ACX_STREAM_ALLOCATE_RTPACKETS EvtAcxStreamAllocateRtpackets;

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

Параметры

Stream

Объект ACXSTREAM представляет аудиопоток, созданный каналом. Поток состоит из списка элементов, созданных на основе элементов родительского канала. Дополнительные сведения см. в разделе ACX — сводка по объектам ACX.

PacketCount

Указывает количество пакетов, которые необходимо выделить. Допустимые значения: 1 или 2. Потоки, управляемые событиями, будут использовать два пакета, а потоки, управляемые таймером, будут использовать один пакет.

PacketSize

Размер пакета, измеряемый в байтах.

Packets

Указатель, получающий указатель на массив ACX_RTPACKET структур , описывающих расположение и размер пакетов.

Начальная версия ACX поддерживает только буферы WdfMemoryDescriptorTypeMdl для элемента ACX_RTPACKET RtPacketBuffer. RtPacketBuffer должен быть выровнен по страницам и иметь количество байтов, выровненных по страницам.

Возвращаемое значение

Возвращает значение STATUS_SUCCESS , если вызов был выполнен успешно. В противном случае возвращается соответствующий код ошибки. Дополнительные сведения см. в разделе Использование значений NTSTATUS.

Комментарии

Исходная версия ACX будет вызываться с PacketCount = 1 или PacketCount = 2, если StreamModel имеет значение AcxStreamModelRtPacket. При использовании PacketCount = 2 драйвер может выделить один буфер, который является общим для двух пакетов, или драйвер может выделить два отдельных буфера.

Если драйвер выделяет один буфер для совместного использования двух пакетов, вторая структура ACX_RTPACKET должна иметь WDF_MEMORY_DESCRIPTOR_TYPE = WdfMemoryDescriptorTypeInvalid. RtPacketOffset для второй структуры ACX_RTPACKET должно быть допустимым смещением в rtPacketBuffer первой структуры ACX_RTPACKET и соответствовать rtPacketOffset + RtPacketSize первой структуры ACX_RTPACKET.

EvtAcxStreamAllocateRtPackets вызывается перед EvtAcxStreamPrepareHardware , чтобы разрешить выделение пакетов RT до EvtAcxStreamPrepareHardware.

Выделение буфера обычно включает только выделение системной памяти таким образом, чтобы ее можно было использовать с оборудованием DMA. Как правило, выделение буфера не оказывает никакого влияния на оборудование потоковой передачи. Этап подготовки оборудования используется для того, чтобы драйвер подготавливал поток к запуску, выполняя такие задачи, как резервирование пропускной способности, программирование DMA и подготовка к запросу на запуск потока. Как правило, код подготовки оборудования использует выделенные буферы для подготовки DMA и связанных действий к запуску потока.

Пример

Ниже приведен пример использования.

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

Минимальная версия ACX: 1.0

Дополнительные сведения о версиях ACX см. в статье Обзор версий ACX.

Требования

Требование Значение
Заголовок acxstreams.h
IRQL PASSIVE_LEVEL

См. также раздел