Audio a bassa latenza

L'audio a bassa latenza rende i giochi più realistici e reattivi.

Completa il seguente elenco di controllo per attivare l'audio a bassa latenza nel tuo gioco su Android:

  1. Usa Oboe
  2. Richiedere la modalità rendimento "bassa latenza"
  3. Richiedere la modalità di condivisione "esclusiva"
  4. Usare la frequenza di campionamento a 48.000 Hz o il convertitore di frequenza per oboe
  5. Imposta l'utilizzo su AAUDIO_USAGE_GAME
  6. Utilizzare i callback dati
  7. Evitare di bloccare le operazioni nel callback
  8. Adatta le dimensioni del buffer a "doppio buffer"

1. Utilizzare l'API Oboe

L'API Oboe è un wrapper C++ che chiama AAudio su Android 8.1 (livello API 27) o versioni successive. Nelle versioni precedenti di Android, Oboe usa OpenSL ES.

L'oboe è disponibile su GitHub o come programma binario predefinito. Oboe dispone anche di QuirksManager che corregge i problemi su dispositivi specifici, rendendo la tua app compatibile con più dispositivi. Se non puoi usare Oboe, usa direttamente AAudio.

2. Richiedi la modalità a bassa latenza

Con Oboe o AAudio, richiedi la modalità a bassa latenza. In caso contrario, otterrai una modalità di latenza più alta per impostazione predefinita.

Oboe

builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);

AAudio

AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

3. Richiedi modalità esclusiva

Puoi anche richiedere l'accesso esclusivo al buffer MMAP. La tua app potrebbe non ottenere l'accesso esclusivo, ma se lo fa, l'app scrive direttamente in un buffer letto dalla DSP, che offre alla tua app la latenza più bassa possibile.

Oboe

builder.setSharingMode(oboe::SharingMode::Exclusive);

AAudio

AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);

4. Evita la conversione del tasso di campionamento

Utilizza la frequenza di campionamento naturale del dispositivo. Puoi farlo non specificando una frequenza di campionamento, e quasi certamente otterrai 48.000 Hz. Se specifichi una frequenza di campionamento, il framework audio invia i tuoi dati su un percorso diverso che può avere una latenza molto più elevata.

Se devi utilizzare una frequenza di campionamento diversa, utilizza Oboe per eseguire la conversione della frequenza di campionamento:

builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);

5. Dichiarare correttamente il caso d'uso

Specificare il motivo per cui l'app riproduce l'audio è fondamentale affinché il sistema applichi le impostazioni corrette per routing, volume e prestazioni. Ad esempio, i giochi dovrebbero indicare l'utilizzo di AAUDIO_USAGE_GAME per sfruttare al massimo le ottimizzazioni della latenza, in particolare se il dispositivo è connesso ad auricolari Bluetooth.

Oboe

builder.setUsage(oboe::Usage::Game);

AAudio

AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);

6. Utilizzare una funzione di callback

Utilizza un callback per lo stream di output. Se utilizzi le scritture di blocco e ti trovi su un dispositivo che non supporta la modalità MMAP AAudio, la latenza potrebbe essere molto più elevata.

Oboe

builder.setDataCallback(&myCallbackObject);

AAudio

AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);

7. Evitare il blocco nel callback

Quando utilizzi uno stream a bassa latenza, l'intervallo tra le richiamate può essere molto breve, di pochi millisecondi. È quindi molto importante che la richiamata non esegua alcuna azione che potrebbe bloccare per molto tempo. Se il callback è bloccato, il buffer passa in basso e si verificano glitch nell'audio.

Evita di:

  • Allocazione o liberazione della memoria
  • I/O su file o rete
  • In attesa di un mutex o di un blocco
  • Faccina che dorme
  • Calcoli intensivi una tantum della CPU

I callback dovrebbero eseguire i calcoli a un ritmo uniforme per una riproduzione fluida senza glitch.

8. Ottimizza la dimensione del buffer

Una volta che l'app apre lo stream audio, devi regolare la dimensione del buffer utilizzabile per una latenza ottimale. L'oboe imposta automaticamente le dimensioni del buffer su due raffiche. Ma con AAudio, il valore predefinito è molto più alto. Utilizza il doppio buffer impostando la dimensione del buffer su due volte la dimensione del burst. La dimensione della serie di foto a raffica è la dimensione massima per il callback.

Audio:

int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);

Se la dimensione del buffer è troppo piccola, potresti riscontrare deglitch causati da inondazioni del buffer. Puoi contare i glitch chiamando il numero AAudioStream_getXRunCount(stream). Aumenta la dimensione del buffer in base alle esigenze.

Consulta la documentazione di GitHub Oboe per una spiegazione della terminologia relativa al buffer.

OpenSL ES

Se supporti versioni di Android precedenti alla 8.1, devi usare OpenSL ES. Se usi Oboe, puoi configurare la tua app per migliorare la latenza. Consulta la sezione Come ottenere una latenza ottimale nella documentazione di GitHub.

Risultati dell'elenco di controllo

La seguente tabella contiene le misurazioni OboeTester della latenza di round trip (da input all'output).

Configurazione Latenza (ms)
Segui tutti i consigli 20
Modalità prestazioni non bassa latenza 205
Non ESCLUSIVA (CONDIVISI) 26
44.100 Hz (AAudio) 160
44100 Hz (Oboe SRC) 23
Mancato utilizzo di un callback di output (MMAP) 21
Non utilizzare un callback di output (non MMAP) 62
Dimensione del buffer impostata al massimo 53