Controle de áudio HAL

O controle de áudio HAL foi introduzido no Android 9 para oferecer suporte a casos de uso de áudio relevantes para o setor automotivo. A partir do Android 14, o HAL de controle de áudio oferece suporte a:

  • Desvanecimento e equilíbrio
  • Solicitação de foco de áudio HAL
  • Silenciamento e redução do dispositivo
  • Alterações no ganho do dispositivo de áudio
  • Alterações na configuração da porta de áudio

A Figura 1 mostra uma visão geral de alto nível da arquitetura do serviço de áudio automotivo, na qual o serviço de áudio automotivo se comunica com o HAL de controle de áudio.

Configurar áudio multizona

Figura 1. Configurar áudio multizona.

Fade e equilíbrio de áudio

O controle de áudio HIDL HAL versão 1 foi introduzido no Android 9 para oferecer suporte ao desbotamento e equilíbrio de áudio em casos de uso automotivo. Separado dos efeitos de áudio genéricos já fornecidos no Android, esse mecanismo permite que os aplicativos do sistema definam o equilíbrio do áudio e o fade por meio das APIs CarAudioManager :

class CarAudioManager {
       /**
       *   Adjust the relative volume in the front vs back of the vehicle cabin.
       *
       *   @param value in the range -1.0 to 1.0 for fully toward the back through
       *   fully toward the front. 0.0 means evenly balanced.
       */
       @SystemApi
       @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
       public void setFadeTowardFront(float value);

       /**
       *   Adjust the relative volume on the left vs right side of the vehicle cabin.
       *
       *   @param value in the range -1.0 to 1.0 for fully toward the left through
       *   fully toward the right. 0.0 means evenly balanced.
       */
       @SystemApi
       @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
       public void setBalanceTowardRight(float value);
}

Depois que essas APIs são chamadas, as respectivas APIs HAL de controle de áudio são chamadas a partir do serviço de áudio do carro:

interface IAudioControl {
       /**
       *   Control the right/left balance setting of the car speakers.
       */
       oneway setBalanceTowardRight(float value);

       /**
       *   Control the fore/aft fade setting of the car speakers.
       */
       oneway setFadeTowardFront(float value);
}

A API está disponível em todas as versões do HAL de controle de áudio, incluindo a nova interface AIDL HAL.

Solicitação de foco de áudio do HAL

AAOS, semelhante ao Android, conta com a participação ativa de aplicativos com foco em áudio para gerenciar a reprodução de áudio nos carros. As informações de foco são usadas para gerenciar quais fluxos controlar quanto ao volume e redução. Assim, para expandir ainda mais o foco no áudio e fornecer uma melhor integração de sons específicos do carro na experiência do Android, os seguintes atributos de áudio foram introduzidos no Android 11:

  • EMERGENCY
  • SAFETY
  • VEHICLE_STATUS
  • ANNOUNCEMENT

Além dessa mudança, foi adicionado um mecanismo para que sons originados de fora do Android participem de solicitações de foco de áudio. Assim, o controle de áudio HIDL HAL versão 2 foi introduzido para permitir solicitações de foco originadas de fora do Android:

interface IAudioControl {
       /**
       *   Registers focus listener to be used by HAL for requesting and
       *   abandoning audio focus.
       *   @param listener the listener interface
       *   @return closeHandle A handle to unregister observer.
       */
       registerFocusListener(IFocusListener listener)
       generates (ICloseHandle closeHandle);

       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   @param usage The audio usage associated with the focus change
       *   @param zoneId The identifier for the audio zone that the HAL is
       *   playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred
       */
       oneway onAudioFocusChange(bitfield<AudioUsage> usage, int32_t zoneId,
       bitfield<AudioFocusChange> focusChange);
}

Onde o IFocusListener é definido como:

interface IFocusListener {
       /**
       *   Called whenever HAL is requesting focus as it is starting to play
       *   audio of a given usage in a specified zone.
       *
       *   @param usage The audio usage associated with the focus request
       *    {@code AttributeUsage}
       *   @param zoneId The identifier for the audio zone where the HAL is
       *    requesting focus
       *   @param focusGain The AudioFocusChange associated with this request.
       */
       oneway requestAudioFocus(bitfield<AudioUsage> usage,
       int32_t zoneId, bitfield<AudioFocusChange> focusGain);
       /**
       *   Called whenever HAL is abandoning focus as it is finished playing audio
       *   of a given usage in a specific zone.
       *
       *   @param usage The audio usage for which the HAL is abandoning focus
       *    {@code AttributeUsage}
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       */
       oneway abandonAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId);
}

As APIs acima podem ser usadas para solicitar e abandonar o foco de áudio do HAL, respectivamente. Em resposta, o serviço de áudio automotivo considera a solicitação de foco de áudio e encaminha os resultados de forma assíncrona para o método IAudioControl#onAudioFocusChange .

Essa API também pode ser usada para monitorar alterações na solicitação de foco de áudio originada do HAL de controle de áudio. Em geral, qualquer solicitação de foco de áudio permanente do HAL é considerada ativa , o que difere de uma solicitação de foco de áudio do Android, na qual apenas uma reprodução de trilha de áudio ativa correspondente é considerada ativa.

Migrar HIDL para AIDL controle de áudio HAL

Com o advento do AIDL e a migração necessária no Android 12 (para saber mais, consulte AIDL para HALs ), o HAL de controle de áudio foi migrado para AIDL. Para APIs existentes da versão 2 do controle de áudio HIDL, a migração exigiu pequenas atualizações nos métodos existentes:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   @param usage The audio usage associated with the focus change
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone that the HAL is
       *        playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred.
       */
       oneway void onAudioFocusChange(in String usage, in int zoneId,
              in AudioFocusChange focusChange);
       /**
       *   Registers focus listener to be used by HAL for requesting and
       *   abandoning audio focus.
       *   @param listener the listener interface.
       */
       oneway void registerFocusListener(in IFocusListener listener);
       /**
       *   Control the right/left balance setting of the car speakers.
       */
       oneway void setBalanceTowardRight(in float value);
       /**
       *   Control the fore/aft fade setting of the car speakers.
       */
       oneway void setFadeTowardFront(in float value);
}

E o IFocusListener correspondente:

       interface IFocusListener {
       /**
       *   Called whenever HAL is abandoning focus as it is finished playing audio
       *   of a given usage in a specific zone.
       *
       *   @param usage The audio usage for which the HAL is abandoning focus
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone that the HAL
       *        abandoning focus
       */
       oneway void abandonAudioFocus(in String usage, in int zoneId);
       /**
       *   Called whenever HAL is requesting focus as it is starting to play audio
       *        of a given usage in a specified zone.
       *
       *   @param usage The audio usage associated with the focus request
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone where the HAL is
       *        requesting focus
       *   @param focusGain The AudioFocusChange associated with this request.
       */
       oneway void requestAudioFocus(in String usage, in int zoneId,
              in AudioFocusChange focusGain);
}

Silenciamento do grupo de volumes

O Android 12 introduziu o silenciamento do grupo de volume para permitir um controle de silenciamento mais abrangente durante as interações de áudio do usuário. Isso permite que o HAL de controle de áudio receba eventos de silenciamento interceptados pelo serviço de áudio do carro.

Para ativar o recurso, os OEMs devem definir a configuração audioUseCarVolumeGroupMuting como true no serviço automotivo config.xml :

<!-- Configuration to enable muting of individual volume groups.
If this is set to false, muting of individual volume groups is disabled,
instead muting will toggle master mute. If this is set to true, car volume
group muting is enabled and each individual volume group can be muted separately. -->
<bool name="audioUseCarVolumeGroupMuting">true</bool>

Antes do Android 13, a configuração precisava ser substituída por uma sobreposição de recursos de tempo de execução para packages/services/Car/service/res/values/config.xml (para saber mais, consulte Personalizando a compilação com sobreposições de recursos ). A partir do Android 13, você pode usar sobreposições de recursos de tempo de execução para alterar um valor de configuração. Para saber mais, consulte Alterar o valor dos recursos de um aplicativo em tempo de execução .

Os aplicativos do sistema podem determinar se o recurso está habilitado usando a API CarAudioManager#isAudioFeatureEnabled . O parâmetro passado deve ser a constante CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING . O método retorna true se o recurso estiver habilitado no dispositivo, caso contrário, false .

Além de ativar o recurso audioUseCarVolumeGroupMuting , o HAL de controle de áudio AIDL deve implementar o mecanismo de silenciamento do grupo de volumes:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in output devices that the HAL should apply
       *   muting to.
       *
       *   This will be called in response to changes in audio mute state for each
       *   volume group and will include a {@link MutingInfo} object per audio
       *   zone that experienced a mute state event.
       *
       *   @param mutingInfos an array of {@link MutingInfo} objects for the audio
       *   zones where audio mute state has changed.
       */
       oneway void onDevicesToMuteChange(in MutingInfo[] mutingInfos);
}

Onde as informações de muting contêm as informações de muting pertinentes para o sistema de áudio:

parcelable MutingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be muted.
       */
       String[] deviceAddressesToMute;
       /**
       *   List of addresses for audio output devices that were previously be
       *   muted and should now be unmuted.
       */
       String[] deviceAddressesToUnmute;
}

AAOS possui dois mecanismos diferentes para silenciar, baseados em:

  • Principais eventos usando o áudio KEYCODE_VOLUME_MUTE {:.external}.

  • Chamadas diretas para o serviço de áudio do carro usando a API mute do gerenciador de áudio do carro, CarAudioManager#setVolumeGroupMute .

Quando habilitados, ambos os mecanismos acionam um silenciamento de chamada para o HAL de controle de áudio.

Áudio do carro diminuindo

O Android 12 introduziu a redução de áudio do carro para otimizar o controle da reprodução simultânea de fluxos de áudio. Isso permite que os OEMs implementem seu próprio comportamento de redução com base na configuração física de áudio do carro e no estado atual de reprodução, conforme determinado pelo serviço de áudio do carro.

O mecanismo de redução é baseado nas alterações da pilha de foco de áudio. Sempre que ocorre uma mudança de foco (seja uma solicitação de foco ou abandono de foco), o HAL de controle de áudio é informado. Semelhante ao suporte para silenciamento do grupo de volume do carro, a redução do áudio do carro pode ser habilitada com o sinalizador de configuração audioUseHalDuckingSignals :

<!-- Configuration to enable IAudioControl#onDevicesToDuckChange API to
inform HAL when to duck. If this is set to true, the API will receive signals
indicating which output devices to duck as well as what usages are currently
holding focus. If set to false, the API will not be called. -->
<bool name="audioUseHalDuckingSignals">true</bool>

Para habilitar o recurso, o HAL de controle de áudio AIDL deve implementar a lógica relevante com o sinal recebido do serviço de áudio automotivo:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in output devices that the HAL should apply
       *   ducking to.
       *
       *   This will be called in response to changes in audio focus, and will
       *   include a {@link DuckingInfo} object per audio zone that experienced
       *   a change in audo focus.
       *
       *   @param duckingInfos an array of {@link DuckingInfo} objects for the
       *   audio zones where audio focus has changed.
       */
       oneway void onDevicesToDuckChange(in DuckingInfo[] duckingInfos);
}

As informações relevantes do sistema de áudio estão contidas nas informações de redução de áudio:

parcelable DuckingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be ducked.
       */
       String[] deviceAddressesToDuck;
       /**
       *   List of addresses for audio output devices that were previously be
       *   ducked and should now be unducked.
       */
       String[] deviceAddressesToUnduck;
       /**
       *   List of usages currently holding focus for this audio zone.
       */
       String[] usagesHoldingFocus;
}

Além das informações de configuração de áudio do carro contidas nos endereços do dispositivo para (des) abaixar, as informações de abaixamento também contêm informações sobre quais usos de atributos de áudio estão mantendo o foco. A intenção desses dados é informar ao sistema de áudio quais usos de atributos de áudio estão ativos.

Isto é necessário porque, na configuração do áudio do carro, vários atributos de áudio podem ser atribuídos a um único dispositivo e, sem as informações extras, não fica claro quais usos estão ativos.

Controle de áudio AIDL HAL 2.0

Para atualizar APIs e facilitar novas funcionalidades, o HAL de controle de áudio AIDL foi atualizado para a versão 2.0 no Android 13:

  • Foco de áudio com PlaybackTrackMetadata
  • Áudio ganha retorno de chamada

Os metadados de reprodução são definidos em android.hardware.audio.common da seguinte forma:

parcelable PlaybackTrackMetadata {
       AudioUsage usage = INVALID;
       AudioContentType contentType = UNKNOWN;
       float gain;
       AudioChannelLayout channelMask;
       AudioDevice sourceDevice;
       String[] tags;
}

Todas as outras funcionalidades do controle de áudio AIDL versão 1.0 permaneceram e podem ser usadas. Uma exceção pertence ao método de mudança de foco de áudio, conforme descrito em Método de mudança de foco de áudio .

Foco de controle de áudio com metadados de faixa de reprodução

Para expor mais informações ao sistema de áudio abaixo do HAL, as atualizações agora expõem PlaybackTrackMetadata . Especificamente, o controle de áudio HAL foi expandido com um novo método:

interface IAudioControl {
       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   The HAL is not required to wait for a callback of AUDIOFOCUS_GAIN
       *   before playing audio, nor is it required to stop playing audio in the
       *   event of a AUDIOFOCUS_LOSS callback is received.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL is
       *    playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred.
       */
       oneway void onAudioFocusChangeWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId,
       in AudioFocusChange focusChange);
}

Uma alteração semelhante e correspondente é feita em IFocusListener :

       /**
       *   Called to indicate that the audio output stream associated with
       *   {@link android.hardware.audio.common.PlaybackTrackMetadata} is
       *   abandoning focus as playback has stopped.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       */
       oneway void abandonAudioFocusWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId);
       /**
       *   Called to indicate that the audio output stream associated with
       *   {@link android.hardware.audio.common.PlaybackTrackMetadata} has taken
       *   the focus as playback is starting for the corresponding stream.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       *   @param focusGain The focus type requested.
       */
       oneway void requestAudioFocusWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId,
       in AudioFocusChange focusGain);
}

No método de mudança de foco de áudio

As operações de foco acima são executadas da mesma maneira descritas em Solicitação de foco de áudio do HAL . Apenas os metadados da faixa de reprodução possuem mais informações junto com o uso dos atributos de áudio. Em geral, a menos que as informações extras fornecidas pelos metadados da faixa de reprodução sejam necessárias, o HAL de controle Android atualizado pode continuar a usar os métodos anteriores.

Se os desenvolvedores HAL decidirem não oferecer suporte IAudioControl#onAudioFocusChangeWithMetaData , o método deverá retornar resultados com o erro UNKNOWN_TRANSACTION conforme descrito Using Versioned Interface Methods .

O serviço de áudio primeiro chama onAudioFocusChangeWithMetaData e, em seguida, tenta novamente com o método onAudioFocusChange se resultar uma falha UNKNOWN_TRANSACTION .

Áudio do carro diminuindo com metadados da faixa de reprodução

A versão 2.0 do controle de áudio AIDL HAL adicionou os metadados da faixa de reprodução às informações de redução de áudio:

parcelable DuckingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be ducked.
       */
       String[] deviceAddressesToDuck;
       /**
       *   List of addresses for audio output devices that were previously be
       *   ducked and should now be unducked.
       */
       String[] deviceAddressesToUnduck;
       /**
       *   List of usages currently holding focus for this audio zone.
       */
       String[] usagesHoldingFocus;
       /**
       *   List of output stream metadata associated with the current focus
       *   holder for this audio zone
       */
       @nullable PlaybackTrackMetadata[] playbackMetaDataHoldingFocus;
}

usagesHoldingFocus está obsoleto. Os desenvolvedores agora devem usar playbackMetaDataHoldingFocus para determinar o uso do atributo de áudio e outras informações de áudio. Dito isto, o parâmetro usagesHoldingFocus ainda contém as informações necessárias até que esta opção seja formalmente removida.

Retorno de chamada de ganho de áudio

Para tornar as alterações de áudio abaixo do HAL mais visíveis para o AAOS no Android 13, adicionamos um mecanismo que você pode usar para comunicar alterações de ganhos de áudio do sistema de áudio do carro para o serviço de áudio do carro. O mecanismo expõe alterações no índice de volume do ganho de áudio com o respectivo motivo pelo qual o ganho foi alterado:

  • Restrições bloqueadas ou silenciadas
  • Limitações restrições
  • Restrições de atenuação

Essas mudanças expõem essas restrições abaixo do HAL ao serviço de áudio automotivo e, finalmente, a um aplicativo de UI do sistema para informar o usuário. A última parte, a exposição a uma possível IU do sistema, foi expandida ainda mais no Android 14 para permitir que os aplicativos da IU do sistema obtenham essas informações mais facilmente por meio de um mecanismo de retorno de chamada de informações do grupo de volumes.

A API HAL de controle de áudio registra o retorno de chamada de ganho da seguinte forma:

interface IAudioControl {
       /**
       *   Registers callback to be used by HAL for reporting unexpected gain(s)
       *    changed and the reason(s) why.
       *
       *   @param callback The {@link IAudioGainCallback}.
       */
       oneway void registerGainCallback(in IAudioGainCallback callback);
}

O IAudioGainCallback é definido da seguinte forma:

interface IAudioGainCallback {
       /**
       *   Used to indicate that one or more audio device port gains have changed,
       *   i.e. initiated by HAL, not by CarAudioService.
       *   This is the counter part of the
       *   {@link onDevicesToDuckChange}, {@link onDevicesToMuteChange} and,
       *   {@link setAudioDeviceGainsChanged} APIs.
       *
       *   @param reasons List of reasons that triggered the given gains changed.
       *   @param gains List of gains affected by the change.
       */
       void onAudioDeviceGainsChanged(in Reasons[] reasons,
       in AudioGainConfigInfo[] gains);
}

Conforme destacado na documentação da API, o retorno de chamada de ganho é registrado pelo serviço de áudio do carro no HAL de controle de áudio. Quando a API é chamada a partir do HAL de controle de áudio, o serviço de áudio do carro responde com uma ação correspondente (como bloquear, limitar ou atenuar índice de ganho).

O HAL determina quando a API é chamada, principalmente para relatar alterações no status do índice de ganho. Específico para os requisitos regulamentares, o sistema de áudio do carro deve tomar as medidas necessárias e usar o retorno de chamada para reportar informações ao serviço de áudio do carro para permitir o consumo do usuário. Por exemplo, para mostrar uma UI ao usuário.

Controle de áudio AIDL HAL 3.0

A versão HAL de controle de áudio AIDL do Android 14 foi atualizada para a versão 3.0 para atualizar as APIs e fornecer uma funcionalidade de índice de ganho de áudio mais robusta. A API HAL de controle de áudio permite que o serviço de áudio defina e desabilite um IModuleChangeCallback :

interface IAudioControl {
       /**
       *   Sets callback with HAL for notifying changes to hardware module
       *   (that is: {@link android.hardware.audio.core.IModule}) configurations.
       *
       *   @param callback The {@link IModuleChangeCallback} interface to use
       *    use when new updates are available for
       */
       void setModuleChangeCallback(in IModuleChangeCallback callback);
       /**
       *   Clears module change callback
       */
       void clearModuleChangeCallback();
}

O setModuleChangeCallback é registrado pelo serviço de áudio automotivo quando o serviço é iniciado ou durante a recuperação de um erro. Por exemplo, uma notificação de morte do fichário HAL de controle de áudio recebida pelo serviço de áudio do carro. A implementação HAL de controle de áudio deve substituir qualquer retorno de chamada de alteração de módulo existente quando a API for chamada.

Para a API clearModuleChangeCallback , a implementação deve limpar o retorno de chamada existente ou não fazer nada se ele não existir. É uma boa prática para a implementação do controle de áudio registrar um observador de morte para o retorno de chamada e, em seguida, limpar o retorno de chamada se a morte no fichário for acionada.

IModuleChangeCallback é definido da seguinte forma:

oneway interface IModuleChangeCallback {
       /**
       *   Used to indicate that one or more {@link AudioPort} configs have
       *   changed. Implementations MUST return at least one AudioPort.
       *
       *   @param audioPorts list of {@link AudioPort} that are updated
       */
       void onAudioPortsChanged(in AudioPort[] audioPorts);
}

Quando o retorno de chamada de alteração do módulo é registrado pelo serviço de áudio do carro, ele está pronto para receber alterações da porta de áudio por meio da API onAudioPortChanged . A API pode ser usada para inicializar os ganhos de volume do sistema de áudio assim que o retorno de chamada for registrado. Para outras alterações dinâmicas de ganho, a API pode ser chamada a qualquer momento. As alterações correspondentes são aplicadas e o serviço de áudio automotivo é atualizado de acordo.