Progettazione per ridurre la latenza

La release di Android 4.1 ha introdotto modifiche interne al framework per un percorso di output audio con latenza inferiore. Sono state apportate modifiche minime alle API client pubbliche o alle API HAL. Questo documento descrive il design iniziale, che ha continuato a evolversi nel tempo. Una buona comprensione di questo design dovrebbe aiutare i produttori di dispositivi OEM e i fornitori di SoC a implementarlo correttamente sui loro dispositivi e chipset specifici. Questo articolo non è rivolto agli sviluppatori di applicazioni.

Creazione di canali

Il client può facoltativamente impostare il bit AUDIO_OUTPUT_FLAG_FAST nel parametro audio_output_flags_t del costruttore C++ di AudioTrack o in AudioTrack::set(). Al momento gli unici client che lo fanno sono:

L'implementazione in C++ di AudioTrack esamina la richiesta AUDIO_OUTPUT_FLAG_FAST e, facoltativamente, può rifiutarla a livello di client. Se decide di inoltrare la richiesta, lo fa utilizzando il bit TRACK_FAST del parametro track_flags_t del metodo di fabbrica IAudioTrackIAudioFlinger::createTrack().

Il server audio AudioFlinger esamina la richiesta TRACK_FAST e può rifiutarla facoltativamente a livello di server. Comunica al client se la richiesta è stata accettata o meno tramite il bit CBLK_FAST del blocco di controllo della memoria condivisa.

I fattori che influiscono sulla decisione includono:

  • Presenza di un thread del mixer veloce per questa uscita (vedi di seguito)
  • Frequenza di campionamento della traccia
  • Presenza di un thread client per eseguire i gestori di callback per questo canale
  • Dimensione del buffer della traccia
  • Slot per il canale prioritario disponibili (vedi di seguito)

Se la richiesta del cliente è stata accettata, si parla di "via rapida". In caso contrario, si tratta di un "canale normale".

Thread del mixer

Quando AudioFlinger crea un thread del mixer normale, decide se creare o meno anche un thread del mixer veloce. Sia il mixer normale che quello veloce non sono associati a una traccia specifica, ma a un insieme di tracce. Esiste sempre un thread del mixer normale. Il thread del mixer veloce, se esistente, è subordinato al thread del mixer normale e agisce sotto il suo controllo.

Mixer veloce

Funzionalità

Il thread del mixer veloce fornisce le seguenti funzionalità:

  • Mixaggio del sottomix del mixer normale e di un massimo di 7 tracce rapide del client
  • Atenuazione per traccia

Funzionalità omesse:

  • Conversione della frequenza di campionamento per traccia
  • Effetti per traccia
  • Per effetti di mix

Punto

Il mixer veloce viene eseguito periodicamente, con un periodo consigliato di due o tre millisecondi (ms) o un periodo leggermente superiore di cinque ms, se necessario per la stabilità della pianificazione. Questo numero è stato scelto in modo che, tenendo conto della pipeline completa del buffer, la latenza totale sia dell'ordine di 10 ms. Sono possibili valori inferiori, ma potrebbero comportare un aumento del consumo energetico e la possibilità di errori, a seconda della prevedibilità della pianificazione della CPU. Sono possibili valori più elevati, fino a 20 ms, ma comportano un peggioramento della latenza complessiva e pertanto devono essere evitati.

Pianificazione

Il mixer veloce viene eseguito con priorità SCHED_FIFO elevata. Richiede pochissimo tempo della CPU, ma deve essere eseguito di frequente e con un jitter di pianificazione ridotto. Il jitter esprime la variazione del tempo di ciclo: è la differenza tra il tempo di ciclo effettivo e quello previsto. Se la pubblicazione avviene troppo tardi, si verificheranno dei problemi a causa di un sottoutilizzo. Se esegui l'esecuzione troppo in anticipo, si verificheranno dei problemi a causa del recupero da un canale rapido prima che il canale abbia fornito dati.

Blocco

Idealmente, il thread del mixer veloce non si blocca mai, tranne che in HAL write(). Altre occorrenze di blocco all'interno del mixer rapido sono considerate bug. In particolare, vengono evitati i mutex. Vengono invece utilizzati algoritmi non bloccanti (noti anche come algoritmi senza blocco). Per scoprire di più su questo argomento, consulta la sezione Evitare l'inversione della priorità.

Relazione con altri componenti

Il mixer veloce ha poca interazione diretta con i clienti. In particolare, non vede le operazioni a livello di binder, ma accede al blocco di controllo della memoria condivisa del client.

Il mixer veloce riceve i comandi dal mixer normale tramite una coda di stato.

A parte l'estrazione dei dati dei canali, l'interazione con i client avviene tramite il normale mixer.

Il sink principale del mixer veloce è l'HAL audio.

Mixer normale

Funzionalità

Tutte le funzionalità sono attive:

  • Fino a 32 tracce
  • Atenuazione per traccia
  • Conversione della frequenza di campionamento per traccia
  • Elaborazione degli effetti

Punto

Il periodo viene calcolato come primo multiplo integrale del periodo del mixer veloce maggiore o uguale a 20 ms.

Pianificazione

Il mixer normale viene eseguito con priorità SCHED_OTHER elevata.

Blocco

Il mixer normale è autorizzato a bloccarsi e spesso lo fa in vari metodi di mutua esclusione e in una pipeline di blocco per scrivere il proprio sottomix.

Relazione con altri componenti

Il mixer normale interagisce ampiamente con l'esterno, inclusi i thread binder, il gestore delle norme audio, il thread del mixer veloce e le tracce client.

Il sink del mixer normale è un canale di blocco per la traccia 0 del mixer veloce.

Bandiere

Il bit AUDIO_OUTPUT_FLAG_FAST è un indizio. Non è garantito che la richiesta verrà soddisfatta.

AUDIO_OUTPUT_FLAG_FAST è un concetto a livello di client. Non viene visualizzato nel server.

TRACK_FAST è un concetto client -> server.