Antes de iniciar um stream lógico, um app precisa solicitar o foco de áudio usando os mesmos atributos de áudio usados para o stream lógico. Embora o envio de uma solicitação de foco seja recomendado, ele não é aplicado pelo sistema. Alguns apps podem pular explicitamente o envio da solicitação para alcançar comportamentos específicos, por exemplo, para reproduzir um som intencionalmente durante uma ligação.
Por esse motivo, considere o foco como uma forma de controlar indiretamente e resolver conflitos de reprodução, e não como um mecanismo principal de controle de áudio. O veículo não pode depender do sistema de foco para operar o subsistema de áudio.
Interações de foco
Para atender às necessidades do AAOS, as solicitações de seleção de áudio são processadas com base em interações
predefinidas entre o CarAudioContext
da solicitação e o dos detentores de foco
atual. Há três tipos de interações: exclusiva, de rejeição e simultânea.
Interação exclusiva
Em interações exclusivas, apenas um aplicativo pode manter o foco por vez.
Portanto, a solicitação de foco recebida recebe o foco, enquanto o detentor de foco atual
perde o foco. Um exemplo disso é quando um usuário inicia um novo aplicativo de música enquanto
a música já está tocando em um aplicativo existente. Como ambos estão tocando mídia, apenas
um dos aplicativos pode manter o foco por vez. Como resultado, a solicitação de foco do aplicativo
recém-iniciado retorna com AUDIOFOCUS_REQUEST_GRANTED
e
o aplicativo que está tocando música recebe um evento de mudança de foco com um status de perda
que corresponde ao tipo de solicitação feita. Esse é o modelo
de interação mais comum com o Android.
Recusar interação
Com as interações de rejeição, a solicitação recebida é sempre rejeitada. Tentar tocar
música enquanto uma chamada está em andamento é um exemplo de interação rejeitada. Nesse caso,
se o discador estiver segurando a seleção de áudio para uma chamada e um segundo aplicativo solicitar
a seleção para tocar música, o app de música vai receber AUDIOFOCUS_REQUEST_FAILED
em resposta à solicitação. Como a solicitação de foco é rejeitada, nenhuma perda de foco de qualquer tipo
é enviada ao detentor de foco atual.
Interação simultânea
O que é mais exclusivo do AAOS são as interações simultâneas. Isso permite que os aplicativos que solicitam a seleção de áudio no carro mantenham a seleção ao mesmo tempo que outros aplicativos. Para que uma interação simultânea ocorra, as seguintes condições precisam ser atendidas. O:
- A solicitação de foco recebida precisa solicitar
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
. - O detentor de foco atual não
setPauseWhenDucked(true)
. - O detentor de foco atual não opta por receber eventos de pato.
Se esses critérios forem atendidos, a solicitação de foco vai retornar com
AUDIOFOCUS_REQUEST_GRANTED
, enquanto o detentor de foco atual não tiver
mudanças no foco. No entanto, se o detentor de foco atual optar por receber eventos de abatimento ou
pausar quando abafado, o detentor de foco atual vai perder o foco, assim como em uma interação
exclusiva.
Como lidar com streams simultâneos
Embora a interação simultânea tenha muitas aplicações úteis, os OEMs precisam cuidar da
mistura e do abatimento no nível do hardware em todos os dispositivos de saída. Por isso, é
recomendado que os CarAudioContext
s sejam roteados apenas para o mesmo dispositivo de saída
que os CarAudioContext
s que não podem ser reproduzidos simultaneamente. Com
dispositivos de saída separados para transmissões simultâneas, o HAL pode pular uma das
transmissões antes de misturá-las ou encaminhar as transmissões físicas para diferentes alto-falantes
no veículo. Se os fluxos lógicos forem misturados no Android, os ganhos deles não serão alterados
e serão entregues como parte do mesmo fluxo físico.
Por exemplo, quando a navegação e a mídia são transmitidas simultaneamente, o ganho do fluxo de mídia pode ser reduzido temporariamente (reduzido) para que as instruções de navegação possam ser ouvidas com mais clareza. Como alternativa, o fluxo de navegação pode ser roteado para os alto-falantes do lado do motorista, enquanto a mídia continua sendo reproduzida no restante da cabine.
Matriz de interação
A tabela abaixo mostra a matriz de interação conforme definida por CarAudioService
.
As linhas representam o CarAudioContext
do detentor de foco atual, e as colunas
representam o da solicitação recebida.
Em um exemplo, em que um app de mídia de música está segurando o foco e um app de navegação está solicitando o foco, a matriz mostra que as duas interações podem ser executadas simultaneamente, assumindo que os outros critérios para Interações simultâneas sejam atendidos.
Devido às interações simultâneas, é possível que mais de um detentor de foco exista. Nesse caso, uma solicitação de foco recebida é comparada com cada um dos detentores de foco atual antes de decidir que tipo de interação aplicar. Nesse caso, a interação mais conservadora vence (rejeição, depois exclusiva e, por fim, simultânea).
Na tabela a seguir, as interações de foco entre o CarAudioContext para uma solicitação de foco recebida (colunas) e o contexto dos detentores de foco atuais (linhas) são fornecidas. Cada célula representa o tipo de interação esperado para os dois contextos.
Figura 1. Interações de seleção de áudio
Navegação durante ligações
No Android 11, uma nova configuração do usuário foi introduzida para permitir que os usuários alterem o
comportamento de interação entre a navegação e as chamadas telefônicas. Quando definido,
android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL
muda
a interação entre as solicitações de foco NAVIGATION
recebidas e os detentores de foco
CALL
atuais de concorrente para rejeitar.
Assim, se um usuário preferir que as instruções de navegação não interrompam a chamada,
ele poderá ativar essa configuração. Isso é mantido para o usuário e pode ser definido dinamicamente
para que as solicitações de foco subsequentes respeitem o novo valor da configuração.
Seleção de áudio com atraso
No Android 11, o AAOS adicionou suporte para solicitar o foco de áudio adiável. Isso permite que solicitações de foco não temporárias sejam adiadas quando a interação com os detentores de foco atuais normalmente resultaria na rejeição delas. Quando uma mudança no foco resulta em um estado em que a solicitação atrasada pode ganhar foco, a solicitação é concedida.
Regras para solicitações de foco de áudio atrasadas
- Somente solicitações não temporárias: como mencionado anteriormente, uma solicitação atrasada só pode ser feita para fontes não temporárias. Isso evita que um som transitório seja reproduzido muito tempo depois de ser relevante.
- Apenas uma solicitação pode ser atrasada por vez: se uma solicitação adiável
for feita enquanto já há uma solicitação atrasada, a solicitação atrasada original
vai receber um evento de mudança
AUDIOFOCUS_LOSS
, e a nova solicitação vai receber uma resposta síncrona deAUDIOFOCUS_REQUEST_DELAYED
. - As solicitações adiáveis precisam ter um
OnAudioFocusChangeListener
. Quando uma solicitação é atrasada, o listener é usado para notificar o solicitante quando a solicitação é concedida (AUDIOFOCUS_GAIN
) ou rejeitada mais tarde (AUDIOFOCUS_LOSS
).
Solicitar foco adiável
Para criar uma solicitação que pode ser atrasada, use o
AudioFocusRequest.Builder#setAcceptsDelayedFocusGain
:
mMediaWithDelayedFocusListener = new MediaWithDelayedFocusListener(); mDelayedFocusRequest = new AudioFocusRequest .Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(mMusicAudioAttrib) .setOnAudioFocusChangeListener(mMediaWithDelayedFocusListener) .setForceDucking(false) .setWillPauseWhenDucked(false) .setAcceptsDelayedFocusGain(true) .build();
Em seguida, ao fazer a solicitação, processe a resposta AUDIOFOCUS_REQUEST_DELAYED
:
int delayedFocusRequestResults = mAudioManager.requestAudioFocus(mDelayedFocusRequest); if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // start audio playback return; } if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { // audio playback delayed to audio focus listener return; }
Quando a solicitação é atrasada, o listener de foco é responsável por processar as mudanças de foco:
private final class MediaWithDelayedFocusListener implements OnAudioFocusChangeListener { @Override public void onAudioFocusChange(int focusChange) { synchronized (mLock) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: … // Start focus playback case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: … // Pause media transiently case AudioManager.AUDIOFOCUS_LOSS: … // Stop media
Gerenciamento de foco em várias zonas
Para veículos com várias zonas de áudio, o foco de áudio é gerenciado de forma independente para cada zona. Portanto, uma solicitação para uma zona não leva em conta o que está segurando o foco em outras zonas, nem faz com que os detentores de foco em outras zonas percam o foco. Com isso, o foco da cabine principal pode ser gerenciado separadamente de um sistema de entretenimento de banco traseiro, evitando interromper a reprodução de áudio em uma zona pelas mudanças de foco em outra.
O gerenciamento de foco de todos os aplicativos é feito automaticamente pelo CarAudioService
. A zona de áudio de uma solicitação de foco é determinada com base no
UserId
ou UID
associado. Para mais detalhes, consulte
Roteamento de áudio.
Solicitar áudio de várias zonas ao mesmo tempo
Se um app quiser reproduzir áudio em várias zonas ao mesmo tempo, ele precisará solicitar o foco para
cada zona incluindo AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID
no pacote:
// Create attribute with bundle and AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID Bundle bundle = new Bundle(); bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID, zoneId); AudioAttributes attributesWithZone = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .addBundle(bundle) .build(); // Create focus request using built attributesWithZone
Esse parâmetro de pacote permite que o solicitante substitua os mapeamentos automáticos de zona de áudio para usar o ID de zona especificado. Assim, um app pode emitir solicitações separadas para diferentes zonas de áudio.
Seleção de áudio HAL
A partir do Android 11, a HAL agora está ativada para solicitar o foco em nome de fluxos externos. Embora sejam opcionais, essas APIs são altamente recomendadas para permitir que sons externos sejam melhores participantes no ecossistema do Android e para proporcionar uma experiência do usuário mais suave.
O HAL ainda é responsável pela decisão final sobre quais sons terão prioridade. Nesse sentido, os sons de emergência e de segurança críticos precisam ser reproduzidos, independentemente de o HAL receber ou não o foco de áudio, e precisam continuar sendo reproduzidos de forma adequada, mesmo que o HAL perca o foco de áudio. O mesmo vale para qualquer som exigido por regulamentos.
Da mesma forma, o HAL ainda precisa silenciar os streams do Android de forma proativa, conforme apropriado, ao reproduzir sons de emergência ou de segurança crítica para garantir que eles sejam ouvidos com clareza.
AudioControl@2.0
A versão 2.0 da HAL AudioControl apresenta várias APIs novas:
API | Objetivo |
---|---|
IAudioControl#registerFocusListener |
Registra uma instância de IFocusListener com a HAL AudioControl.
Esse listener permite que o HAL solicite e abandone a seleção de áudio. Espera-se que o HAL
forneça uma instância ICloseHandle para ser usada pelo Android para cancelar o registro
do listener.
|
IAudioControl#onAudioFocusChange |
Notifica o HAL sobre mudanças no status para focar as solicitações feitas pelo HAL usando
o IFocusListener . Isso inclui respostas a solicitações de foco inicial.
|
IFocusListener#requestAudioFocus |
As solicitações são focadas em nome do HAL para um uso, ID de zona e tipo de ganho de foco especificados. |
IFocusListener#abandonAudioFocus |
Abandona as solicitações de foco do HAL para o uso e o ID da zona especificados. |
O HAL pode ter várias solicitações de foco ao mesmo tempo, mas é limitado a uma solicitação por pareamento de uso e ID de zona. O Android assume que o HAL começa a tocar sons para um uso assim que uma solicitação é feita e continua fazendo isso até que perca o foco.
Além de registerFocusListener
, essas solicitações são todas oneway
para garantir que o Android não atrase o HAL enquanto uma solicitação de foco é processada. O HAL
não deve esperar para receber o foco antes de reproduzir sons críticos para a segurança. É
opcional que o HAL detecte e responda a mudanças no foco de áudio usando
IAudioControl#onAudioFocusChange
, embora seja recomendado quando apropriado.