O áudio de baixa latência deixa os jogos mais realistas e responsivos.
Conclua a checklist a seguir para ativar o áudio de baixa latência no seu jogo no Android:
- Usar a Oboe
- Solicitar o modo performance "baixa latência"
- Solicitar o modo de compartilhamento "exclusivo"
- Usar 48.000 Hz ou o conversor de taxa de amostragem da API Oboe
- Declarar o uso como AAUDIO_USAGE_GAME
- Usar callbacks de dados
- Evitar o bloqueio de operações no callback
- Ajustar o tamanho para "buffer duplo"
1. Usar a API Oboe
A API Oboe é um wrapper C++ que chama AAudio no Android 8.1 (nível 27 da API) ou versões mais recentes. Em versões anteriores do Android, a Oboe usa o OpenSL ES.
A Oboe está disponível no GitHub ou como um binário pré-criado (links em inglês). Essa API também tem um QuirksManager que corrige problemas em dispositivos específicos, o que torna seu app compatível com mais dispositivos. Se não for possível usar a API Oboe, use a AAudio diretamente.
2. Solicitar o modo de baixa latência
Solicite-o com a Oboe ou a AAudio. Caso contrário, você terá um modo de latência maior por padrão.
Oboe
builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
AAudio
AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
3. Solicitar o modo exclusivo
Também é possível solicitar acesso exclusivo ao buffer MMAP. Seu app pode não ter acesso exclusivo, mas se isso acontecer, ele vai gravar dados diretamente em um buffer que é lido pelo DSP, o que proporciona a menor latência possível.
Oboe
builder.setSharingMode(oboe::SharingMode::Exclusive);
AAudio
AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
4. Evitar a conversão da taxa de amostragem
Use a taxa de amostragem normal do dispositivo. Para fazer isso, não especifique uma taxa de amostragem para ter uma taxa de 48.000 Hz. Se você fizer essa especificação, o framework de áudio vai enviar seus dados por um caminho diferente que poderá ter uma latência muito maior.
Se você precisar usar uma taxa, use a Oboe para fazer a conversão dela:
builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);
5. Declarar seu caso de uso corretamente
Especifique o motivo pelo qual seu app reproduz áudio para que o sistema aplique
as configurações corretas de roteamento, volume e desempenho. Por exemplo, jogos precisam
indicar o uso de AAUDIO_USAGE_GAME
para aproveitar as otimizações de
latência ao máximo, especialmente quando conectados a fones de ouvido Bluetooth.
Oboe
builder.setUsage(oboe::Usage::Game);
AAudio
AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);
6. Usar uma função de callback
Use um callback para o stream de saída. Se você usa gravações de bloqueio e está usando um dispositivo que não oferece suporte ao modo MMAP da AAudio, a latência pode ser muito maior.
Oboe
builder.setDataCallback(&myCallbackObject);
AAudio
AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);
7. Evitar bloquear o callback
Quando você usa streams de baixa latência, o tempo entre os callbacks pode ser de apenas alguns milissegundos. Então, é muito importante que você não faça nada que no callback possa bloqueá-lo por muito tempo. Se o callback for bloqueado, vão ocorrer e falhas do buffer no áudio.
Evite realizar as seguintes ações em um callback:
- Alocar ou liberar memória
- E/S de arquivo ou rede
- Aguardar um mutex ou um bloqueio
- Suspensão
- Cálculos complexos de CPU única
Os callbacks precisam fazer cálculos em um ritmo constante para garantir uma reprodução suave sem falhas.
8. Ajustar o tamanho do buffer
Quando seu app abrir o stream de áudio, será necessário ajustar o tamanho do buffer utilizável para ter a latência ideal. A Oboe define o tamanho do buffer como dois bursts automaticamente. No entanto, o padrão é muito mais alto na AAudio. Para usar o buffer duplo, defina o tamanho do buffer como o dobro do burst. O tamanho do burst é igual ao tamanho máximo do callback.
AAudio:
int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);
Se o tamanho do buffer for muito pequeno, você poderá receber falhas causadas por underruns de buffer. Chame AAudioStream_getXRunCount(stream)
para receber uma contagem das falhas. Aumente o tamanho do buffer conforme necessário.
Consulte a Documentos do GitHub Oboe (link em inglês) para conferir uma explicação da terminologia relacionada ao buffer.
OpenSL ES
Se você oferecer suporte a versões do Android anteriores à 8.1, será necessário usar a OpenSL ES. Se você estiver usando a Oboe, poderá configurar seu app para melhorar a latência. Consulte Como conseguir a latência ideal nos documentos do GitHub.
Resultados da checklist
A tabela a seguir contém medidas de latência do OboeTester (app disponível em inglês) de ida e volta (de entrada para saída).
Configuração | Latência (ms) |
---|---|
Siga todas as recomendações | 20 |
Modo performance não é baixa latência | 205 |
Não EXCLUSIVO (COMPARTILHADO) | 26 |
44.100 Hz (AAudio) | 160 |
44.100 Hz (Oboe SRC) | 23 |
Não usar um callback de saída (MMAP) | 21 |
Não usar um callback de saída (não MMAP) | 62 |
Tamanho do buffer definido para máximo | 53 |