Android音频模块启动流程分析

68 篇文章 14 订阅
12 篇文章 0 订阅

Android音频模块启动流程分析

Qidi 06.08.2017 (Markdown & Haroopad)


注意:本文基于 Android 7.0 进行分析。


1) 设备开机,系统启动时将执行 /system/etc/init/audioserver.rc ,运行 /system/bin/ 目录下的 audioserver 服务。audioserver.rc 内容如下:

service audioserver /system/bin/audioserver
    class main
    user audioserver
    # media gid needed for /dev/fm (radio ) and for  /data/misc/media (tee)
    group audio radio camera drmpc inet media mediarm net_bt net_bt_admin net_bw_acct
    ioprio rt 4
    writepid /dev/cpuset/forground/tasks /dev/stune/foreground/tasks

2) audioserver 进程会依次对 AudioFlinger、AudioPolicyService、RadioService、SoundTriggerHwService 进行实例化。如果设备集成了杜比音效,杜比音效的内存管理服务 DolbyMemoryService 也会在这里进行实例化。frameworks/av/media/audioserver/main_audioserver.cpp 的 main() 函数关键代码如下:

int main(int argc __unused, char** argv)
{
    ....
    if (doLog && (child = fork()) != 0) {
        // 启动 Log 线程
        ....
    } else {
        ....
        AudioFlinger::instantiate();    // AudioFlinger 的实例化先于AudioPolicyService
        AudioPolicyService::instantiate();
        RadioService::instantiate();
#ifdef DOLBY_ENABLE
        DolbyMemoryService::instantiate();
#endif
        SoundTriggerHwService::instantiate();
        ....
    }
}

3) AudioFlinger 开始构造并调用 AudioFlinger::onFirstRef() 方法进行初始化,这个过程中会初始化 MIXER 和 DUPLICATING 类型的 playback 线程被创建后的等待延时时间,然后创建 PatchPanel 对象,并将系统的音频模式设置为 AUDIO_MODE_NORMAL。相关代码位于 frameworks/av/services/audioflinger/audioflinger.cpp


4) AudioPolicyService 开始构造并调用 AudioPolicyService::onFirstRef() 方法进行初始化,这个过程中会创建 AudioPolicyManager 对象。Android 7.0系统为了兼容老版本系统中的函数调用,提供了 2 种创建 AudioPolicyManager 的方式,默认情况下,我们是使用的新的创建方式。frameworks/av/services/audiopolicy/AudioPolicyService.cpp 的 AudioPolicyService::onFirstRef() 函数关键代码如下:

void AudioPolicyService::onFirstRef()
{
    {
        ....
        // start tone playback thread
        mTonePlaybackThread = new AudioCommandThread(String8("ApmTone", this));
        // start audio commands thread
        mTonePlaybackThread = new AudioCommandThread(String8("ApmAudio", this));
        // start output activity command thread
        mTonePlaybackThread = new AudioCommandThread(String8("ApmOutput", this));
#ifdef USE_LEGACY_AUDIO_POLICY
        // 使用老版本的 audio policy 初始化方式
        ....
#else
        // 使用最新的 audio policy 初始化方式
        ALOGI("AudioPolicyService CSTOR in new mode");

        mAudioPolicyClient = new AudioPolicyClient(this);
        mAudioPolicyManager =createAudioPolicyManager(mAudioPolicyClient);    // 创建 AudioPolicyManager 对象
        ....
#endif
    }
    // load audio processing modules
    sp<AudioPolicyEffects> audioPolicyEffects = new AudioPolicyEffects();
    {
        ....
        mAudioPolicyEffects = audioPolicyEffects;
    }
}

4.1) createAudioPolicyManager() 函数的实现位于 frameworks/av/services/audiopolicy/manager/AudioPolicyFactory.cpp文件中。查看源码后我们会发现它实际上是直接调用了 AudioPolicyManager 的构造函数。代码如下:

namespace android {
extern "C" AndroidPolicyInterface* createAudioPolicyManager(
     AudioPolicyInterface *clientInterface)
{
    return new AudioPolicyManager(clientInterface);    // 调用 AudioPolicyManager 的构造函数创建对象
}
}

4.2) AudioPolicyManager 的构造函数将解析音频策略配置文件,从而获取到设备所支持的音频设备信息(包括设备是否支持 Offload、Direct 模式输出,各输入输出 profile 所支持的采样率、通道数、数据格式等),加载全部 HwModule,为之创建所有非 direct 输出类型的 outputStream 和所有 inputStream,并创建相应的 playbackThread 或 recordThread 线程。需要注意的是,Android 7.0上的音频策略配置文件开始使用 XML 格式,其文件名为 audio_policy_configuration.xml,而在之前的版本上音频策略配置文件为 audio_policy.conf。frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp 中 AudioPolicyManager 构造函数的关键代码如下:

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
    :
#ifdef AUDIO_POLICY_TEST
    Thread(false),
#endif //AUDIO_POLICY_TEST
    mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
    mA2dpSuspended(false),
    mAudioPortGeneration(1),
    mBeaconMuteRefCount(0),
    mBeaconPlayingRefCount(0),
    mBeaconMuted(false),
    mTtsOutputAvailable(false),
    mMasterMono(false)
{
    ....

#ifdef USE_XML_AUDIO_POLICY_CONF
    // 设备使用的配置文件为 audio_policy_configuration.xml
    mVolumeCurves = new VolumeCurvesCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
                             mDefaultOutputDevice, speakerDrcEnabled,
                             static_cast<VolumeCurvesCollection *>(mVolumeCurves));
    PolicySerializer serializer;
    // 解析 xml 配置文件,将设备支持的音频输出设备保存在 mAvailableOutputDevices 变量中,
    // 将设备支持的音频输入设备保存在 mAvailableInputDevices 变量中,将设备的默认音频输出
    // 设备保存在 mDefaultOutputDevice 变量中。
    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
#else
    // 设备使用的配置文件为 audio_policy.conf
    mVolumeCurves = new StreamDescriptorCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
                             mDefaultOutputDevice, speakerDrcEnabled);
    // 优先解析 vendor 目录下的 conf 配置文件,然后解析 device 目录下的 conf 配置文件。
    // 将设备支持的音频输出设备保存在 mAvailableOutputDevices 变量中,
    // 将设备支持的音频输入设备保存在 mAvailableInputDevices 变量中,将设备的默认音频输出
    // 设备保存在 mDefaultOutputDevice 变量中。
    if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
            (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
#endif
        ALOGE("could not load audio policy configuration file, setting defaults");
        config.setDefault();
    }
    // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
    mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);    // 设置音量调节曲线

    ....
    // 依次加载 HwModule 并打开其所含 profile 的 outputStream 及 inputStream
    for (size_t i = 0; i < mHwModules.size(); i++) {
        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());
        if (mHwModules[i]->mHandle == 0) {
            ALOGW("could not open HW module %s", mHwModules[i]->getName());
            continue;
        }
        // open all output streams needed to access attached devices
        // except for direct output streams that are only opened when they are actually
        // required by an app.
        // This also validates mAvailableOutputDevices list
        // 打开当前 module 下所有非 direct 类型 profile 的 outputStream
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
        {
            const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];

            ....
            // 如果当前操作的 module.profile 是 direct 类型,则不为其打开 outputStream
            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                continue;
            }
            ....
            // 获取采样率、通道数、数据格式等各音频参数
            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
                                                                                 mpClientInterface);
            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
            const DeviceVector &devicesForType = supportedDevices.getDevicesFromType(profileType);
            String8 address = devicesForType.size() > 0 ? devicesForType.itemAt(0)->mAddress
                    : String8("");

            outputDesc->mDevice = profileType;
            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
            config.sample_rate = outputDesc->mSamplingRate;
            config.channel_mask = outputDesc->mChannelMask;
            config.format = outputDesc->mFormat;
            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
            // 为当前 module.profile 打开对应的 outputStream 并创建 playbackThread 线程
            status_t status = mpClientInterface->openOutput(outProfile->getModuleHandle(),
                                                            &output,
                                                            &config,
                                                            &outputDesc->mDevice,
                                                            address,
                                                            &outputDesc->mLatency,
                                                            outputDesc->mFlags);

            ....
        }
        // open input streams needed to access attached devices to validate
        // mAvailableInputDevices list
        // 打开当前 module 下所有 profile 的 inputStream
        for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
        {
            const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];

            ....
            sp<AudioInputDescriptor> inputDesc =
                    new AudioInputDescriptor(inProfile);

            inputDesc->mDevice = profileType;

            // 获取采样率、通道数、数据格式等各音频参数
            // find the address
            DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
            //   the inputs vector must be of size 1, but we don't want to crash here
            String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
                    : String8("");
            ALOGV("  for input device 0x%x using address %s", profileType, address.string());
            ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!");

            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
            config.sample_rate = inputDesc->mSamplingRate;
            config.channel_mask = inputDesc->mChannelMask;
            config.format = inputDesc->mFormat;
            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
            // 为当前 module.profile 打开对应的 inputStream 并创建 recordThread 线程
            status_t status = mpClientInterface->openInput(inProfile->getModuleHandle(),
                                                           &input,
                                                           &config,
                                                           &inputDesc->mDevice,
                                                           address,
                                                           AUDIO_SOURCE_MIC,
                                                           AUDIO_INPUT_FLAG_NONE);

            ....
        }
    }
    ....

    updateDevicesAndOutputs();    // 更新系统缓存的音频输出设备信息
    ....
}

5) 至此,Android 系统中音频模块的启动就完成了,两大关键音频组件 AudioFlinger 和 AudioPolicyService 均已创建并运行,设备所支持的音频输入输出硬件信息也已经被 AudioPolicyManager 所解析。如果此时发生了插入耳机等操作,则 AudioPolicyService 将会接收到底层通知并把 Audio Route 切换到 WiredHeadset 等响应配置;如果此时在 APP 发生了播放音乐的操作,则 AudioFlinger 会接收到上层通知并创建相应 Track。


6) 之后设备开始播放声音时,音频数据将从 AudioTrack 传输到 AudioFlinger,再传输到 Audio HAL,直到最终写入硬件,这也是一个冗长复杂的过程。想了解这部分流程的朋友们,我推荐你们阅读 zyuanyun 写的《Android 音频系统:从 AudioTrack 到 AudioFlinger》这篇文章,他已经写得非常详细清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值