Audio Focus

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:

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 CarAudioContexts sejam roteados apenas para o mesmo dispositivo de saída que os CarAudioContexts 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.

Interações de seleção de áudio

Figura 1. Interações de seleção de áudio

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 de AUDIOFOCUS_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.