Audio de baja latencia

En este artículo se describen los cambios de latencia de audio en Windows 10. Abarca las opciones de API para los desarrolladores de aplicaciones y los cambios en los controladores que se pueden realizar para admitir audio de baja latencia. La latencia de audio es el retraso entre ese momento en que se crea el sonido y cuando se escucha. Tener una latencia de audio baja es importante para varios escenarios clave, como:

  • Audio pro
  • Creación de música
  • Comunicaciones
  • Realidad virtual
  • Juegos

Los objetivos de este documento son:

  1. Describir los orígenes de latencia de audio en Windows.
  2. Explicar los cambios que reducen la latencia de audio en la pila de audio Windows 10.
  3. Proporcione una referencia sobre cómo los desarrolladores de aplicaciones y los fabricantes de hardware pueden aprovechar la nueva infraestructura para desarrollar aplicaciones y controladores con baja latencia de audio.

En este artículo se describe:

  1. La nueva API de AudioGraph para escenarios de creación interactiva y multimedia.
  2. Cambios en WASAPI para admitir una latencia baja.
  3. Mejoras en los DDIs del controlador.

Terminología

Término Descripción
Latencia de representación Retraso entre el momento en que una aplicación envía un búfer de datos de audio a las API de representación, hasta el momento en que se escucha de los altavoces.
Latencia de captura Retraso entre el momento en que se captura un sonido desde el micrófono, hasta el momento en que se envía a las API de captura que usa la aplicación.
Latencia de ida y vuelta Retraso entre el momento en que se captura un sonido desde el micrófono, procesado por la aplicación y enviado por la aplicación para su representación en los altavoces. Es aproximadamente igual a representar la latencia y la latencia de captura.
Latencia táctil a la aplicación Retraso entre el momento en que un usuario pulsa la pantalla hasta el momento en que se envía la señal a la aplicación.
Latencia táctil a sonido Retraso entre el momento en que un usuario pulsa la pantalla, el evento va a la aplicación y se escucha un sonido a través de los altavoces. Es igual a representar la latencia + latencia táctil a la aplicación.

Pila de audio de Windows

En el diagrama siguiente se muestra una versión simplificada de la pila de audio de Windows.

Diagrama que muestra la pila de audio de baja latencia con aplicaciones, controlador de motor de audio y hardware.

Este es un resumen de las latencias de la ruta de representación: objetos de procesamiento de audio.

  1. La aplicación escribe los datos en un búfer.

  2. El motor de audio lee los datos del búfer y los procesa. También carga efectos de audio en forma de objetos de procesamiento de audio (API). Para obtener más información sobre las API, consulte Objetos de procesamiento de audio de Windows.

  3. La latencia de las API varía en función del procesamiento de señal dentro de las API.

  4. Antes de Windows 10, la latencia del motor de audio era igual a ~12 ms para las aplicaciones que usan datos de punto flotante y ~6 ms para las aplicaciones que usan datos enteros

  5. En Windows 10 y versiones posteriores, la latencia se ha reducido a 1,3 ms para todas las aplicaciones.

  6. El motor de audio escribe los datos procesados en un búfer.

  7. Antes de Windows 10, el búfer siempre se estableció en ~10 ms.

  8. A partir de Windows 10, el controlador de audio define el tamaño del búfer (más detalles sobre el búfer se describen más adelante en este artículo).

  9. El controlador de audio lee los datos del búfer y los escribe en el hardware.

  10. El hardware también puede procesar los datos de nuevo en forma de más efectos de audio.

  11. El usuario escucha audio del altavoz.

Este es un resumen de la latencia en la ruta de acceso de captura:

  1. El audio se captura desde el micrófono.

  2. El hardware puede procesar los datos. Por ejemplo, para agregar efectos de audio.

  3. El controlador lee los datos del hardware y escribe los datos en un búfer.

  4. Antes de Windows 10, este búfer siempre se estableció en 10 ms.

  5. A partir de Windows 10, el controlador de audio define el tamaño del búfer (más detalles a continuación).

  6. El motor de audio lee los datos del búfer y los procesa. También carga efectos de audio en forma de objetos de procesamiento de audio (API).

  7. La latencia de las API varía en función del procesamiento de señal dentro de las API.

  8. Antes de Windows 10, la latencia del motor de audio era igual a ~6 ms para las aplicaciones que usan datos de punto flotante y ~0 ms para las aplicaciones que usan datos enteros.

  9. En Windows 10 y versiones posteriores, la latencia se ha reducido a ~0 ms para todas las aplicaciones.

  10. La aplicación está señalizado de que los datos están disponibles para ser leídos, en cuanto el motor de audio finaliza con su procesamiento. La pila de audio también proporciona la opción de modo exclusivo. En ese caso, los datos omiten el motor de audio y van directamente de la aplicación al búfer desde el que el controlador lo lee. Sin embargo, si una aplicación abre un punto de conexión en modo exclusivo, no hay ninguna otra aplicación que pueda usar ese punto de conexión para representar o capturar audio.

Otra alternativa popular para las aplicaciones que necesitan baja latencia es usar el modelo ASIO (entrada y salida de flujo de audio), que utiliza el modo exclusivo. Una vez que un usuario instala un controlador ASIO de terceros, las aplicaciones pueden enviar datos directamente desde la aplicación al controlador ASIO. Sin embargo, la aplicación debe escribirse de tal manera que se comunique directamente con el controlador ASIO.

Ambas alternativas (modo exclusivo y ASIO) tienen sus propias limitaciones. Proporcionan una latencia baja, pero tienen sus propias limitaciones (algunas de las cuales se describen anteriormente). Como resultado, el motor de audio se ha modificado, con el fin de reducir la latencia, a la vez que conserva la flexibilidad.

Mejoras en la pila de audio

Windows 10 y versiones posteriores se han mejorado en tres áreas para reducir la latencia:

  1. Todas las aplicaciones que usan audio verán una reducción de 4,5 a 16 ms en la latencia de ida y vuelta (como se explicó en la sección anterior) sin cambios de código ni actualizaciones de controladores, en comparación con Windows 8.1.
    1. Las aplicaciones que usan datos de punto flotante tendrán una latencia de 16 ms menor.
    2. Las aplicaciones que usan datos enteros tendrán una latencia inferior de 4,5 ms.
  2. Los sistemas con controladores actualizados proporcionarán una latencia de ida y vuelta incluso menor:
    1. Los controladores pueden usar nuevos DDIs para informar de los tamaños admitidos del búfer que se usa para transferir datos entre Windows y el hardware. Las transferencias de datos no tienen que usar siempre búferes de 10 ms, como lo hacían en versiones anteriores de Windows. En su lugar, el controlador puede especificar si puede usar búferes pequeños, por ejemplo, 5 ms, 3 ms, 1 ms, etc.
    2. Las aplicaciones que requieren baja latencia pueden usar nuevas API de audio (AudioGraph o WASAPI), para consultar los tamaños de búfer admitidos por el controlador y seleccionar el que se usará para la transferencia de datos hacia o desde el hardware.
  3. Cuando una aplicación usa tamaños de búfer por debajo de un umbral determinado para representar y capturar audio, Windows entra en un modo especial, donde administra sus recursos de una manera que evita interferencias entre el streaming de audio y otros subsistemas. Esto reducirá las interrupciones en la ejecución del subsistema de audio y minimizará la probabilidad de problemas de audio. Cuando la aplicación detiene el streaming, Windows vuelve a su modo de ejecución normal. El subsistema de audio consta de los siguientes recursos:
    1. Subproceso del motor de audio que está procesando audio de baja latencia.
    2. Todos los subprocesos e interrupciones registrados por el controlador (mediante las nuevas DDIs que se describen en la sección sobre el registro de recursos del controlador).
    3. Algunos o todos los subprocesos de audio de las aplicaciones que solicitan búferes pequeños y de todas las aplicaciones que comparten el mismo gráfico de dispositivos de audio (por ejemplo, el mismo modo de procesamiento de señal) con cualquier aplicación que solicitó pequeños búferes:
  4. Devoluciones de llamada de AudioGraph en la ruta de acceso de streaming.
  5. Si la aplicación usa WASAPI, solo los elementos de trabajo que se enviaron a la API de cola de trabajo en tiempo real o MFCreateMFByteStreamOnStreamEx y se etiquetaron como "Audio" o "ProAudio".

Mejoras en la API

Las dos API de Windows 10 siguientes proporcionan funcionalidades de baja latencia:

Para determinar cuál de las dos API se van a usar:

  • Favorece AudioGraph, siempre que sea posible para el desarrollo de nuevas aplicaciones.
  • Use solo WASAPI, si:
    • Necesita más control que el proporcionado por AudioGraph.
    • Necesita una latencia menor que la proporcionada por AudioGraph.

En la sección herramientas de medición de este artículo se muestran medidas específicas de un sistema Haswell mediante el controlador HDAudio de bandeja de entrada.

En las secciones siguientes se explican las funcionalidades de baja latencia en cada API. Como se indicó en la sección anterior, para que el sistema logre la latencia mínima, debe tener controladores actualizados que admitan tamaños de búfer pequeños.

AudioGraph

AudioGraph es una nueva API de Plataforma universal de Windows en Windows 10 y versiones posteriores destinadas a realizar escenarios interactivos y de creación de música con facilidad. AudioGraph está disponible en varios lenguajes de programación (C++, C#, JavaScript) y tiene un modelo de programación sencillo y enriquecido con características.

Para establecer como destino escenarios de baja latencia, AudioGraph proporciona la propiedad AudioGraphSettings::QuantumSizeSelectionMode . Esta propiedad puede ser cualquiera de los valores que se muestran en la tabla siguiente:

Valor Descripción
SystemDefault Establece el búfer en el tamaño de búfer predeterminado (~10 ms)
Menor latencia Establece el búfer en el valor mínimo admitido por el controlador.
ClosestToDesired Establece el tamaño del búfer para que sea igual al valor definido por la propiedad DesiredSamplesPerQuantum o en un valor que esté tan cerca de DesiredSamplesPerQuantum como es compatible con el controlador.

En el ejemplo AudioCreation se muestra cómo usar AudioGraph para una latencia baja. El siguiente fragmento de código muestra cómo establecer el tamaño mínimo del búfer:

AudioGraphSettings settings = new AudioGraphSettings(AudioRenderCategory.Media);
settings.QuantumSizeSelectionMode = QuantumSizeSelectionMode.LowestLatency;
CreateAudioGraphResult result = await AudioGraph.CreateAsync(settings);

API de sesión de audio de Windows (WASAPI)

A partir de Windows 10, WASAPI se ha mejorado para:

  • Permitir que una aplicación detecte el intervalo de tamaños de búfer (es decir, valores de periodicidad) admitidos por el controlador de audio de un dispositivo de audio determinado. Esto permite que una aplicación elija entre el tamaño de búfer predeterminado (10 ms) o un búfer pequeño (menos de 10 ms) al abrir una secuencia en modo compartido. Si una aplicación no especifica un tamaño de búfer, usará el tamaño de búfer predeterminado.
  • Permitir que una aplicación detecte el formato actual y la periodicidad del motor de audio. Esto permite que las aplicaciones se ajusten a la configuración actual del motor de audio.
  • Permitir que una aplicación especifique que desea representar o capturar en el formato que especifica sin necesidad de volver a muestrear el motor de audio

Las características anteriores estarán disponibles en todos los dispositivos Windows. Sin embargo, determinados dispositivos con suficientes recursos y controladores actualizados proporcionarán una mejor experiencia de usuario que otras.

La funcionalidad anterior se proporciona mediante una nueva interfaz, denominada IAudioClient3, que deriva de IAudioClient2.

IAudioClient3 define los tres métodos siguientes:

Método Descripción
GetCurrentSharedModeEnginePeriod Devuelve el formato actual y la periodicidad del motor de audio.
GetSharedModeEnginePeriod Devuelve el intervalo de periodicidades admitidas por el motor para el formato de secuencia especificado.
InitializeSharedAudioStream Inicializa una secuencia compartida con la periodicidad especificada.

En el ejemplo WASAPIAudio se muestra cómo usar IAudioClient3 para una latencia baja.

El siguiente fragmento de código muestra cómo una aplicación de creación de música puede funcionar en la configuración de latencia más baja compatible con el sistema.

// 1. Activation

// Get a string representing the Default Audio (Render|Capture) Device
m_DeviceIdString = MediaDevice::GetDefaultAudio(Render|Capture)Id(
Windows::Media::Devices::AudioDeviceRole::Default );

// This call must be made on the main UI thread.  Async operation will call back to
// IActivateAudioInterfaceCompletionHandler::ActivateCompleted, which must be an agile // interface implementation
hr = ActivateAudioInterfaceAsync( m_DeviceIdString->Data(), __uuidof(IAudioClient3),
nullptr, this, &asyncOp );

// 2. Setting the audio client properties – note that low latency offload is not supported

AudioClientProperties audioProps = {0};
audioProps.cbSize = sizeof( AudioClientProperties );
audioProps.eCategory = AudioCategory_Media;

// if the device has System.Devices.AudioDevice.RawProcessingSupported set to true and you want to use raw mode
// audioProps.Options |= AUDCLNT_STREAMOPTIONS_RAW;
//
// if it is important to avoid resampling in the audio engine, set this flag
// audioProps.Options |= AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;


hr = m_AudioClient->SetClientProperties( &audioProps ); if (FAILED(hr)) { ... }

// 3. Querying the legal periods

hr = m_AudioClient->GetMixFormat( &mixFormat ); if (FAILED(hr)) { ... }

hr = m_AudioClient->GetSharedModeEnginePeriod(wfx, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames); if (FAILED(hr)) { ... }

// legal periods are any multiple of fundamentalPeriodInFrames between
// minPeriodInFrames and maxPeriodInFrames, inclusive
// the Windows shared-mode engine uses defaultPeriodInFrames unless an audio client // has specifically requested otherwise

// 4. Initializing a low-latency client

hr = m_AudioClient->InitializeSharedAudioStream(
         AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
         desiredPeriodInFrames,
         mixFormat,
         nullptr); // audio session GUID
         if (AUDCLNT_E_ENGINE_PERIODICITY_LOCKED == hr) {
         /* engine is already running at a different period; call m_AudioClient->GetSharedModeEnginePeriod to see what it is */
         } else if (FAILED(hr)) {
             ...
         }

// 5. Initializing a client with a specific format (if the format needs to be different than the default format)

AudioClientProperties audioProps = {0};
audioProps.cbSize = sizeof( AudioClientProperties );
audioProps.eCategory = AudioCategory_Media;
audioProps.Options |= AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;

hr = m_AudioClient->SetClientProperties( &audioProps );
if (FAILED(hr)) { ... }

hr = m_AudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, appFormat, &closest);
if (S_OK == hr) {
       /* device supports the app format */
} else if (S_FALSE == hr) {
       /* device DOES NOT support the app format; closest supported format is in the "closest" output variable */
} else {
       /* device DOES NOT support the app format, and Windows could not find a close supported format */
}

hr = m_AudioClient->InitializeSharedAudioStream(
       AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
       defaultPeriodInFrames,
       appFormat,
       nullptr); // audio session GUID
if (AUDCLNT_E_ENGINE_FORMAT_LOCKED == hr) {
       /* engine is already running at a different format */
} else if (FAILED(hr)) {
       ...
}

Además, Microsoft recomienda que las aplicaciones que usan WASAPI también usen la API de cola de trabajo en tiempo real o MFCreateMFByteStreamOnStreamEx para crear elementos de trabajo y etiquetarlos como Audio o Audio Pro, en lugar de sus propios subprocesos. Esto permitirá a Windows administrarlos de forma que evite interferencias que no sean subsistemas de audio. Por el contrario, Windows administra automáticamente todos los subprocesos de AudioGraph. El siguiente fragmento de código del ejemplo WASAPIAudio muestra cómo usar las API de cola de trabajo MF.

// Specify Source Reader Attributes
Attributes->SetUnknown( MF_SOURCE_READER_ASYNC_CALLBACK, static_cast<IMFSourceReaderCallback *>(this) );
    if (FAILED( hr ))
    {
        goto exit;
    }
    Attributes->SetString( MF_READWRITE_MMCSS_CLASS_AUDIO, L"Audio" );
    if (FAILED( hr ))
    {
        goto exit;
    }
    Attributes->SetUINT32( MF_READWRITE_MMCSS_PRIORITY_AUDIO, 0 );
    if (FAILED( hr ))
    {
        goto exit;
    }
    // Create a stream from IRandomAccessStream
    hr = MFCreateMFByteStreamOnStreamEx (reinterpret_cast<IUnknown*>(m_ContentStream), &ByteStream );
    if ( FAILED( hr ) )
    {
        goto exit;
    }
    // Create source reader
    hr = MFCreateSourceReaderFromByteStream( ByteStream, Attributes, &m_MFSourceReader );

Como alternativa, el siguiente fragmento de código muestra cómo usar las API rt Work Queue.

#define INVALID_WORK_QUEUE_ID 0xffffffff
DWORD g_WorkQueueId = INVALID_WORK_QUEUE_ID;
//#define MMCSS_AUDIO_CLASS    L"Audio"
//#define MMCSS_PROAUDIO_CLASS L"ProAudio"

STDMETHODIMP TestClass::GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
       HRESULT hr = S_OK;
       *pdwFlags = 0;
       *pdwQueue = g_WorkQueueId;
       return hr;
}

//-------------------------------------------------------
STDMETHODIMP TestClass::Invoke(IRtwqAsyncResult* pAsyncResult)
{
       HRESULT hr = S_OK;
       IUnknown *pState = NULL;
       WCHAR className[20];
       DWORD  bufferLength = 20;
       DWORD taskID = 0;
       LONG priority = 0;

       printf("Callback is invoked pAsyncResult(0x%0x)  Current process id :0x%0x Current thread id :0x%0x\n", (INT64)pAsyncResult, GetCurrentProcessId(), GetCurrentThreadId());

       hr = RtwqGetWorkQueueMMCSSClass(g_WorkQueueId, className, &bufferLength);
       IF_FAIL_EXIT(hr, Exit);

       if (className[0])
       {
              hr = RtwqGetWorkQueueMMCSSTaskId(g_WorkQueueId, &taskID);
              IF_FAIL_EXIT(hr, Exit);

              hr = RtwqGetWorkQueueMMCSSPriority(g_WorkQueueId, &priority);
              IF_FAIL_EXIT(hr, Exit);
              printf("MMCSS: [%ws] taskID (%d) priority(%d)\n", className, taskID, priority);
       }
       else
       {
              printf("non-MMCSS\n");
       }
       hr = pAsyncResult->GetState(&pState);
       IF_FAIL_EXIT(hr, Exit);

Exit:
       return S_OK;
}
//-------------------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{
       HRESULT hr = S_OK;
       HANDLE signalEvent;
       LONG Priority = 1;
       IRtwqAsyncResult *pAsyncResult = NULL;
       RTWQWORKITEM_KEY workItemKey = NULL;;
       IRtwqAsyncCallback *callback = NULL;
       IUnknown *appObject = NULL;
       IUnknown *appState = NULL;
       DWORD taskId = 0;
       TestClass cbClass;
       NTSTATUS status;

       hr = RtwqStartup();
       IF_FAIL_EXIT(hr, Exit);

       signalEvent = CreateEvent(NULL, true, FALSE, NULL);
       IF_TRUE_ACTION_EXIT(signalEvent == NULL, hr = E_OUTOFMEMORY, Exit);

       g_WorkQueueId = RTWQ_MULTITHREADED_WORKQUEUE;

       hr = RtwqLockSharedWorkQueue(L"Audio", 0, &taskId, &g_WorkQueueId);
       IF_FAIL_EXIT(hr, Exit);

       hr = RtwqCreateAsyncResult(NULL, reinterpret_cast<IRtwqAsyncCallback*>(&cbClass), NULL, &pAsyncResult);
       IF_FAIL_EXIT(hr, Exit);

       hr = RtwqPutWaitingWorkItem(signalEvent, Priority, pAsyncResult, &workItemKey);
       IF_FAIL_EXIT(hr, Exit);

       for (int i = 0; i < 5; i++)
       {
              SetEvent(signalEvent);
              Sleep(30);
              hr = RtwqPutWaitingWorkItem(signalEvent, Priority, pAsyncResult, &workItemKey);
              IF_FAIL_EXIT(hr, Exit);
    }

Exit:
       if (pAsyncResult)
       {
              pAsyncResult->Release();
       }

      if (INVALID_WORK_QUEUE_ID != g_WorkQueueId)
      {
        hr = RtwqUnlockWorkQueue(g_WorkQueueId);
        if (FAILED(hr))
        {
            printf("Failed with RtwqUnlockWorkQueue 0x%x\n", hr);
        }

        hr = RtwqShutdown();
        if (FAILED(hr))
        {
            printf("Failed with RtwqShutdown 0x%x\n", hr);
        }
      }

       if (FAILED(hr))
       {
          printf("Failed with error code 0x%x\n", hr);
       }
       return 0;
}

Por último, los desarrolladores de aplicaciones que usan WASAPI necesitan etiquetar sus secuencias con la categoría de audio y si usar el modo de procesamiento de señal sin procesar, en función de la funcionalidad de cada secuencia. Microsoft recomienda que todas las secuencias de audio no usen el modo de procesamiento de señal sin procesar, a menos que se comprendan las implicaciones. El modo sin formato omite todo el procesamiento de señal elegido por el OEM, por lo que:

  • La señal de representación de un punto de conexión determinado podría ser poco óptima.
  • La señal de captura puede tener un formato que la aplicación no pueda entender.
  • La latencia podría mejorarse.

Mejoras en el controlador

Para que los controladores de audio admitan una latencia baja, Windows 10 y versiones posteriores proporcionan las siguientes características:

  1. [Obligatorio] Declare el tamaño mínimo del búfer que se admite en cada modo.
  2. [Opcional, pero recomendado] Mejore la coordinación del flujo de datos entre el controlador y Windows.
  3. [Opcional, pero recomendado] Registre los recursos del controlador (interrupciones, subprocesos), para que se puedan proteger mediante Windows en escenarios de baja latencia. Los controladores de función de miniport de HDAudio enumerados por el controlador de bus HDAudio de la bandeja de entrada hdaudbus.sys no necesitan registrar las interrupciones de HDAudio, ya que esto ya se realiza mediante hdaudbus.sys. Sin embargo, si el controlador de minipuerto crea sus propios subprocesos, debe registrarlos.

En las tres secciones siguientes se explicará cada nueva característica con más profundidad.

Declarar el tamaño mínimo del búfer

Un controlador funciona con varias restricciones al mover datos de audio entre Windows, el controlador y el hardware. Estas restricciones pueden deberse al transporte de hardware físico que mueve datos entre la memoria y el hardware, o debido a los módulos de procesamiento de señal dentro del hardware o DSP asociado.

A partir de Windows 10, versión 1607, el controlador puede expresar sus funcionalidades de tamaño de búfer mediante la propiedad DEVPKEY_KsAudio_PacketSize_Constraints2 dispositivo. Esta propiedad permite al usuario definir el tamaño mínimo absoluto del búfer admitido por el controlador y restricciones de tamaño de búfer específicas para cada modo de procesamiento de señal. Las restricciones específicas del modo deben ser mayores que el tamaño mínimo del búfer de los controladores; de lo contrario, la pila de audio los omite.

Por ejemplo, el siguiente fragmento de código muestra cómo un controlador puede declarar que el tamaño de búfer mínimo absoluto admitido es de 2 ms, pero el modo predeterminado admite 128 fotogramas, que corresponde a 3 ms si se supone una frecuencia de muestreo de 48 kHz.

 
//
// Describe buffer size constraints for WaveRT buffers
//
static struct
{
    KSAUDIO_PACKETSIZE_CONSTRAINTS2 TransportPacketConstraints;
    KSAUDIO_PACKETSIZE_PROCESSINGMODE_CONSTRAINT AdditionalProcessingConstraints[1];
} SysvadWaveRtPacketSizeConstraintsRender =
{
    {
        2 * HNSTIME_PER_MILLISECOND,                // 2 ms minimum processing interval
        FILE_BYTE_ALIGNMENT,                        // 1 byte packet size alignment
        0,                                          // no maximum packet size constraint
        2,                                          // 2 processing constraints follow
        {
            STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT,          // constraint for default processing mode
            128,                                                // 128 samples per processing frame
            0,                                                  // NA hns per processing frame
        },
    },
    {
        {
            STATIC_AUDIO_SIGNALPROCESSINGMODE_MOVIE,            // constraint for movie processing mode
            1024,                                               // 1024 samples per processing frame
            0,                                                  // NA hns per processing frame
        },
    }
};

Consulte los siguientes artículos para obtener información más detallada sobre estas estructuras:

Además, el ejemplo sysvad muestra cómo usar estas propiedades para que un controlador declare el búfer mínimo para cada modo.

Mejorar la coordinación entre el controlador y el sistema operativo

Las DDIs que se describen en esta sección permiten al controlador:

  • Indique claramente qué mitad (paquete) del búfer está disponible para Windows, en lugar de la estimación del sistema operativo en función de una posición de vínculo de códec. Esto ayuda a Windows a recuperarse de problemas de audio más rápido.
  • Opcionalmente, optimice o simplifique sus transferencias de datos dentro y fuera del búfer de WaveRT. La cantidad de ventajas aquí depende del diseño del motor DMA u otro mecanismo de transferencia de datos entre el búfer waveRT y el hardware (posiblemente DSP).
  • "Ráfaga" capturó datos más rápido que en tiempo real si el controlador ha acumulado internamente los datos capturados. Esto está pensado principalmente para escenarios de activación por voz, pero también se puede aplicar durante el streaming normal.
  • Proporcione información de marca de tiempo sobre su posición de flujo actual en lugar de la estimación de Windows, lo que podría permitir información de posición precisa.

Esta DDI es útil en el caso de que se use un DSP. Sin embargo, es posible que un controlador de audio HD estándar u otros diseños de búfer de DMA circulares simples no encuentre mucha ventaja en estos nuevos DDIs enumerados aquí.

Varias de las rutinas del controlador devuelven marcas de tiempo del contador de rendimiento de Windows que reflejan la hora en la que el dispositivo captura o presenta las muestras.

En los dispositivos que tienen canalizaciones DSP complejas y procesamiento de señales, el cálculo de una marca de tiempo precisa puede ser difícil y debe realizarse cuidadosamente. Las marcas de tiempo no deben reflejar el momento en el que las muestras se transfirieron a o desde Windows al DSP.

Para calcular los valores del contador de rendimiento, el controlador y DSP pueden emplear algunos de los métodos siguientes.

  • Dentro del DSP, realice un seguimiento de las marcas de tiempo de ejemplo mediante un reloj de pared DSP interno.
  • Entre el controlador y DSP, calcule una correlación entre el contador de rendimiento de Windows y el reloj de pared DSP. Los procedimientos para esto pueden ir desde simples (pero menos precisos) hasta bastante complejos o noveles (pero más precisos).
  • Tenga en cuenta los retrasos constantes debidos a algoritmos de procesamiento de señales o transportes de canalización o hardware, a menos que se contabilizan estos retrasos.

En el ejemplo sysvad se muestra cómo usar los DDIs anteriores.

Registro de recursos de controladores

Para ayudar a garantizar una operación sin problemas, los controladores de audio deben registrar sus recursos de streaming con Portcls. Esto permite a Windows administrar recursos para evitar interferencias entre el streaming de audio y otros subsistemas.

Los recursos de flujo son los recursos que usa el controlador de audio para procesar secuencias de audio o garantizar el flujo de datos de audio. Solo se admiten dos tipos de recursos de flujo: interrupciones y subprocesos propiedad del controlador. Los controladores de audio deben registrar un recurso después de crear el recurso y anular el registro del recurso antes de eliminarlo.

Los controladores de audio pueden registrar recursos en tiempo de inicialización cuando se carga el controlador o en tiempo de ejecución, por ejemplo, cuando hay un reequilibrio de recursos de E/S. Portcls usa un estado global para realizar un seguimiento de todos los recursos de streaming de audio.

En algunos casos de uso, como aquellos que requieren audio de latencia muy baja, Windows intenta aislar los recursos registrados del controlador de audio de la interferencia de otros sistemas operativos, aplicaciones y actividad de hardware. El sistema operativo y el subsistema de audio lo hacen según sea necesario sin interactuar con el controlador de audio, excepto para el registro del controlador de audio de los recursos.

Este requisito para registrar recursos de secuencia implica que todos los controladores que se encuentran en la ruta de acceso de la canalización de streaming deben registrar sus recursos directamente o indirectamente con Portcls. El controlador de minipuerto de audio tiene estas opciones:

  • El controlador de minipuerto de audio es el controlador inferior de su pila (interfacing the h/w directamente), en este caso, el controlador conoce sus recursos de secuencia y puede registrarlos con Portcls.
  • El controlador de minipuerto de audio es streaming de audio con la ayuda de otros controladores (por ejemplo, controladores de bus de audio). Estos otros controladores también usan recursos que deben registrarse con Portcls. Estas pilas de controladores paralelos o de autobús pueden exponer una interfaz pública (o privada, si un único proveedor posee todos los controladores) que los controladores de miniporte de audio usan para recopilar esta información.
  • El controlador de minipuerto de audio es el streaming de audio con la ayuda de otros controladores (por ejemplo, hdaudbus). Estos otros controladores también usan recursos que deben registrarse con Portcls. Estos controladores paralelos o de autobús pueden vincularse con Portcls y registrar directamente sus recursos. Los controladores de minipuerto de audio deben informar a Portcls de que dependen de los recursos de estos otros dispositivos paralelos o de bus (PPO). La infraestructura de audio HD usa esta opción, es decir, los vínculos del controlador del bus de audio HD con Portcls y realizan automáticamente los pasos siguientes:
    • registra los recursos de su conductor de autobús y
    • notifica a Portcls que los recursos secundarios dependen de los recursos del elemento primario. En la arquitectura de audio HD, el controlador de miniporte de audio solo necesita registrar sus propios recursos de subprocesos propiedad del controlador.

Notas:

  • Los controladores de función miniport de HDAudio enumerados por el controlador de bus HDAudio de bandeja de entrada hdaudbus.sys no necesitan registrar las interrupciones de HDAudio, ya que ya lo hace hdaudbus.sys. Sin embargo, si el controlador de miniporte crea sus propios subprocesos, debe registrarlos.
  • Los controladores que se vinculan con Portcls solo para registrar recursos de streaming deben actualizar sus INFs para incluir wdmaudio.inf y copiar portcls.sys (y archivos dependientes). Se define una nueva sección de copia INF en wdmaudio.inf para copiar solo esos archivos.
  • Los controladores de audio que solo se ejecutan en Windows 10 y versiones posteriores pueden vincularse de forma difícil a:
  • Los controladores de audio que deben ejecutarse en un sistema operativo de nivel descendente pueden usar la siguiente interfaz (la miniporte puede llamar a QueryInterface para la interfaz IID_IPortClsStreamResourceManager y registrar sus recursos solo cuando PortCls admite la interfaz).
  • Estas DDIs, use esta enumeración y estructura:

Por último, los controladores que vinculan PortCls para el único propósito de registrar recursos deben agregar las dos líneas siguientes en la sección DDInstall de su inf. Los controladores de minipuerto de audio no necesitan esto porque ya tienen inclusión/necesidades en wdmaudio.inf.

[<install-section-name>]
Include=wdmaudio.inf
Needs=WDMPORTCLS.CopyFilesOnly

Las líneas anteriores se aseguran de que PortCls y sus archivos dependientes estén instalados.

Herramientas de medición

Para medir la latencia de ida y vuelta, el usuario puede usar herramientas que reproducen pulsos a través de los altavoces y capturarlas a través del micrófono. Miden el retraso de la ruta de acceso siguiente:

  1. La aplicación llama a la API de representación (AudioGraph o WASAPI) para reproducir el pulso.
  2. El audio se reproduce a través de los altavoces.
  3. El audio se captura desde el micrófono.
  4. La API de captura detecta el pulso (AudioGraph o WASAPI) para medir la latencia de ida y vuelta para diferentes tamaños de búfer, los usuarios deben instalar un controlador que admita búferes pequeños. El controlador HDAudio de bandeja de entrada se ha actualizado para admitir tamaños de búfer entre 128 muestras (2.66ms@48kHz) y 480 muestras (10ms@48kHz). En los pasos siguientes se muestra cómo instalar el controlador HDAudio de bandeja de entrada (que forma parte de todas las SKU de Windows 10 y posteriores):
  • Inicie el Administrador de dispositivos.
  • En Controladores de vídeo y juegos de sonido, haga doble clic en el dispositivo que corresponde a los altavoces internos.
  • En la ventana siguiente, vaya a la pestaña Controlador .
  • Seleccione Update driver ->Browse my computer for driver software ->Let me pick from a list of device drivers in this computer ->Select High Definition Audio Device and select Next.
  • Si aparece una ventana titulada "Update driver warning" (Advertencia del controlador de actualización), seleccione .
  • Seleccione Cerrar.
  • Si se le pide que reinicie el sistema, seleccione para reiniciar.
  • Después del reinicio, el sistema usará el controlador Microsoft HDAudio de la bandeja de entrada y no el controlador de códec de terceros. Recuerde qué controlador estaba usando antes para que pueda volver a ese controlador si desea usar la configuración óptima para el códec de audio.

Gráfico que ilustra las diferencias de latencia de ida y vuelta entre WASAPI y AudioGraph para varios tamaños de búfer.

Las diferencias en la latencia entre WASAPI y AudioGraph se deben a los siguientes motivos:

  • AudioGraph agrega un búfer de latencia en el lado de captura, con el fin de sincronizar la representación y la captura, que no proporciona WASAPI. Esta adición simplifica el código de las aplicaciones escritas mediante AudioGraph.
  • Hay otro búfer de latencia en el lado de representación de AudioGraph cuando el sistema usa búferes de más de 6 ms.
  • AudioGraph no tiene la opción de deshabilitar los efectos de audio de captura.

Ejemplos

Preguntas más frecuentes

¿No sería mejor, si todas las aplicaciones usan las nuevas API para una latencia baja? ¿No garantiza una latencia baja siempre una mejor experiencia de usuario?

No necesariamente. La baja latencia tiene sus ventajas:

  • Baja latencia significa un mayor consumo de energía. Si el sistema usa búferes de 10 ms, significa que la CPU se reactivará cada 10 ms, rellene el búfer de datos y vaya a suspensión. Sin embargo, si el sistema usa búferes de 1 ms, significa que la CPU se reactivará cada 1 ms. En el segundo escenario, esto significa que la CPU se reactivará con más frecuencia y el consumo de energía aumentará. Esto reducirá la duración de la batería.
  • La mayoría de las aplicaciones dependen de efectos de audio para proporcionar la mejor experiencia de usuario. Por ejemplo, los reproductores multimedia quieren proporcionar audio de alta fidelidad. Las aplicaciones de comunicación quieren un mínimo de eco y ruido. Agregar estos tipos de efectos de audio a una secuencia aumenta su latencia. Estas aplicaciones están más interesadas en la calidad del audio que en la latencia de audio.

En resumen, cada tipo de aplicación tiene necesidades diferentes con respecto a la latencia de audio. Si una aplicación no necesita una latencia baja, no debe usar las nuevas API para una latencia baja.

¿Todos los sistemas que se actualizan a Windows 10 y versiones posteriores se actualizarán automáticamente para admitir búferes pequeños? ¿Todos los sistemas admitirán el mismo tamaño mínimo de búfer?

No, para que un sistema admita pequeños búferes, debe tener controladores actualizados. Es necesario que los OEM decidan qué sistemas se actualizarán para admitir búferes pequeños. Además, es más probable que los sistemas más recientes admitan búferes más pequeños que los sistemas más antiguos. La latencia en los nuevos sistemas probablemente será menor que la de los sistemas más antiguos.

Si un controlador admite tamaños de búfer pequeños, ¿todas las aplicaciones de Windows 10 y versiones posteriores usarán automáticamente búferes pequeños para representar y capturar audio?

No, de forma predeterminada, todas las aplicaciones de Windows 10 y versiones posteriores usarán búferes de 10 ms para representar y capturar audio. Si una aplicación necesita usar búferes pequeños, debe usar la nueva configuración de AudioGraph o la interfaz WASAPI IAudioClient3 para hacerlo. Sin embargo, si una aplicación solicita el uso de búferes pequeños, el motor de audio comenzará a transferir audio mediante ese tamaño de búfer determinado. En ese caso, todas las aplicaciones que usan el mismo punto de conexión y modo cambiarán automáticamente a ese tamaño de búfer pequeño. Cuando se cierra la aplicación de baja latencia, el motor de audio cambiará de nuevo a búferes de 10 ms.