Android音频子系统分析-音频流区分处理

在车机上,可能会遇到这种需求:

  1. 铃声和导航只在主驾扬声器播放。其它声音在所有扬声器播放。
  2. 对播放的音乐添加音效,但导航音或其它声音不添加音效。

这类需求如果在手机平台上实现,会比较复杂,修改的内容也会比较多。手机由于只有一个主扬声器,所以不管是什么类型的声音都从一个地方出来,因为大部分情况也不需要这样处理。

但如果是在车机平台,车机拥有更多的扬声器,需求就非常合理,事实上Android已经考虑到这种情况,只需要修改配置及少量的代码就可以实现。

1. 使用动态路由

通过overlay将audioUseDynamicRouting设置为true。默认为false,使用的还是手机的那一套audio_routing 配置方法。

<bool name="audioUseDynamicRouting">true</bool>

改为动态路由后,audio_policy_configuration.xml的配置方法略有不同,主要是devicePort,type将统一采用AUDIO_DEVICE_OUT_BUS,并且需要指明address,后续区分不同的音频流也是根据address来的。

2. 配置audio_policy_configuration.xml

附上一个audio_policy_configuration.xml示例

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (C) 2015 The Android Open Source Project
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
          http://www.apache.org/licenses/LICENSE-2.0
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <modules>
        <module name="primary" halVersion="2.0">
            <attachedDevices>
                <item>Speaker</item>
                <item>Built-In Mic</item>
				<item>bus0_media_out</item>
				<item>bus1_navigation_out</item>
				<item>bus2_voice_command_out</item>
				<item>bus3_call_ring_out</item>
				<item>bus4_call_out</item>
				<item>bus5_alarm_out</item>
				<item>bus6_notification_out</item>
				<item>bus7_system_sound_out</item>
            </attachedDevices>
            <defaultOutputDevice>bus0_media_out</defaultOutputDevice>
            <mixPorts>
                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus0_media_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus1_navigation_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus2_voice_command_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus3_call_ring_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus4_call_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus5_alarm_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus6_notification_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
				<mixPort name="mix_bus7_system_sound_out" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="primary input" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
                </mixPort>
            </mixPorts>
            <devicePorts>
                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus0_media_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus0_media_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus1_navigation_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus1_navigation_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus2_voice_command_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus2_voice_command_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus3_call_ring_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus3_call_ring_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus4_call_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus4_call_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus5_alarm_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus5_alarm_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus6_notification_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus6_notification_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
				<devicePort tagName="bus7_system_sound_out" type="AUDIO_DEVICE_OUT_BUS" role="sink" address="bus7_system_sound_out">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
					<gains>
                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
                                minValueMB="0" maxValueMB="49" defaultValueMB="25" stepValueMB="1"/>
                    </gains>
                </devicePort>
                <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
                <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000"
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </devicePort>
                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000 16000"
                             channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000 16000"
                             channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000 16000"
                             channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
                </devicePort>
                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
                </devicePort>
                <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
                </devicePort>
                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000 16000"
                             channelMasks="AUDIO_CHANNEL_IN_MONO"/>
                </devicePort>
            </devicePorts>
            <routes>
                <route type="mix" sink="Speaker"
                       sources="primary output"/>
				<route type="mix" sink="bus0_media_out"
                       sources="mix_bus0_media_out"/>
				<route type="mix" sink="bus1_navigation_out"
                       sources="mix_bus1_navigation_out"/>
				<route type="mix" sink="bus2_voice_command_out"
                       sources="mix_bus2_voice_command_out"/>
				<route type="mix" sink="bus3_call_ring_out"
                       sources="mix_bus3_call_ring_out"/>
				<route type="mix" sink="bus4_call_out"
                       sources="mix_bus4_call_out"/>
				<route type="mix" sink="bus5_alarm_out"
                       sources="mix_bus5_alarm_out"/>
				<route type="mix" sink="bus6_notification_out"
                       sources="mix_bus6_notification_out"/>
				<route type="mix" sink="bus7_system_sound_out"
                       sources="mix_bus7_system_sound_out"/>
                <route type="mix" sink="Wired Headset"
                       sources="primary output"/>
                <route type="mix" sink="Wired Headphones"
                       sources="primary output"/>
                <route type="mix" sink="BT SCO"
                       sources="primary output"/>
                <route type="mix" sink="BT SCO Headset"
                       sources="primary output"/>
                <route type="mix" sink="BT SCO Car Kit"
                       sources="primary output"/>
                <route type="mix" sink="primary input"
                       sources="Built-In Mic,Wired Headset Mic,BT SCO Headset Mic"/>
            </routes>
        </module>

        <xi:include href="a2dp_in_audio_policy_configuration_7_0.xml"/>
        <xi:include href="usb_audio_policy_configuration.xml"/>
        <xi:include href="r_submix_audio_policy_configuration.xml"/>
        <xi:include href="bluetooth_audio_policy_configuration_7_0.xml"/>
    </modules>

    <xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>
</audioPolicyConfiguration>

1. 先为每种类型的音频流声明一个播放设备(devicePort),注意需要同时声明gain,car service启动时会解析gain,否则car service无法正常启动。

2. 为该设备声明一个可接收的流(mixPort)。

3. 将流和设备连接起来。

3. 配置car_audio_configuration.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2020 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!--
  Defines the audio configuration in a car, including
    - Audio zones
    - Context to audio bus mappings
    - Volume groups
  in the car environment.
-->
<carAudioConfiguration version="2">
    <zones>
        <zone name="primary zone" isPrimary="true" occupantZoneId="0">
            <volumeGroups>
                <group>
                    <device address="bus0_media_out">
                        <context context="music"/>
                        <context context="announcement"/>
                    </device>
                    <device address="bus6_notification_out">
                        <context context="notification"/>
                    </device>
                </group>
                <group>
                    <device address="bus1_navigation_out">
                        <context context="navigation"/>
                    </device>
                    <device address="bus2_voice_command_out">
                        <context context="voice_command"/>
                    </device>
                </group>
                <group>
                    <device address="bus4_call_out">
                        <context context="call"/>
                    </device>
                    <device address="bus3_call_ring_out">
                        <context context="call_ring"/>
                    </device>
                </group>
                <group>
                    <device address="bus5_alarm_out">
                        <context context="alarm"/>
                    </device>
                    <device address="bus7_system_sound_out">
                        <context context="system_sound"/>
                        <context context="emergency"/>
                        <context context="safety"/>
                        <context context="vehicle_status"/>
                    </device>
                </group>
            </volumeGroups>
        </zone>
    </zones>
</carAudioConfiguration>

对应到系统设置,可以看到有4个音量调试Bar,分别对应上面的volumeGroup。

4. 如何使用address

address会通过audioflinger传递给hal

Device.cpp

std::tuple<Result, sp<IStreamOut>> Device::openOutputStreamImpl(int32_t ioHandle,
                                                                const DeviceAddress& device,
                                                                const AudioConfig& config,
                                                                const AudioOutputFlags& flags,
                                                                AudioConfig* suggestedConfig) {
    audio_config_t halConfig;
    if (HidlUtils::audioConfigToHal(config, &halConfig) != NO_ERROR) {
        return {Result::INVALID_ARGUMENTS, nullptr};
    }
    audio_stream_out_t* halStream;
    audio_devices_t halDevice;
    char halDeviceAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
    if (CoreUtils::deviceAddressToHal(device, &halDevice, halDeviceAddress) != NO_ERROR) {
        return {Result::INVALID_ARGUMENTS, nullptr};
    }
    audio_output_flags_t halFlags;
    if (CoreUtils::audioOutputFlagsToHal(flags, &halFlags) != NO_ERROR) {
        return {Result::INVALID_ARGUMENTS, nullptr};
    }
    ALOGE("CCDEBUG open_output_stream handle: %d devices: %x flags: %#x "
          "srate: %d format %#x channels %x address %s",
          ioHandle, halDevice, halFlags, halConfig.sample_rate, halConfig.format,
          halConfig.channel_mask, halDeviceAddress);
    int status = mDevice->open_output_stream(mDevice, ioHandle, halDevice, halFlags, &halConfig,
                                             &halStream, halDeviceAddress);
    ALOGV("open_output_stream status %d stream %p", status, halStream);
    sp<IStreamOut> streamOut;
    if (status == OK) {
        streamOut = new StreamOut(this, halStream, halDeviceAddress);
        ++mOpenedStreamsCount;
    }
    status_t convertStatus =
            HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, suggestedConfig);
    ALOGW_IF(convertStatus != OK, "%s: suggested config with incompatible fields", __func__);
    return {analyzeStatus("open_output_stream", status, {EINVAL} /*ignore*/), streamOut};
}

这里的halDeviceAddress就是audio_policy_configuration.xml中定义的address了。

将halDeviceAddress进一步传递给StreamOut,然后再传给WriteThread,这样从data message queue中读取的pcm数据就可以和address绑定起来了。

下面是分别点击四个音量调的日志,可以看到不同类型的音频输出已经可以区分了,并且他们分别运行在不同的线程中,说明。这样一来,就可以单独对它们做进一步处理了。

07-18 10:44:40.069   260  2722 I StreamOutHAL: CCDEBUG doWrite address bus0_media_out
07-18 10:44:55.798   260  2738 I StreamOutHAL: CCDEBUG doWrite address bus1_navigation_out
07-18 10:45:09.696   260  2753 I StreamOutHAL: CCDEBUG doWrite address bus4_call_out
07-18 10:45:21.261   260  2768 I StreamOutHAL: CCDEBUG doWrite address bus5_alarm_out

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值