Audio a bassa latenza
Questo articolo illustra le modifiche alla latenza audio in 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 momento in cui viene creato il suono e quando viene sentito. La latenza audio bassa è importante per diversi scenari chiave, ad esempio:
- Audio professionale
- Creazione di musica
- Comunicazioni
- Realtà virtuale
- Giochi
Gli obiettivi di questo documento sono:
- Descrivere le origini della latenza audio in Windows.
- Spiegare le modifiche che riducono la latenza audio nello stack audio di Windows 10.
- 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 illustra:
- L'API AudioGraph per scenari di creazione multimediale e interattiva.
- Modifiche in WASAPI per supportare una bassa latenza.
- 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 del percorso di andata e ritorno | Ritardo tra il momento in cui un suono viene acquisito dal microfono, elaborato e inviato dall'applicazione per essere riprodotto dagli altoparlanti. È approssimativamente uguale alla latenza di rendering e alla latenza di acquisizione. |
Latenza dal tocco all'app | Ritardo tra il tempo in cui un utente tocca lo schermo fino al momento in cui il segnale viene inviato all'applicazione. |
Latenza del tocco al 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 + alla latenza di tocco all'applicazione. |
Stack audio di Windows
Il diagramma seguente mostra una versione semplificata dello stack audio di Windows.
Ecco un riepilogo delle latenze nel percorso di rendering: oggetti di elaborazione audio
L'applicazione scrive i dati in un buffer
Il motore audio legge i dati dal buffer ed elabora i dati. Carica anche effetti audio sotto forma di oggetti di elaborazione audio (API). Per ulteriori informazioni sugli APO, vedere gli oggetti di elaborazione audio di Windows.
La latenza delle API varia in base all'elaborazione dei segnali all'interno delle API.
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 interi
In Windows 10 e versioni successive la latenza è stata ridotta a 1,3 ms per tutte le applicazioni
Il motore audio scrive i dati elaborati in un buffer.
Prima di Windows 10, il buffer era sempre impostato su ~10 ms.
A partire da Windows 10, le dimensioni del buffer sono definite dal driver audio (altri dettagli sul buffer sono descritti più avanti in questo articolo).
Il driver audio legge i dati dal buffer e li scrive nell'hardware.
L'hardware può anche elaborare nuovamente i dati sotto forma di più effetti audio.
L'utente sente l'audio dall'altoparlante.
Ecco un riepilogo della latenza nel percorso di acquisizione:
L'audio viene acquisito dal microfono.
L'hardware può elaborare i dati. Ad esempio, per aggiungere effetti audio.
Il driver legge i dati dall'hardware e scrive i dati in un buffer.
Prima di Windows 10, questo buffer era sempre impostato su 10 ms.
A partire da Windows 10, la dimensione del buffer è definita dal driver audio (altri dettagli di seguito).
Il motore audio legge i dati dal buffer e li elabora. Carica anche effetti audio sotto forma di oggetti di elaborazione audio (API).
La latenza delle API varia in base all'elaborazione dei segnali all'interno delle API.
Prima di Windows 10, la latenza del motore audio era uguale a ~6 ms per le applicazioni che usano dati a virgola mobile e ~0 ms per le applicazioni che usano dati integer.
In Windows 10 e versioni successive la latenza è stata ridotta a ~0 ms per tutte le applicazioni.
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 operare in 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 che un utente installa 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 limitazioni proprie. 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 stati migliorati in tre aree per ridurre la latenza:
- Tutte le applicazioni che usano l'audio vedranno una riduzione della latenza di round trip da 4,5 a 16 ms (come illustrato nella sezione precedente) senza modifiche al codice o aggiornamenti del driver, rispetto a Windows 8.1.
- Le applicazioni che usano dati a virgola mobile avranno una latenza inferiore di 16 ms.
- Le applicazioni che usano dati integer avranno una latenza inferiore di 4,5 ms.
- I sistemi con driver aggiornati forniranno una latenza di round trip ancora più bassa:
- I driver possono usare le DDI a bassa latenza 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.
- Le applicazioni che richiedono bassa latenza possono usare le API audio a bassa latenza (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 e verso l'hardware.
- 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 lo streaming 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:
- Thread del motore audio che elabora l'audio a bassa latenza.
- Tutti i thread e gli interrupt registrati dal driver (usando le DDI a bassa latenza descritte nella sezione relativa alla registrazione delle risorse del driver).
- 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:
- Callback AudioGraph nel percorso di streaming.
- Se l'applicazione usa WASAPI, allora solo gli elementi di lavoro inviati all'API della coda di lavoro Real-Time o MFCreateMFByteStreamOnStreamEx che 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 WASAPI solo se:
- È necessario un maggiore controllo rispetto a quello fornito da AudioGraph.
- È necessaria una latenza inferiore a quella fornita da AudioGraph.
La sezione strumenti di misurazione di questo articolo mostra 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 raggiunga la latenza minima, deve avere driver aggiornati che supportano piccole dimensioni del buffer.
AudioGraph
AudioGraph è un'API della piattaforma UWP (Universal Windows Platform) in Windows 10 e versioni successive che consente di 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 definire scenari a bassa latenza, AudioGraph fornisce la proprietà AudioGraphSettings::QuantumSizeSelectionMode. Questa proprietà può essere uno qualsiasi dei valori illustrati nella tabella seguente:
Valore | Descrizione |
---|---|
Impostazioni predefinite di sistema | Imposta il buffer sulle dimensioni predefinite del buffer (~10 ms) |
Latenza più Bassa | Imposta il buffer sul valore minimo supportato dal driver |
Più Vicino al Desiderato | Imposta le dimensioni del buffer in modo che siano uguali al valore definito dalla proprietà DesiredSamplesPerQuantum o a un valore simile a DesiredSamplesPerQuantum supportato dal driver. |
L'esempio di AudioCreation illustra come usare AudioGraph per una 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);
Windows Audio Session API (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 piccolo (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 agganciarsi alle impostazioni correnti del motore audio.
- Consenti a un'app di specificare che desidera eseguire il rendering/acquisizione nel formato specificato senza ricampionamento da parte del motore audio
Le funzionalità precedenti saranno disponibili in tutti i dispositivi Windows. Tuttavia, alcuni dispositivi con risorse sufficienti e driver aggiornati offriranno un'esperienza utente migliore rispetto ad altri.
La funzionalità precedente è fornita da un'interfaccia denominata IAudioClient3, che deriva da IAudioClient2.
IAudioClient3 definisce i 3 metodi seguenti:
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 una bassa latenza.
Il frammento di codice seguente mostra come un'app per la creazione di musica può operare 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)) {
...
}
Inoltre, Microsoft consiglia alle applicazioni che usano WASAPI di usare anche l'API Real-Time coda di lavoro o l'API MFCreateMFByteStreamOnStreamEx per creare attività di lavoro e contrassegnarle come Audio o Pro Audio, invece dei propri thread. Ciò consentirà a Windows di gestirli in modo da evitare sottosistemi non audio di interferenza. 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 flussi con la categoria audio e se usare la modalità di elaborazione del segnale non elaborato, in base alle 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à raw ignora tutte le elaborazioni dei segnali 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 è in grado di comprendere.
- La latenza potrebbe essere migliorata.
Miglioramenti dei driver
Per consentire ai driver audio di supportare bassa latenza, Windows 10 e versioni successive forniscono le funzionalità seguenti:
- [Obbligatorio] Dichiarare le dimensioni minime del buffer supportate in ogni modalità.
- [Facoltativo, ma consigliato] Migliorare il coordinamento del flusso di dati tra il driver e Windows.
- [Facoltativo, ma consigliato] Registrare le risorse del driver (interrupt, thread), in modo che possano essere protette da Windows in scenari a bassa latenza. I driver della funzione miniport HDAudio che sono enumerati dal driver del bus HDAudio integrato hdaudbus.sys non hanno bisogno di registrare gli interrupt HDAudio, poiché questa operazione è già stata eseguita da hdaudbus.sys. Tuttavia, se il driver miniport crea i propri thread, deve registrarli.
Le tre sezioni seguenti illustrano in modo più approfondito ogni funzionalità.
Dichiarare le dimensioni minime del buffer
Un driver opera in vari vincoli quando si spostano 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 o 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 sue capacità di dimensionamento del buffer utilizzando la proprietà del dispositivo DEVPKEY_KsAudio_PacketSize_Constraints2. Questa proprietà consente all'utente di definire la dimensione minima assoluta del buffer supportata dal driver e vincoli di dimensione del buffer specifici per ogni modalità di elaborazione del segnale. I vincoli specifici della modalità devono essere superiori alla dimensione minima del buffer del driver, altrimenti vengono ignorati dallo stack audio.
Ad esempio, il frammento di codice seguente mostra come un driver può dichiarare che la dimensione minima assoluta supportata del buffer è 2 ms, ma la modalità predefinita supporta 128 fotogrammi, che corrisponde a 3 ms se si presuppone una frequenza di campionamento di 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:
- KSAUDIO_PACKETSIZE_CONSTRAINTS struttura
- KSAUDIO_PACKETSIZE_CONSTRAINTS2 struttura
- KSAUDIO_PACKETSIZE_PROCESSINGMODE_CONSTRAINT struttura
Inoltre, l'esempio sysvad illustra come usare queste proprietà, affinché 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é lasciare che il sistema operativo ipotizzi basandosi su una posizione del collegamento codec. Ciò consente a Windows di eseguire il ripristino da errori audio più velocemente.
- Facoltativamente, ottimizzare o semplificare i trasferimenti di dati all'interno e all'esterno del buffer WaveRT. La quantità di vantaggio 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" cattura i dati più rapidamente del 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 relative alla posizione corrente del flusso, anziché fare in modo che Windows indovini, consentendo potenzialmente di ottenere informazioni accurate sulla posizione.
Questa DDI è utile nel caso in cui viene usato un DSP. Tuttavia, un driver audio HD standard o altre semplici progettazioni di buffer DMA circolare potrebbero non trarre grandi vantaggi nelle DDI elencate qui.
Diverse routine dei driver restituiscono timestamp del contatore delle prestazioni di Windows che riflettono il momento in cui i campioni 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 complesso e deve essere eseguito attentamente. I timestamp non devono riflettere il momento in cui i campioni sono stati trasferiti da o verso Windows al DSP.
Per calcolare i valori dei contatori delle prestazioni, il driver e il DSP potrebbero usare alcuni dei metodi seguenti.
- All'interno del DSP, traccia i timestamp dei campioni utilizzando un orologio interno DSP.
- 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 innovative (ma più precise).
- Tenere conto di eventuali ritardi costanti dovuti ad algoritmi di elaborazione dei segnali o a trasporti hardware o pipeline, a meno che questi ritardi non vengano altrimenti rilevati.
L'esempio sysvad illustra come usare le DDI precedenti.
Registrare le risorse del driver
Per garantire un'operazione senza problemi, i driver audio devono registrare le risorse di streaming con Portcls. In questo modo Windows può gestire le risorse per evitare interferenze tra lo 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 gestiti dal 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 al bisogno senza interagire con il driver audio, ad eccezione della registrazione delle risorse da parte del driver audio.
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 alla base dello stack (interfacciandosi direttamente con l'hardware); in questo caso, il driver conosce le risorse di flusso e può registrarle con Portcls.
- Il driver miniport audio sta riproducendo audio in streaming con l'aiuto di altri driver (ad esempio i driver del bus audio). 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 sta trasmettendo audio con l'assistenza 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 della loro dipendenza 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 del bus e
- notifica a Portcls che le risorse dei figli dipendono dalle risorse dei genitori. Nell'architettura audio HD, il driver miniport audio deve solo registrare le risorse di thread appartenenti al driver.
Note:
- I driver di funzione miniport HDAudio enumerati dal driver del bus HDAudio predefinito hdaudbus.sys non devono registrare gli interrupt HDAudio, perché questa operazione è già stata eseguita da hdaudbus.sys. Tuttavia, se il driver miniport crea i propri thread, deve registrarli.
- I driver che si collegano a Portcls solo per la registrazione delle risorse di streaming devono aggiornare i file INFS per includere wdmaudio.inf e copiare portcls.sys (e i file dipendenti). Una nuova sezione di copia INF è definita in wdmaudio.inf per copiare solo tali file.
- I driver audio che funzionano solo in Windows 10 e versioni successive possono creare hard link 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 registrarne le risorse solo quando PortCls supporta l'interfaccia).
- Queste DDI usano questa enumerazione e struttura:
Infine, i driver che collegano PortCls per l'unico scopo della registrazione delle risorse devono aggiungere le due righe seguenti nella sezione DDInstall del loro file inf. I driver miniport audio non hanno bisogno di questo perché hanno già i termini "include/needs" nel file 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ò utilizzare strumenti che emettono impulsi tramite gli altoparlanti e li catturano tramite il microfono. Misurano il ritardo del percorso seguente:
- L'applicazione chiama l'API di rendering (AudioGraph o WASAPI) per riprodurre l'impulso
- L'audio viene riprodotto tramite gli altoparlanti
- L'audio viene acquisito dal microfono
- Per misurare la latenza di andata e ritorno per diverse dimensioni del buffer, l'impulso viene rilevato dall'API di acquisizione (AudioGraph o WASAPI). Gli utenti devono installare un driver che supporta buffer piccoli. Il driver HDAudio in arrivo è stato aggiornato per supportare dimensioni del buffer tra 128 campioni (2.66ms@48kHz) e 480 campioni (10ms@48kHz). I passaggi seguenti illustrano come installare il driver HDAudio in arrivo (che fa parte di tutti gli SKU di Windows 10 e versioni successive):
- Avviare Gestione dispositivi.
- In controller audio, video e giochi, fare doppio clic sul dispositivo che corrisponde agli altoparlanti interni.
- Nella finestra successiva, passare alla scheda driver.
- Selezionare Aggiorna driver ->Cerca il software del driver nel mio computer ->Permettimi di scegliere da un elenco di driver di dispositivo in questo computer ->Seleziona Dispositivo Audio ad Alta Definizione e seleziona Avanti.
- Se viene visualizzata una finestra denominata "Aggiorna avviso driver", selezionare Sì.
- Seleziona chiudi.
- Se viene chiesto di riavviare il sistema, selezionare Sì per riavviare.
- Dopo il riavvio, il sistema utilizzerà il driver Microsoft HDAudio fornito dal sistema operativo 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.
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 è fornito da WASAPI. Questa aggiunta semplifica il codice per le applicazioni scritte con AudioGraph.
- Esiste un altro buffer di latenza nel lato rendering di AudioGraph quando il sistema usa buffer maggiori di 6 ms.
- AudioGraph non ha la possibilità di disabilitare l'acquisizione degli effetti audio.
Campioni
Domande frequenti
Non sarebbe meglio, se tutte le applicazioni usano le nuove API per una bassa latenza? La bassa latenza non garantisce sempre un'esperienza utente migliore?
Non necessariamente. La bassa latenza presenta compromessi:
- Bassa latenza significa un consumo di energia più elevato. Se il sistema usa buffer da 10 ms, significa che la CPU si riattiverà ogni 10 ms, riempirà il buffer dei dati e andrà in sospensione. Tuttavia, se il sistema usa buffer da 1 ms, significa che la CPU si riattiva ogni 1 ms. Nel secondo scenario, ciò significa che la CPU si riattiva più spesso e il consumo di energia aumenterà. Questo 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 vogliono ottenere 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 supportano la stessa dimensione minima 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, i sistemi più recenti sono più propensi a supportare 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 versioni successive useranno 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 quella piccola dimensione del buffer. Quando l'applicazione a bassa latenza viene chiusa, il motore audio passerà nuovamente a buffer da 10 ms.