функция обратного вызова 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. Для второй ACX_RTPACKET структура RtPacketOffset должна быть допустимым смещением в RtPacketBuffer первой ACX_RTPACKET структуры и должна соответствовать первой ACX_RTPACKET структуры RtPacketOffset + RtPacketSize.
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 |