Audio a bassa latenza

Questo articolo illustra le modifiche alla latenza audio nelle Windows 10. Vengono illustrate le opzioni API per gli sviluppatori di applicazioni e le modifiche apportate ai driver che possono essere apportate per supportare l'audio a bassa latenza. La latenza audio è il ritardo tra quel tempo in cui viene creato il suono e quando viene sentito. La latenza audio bassa è importante per diversi scenari chiave, ad esempio:

  • Audio Pro
  • Creazione di musica
  • Comunicazioni
  • Realtà virtuale
  • Giochi

Gli obiettivi di questo documento sono:

  1. Descrivere le origini della latenza audio in Windows.
  2. Spiegare le modifiche che riducono la latenza audio nello stack audio Windows 10.
  3. Fornire un riferimento sul modo in cui gli sviluppatori di applicazioni e i produttori di hardware possono sfruttare la nuova infrastruttura per sviluppare applicazioni e driver con bassa latenza audio.

Questo articolo riguarda:

  1. Nuova API AudioGraph per scenari di creazione interattiva e multimediale.
  2. Modifiche in WASAPI per supportare la bassa latenza.
  3. Miglioramenti nelle DDI del driver.

Terminologia

Termine Descrizione
Latenza di rendering Ritardo tra il tempo in cui un'applicazione invia un buffer di dati audio alle API di rendering, fino al momento in cui viene sentito dagli altoparlanti.
Latenza di acquisizione Ritardo tra il tempo in cui un suono viene acquisito dal microfono, fino al momento in cui viene inviato alle API di acquisizione usate dall'applicazione.
Latenza round trip Ritardo tra il tempo in cui un suono viene acquisito dal microfono, elaborato dall'applicazione e inviato dall'applicazione per il rendering agli altoparlanti. È approssimativamente uguale alla latenza di rendering e alla latenza di acquisizione.
Latenza da tocco a app Ritardo tra il tempo in cui un utente tocca lo schermo fino al momento in cui il segnale viene inviato all'applicazione.
Latenza da tocco a suono Ritardo tra il tempo in cui un utente tocca lo schermo, l'evento passa all'applicazione e un suono viene sentito tramite gli altoparlanti. È uguale alla latenza di rendering e la latenza da tocco a app.

Stack audio di Windows

Il diagramma seguente mostra una versione semplificata dello stack audio di Windows.

Diagramma che mostra lo stack audio a bassa latenza con app, driver del motore audio e hardware.

Ecco un riepilogo delle latenze nel percorso di rendering: oggetti di elaborazione audio

  1. L'applicazione scrive i dati in un buffer

  2. Il motore audio legge i dati dal buffer ed elabora i dati. Carica anche gli effetti audio sotto forma di oggetti di elaborazione audio (APO). Per altre informazioni sulle API, vedere Oggetti di elaborazione audio di Windows.

  3. La latenza delle API varia in base all'elaborazione del segnale all'interno delle API.

  4. Prima di Windows 10, la latenza del motore audio era uguale a ~12 ms per le applicazioni che usano dati a virgola mobile e ~6 ms per le applicazioni che usano dati integer

  5. In Windows 10 e versioni successive la latenza è stata ridotta a 1,3 ms per tutte le applicazioni

  6. Il motore audio scrive i dati elaborati in un buffer.

  7. Prima di Windows 10, il buffer era sempre impostato su ~10 ms.

  8. A partire da Windows 10, le dimensioni del buffer vengono definite dal driver audio . Altri dettagli sul buffer sono descritti più avanti in questo articolo.

  9. Il driver Audio legge i dati dal buffer e li scrive nell'hardware.

  10. L'hardware può anche elaborare nuovamente i dati sotto forma di più effetti audio.

  11. L'utente sente l'audio dall'altoparlante.

Ecco un riepilogo della latenza nel percorso di acquisizione:

  1. L'audio viene acquisito dal microfono.

  2. L'hardware può elaborare i dati. Ad esempio, per aggiungere effetti audio.

  3. Il driver legge i dati dall'hardware e scrive i dati in un buffer.

  4. Prima di Windows 10, questo buffer era sempre impostato su 10 ms.

  5. A partire da Windows 10, la dimensione del buffer è definita dal driver audio (altri dettagli di seguito).

  6. Il motore audio legge i dati dal buffer e li elabora. Carica anche gli effetti audio sotto forma di oggetti di elaborazione audio (APO).

  7. La latenza delle API varia in base all'elaborazione del segnale all'interno delle API.

  8. Prima di Windows 10, la latenza del motore audio era uguale a ~6 ms per le applicazioni che usano dati a virgola mobile e ~0ms per le applicazioni che usano dati integer.

  9. In Windows 10 e versioni successive, la latenza è stata ridotta a ~0ms per tutte le applicazioni.

  10. L'applicazione segnala che i dati sono disponibili per la lettura, non appena il motore audio termina con l'elaborazione. Lo stack audio offre anche la possibilità di modalità esclusiva. In tal caso, i dati ignorano il motore audio e passano direttamente dall'applicazione al buffer da cui il driver lo legge. Tuttavia, se un'applicazione apre un endpoint in modalità esclusiva, non esiste un'altra applicazione in grado di usare tale endpoint per eseguire il rendering o l'acquisizione dell'audio.

Un'altra alternativa comune per le applicazioni che richiedono bassa latenza consiste nell'usare il modello ASIO (Audio Stream Input/Output), che usa la modalità esclusiva. Dopo l'installazione di un driver ASIO di terze parti, le applicazioni possono inviare dati direttamente dall'applicazione al driver ASIO. Tuttavia, l'applicazione deve essere scritta in modo tale che comunica direttamente con il driver ASIO.

Entrambe le alternative (modalità esclusiva e ASIO) hanno le proprie limitazioni. Forniscono bassa latenza, ma presentano limitazioni proprie (alcune delle quali sono state descritte in precedenza). Di conseguenza, il motore audio è stato modificato, per ridurre la latenza, mantenendo al tempo stesso la flessibilità.

Miglioramenti dello stack audio

Windows 10 e versioni successive sono state migliorate in tre aree per ridurre la latenza:

  1. Tutte le applicazioni che usano l'audio vedranno una riduzione di 4,5-16 ms nella latenza di round trip (come illustrato nella sezione precedente) senza modifiche al codice o aggiornamenti del driver, rispetto a Windows 8.1.
    1. Le applicazioni che usano dati a virgola mobile avranno una latenza inferiore di 16 ms.
    2. Le applicazioni che usano dati integer avranno una latenza inferiore di 4,5 ms.
  2. I sistemi con driver aggiornati forniranno una latenza di round trip ancora più bassa:
    1. I driver possono usare nuove DDI per segnalare le dimensioni supportate del buffer usato per trasferire i dati tra Windows e l'hardware. I trasferimenti di dati non devono sempre usare buffer da 10 ms, come nelle versioni precedenti di Windows. Il driver può invece specificare se può usare buffer di piccole dimensioni, ad esempio 5 ms, 3 ms, 1 ms e così via.
    2. Le applicazioni che richiedono bassa latenza possono usare nuove API audio (AudioGraph o WASAPI), per eseguire query sulle dimensioni del buffer supportate dal driver e selezionare quella che verrà usata per il trasferimento dei dati da/verso l'hardware.
  3. Quando un'applicazione usa dimensioni del buffer inferiori a una determinata soglia per eseguire il rendering e l'acquisizione dell'audio, Windows entra in una modalità speciale, in cui gestisce le risorse in modo da evitare interferenze tra il flusso audio e altri sottosistemi. Ciò ridurrà le interruzioni nell'esecuzione del sottosistema audio e ridurrà al minimo la probabilità di errori audio. Quando l'applicazione arresta lo streaming, Windows torna alla modalità di esecuzione normale. Il sottosistema audio è costituito dalle risorse seguenti:
    1. Thread del motore audio che elabora audio a bassa latenza.
    2. Tutti i thread e gli interrupt registrati dal driver (usando le nuove DDI descritte nella sezione relativa alla registrazione delle risorse del driver).
    3. Alcuni o tutti i thread audio delle applicazioni che richiedono buffer di piccole dimensioni e da tutte le applicazioni che condividono lo stesso grafico del dispositivo audio (ad esempio, la stessa modalità di elaborazione del segnale) con qualsiasi applicazione che ha richiesto buffer di piccole dimensioni:
  4. Callback audioGraph nel percorso di streaming.
  5. Se l'applicazione usa WASAPI, solo gli elementi di lavoro inviati all'API della coda di lavoro in tempo reale o MFCreateMFByteStreamOnStreamEx e sono stati contrassegnati come "Audio" o "ProAudio".

Miglioramenti delle API

Le due API di Windows 10 seguenti offrono funzionalità a bassa latenza:

Per determinare quale delle due API usare:

  • Prediligi AudioGraph, ove possibile per lo sviluppo di nuove applicazioni.
  • Usare SOLO WASAPI, se:
    • È necessario più controllo di quello fornito da AudioGraph.
    • È necessaria una latenza inferiore rispetto a quella fornita da AudioGraph.

La sezione degli strumenti di misurazione di questo articolo illustra le misurazioni specifiche di un sistema Haswell usando il driver HDAudio in arrivo.

Le sezioni seguenti illustrano le funzionalità a bassa latenza in ogni API. Come indicato nella sezione precedente, affinché il sistema ottenga la latenza minima, deve avere driver aggiornati che supportano dimensioni di buffer ridotte.

AudioGraph

AudioGraph è una nuova API piattaforma UWP (Universal Windows Platform) in Windows 10 e versioni successive destinate a realizzare scenari di creazione interattiva e musicale con facilità. AudioGraph è disponibile in diversi linguaggi di programmazione (C++, C#, JavaScript) e ha un modello di programmazione semplice e ricco di funzionalità.

Per indirizzare scenari a bassa latenza, AudioGraph fornisce la proprietà AudioGraphSettings::QuantumSizeSelectionMode . Questa proprietà può essere uno dei valori illustrati nella tabella seguente:

Valore Descrizione
SystemDefault Imposta il buffer sulla dimensione del buffer predefinita (~10 ms)
Bassa Latenza Imposta il buffer sul valore minimo supportato dal driver
ClosestToDesired Imposta la dimensione del buffer per essere uguale al valore definito dalla proprietà DesiredSamplesPerQuantum o su un valore vicino a DesiredSamplesPerQuantum, supportato dal driver.

L'esempio AudioCreation illustra come usare AudioGraph per bassa latenza. Il frammento di codice seguente illustra come impostare le dimensioni minime del buffer:

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

API sessione audio windows (WASAPI)

A partire da Windows 10, WASAPI è stato migliorato per:

  • Consentire a un'applicazione di individuare l'intervallo di dimensioni del buffer, ovvero i valori di periodicità, supportati dal driver audio di un determinato dispositivo audio. Ciò consente a un'applicazione di scegliere tra le dimensioni predefinite del buffer (10 ms) o un buffer di piccole dimensioni (minore di 10 ms) quando si apre un flusso in modalità condivisa. Se un'applicazione non specifica una dimensione del buffer, userà le dimensioni predefinite del buffer.
  • Consentire a un'applicazione di individuare il formato corrente e la periodicità del motore audio. Ciò consente alle applicazioni di eseguire lo snap alle impostazioni correnti del motore audio.
  • Consentire a un'app di specificare che desidera eseguire il rendering/acquisizione nel formato specificato senza alcun ricampionamento dal motore audio

Le funzionalità precedenti saranno disponibili in tutti i dispositivi Windows. Tuttavia, alcuni dispositivi con risorse sufficienti e driver aggiornati offrono un'esperienza utente migliore rispetto ad altri.

La funzionalità precedente è fornita da una nuova interfaccia, denominata IAudioClient3, che deriva da IAudioClient2.

IAudioClient3 definisce i seguenti 3 metodi:

Metodo Descrizione
GetCurrentSharedModeEnginePeriod Restituisce il formato corrente e la periodicità del motore audio
GetSharedModeEnginePeriod Restituisce l'intervallo di periodicità supportate dal motore per il formato di flusso specificato
InitializeSharedAudioStream Inizializza un flusso condiviso con la periodicità specificata

L'esempio WASAPIAudio illustra come usare IAudioClient3 per bassa latenza.

Il frammento di codice seguente mostra come un'app per la creazione di musica può funzionare nell'impostazione di latenza più bassa supportata dal 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)) {
       ...
}

Microsoft consiglia anche alle applicazioni che usano WASAPI di usare anche l'API Coda di lavoro in tempo reale o mfCreateMFByteStreamOnStreamEx per creare elementi di lavoro e contrassegnarli come Audio o Pro Audio anziché i propri thread. Ciò consentirà a Windows di gestirli in modo da evitare l'interferenza dei sottosistemi non audio. Al contrario, tutti i thread AudioGraph vengono gestiti automaticamente da Windows. Il frammento di codice seguente dell'esempio WASAPIAudio illustra come usare le API della coda di lavoro 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 );

In alternativa, il frammento di codice seguente illustra come usare le API della coda di lavoro RT.

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

Infine, gli sviluppatori di applicazioni che usano WASAPI devono contrassegnare i propri flussi con la categoria audio e se usare la modalità di elaborazione del segnale non elaborato, in base alla funzionalità di ogni flusso. Microsoft consiglia che tutti i flussi audio non usino la modalità di elaborazione del segnale non elaborato, a meno che non vengano comprese le implicazioni. La modalità non elaborata ignora tutte le elaborazioni di segnale scelte dall'OEM, quindi:

  • Il segnale di rendering per un determinato endpoint potrebbe essere non ottimale.
  • Il segnale di acquisizione potrebbe venire in un formato che l'applicazione non può comprendere.
  • La latenza potrebbe essere migliorata.

Miglioramenti del driver

Per consentire ai driver audio di supportare bassa latenza, Windows 10 e versioni successive forniscono le funzionalità seguenti:

  1. [Obbligatorio] Dichiarare le dimensioni minime del buffer supportate in ogni modalità.
  2. [Facoltativo, ma consigliato] Migliorare il coordinamento per il flusso di dati tra il driver e Windows.
  3. [Facoltativo, ma consigliato] Registrare le risorse del driver (interruzioni, thread), in modo che possano essere protette da Windows in scenari a bassa latenza. I driver di funzione miniport HDAudio enumerati dal driver del bus HDAudio in arrivo hdaudbus.sys non devono registrare gli interruzioni DI HDAudio, perché questa operazione è già stata eseguita da hdaudbus.sys. Tuttavia, se il driver miniport crea i propri thread, deve registrarli.

Le tre sezioni seguenti illustrano ogni nuova funzionalità in modo più approfondito.

Dichiarare le dimensioni minime del buffer

Un driver opera sotto vari vincoli durante lo spostamento di dati audio tra Windows, il driver e l'hardware. Questi vincoli possono essere dovuti al trasporto hardware fisico che sposta i dati tra memoria e hardware oppure a causa dei moduli di elaborazione dei segnali all'interno dell'hardware o del DSP associato.

A partire da Windows 10 versione 1607, il driver può esprimere le relative funzionalità di dimensioni del buffer usando la proprietà del dispositivo DEVPKEY_KsAudio_PacketSize_Constraints2. Questa proprietà consente all'utente di definire le dimensioni minime del buffer assoluto supportate dal driver e vincoli di dimensione del buffer specifici per ogni modalità di elaborazione del segnale. I vincoli specifici della modalità devono essere superiori alle dimensioni minime del buffer dei driver, altrimenti vengono ignorati dallo stack audio.

Ad esempio, il frammento di codice seguente mostra come un driver può dichiarare che la dimensione minima supportata del buffer è 2 ms, ma la modalità predefinita supporta 128 fotogrammi, che corrisponde a 3 ms se si presuppone una frequenza di esempio da 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
        },
    }
};

Per informazioni più approfondite su queste strutture, vedere gli articoli seguenti:

Inoltre, l'esempio sysvad mostra come usare queste proprietà, in modo che un driver dichiari il buffer minimo per ogni modalità.

Migliorare il coordinamento tra driver e sistema operativo

Le DDI descritte in questa sezione consentono al driver di:

  • Indicare chiaramente quale metà (pacchetto) del buffer è disponibile per Windows, anziché il sistema operativo indovinando in base a una posizione di collegamento codec. In questo modo Windows consente di ripristinare gli errori audio più velocemente.
  • Facoltativamente ottimizzare o semplificare i trasferimenti di dati nel buffer WaveRT. La quantità di vantaggio qui dipende dalla progettazione del motore DMA o da un altro meccanismo di trasferimento dei dati tra il buffer WaveRT e l'hardware (possibilmente DSP).
  • "Burst" ha acquisito i dati più velocemente rispetto al tempo reale se il driver ha accumulato internamente i dati acquisiti. Si tratta principalmente di scenari di attivazione vocale, ma possono essere applicati anche durante lo streaming normale.
  • Fornire informazioni sul timestamp sulla posizione corrente del flusso anziché su Windows indovinando, potenzialmente consentendo informazioni precise sulla posizione.

Questo DDI è utile nel caso in cui viene usato un DSP. Tuttavia, un driver audio HD standard o altri semplici progetti di buffer DMA circolare potrebbe non trovare molto vantaggio in questi nuovi DDI elencati qui.

Diverse routine del driver restituiscono timestamp del contatore delle prestazioni di Windows che riflettono il momento in cui gli esempi vengono acquisiti o presentati dal dispositivo.

Nei dispositivi che dispongono di pipeline DSP complesse e elaborazione dei segnali, il calcolo di un timestamp accurato può essere impegnativo e deve essere eseguito in modo ponderato. I timestamp non devono riflettere il momento in cui i campioni sono stati trasferiti a o da Windows al DSP.

Per calcolare i valori del contatore delle prestazioni, il driver e il DSP potrebbero usare alcuni dei metodi seguenti.

  • All'interno del DSP tenere traccia dei timestamp di esempio usando un orologio ASP interno.
  • Tra il driver e il DSP, calcolare una correlazione tra il contatore delle prestazioni di Windows e l'orologio a parete DSP. Le procedure per questo possono variare da semplici (ma meno precise) a piuttosto complesse o nuove (ma più precise).
  • Fattore in eventuali ritardi costanti a causa di algoritmi di elaborazione del segnale o di trasporto hardware o di pipeline, a meno che questi ritardi non siano altrimenti conteggiati.

L'esempio sysvad illustra come usare le DDI precedenti.

Registrare le risorse del driver

Per garantire un'operazione senza interruzioni, i driver audio devono registrare le risorse di streaming con Portcls. Ciò consente a Windows di gestire le risorse per evitare l'interferenza tra streaming audio e altri sottosistemi.

Le risorse di flusso sono tutte le risorse usate dal driver audio per elaborare i flussi audio o garantire il flusso di dati audio. Sono supportati solo due tipi di risorse di flusso: interrupt e thread di proprietà del driver. I driver audio devono registrare una risorsa dopo aver creato la risorsa e annullare la registrazione della risorsa prima di eliminarla.

I driver audio possono registrare le risorse in fase di inizializzazione quando il driver viene caricato o in fase di esecuzione, ad esempio quando è presente un ribilanciamento della risorsa di I/O. Portcls usa uno stato globale per tenere traccia di tutte le risorse di streaming audio.

In alcuni casi d'uso, ad esempio quelli che richiedono audio a bassa latenza, Windows tenta di isolare le risorse registrate del driver audio da interferenze da altre attività del sistema operativo, dell'applicazione e dell'hardware. Il sistema operativo e il sottosistema audio eseguono questa operazione in base alle esigenze senza interagire con il driver audio, ad eccezione della registrazione del driver audio delle risorse.

Questo requisito per registrare le risorse di flusso implica che tutti i driver presenti nel percorso della pipeline di streaming devono registrare le risorse direttamente o indirettamente con Portcls. Il driver miniport audio include queste opzioni:

  • Il driver miniport audio è il driver inferiore dello stack (interfacciando direttamente h/w), in questo caso il driver conosce le risorse di flusso e può registrarle con Portcls.
  • Il driver miniport audio è audio in streaming con l'aiuto di altri driver (ad esempio driver audio bus). Questi altri driver usano anche risorse che devono essere registrate con Portcls. Questi stack di driver paralleli/bus possono esporre un'interfaccia pubblica (o privata, se un singolo fornitore possiede tutti i driver) che i driver audio miniport usano per raccogliere queste informazioni.
  • Il driver miniport audio è l'audio in streaming con l'aiuto di altri driver (ad esempio hdaudbus). Questi altri driver usano anche risorse che devono essere registrate con Portcls. Questi driver paralleli/bus possono collegarsi a Portcls e registrare direttamente le risorse. I driver miniport audio devono informare Portcls che dipendono dalle risorse di questi altri dispositivi paralleli/bus (PDO). L'infrastruttura audio HD usa questa opzione, ovvero il driver audio-bus HD collega con Portcls ed esegue automaticamente i passaggi seguenti:
    • registra le risorse del conducente dell'autobus e
    • notifica a Portcls che le risorse figlio dipendono dalle risorse dell'elemento padre. Nell'architettura audio HD, il driver miniport audio deve solo registrare le proprie risorse thread di proprietà del driver.

Note:

  • I driver di funzione miniport HDAudio enumerati dal driver del bus HDAudio in arrivo hdaudbus.sys non devono registrare gli interrupt di HDAudio, perché questa operazione è già eseguita da hdaudbus.sys. Tuttavia, se il driver miniport crea i propri thread, è necessario registrarli.
  • I driver che collegano con Portcls solo per la registrazione delle risorse di streaming devono aggiornare i file INFS per includere wdmaudio.inf e copiare portcls.sys (e file dipendenti). Una nuova sezione di copia INF è definita in wdmaudio.inf per copiare solo tali file.
  • I driver audio eseguiti solo in Windows 10 e versioni successive possono essere collegati a:
  • I driver audio che devono essere eseguiti in un sistema operativo di livello inferiore possono usare l'interfaccia seguente (il miniport può chiamare QueryInterface per l'interfaccia IID_IPortClsStreamResourceManager e registrare le relative risorse solo quando PortCls supporta l'interfaccia).
  • Queste DDI usano questa enumerazione e struttura:

Infine, i driver che si collegano a PortCls esclusivamente allo scopo di registrare le risorse devono aggiungere le due righe seguenti nella sezione DDInstall di inf. I driver miniport audio non hanno bisogno di questo perché hanno già inclusione/esigenze in wdmaudio.inf.

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

Le righe precedenti assicurano che siano installati PortCls e i relativi file dipendenti.

Strumenti di misurazione

Per misurare la latenza di andata e ritorno, l'utente può usare gli strumenti per riprodurre impulsi tramite gli altoparlanti e catturarli tramite il microfono. Misurano il ritardo del percorso seguente:

  1. L'applicazione chiama l'API di rendering (AudioGraph o WASAPI) per riprodurre l'impulso
  2. L'audio viene riprodotto tramite gli altoparlanti
  3. L'audio viene acquisito dal microfono
  4. L'impulso viene rilevato dall'API di acquisizione (AudioGraph o WASAPI) per misurare la latenza di round trip per dimensioni del buffer diverse, gli utenti devono installare un driver che supporta buffer di piccole dimensioni. Il driver HDAudio in arrivo è stato aggiornato per supportare dimensioni del buffer tra 128 campioni (2.66ms@48kHz) e 480 campioni (10ms@48kHz). La procedura seguente illustra come installare il driver HDAudio in arrivo (che fa parte di tutti i Windows 10 e sku successivi):
  • Avviare Gestione dispositivi.
  • In Audio video e controller di gioco fare doppio clic sul dispositivo che corrisponde agli altoparlanti interni.
  • Nella finestra successiva passare alla scheda Driver .
  • Selezionare Aggiorna driver ->Browse my computer for driver software ->Let me pick from a list of device drivers in this computer ->Select High Definition Audio Device (Seleziona dispositivo audio ad alta definizione ) e seleziona Avanti.
  • Se viene visualizzata una finestra denominata "Aggiorna avviso driver", selezionare .
  • Selezionare Chiudi.
  • Se viene chiesto di riavviare il sistema, selezionare per il riavvio.
  • Dopo il riavvio, il sistema usa il driver Microsoft HDAudio in arrivo e non il driver codec di terze parti. Ricorda il driver usato in precedenza in modo da poter eseguire il fallback a tale driver se vuoi usare le impostazioni ottimali per il tuo codec audio.

Grafico che illustra le differenze di latenza di round trip tra WASAPI e AudioGraph per diverse dimensioni del buffer.

Le differenze nella latenza tra WASAPI e AudioGraph sono dovute ai motivi seguenti:

  • AudioGraph aggiunge un buffer di latenza sul lato acquisizione, per sincronizzare il rendering e l'acquisizione, che non viene fornito da WASAPI. Questa aggiunta semplifica il codice per le applicazioni scritte con AudioGraph.
  • Esiste un altro buffer di latenza nel lato di rendering di AudioGraph quando il sistema usa buffer maggiori di 6 ms.
  • AudioGraph non ha la possibilità di disabilitare l'acquisizione degli effetti audio.

Esempi

Domande frequenti

Non sarebbe meglio, se tutte le applicazioni usano le nuove API per una bassa latenza? La latenza bassa non garantisce sempre un'esperienza utente migliore?

Non necessariamente. La bassa latenza presenta compromessi:

  • Bassa latenza significa un consumo di energia superiore. Se il sistema usa buffer da 10 ms, significa che la CPU si sveglierà ogni 10 ms, riempire il buffer dei dati e passare alla sospensione. Tuttavia, se il sistema usa buffer da 1 ms, significa che la CPU verrà riattivata ogni 1 ms. Nel secondo scenario, ciò significa che la CPU si riattiva più spesso e il consumo di energia aumenterà. Ciò ridurrà la durata della batteria.
  • La maggior parte delle applicazioni si basa sugli effetti audio per offrire la migliore esperienza utente. Ad esempio, i lettori multimediali vogliono fornire audio ad alta fedeltà. Le applicazioni di comunicazione desiderano un eco e un rumore minimi. L'aggiunta di questi tipi di effetti audio a un flusso aumenta la latenza. Queste applicazioni sono più interessate alla qualità audio che alla latenza audio.

In sintesi, ogni tipo di applicazione ha esigenze diverse per quanto riguarda la latenza audio. Se un'applicazione non necessita di bassa latenza, non deve usare le nuove API per una bassa latenza.

Tutti i sistemi che vengono aggiornati a Windows 10 e versioni successive verranno aggiornati automaticamente per supportare buffer di piccole dimensioni? Tutti i sistemi supporteranno le stesse dimensioni minime del buffer?

No, per consentire a un sistema di supportare buffer di piccole dimensioni, è necessario avere driver aggiornati. Spetta agli OEM decidere quali sistemi verranno aggiornati per supportare buffer di piccole dimensioni. Inoltre, è più probabile che i sistemi più recenti supportino buffer più piccoli rispetto ai sistemi meno recenti. La latenza nei nuovi sistemi sarà probabilmente inferiore a quella dei sistemi meno recenti.

Se un driver supporta dimensioni di buffer ridotte, tutte le applicazioni in Windows 10 e successivamente usano automaticamente buffer di piccole dimensioni per eseguire il rendering e l'acquisizione dell'audio?

No, per impostazione predefinita tutte le applicazioni in Windows 10 e versioni successive useranno buffer da 10 ms per eseguire il rendering e l'acquisizione dell'audio. Se un'applicazione deve usare buffer di piccole dimensioni, è necessario usare le nuove impostazioni AudioGraph o l'interfaccia IAudioClient3 WASAPI, per farlo. Tuttavia, se un'applicazione richiede l'utilizzo di buffer di piccole dimensioni, il motore audio inizierà a trasferire l'audio usando quella determinata dimensione del buffer. In tal caso, tutte le applicazioni che usano lo stesso endpoint e la stessa modalità passeranno automaticamente a tale dimensione di buffer ridotto. Quando l'applicazione a bassa latenza viene chiusa, il motore audio passerà nuovamente a buffer da 10 ms.