Automotive audio策略总结

1.音频焦点

1.1 为什么会有音频焦点机制?

在车辆环境中,可能存在多个应用或者服务需要同时或者交替播放音频,如导航、音乐、语音助手等。音频焦点机制允许系统协调这些音频流,确保在某一时刻只有一个或几个应用能够播放音频,从而避免声音混杂和冲突。

1.2 音频焦点的基本规则和逻辑

1.2.1 当某个应用或者服务需要播放声音的时候,它首先需要向系统请求音频焦点。系统会根据当前焦点的持有情况和应用请求的焦点类型,来决定是否授予音频焦点。如果应用获取到焦点,就可以开始播放音频内容;如果请求焦点被拒绝,则不能播放。
1.2.2 有音频播放需求的应用或者服务,在发起音频请求焦点前,应该去注册监听系统的音频焦点变化。在收到系统的系统监听变化的回调后,做出相应的动作,如开始播放、暂停播放或者释放焦点。
1.2.3 当音频播放完成后,应用需要去释放之前已经申请到的音频焦点,并注销音频变化监听器。
1.2.4 音频焦点机制是一套协调各个声源应用发声的规则,但是并不能强制去控制各个应用是否发声。因此,如果某些声源应用不遵守焦点规则,就会出现播放混乱的情况。比如在播放音乐的时候触发语音,正常情况需要暂停或者压低媒体音量,如果语音服务或者多媒体应用没有遵守焦点机制,就会出现两个声音混合听不清楚。

1.3 音频焦点请求的类型

  • AUDIOFOCUS_GAIN:请求独占的长时间的音频焦点,例如音乐播放的焦点请求。

  • AUDIOFOCUS_GAIN_TRANSIENT:请求短暂的独占的音频焦点,比如短暂的语音交互。

  • AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:请求短暂的播报,但是允许其他音源压低并继续播放,比如播放视频的时候有新消息提示或者地图播报。

  • AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:请求短暂的独占的音频焦点,且不允许其他音源有任何声音,与 GAIN_TRANSIENT 类似,不常用。

1.4 音频焦点变化回调的类型

焦点变化回调的类型包括:

  • AUDIOFOCUS_GAIN :获得音频焦点,可以播放音源。
  • AUDIOFOCUS_LOSS:长时间失去音频焦点,此时应该停止播放,并释放资源。
  • AUDIOFOCUS_LOSS_TRANSIENT:短暂失去焦点,需要暂停播放,但不必释放资源,很快会得到焦点。
  • AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:短暂失去焦点,但不必暂停播放,需要把自己的声音压低。比如音乐播放的时候,有导航播报,音乐声音压低。

1.5 车机系统中音频焦点的三种交互类型

  • 独占
    这是 Android 中最常用的交互模型。在独占交互中,一次只允许一个应用持有焦点。因此,在传入的焦点请求被授予焦点的同时,现有的焦点持有者会失去焦点。
  • 拒绝
    在拒绝交互中,传入的请求一律会遭到拒绝。例如,在通话过程中尝试播放音乐。在这种情况下,如果拨号器为某个通话持有音频焦点,而第二个应用请求获得焦点以播放音乐,则音乐应用发出的请求会收到 AUDIOFOCUS_REQUEST_FAILED 响应。由于焦点请求遭拒,因此系统不会向当前焦点持有者分派任何焦点丢失事件。
  • 并发
    并发交互是 AAOS (Android 车载系统)独有的。要实现并发交互,传入的焦点请求类型必须是 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,当前焦点持有者的焦点不会丢失焦点,而新请求的应用也可以获取到焦点,允许同时发声。
    处理并发的声音流通常有两种方式,一种是做音量压低处理(闪避),另一种是把不同的声音路由到不同的音响设备。
    例如,如果同时提供导航提示音和媒体播放声音,媒体声音流的增益会暂时降低(闪避),以便用户能更清楚地听到导航提示。或者,导航声音流会被路由到驾驶员侧的头枕音响设备,媒体则在驾驶舱的其余音响设备中继续播放。

2.音频路由

音频路由指的是系统如何将音频流从一个或多个音频源(如音乐播放器、视频播放器、导航应用等)发送到哪些音频输出设备(如扬声器、耳机、蓝牙设备等)的过程。
大致的流程如下:
Automotive audio策略总结_第1张图片
首先是各种音源应用产生逻辑音频流,然后在Audio Flinger中根据音频路由策略去做声音的混合,得到物理音频流,并通过HAL层输出到Android系统外部。在Android系统之外,会有一个外部混音器,用于接收Android的物理音频流,并以合适的方式将这些音频流和车辆外部的声音做混合,并将混音结果路由到合适的音响设备。
总体的结构图如下:
Automotive audio策略总结_第2张图片

3.音量管理

3.1传统Android的音量设置

Android系统中去设置音量值的时候,会传入一个音频流类型的参数,以便对不同的类型做的音量的控制和记忆。音频流类型定义如下:

public static final String[] STREAM_NAMES = new String[] {
        "STREAM_VOICE_CALL",  	//电话
        "STREAM_SYSTEM",		//系统
        "STREAM_RING", 		//铃声
        "STREAM_MUSIC",		//音乐
        "STREAM_ALARM",		//闹钟
        "STREAM_NOTIFICATION",//通知
        "STREAM_BLUETOOTH_SCO",//蓝牙
        "STREAM_SYSTEM_ENFORCED",//系统强制
        "STREAM_DTMF",			//双音多频(拨号音)
        "STREAM_TTS",				//语音播报
};

但在底层的音量控制中,会对以上的音频类型做一次映射,根据系统指定的需求,把这些音频类型做一次分类,有些音频流类型复用同一个存储值。
通常的映射定义如下:

private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
    AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
    AudioSystem.STREAM_RING,            // STREAM_SYSTEM
    AudioSystem.STREAM_RING,            // STREAM_RING
    AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
    AudioSystem.STREAM_ALARM,           // STREAM_ALARM
    AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
    AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
	AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
    AudioSystem.STREAM_RING,            // STREAM_DTMF
    AudioSystem.STREAM_MUSIC            // STREAM_TTS
};

可以看到系统声音、铃声、提示音、系统强制音、拨号音都共用一个类型 STREAM_RING 的音量值 ;音乐媒体和语音公用一个类型 STREAM_MUSIC 的音量值 。比如当调节了音乐媒体的音量值之后,语音播报的声音也会变大。当然,这种映射关系可以根据项目的需求修改,如果语音播报的声音不想跟着媒体音一起调节,那么也可以做单独的定义。

3.2 AAOS的音量设置

AAOS提供了CarAudioService,它主要提供了两个能力,一是增加了多音区分组的概念,另一个是支持硬件放大器调节音量,而非使用传统的AudioFlinger软件调节。
由于座舱的环境变更越来越复杂,已经出现了中控主音区、后排音区、头枕音区等多个音区,所以最新的AAOS是通过zone(音区)+group(分组)的方式去组织,如下:

// device/generic/car/emulator/audio/car_audio_configuration.xml
<zone name="primary zone" isPrimary="true" occupantZoneId="0">
            <zoneConfigs>
                <zoneConfig name="primary zone config 0" isDefault="true">
                    <volumeGroups>
                        <group maxActivationVolumePercentage="90" activationConfig="activation_volume_on_boot_config">
                            <device address="bus0_media_out">
                                <context context="music"/>
                                <context context="announcement"/>
                            </device>
                            <device address="bus6_notification_out">
                                <context context="notification"/>
                            </device>
                        </group>
                        <group minActivationVolumePercentage="20" activationConfig="activation_volume_on_source_changed_config">
                            <device address="bus1_navigation_out">
                                <context context="navigation"/>
                            </device>
                            <device address="bus2_voice_command_out">
                                <context context="voice_command"/>
                            </device>
                        </group>
                        <group minActivationVolumePercentage="20" activationConfig="activation_volume_on_playback_changed_config">
                            <device address="bus4_call_out">
                                <context context="call"/>
                            </device>
                            <device address="bus3_call_ring_out">
                                <context context="call_ring"/>
                            </device>
                        </group>
                    </volumeGroups>               
                </zoneConfig>
            </zoneConfigs>
        </zone>
    <zone name="rear seat zone 1" audioZoneId="1">
            <zoneConfigs>
                <zoneConfig name="rear seat zone 1 config 0" isDefault="true">
                    <volumeGroups>
                        <group>
                            <device address="bus100_audio_zone_1">
                                <context context="music"/>
                            </device>
                        </group>
                        <group>
                            <device address="bus101_audio_zone_1">
                                <context context="navigation"/>
                                <context context="voice_command"/>
                                <context context="call_ring"/>
                                <context context="call"/>
                                <context context="alarm"/>
                                <context context="notification"/>
                                <context context="system_sound"/>
                                <context context="emergency"/>
                                <context context="safety"/>
                                <context context="vehicle_status"/>
                                <context context="announcement"/>
                            </device>
                        </group>
                    </volumeGroups>              
                </zoneConfig>              
            </zoneConfigs>
        </zone>

在同一个组里面的的音频上下文,音量设置会同步,比如上面的music、announcement和notification是一组,改变了其中一种类型的音量,两外的也会跟着改变。当然,OEM厂商也可以去自定义自己的分组。
以上分组配置文件中还有一个device address的字段,这是代表音频动态路由的指定设备。在AAOS中,推荐使用硬件混音器去做音量的调节,即不使用AudioFlinger的软件调节方式。想要达到这种目的,需要在源码frameworks/base/core/res/res/values/config.xml的配置文件中,去修改config_useFixedVolume为ture,表示音量的调节在软件层面是固定的,此配置默认是false。

<!-- Flag indicating that the media framework should not allow changes or mute on any
         stream or global volumes. -->
    <bool name="config_useFixedVolume">false</bool>

同时,禁止了软件的音量调节后,还需要开启动态路由的配置,位置在packages/services/Car/service/res/values/config.xml,修改audioUseDynamicRouting字段为true,开启动态路由。此字段的默认配置是false,需要在源代码中打开:

<!--  Configuration to enable usage of dynamic audio routing. If this is set to false,
          dynamic audio routing is disabled and audio works in legacy mode. It may be useful
          during initial development where audio hal does not support bus based addressing yet. -->
    <bool name="audioUseDynamicRouting">false</bool>

你可能感兴趣的:(audio,AAOS,android,audio,AAOS)