EVT_ACX_STREAM_ALLOCATE_RTPACKETS función de devolución de llamada (acxstreams.h)
El evento EvtAcxStreamAllocateRtPackets indica al controlador que asigne RtPackets para streaming.
EVT_ACX_STREAM_ALLOCATE_RTPACKETS EvtAcxStreamAllocateRtpackets;
NTSTATUS EvtAcxStreamAllocateRtpackets(
ACXSTREAM Stream,
ULONG PacketCount,
ULONG PacketSize,
PACX_RTPACKET *Packets
)
{...}
Stream
Un objeto ACXSTREAM representa una secuencia de audio creada por un circuito. La secuencia se compone de una lista de elementos creados en función de los elementos del circuito primario. Para obtener más información, vea ACX : resumen de objetos ACX.
PacketCount
Especifica el número de paquetes que se van a asignar. Los valores válidos son 1 o 2. Los flujos controlados por eventos usarán dos paquetes, mientras que los flujos controlados por temporizador usarán un paquete.
PacketSize
Tamaño del paquete, medido en bytes.
Packets
Puntero que recibe un puntero a una matriz de estructuras de ACX_RTPACKET que describe la ubicación y el tamaño de los paquetes.
La versión inicial de ACX solo admite búferes WdfMemoryDescriptorTypeMdl para el miembro rtPacketBuffer de ACX_RTPACKET. RtPacketBuffer debe estar alineado con páginas y tener un recuento de bytes alineados con páginas.
Devuelve STATUS_SUCCESS
si la llamada se realizó correctamente. De lo contrario, devuelve un código de error adecuado. Para obtener más información, vea Uso de valores NTSTATUS.
La versión inicial de ACX llamará con PacketCount = 1 o PacketCount = 2 cuando StreamModel es AcxStreamModelRtPacket. Con PacketCount = 2, el controlador puede asignar un único búfer que se comparte entre los dos paquetes o el controlador puede asignar dos búferes independientes.
Si el controlador asigna un único búfer que se va a compartir entre dos paquetes, la segunda estructura de ACX_RTPACKET debe tener un WDF_MEMORY_DESCRIPTOR_TYPE = WdfMemoryDescriptorTypeInvalid. RtPacketOffset para la segunda estructura de ACX_RTPACKET debe ser un desplazamiento válido en RtPacketBuffer de la primera estructura de ACX_RTPACKET y debe alinearse con el primer ACX_RTPACKET estructura RtPacketOffset + RtPacketSize de la estructura.
Se llama a EvtAcxStreamAllocateRtPackets antes de que EvtAcxStreamPrepareHardware permita que se produzca la asignación de paquetes RT antes de EvtAcxStreamPrepareHardware.
Normalmente, la asignación del búfer solo implica asignar memoria del sistema de tal manera que se pueda usar con el hardware DMA. Normalmente, la asignación del búfer no tendrá ningún efecto en el hardware de streaming. La fase de preparación del hardware se usa cuando el controlador está preparando el flujo para ejecutarse, completando tareas como reservar ancho de banda, programar DMA y completar la preparación de la solicitud para ejecutar la secuencia. Normalmente, el código de hardware de preparación usará los búferes asignados para preparar la DMA y las actividades relacionadas para estar listos para iniciar la secuencia.
A continuación se muestra el uso de ejemplo.
//
// 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;
}
Versión mínima de ACX: 1.0
Para obtener más información sobre las versiones de ACX, consulte Introducción a la versión de ACX.
Requisito | Valor |
---|---|
Header | acxstreams.h |
IRQL | PASSIVE_LEVEL |