Audio System 七 之 AudioFlinger


Google Pixel、Pixel XL 内核代码(Kernel-3.18): Kernel source for Pixel and Pixel XL - GitHub

AOSP 源码(文章基于 Android 7.1.2): Android 系统全套源代码分享 (更新到 8.1.0_r1)

源码(主要源码路径):

User space audio code 源码:

• /hardware/qcom/audio/hal/(Audio 高通HAL 源码)/libhardware/modules/audio/(Audio 原生HAL 源码)/external/tinyalsa/(tinymix, tinyplay, tinycap 源码)/vendor/qcom/proprietary/mm-audio/(QTI OMX audio encoder and decoders 源码,未公开)/frameworks/av/media/audioserver/(Audioserver 源码)/hardware/libhardware_legacy/audio – (Audio legacy 源码)/frameworks/av/media/libstagefright/(Google Stagefright 多媒体框架源码)/frameworks/av/services/audioflinger/(Audioflinger 相关源码)/external/bluetooth/bluedroid/(A2DP audio HAL 相关源码)//hardware/libhardware/modules/usbaudio/(USB HAL 源码)//vendor/qcom/proprietary/wfd/mm/source/framework/src/(Wi-Fi Display (WFD)、 WFDMMSourceAudioSource.cpp,未公开)/system/core/include/system/(audio.h)/

十二、深入剖析Android音频之AudioFlinger

12.1 总体框架

在这里插入图片描述

系统启动时将执行 /system/etc/init/audioserver.rc,运行 /system/bin/ 目录下的 audioserver 服务。

audioserver.rc 内容如下:

[->\frameworks\av\media\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

audioserver 是由同目录下main_audioserver编译生成的。

12.2 AudioFlinger

AudioFlinger是整个音频系统的核心与难点。
作为Android系统中的音频中枢,它同时也是一个系统服务,启到 承上(为上层提供访问接口) 启下(通过HAL来管理音频设备) 的作用。

只有理解了AudioFlinger,才能以此为基础更好地深入到其它模块,
并且Audioserver最先启动的也是AudioFlinger,因而我们把它放在前面进行分析。

[->\frameworks\av\media\audioserver\main_audioserver.cpp]
int main(int argc __unused, char **argv)
{
    ......
    if (doLog && (childPid = fork()) != 0) {
    ......
        } else {
        // all other services
        if (doLog) {
            prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
            setpgid(0, 0);                      // but if I die first, don't kill my parent
        }
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        AudioPolicyService::instantiate();
        RadioService::instantiate();
        SoundTriggerHwService::instantiate();
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}

AudioFlinger继承了模板类BinderService,该类用于注册native service。
BinderService是一个模板类,该类的publish函数就是完成向ServiceManager注册服务。
AudioFlinger注册名为”media.audio_flinger”的服务。


12.2.1 AudioFlinger 服务的启动 和 运行

AudioFlinger的构造函数,发现它只是简单地为内部一些变量做了初始化,除此之外就没有任何代码了:

[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]
AudioFlinger::AudioFlinger()
    : BnAudioFlinger(),
      mPrimaryHardwareDev(NULL),
      mAudioHwDevs(NULL),
      mHardwareStatus(AUDIO_HW_IDLE),
      mMasterVolume(1.0f),
      mMasterMute(false),
      // mNextUniqueId(AUDIO_UNIQUE_ID_USE_MAX),
      mMode(AUDIO_MODE_INVALID),
      mBtNrecIsOff(false),
      mIsLowRamDevice(true),
      mIsDeviceTypeKnown(false),
      mGlobalEffectEnableTime(0),
      mSystemReady(false)
{
    // unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
    for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use < AUDIO_UNIQUE_ID_USE_MAX; use++) {
        // zero ID has a special meaning, so unavailable
        mNextUniqueIds[use] = AUDIO_UNIQUE_ID_USE_MAX;
    }
    ......
}

BnAudioFlinger 是由 RefBase 层层继承而来的,并且 IServiceManager::addService 的第二个参数实际上是一个强指针引用(constsp&),因而AudioFlinger具备了强指针被第一次引用时调用onFirstRef的程序逻辑。

[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]
void AudioFlinger::onFirstRef()
{
    Mutex::Autolock _l(mLock);

    /* TODO: move all this work into an Init() function */
    char val_str[PROPERTY_VALUE_MAX] = { 0 };
    if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) {
        uint32_t int_val;
        if (1 == sscanf(val_str, "%u", &int_val)) {
            mStandbyTimeInNsecs = milliseconds(int_val);
            ALOGI("Using %u mSec as standby time.", int_val);
        } else {
            mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
            ALOGI("Using default %u mSec as standby time.",
                    (uint32_t)(mStandbyTimeInNsecs / 1000000));
        }
    }

    mPatchPanel = new PatchPanel(this);

    mMode = AUDIO_MODE_NORMAL;
}

从这时开始,AudioFlinger就是一个“有意义”的实体了


12.2.2 音频设备的管理

虽然AudioFlinger实体已经成功创建并初始化,但到目前为止它还是一块静态的内存空间,没有涉及到具体的工作。

从职能分布上来讲,
AudioPolicyService是策略的制定者,比如什么时候打开音频接口设备、某种Stream类型的音频对应什么设备等等。

而AudioFlinger则是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完成。

目前Audio系统中支持的音频设备接口(Audio Interface)分为三大类,即:

[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]
static const char * const audio_interfaces[] = {
    AUDIO_HARDWARE_MODULE_ID_PRIMARY,
    AUDIO_HARDWARE_MODULE_ID_A2DP,
    AUDIO_HARDWARE_MODULE_ID_USB,
};

每种音频设备接口由一个对应的so库提供支持。
那么AudioFlinger怎么会知道当前设备中支持上述的哪些接口,每种接口又支持哪些具体的音频设备呢?
这是AudioPolicyService的责任之一,即根据用户配置来指导AudioFlinger加载设备接口。

当AudioPolicyManagerBase(AudioPolicyService中持有的Policy管理者,后面小节有详细介绍)构造时,
它会读取厂商关于音频设备的描述文件(audio_policy.conf),然后据此来打开以上三类音频接口(如果存在的话)。

这一过程最终会调用loadHwModule@AudioFlinger,如下所示:


12.2.2.1 加载设备loadHwModule()
[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]

/*name就是前面audio_interfaces 数组成员中的字符串*/
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
{
    if (name == NULL) {
        return AUDIO_MODULE_HANDLE_NONE;
    }
    if (!settingsAllowed()) {
        return AUDIO_MODULE_HANDLE_NONE;
    }
    Mutex::Autolock _l(mLock);
    return loadHwModule_l(name);
}

这个函数没有做实质性的工作,只是执行了加锁动作,然后接着调用下面的函数:

[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]
// loadHwModule_l() must be called with AudioFlinger::mLock held
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{

    /* Step 1. 是否已经添加了这个interface ? */
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
            ALOGW("loadHwModule() module %s already loaded", name);
            return mAudioHwDevs.keyAt(i);
        }
    }

    audio_hw_device_t *dev;
    /* Step 2. 加载audio interface */
    int rc = load_audio_interface(name, &dev);
    ......
    
    /* Step 3. 初始化 */
    mHardwareStatus = AUDIO_HW_INIT;
    rc = dev->init_check(dev);
    mHardwareStatus = AUDIO_HW_IDLE;
    
    ......
    /* Step 4. 添加到全局变量中 */
    audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));

    return handle;
}
  • Step1@ loadHwModule_l.
    首先查找mAudioHwDevs是否已经添加了变量name所指示的audio interface,如果是的话直接返回。
    第一次进入时mAudioHwDevs的size为0,所以还会继续往下执行。

  • Step2@ loadHwModule_l.
    加载指定的 audiointerface,比如 “primary”、“a2dp”或者“usb”。
    函数 load_audio_interface 用来加载设备所需的库文件,然后打开设备并创建一个 audio_hw_device_t 实例。
    音频接口设备所对应的库文件名称是有一定格式的,比如 a2dp 的模块名可能是 audio.a2dp.so 或者 audio.a2dp.default.so 等等。

查找路径主要有两个,即:

[->\hardware\libhardware\hardware.c]
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"

当然,因为Android是完全开源的,各开发商可以根据自己的需要来进行相应的修改,比如下面是Google pixel 设备的音频库:

adb shell && cd system/lib64/hw && ls -l
-rw-r--r-- 1 root root   30440 2009-01-01 00:00 audio.a2dp.default.so
-rw-r--r-- 1 root root   18156 2009-01-01 00:00 audio.primary.default.so
-rw-r--r-- 1 root root  275612 2009-01-01 00:00 audio.primary.msm8996.so
-rw-r--r-- 1 root root   34540 2009-01-01 00:00 audio.r_submix.default.so
-rw-r--r-- 1 root root   22248 2009-01-01 00:00 audio.usb.default.so
-rw-r--r-- 1 root root   96096 2009-01-01 00:00 audio_policy.default.so
-rw-r--r-- 1 root root 1637208 2009-01-01 00:00 bluetooth.default.so
......
  • Step3@ loadHwModule_l
    进行初始化操作。
    其中 init_check 是为了确定这个 audio interface 是否已经成功初始化,0是成功,其它值表示失败。
    接下来如果这个 device 支持主音量,我们还需要通过 set_master_volume 进行设置。
    在每次操作 device 前,都要先改变 mHardwareStatus 的状态值,
    操作结束后将其复原为 AUDIO_HW_IDLE (根据源码中的注释,这样做是为了方便dump时正确输出内部状态,这里我们就不去深究了)。

  • Step4@ loadHwModule_l
    把加载后的设备添加入mAudioHwDevs键值对中,其中key的值是由nextUniqueId生成的,
    这样做保证了这个audiointerface拥有全局唯一的id号。


完成了 audiointerface 的模块加载只是万里长征的第一步。
因为每一个interface包含的设备通常不止一个,Android系统目前支持的音频设备如下列表所示:
Android系统支持的音频设备列表(输出)

[->\hardware\libhardware_legacy\audio\audio_hw_hal.cpp]
static uint32_t audio_device_conv_table[][HAL_API_REV_NUM] =
{
    /* output devices */
    { AudioSystem::DEVICE_OUT_EARPIECE, AUDIO_DEVICE_OUT_EARPIECE },//
    { AudioSystem::DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER },//SPEAKER
    { AudioSystem::DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADSET },//HEADSET
    { AudioSystem::DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADPHONE },//HEADPHONE
    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, AUDIO_DEVICE_OUT_BLUETOOTH_SCO },
    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET },
    { AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT },
    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP },
    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES },
    { AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER },
    { AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL },
    { AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET },
    { AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET },
    { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT },//默认设备
    ......
}

大家可能会有疑问:
Ø 这么多的输出设备,那么当我们回放音频流(录音也是类似的情况)时,该选择哪一种呢?
Ø 而且当前系统中audio interface也很可能不止一个,应该如何选择?

显然这些决策工作将由AudioPolicyService来完成,我们会在下一小节做详细阐述。这里先给大家分析下,AudioFlinger是如何打开一个Output通道的(一个audiointerface可能包含若干个output)。


12.2.2.2 打开音频输出通道openOutput()

打开音频输出通道(output)在AudioFlinger中对应的接口是openOutput(),即:

[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]
status_t AudioFlinger::openOutput(audio_module_handle_t module,
                                  audio_io_handle_t *output,
                                  audio_config_t *config,
                                  audio_devices_t *devices,
                                  const String8& address,
                                  uint32_t *latencyMs,
                                  audio_output_flags_t flags)
{
    ......
    Mutex::Autolock _l(mLock);

    sp<PlaybackThread> thread = openOutput_l(module, output, config, *devices, address, flags);
    if (thread != 0) {
        *latencyMs = thread->latency();

        // notify client processes of the new output creation
        thread->ioConfigChanged(AUDIO_OUTPUT_OPENED);

        // the first primary output opened designates the primary hw device
        if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
            ALOGI("Using module %d has the primary audio interface", module);
            mPrimaryHardwareDev = thread->getOutput()->audioHwDev;

            AutoMutex lock(mHardwareLock);
            mHardwareStatus = AUDIO_HW_SET_MODE;
            mPrimaryHardwareDev->hwDevice()->set_mode(mPrimaryHardwareDev->hwDevice(), mMode);
            mHardwareStatus = AUDIO_HW_IDLE;
        }
        return NO_ERROR;
    }
    return NO_INIT;
}

继续调用 openOutput_l()函数从处理。

[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]
sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_t module,
                                                            audio_io_handle_t *output,
                                                            audio_config_t *config,
                                                            audio_devices_t devices,
                                                            const String8& address,
                                                            audio_output_flags_t flags)
{
    /*Step 1. 查找相应的audio interface */
    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
    ......
    mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;

     ......

    AudioStreamOut *outputStream = NULL;
     /*Step 2. 为设备打开一个输出流*/
    status_t status = outHwDev->openOutputStream(
            &outputStream,
            *output,
            devices,
            flags,
            config,
            address.string());

    mHardwareStatus = AUDIO_HW_IDLE;
    /*Step 3.创建PlaybackThread*/
    if (status == NO_ERROR) {

        PlaybackThread *thread;
        if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
            ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread);
        } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                || !isValidPcmSinkFormat(config->format)
                || !isValidPcmSinkChannelMask(config->channel_mask)) {
            thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
            ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread);
        } else {
            thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
            ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread);
        }
        mPlaybackThreads.add(*output, thread);
        return thread;
    }

    return 0;
}

上面这段代码中,颜色加深的部分是我们接下来分析的重点,
主要还是围绕outHwDev这个变量所做的一系列操作,即:

  • 查找合适的音频接口设备( findSuitableHwDev_l() )
  • 创建音频输出流( 通过openOutputStream()创建AudioStreamOut )
  • 创建播放线程( PlaybackThread )

outHwDev用于记录一个打开的音频接口设备,它的数据类型是audio_hw_device_t,
是由HAL规定的一个音频接口设备所应具有的属性集合,

如下所示:

[->\frameworks\av\services\audioflinger\AudioHwDevice.h]
class AudioHwDevice {
......
    audio_module_handle_t handle() const { return mHandle; }
    const char *moduleName() const { return mModuleName; }
    audio_hw_device_t *hwDevice() const { return mHwDevice; }
    uint32_t version() const { return mHwDevice->common.version; }
    
    status_t openOutputStream(
            AudioStreamOut **ppStreamOut,
            audio_io_handle_t handle,
            audio_devices_t devices,
            audio_output_flags_t flags,
            struct audio_config *config,
            const char *address);
private:
    const audio_module_handle_t mHandle;
    const char * const          mModuleName;
    audio_hw_device_t * const   mHwDevice;
    const Flags                 mFlags;
};
}

其中common代表了HAL层所有设备的共有属性;
set_master_volume、set_mode、open_output_stream分别为我们设置audio interface的主音量、
设置音频模式类型(比如AUDIO_MODE_RINGTONE、AUDIO_MODE_IN_CALL等等、
打开输出数据流提供了接口。

接下来我们分步来阐述。


12.2.2.2.1 查找合适的音频接口设备findSuitableHwDev_l()

Step1@
AudioFlinger::openOutput. 在openOutput中,设备outHwDev是通过查找当前系统来得到的
代码如下:

[->\frameworks\av\services\audioflinger\AudioFlinger.cpp]
AudioHwDevice* AudioFlinger::findSuitableHwDev_l( audio_module_handle_t module, audio_devices_t devices)
{
    // if module is 0, the request comes from an old policy manager and we should load
    // well known modules
    if (module == 0) {
        ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
        for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
            loadHwModule_l(audio_interfaces[i]);
        }
        // then try to find a module supporting the requested device.
        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
            AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);
            audio_hw_device_t *dev = audioHwDevice->hwDevice();
            if ((dev->get_supported_devices != NULL) && (dev->get_supported_devices(dev) & devices) == devices)
                return audioHwDevice;
        }
    } else {
        // check a match for the requested module handle
        AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);
        if (audioHwDevice != NULL) {
            return audioHwDevice;
        }
    }
    return NULL;
}

变量module值为0的情况,是为了兼容之前的Audio Policy而特别做的处理。
当module等于0时,首先加载所有已知的音频接口设备,然后再根据devices来确定其中符合要求的。
入参devices的值实际上来源于“ Android系统支持的音频设备列表(输出)”所示的设备。
可以看到,enum中每个设备类型都对应一个特定的比特位,因而上述代码段中可以通过“与运算”来找到匹配的设备。

当modules为非0值时,说明Audio Policy指定了具体的设备id号,这时就通过查找全局的mAudioHwDevs变量来确认是否存在符合要求的设备。

[->\frameworks\av\services\audioflinger\AudioFlinger.h]
DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>  mAudioHwDevs;

变量mAudioHwDevs是一个Vector,以audio_module_handle_t为key,每一个handle值唯一确定了已经添加的音频设备。

那么在什么时候添加设备呢?
一种情况就是前面看到的modules为0时,会load所有潜在设备,
另一种情况就是AudioPolicyManagerBase在构造时会预加载所有audio_policy.conf中所描述的output。

不管是哪一种情况,最终都会调用loadHwModuleloadHwModule_l,这个函数我们开头就分析过了。

如果modules为非0,且从mAudioHwDevs中也找不到符合要求的设备,程序并不会就此终结——它会退而求其次,遍历数组中的所有元素寻找支持devices的任何一个audio interface。

12.2.2.2.2 创建音频输出流openOutputStream()

Step2@
AudioFlinger::openOutput,调用openOutputStream()函数打开一个AudioStreamOut 。

源码实现如下:

[->\frameworks\av\services\audioflinger\AudioHwDevice.cpp]
status_t AudioHwDevice::openOutputStream(
        AudioStreamOut **ppStreamOut,
        audio_io_handle_t handle,
        audio_devices_t devices,
        audio_output_flags_t flags,
        struct audio_config *config,
        const char *address)
{

    struct audio_config originalConfig = *config;
    AudioStreamOut *outputStream = new AudioStreamOut(this, flags);
    
    status_t status = outputStream->open(handle, devices, config, address);

    ......
    *ppStreamOut = outputStream;
    return status;
}

生成AudioStreamOut对象并赋值给ppStreamOut ,进一步调用了AudioStreamOut->open()函数。

[->\frameworks\av\services\audioflinger\AudioStreamOut.cpp]
status_t AudioStreamOut::open(
        audio_io_handle_t handle,
        audio_devices_t devices,
        struct audio_config *config,
        const char *address)
{
    audio_stream_out_t *outStream;
    .......
    int status = hwDev()->open_output_stream(
            hwDev(),
            handle,
            devices,
            customFlags,
            config,
            &outStream,
            address);
    ......
    return status;
}

即会通过 audio_hw_device_t->->open_output_stream() 创建音频输出流.

  • (1) audio_hw_device_t->->open_output_stream()
    我们先看一下HAL层代码
[->\hardware\qcom\audio\hal\audio_hw.c]
static int adev_open(const hw_module_t *module, const char *name,
                     hw_device_t **device)
{
    ......
    adev = calloc(1, sizeof(struct audio_device));

    pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);

    adev->device.common.tag = HARDWARE_DEVICE_TAG;
    adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
    adev->device.common.module = (struct hw_module_t *)module;
    adev->device.common.close = adev_close;

    adev->device.init_check = adev_init_check;
    adev->device.set_voice_volume = adev_set_voice_volume;
    adev->device.set_master_volume = adev_set_master_volume;
    adev->device.get_master_volume = adev_get_master_volume;
    adev->device.set_master_mute = adev_set_master_mute;
    adev->device.get_master_mute = adev_get_master_mute;
    adev->device.set_mode = adev_set_mode;
    adev->device.set_mic_mute = adev_set_mic_mute;
    adev->device.get_mic_mute = adev_get_mic_mute;
    adev->device.set_parameters = adev_set_parameters;
    adev->device.get_parameters = adev_get_parameters;
    adev->device.get_input_buffer_size = adev_get_input_buffer_size;
    adev->device.open_output_stream = adev_open_output_stream;
    adev->device.close_output_stream = adev_close_output_stream;
    adev->device.open_input_stream = adev_open_input_stream;
    adev->device.close_input_stream = adev_close_input_stream;
    ......
}

可以看到当调用open_output_stream 就会调用adev_open_output_stream。

[->\hardware\qcom\audio\hal\audio_hw.c]
static int adev_open_output_stream(struct audio_hw_device *dev,
                audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags,
                struct audio_config *config, struct audio_stream_out **stream_out, const char *address __unused)
{
    struct audio_device *adev = (struct audio_device *)dev;
    struct stream_out *out;
    
    *stream_out = NULL;
    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));

    ......
    out->stream.common.get_sample_rate = out_get_sample_rate;
    out->stream.common.set_sample_rate = out_set_sample_rate;
    out->stream.common.get_buffer_size = out_get_buffer_size;
    out->stream.common.get_channels = out_get_channels;
    out->stream.common.get_format = out_get_format;
    out->stream.common.set_format = out_set_format;
    out->stream.common.standby = out_standby;
    out->stream.common.dump = out_dump;
    out->stream.common.set_parameters = out_set_parameters;
    out->stream.common.get_parameters = out_get_parameters;
    out->stream.common.add_audio_effect = out_add_audio_effect;
    out->stream.common.remove_audio_effect = out_remove_audio_effect;
    out->stream.get_latency = out_get_latency;
    out->stream.set_volume = out_set_volume;
#ifdef NO_AUDIO_OUT
    out->stream.write = out_write_for_no_output;
#else
    out->stream.write = out_write;
#endif
    out->stream.get_render_position = out_get_render_position;
    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
    out->stream.get_presentation_position = out_get_presentation_position;

    out->af_period_multiplier  = out->realtime ? af_period_multiplier : 1;
    out->standby = 1;
    ......

    *stream_out = &out->stream;
    ALOGV("%s: exit", __func__);
    return 0;
}

根据音频流的熟悉做一系列初始化操作。转了一大圈,继续看看


12.2.2.2.3 创建播放线程(PlaybackThread)

Step3@
AudioFlinger::openOutput. 既然通道已经打开,那么由谁来往通道里放东西呢?
这就是PlaybackThread。

这里分三种不同的情况:

  • OffloadThread
  • DirectOutput 如果不需要混音
  • Mixer 需要混音

这三种情况分别对应DirectOutputThread、OffloadThread和MixerThread三种线程。

我们以后者为例来分析下PlaybackThread的工作模式,也会后面小节打下基础。
回放线程(PlaybackThread 及其派生的子类)和录制线程(RecordThread)进行的,

先简单看看回放线程和录制线程类关系:
在这里插入图片描述

  • ThreadBase:PlaybackThread 和 RecordThread 的基类

  • RecordThread:录制线程类,由 ThreadBase 派生

  • PlaybackThread:回放线程基类,同由 ThreadBase 派生

  • MixerThread
    混音回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流,MixerThread 可以把多个音轨的数据混音后再输出

  • DirectOutputThread
    直输回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_DIRECT 的音频流,这种音频流数据不需要软件混音,直接输出到音频设备即可

  • DuplicatingThread
    复制回放线程类,由 MixerThread 派生,负责复制音频流数据到其他输出设备,
    使用场景如主声卡设备、蓝牙耳机设备、USB 声卡设备同时输出

  • OffloadThread
    硬解回放线程类,由 DirectOutputThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流,这种音频流未经软件解码的(一般是 MP3、AAC 等格式的数据),需要输出到硬件解码器,由硬件解码器解码成 PCM 数据

PlaybackThread 中有个极为重要的函数 threadLoop(),当 PlaybackThread 被强引用时,threadLoop() 会真正运行起来进入循环主体,处理音频流数据相关事务,threadLoop() 大致流程如下(以 MixerThread 为例):

[->\frameworks\av\services\audioflinger\Threads.cpp]
bool AudioFlinger::PlaybackThread::threadLoop()
{
    // ......

    while (!exitPending())
    {
        // ......

        { // scope for mLock

            Mutex::Autolock _l(mLock);

            processConfigEvents_l();

            // ......

            if ((!mActiveTracks.size() && systemTime() > mStandbyTimeNs) || isSuspended()) {
                // put audio hardware into standby after short delay
                if (shouldStandby_l()) {

                    threadLoop_standby();

                    mStandby = true;
                }

                // ......
            }
            // mMixerStatusIgnoringFastTracks is also updated internally
            mMixerStatus = prepareTracks_l(&tracksToRemove);

            // ......
        } // mLock scope ends

        // ......

        if (mBytesRemaining == 0) {
            mCurrentWriteLength = 0;
            if (mMixerStatus == MIXER_TRACKS_READY) {
                // threadLoop_mix() sets mCurrentWriteLength
                threadLoop_mix();
            }
            // ......
        }

        // ......

        if (!waitingAsyncCallback()) {
            // mSleepTimeUs == 0 means we must write to audio hardware
            if (mSleepTimeUs == 0) {
                // ......
                if (mBytesRemaining) {
                    // FIXME rewrite to reduce number of system calls
                    ret = threadLoop_write();
                    lastWriteFinished = systemTime();
                    delta = lastWriteFinished - mLastWriteTime;
                    if (ret < 0) {
                        mBytesRemaining = 0;
                    } else {
                        mBytesWritten += ret;
                        mBytesRemaining -= ret;
                        mFramesWritten += ret / mFrameSize;
                    }
                }
                // ......
            }
            // ......
        }

        // Finally let go of removed track(s), without the lock held
        // since we can't guarantee the destructors won't acquire that
        // same lock.  This will also mutate and push a new fast mixer state.
        threadLoop_removeTracks(tracksToRemove);
        tracksToRemove.clear();

        // ......
    }

    threadLoop_exit();

    if (!mStandby) {
        threadLoop_standby();
        mStandby = true;
    }

    // ......
    return false;
}
  1. threadLoop()
    循环的条件是 exitPending() 返回 false,
    如果想要 PlaybackThread 结束循环,则可以调用 requestExit() 来请求退出;

  2. processConfigEvents_l()
    处理配置事件;
    当有配置改变的事件发生时,需要调用 sendConfigEvent_l() 来通知 PlaybackThread,这样 PlaybackThread 才能及时处理配置事件;
    常见的配置事件是切换音频通路;
    检查此时此刻是否符合 standby 条件,比如当前并没有 ACTIVE 状态的 Track(mActiveTracks.size() = 0),
    那么调用threadLoop_standby() 关闭音频硬件设备以节省能耗;

  3. prepareTracks_l()
    准备音频流和混音器,该函数非常复杂,这里不详细分析了,仅列一下流程要点:
    遍历 mActiveTracks,逐个处理 mActiveTracks 上的 Track,检查该 Track 是否为 ACTIVE 状态;
    如果 Track 设置是 ACTIVE 状态,则再检查该 Track 的数据是否准备就绪了;
    根据音频流的音量值、格式、声道数、音轨的采样率、硬件设备的采样率,配置好混音器参数;
    如果 Track 的状态是 PAUSED 或 STOPPED,则把该 Track 添加到 tracksToRemove 向量中;

  4. threadLoop_mix()
    读取所有置了 ACTIVE 状态的音频流数据,混音器开始处理这些数据;

  5. threadLoop_write()
    把混音器处理后的数据写到输出流设备;

  6. threadLoop_removeTracks()
    把 tracksToRemove 上的所有 Track 从 mActiveTracks 中移除出来;这样下一次循环时就不会处理这些 Track 了。


这里说说 PlaybackThread 与输出流设备的关系:
PlaybackThread 实例与输出流设备是一一对应的,
比方说 OffloadThread 只会将音频数据输出到 compress_offload 设备中,
MixerThread(with FastMixer) 只会将音频数据输出到 low_latency 设备中。


从 Audio HAL 中,我们通常看到如下 4 种输出流设备,分别对应着不同的播放场景:
  1. primary_out
    主输出流设备,用于铃声类声音输出,
    对应着标识为 AUDIO_OUTPUT_FLAG_PRIMARY 的音频流 和 一个 MixerThread 回放线程实例。

  2. low_latency
    低延迟输出流设备,
    用于按键音、游戏背景音等对时延要求高的声音输出,
    对应着标识为 AUDIO_OUTPUT_FLAG_FAST 的音频流 和 一个 MixerThread 回放线程实例。

  3. deep_buffer
    音乐音轨输出流设备,用于音乐等对时延要求不高的声音输出.
    对应着标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流 和 一个 MixerThread 回放线程实例。

  4. compress_offload
    硬解输出流设备,用于需要硬件解码的数据输出,
    对应着标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流和一个 OffloadThread 回放线程实例

其中 primary_out 设备是必须声明支持的,而且系统启动时就已经打开 primary_out 设备并创建好对应的 MixerThread 实例。
其他类型的输出流设备并非必须声明支持的,主要是看硬件上有无这个能力。


可能有人产生这样的疑问:既然 primary_out 设备一直保持打开,那么能耗岂不是很大?

这里阐释一个概念:
输出流设备属于逻辑设备,并不是硬件设备。所以即使输出流设备一直保持打开,只要硬件设备不工作,那么就不会影响能耗。

那么硬件设备什么时候才会打开呢?
答案是 PlaybackThread 将音频数据写入到输出流设备时。

下图简单描述 AudioTrack、PlaybackThread、输出流设备三者的对应关系:
在这里插入图片描述
我们可以这么说: 输出流设备决定了它对应的 PlaybackThread 是什么类型。

怎么理解呢?意思是说:
只有支持了该类型的输出流设备,那么该类型的 PlaybackThread 才有可能被创建。

举个例子:
只有硬件上具备硬件解码器,系统才建立 compress_offload 设备,然后播放 mp3 格式的音乐文件时,才会创建 OffloadThread 把数据输出到 compress_offload 设备上;
反之,如果硬件上并不具备硬件解码器,系统则不应该建立 compress_offload 设备,那么播放 mp3 格式的音乐文件时,通过 MixerThread 把数据输出到其他输出流设备上。


那么有无可能出现这种情况: 底层并不支持 compress_offload 设备,但偏偏有个标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流送到 AudioFlinger 了呢?

答案是:这是不可能的。

系统启动时,会检查并保存输入输出流设备的支持信息;播放器在播放 mp3 文件时,
首先看 compress_offload 设备是否支持了,
如果支持,那么不进行软件解码,直接把数据标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
如果不支持,那么先进行软件解码,然后把解码好的数据标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER,前提是 deep_buffer 设备是支持了的;
如果 deep_buffer 设备也不支持,那么把数据标识为 AUDIO_OUTPUT_FLAG_PRIMARY。

系统启动时,就已经打开 primary_out、low_latency、deep_buffer 这三种输出流设备,并创建对应的 MixerThread 了;
而此时 DirectOutputThread 与 OffloadThread 不会被创建,
直到标识为AUDIO_OUTPUT_FLAG_DIRECT/AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流需要输出时,
才开始创建 DirectOutputThread/OffloadThread 和打开 direct_out/compress_offload 设备。

这一点请参考如下代码,注释非常清晰:

[->\frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp]
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
    // ......
{
    // ......

    // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
    // open all output streams needed to access attached devices
    // ......
    for (size_t i = 0; i < mHwModules.size(); i++) {
        // ......
        // 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
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
        {
            // ......
            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                continue;
            }
            // ......
            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
            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
        for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
        {
            // ......
            status_t status = mpClientInterface->openInput(inProfile->getModuleHandle(),
                                                           &input,
                                                           &config,
                                                           &inputDesc->mDevice,
                                                           address,
                                                           AUDIO_SOURCE_MIC,
                                                           AUDIO_INPUT_FLAG_NONE);

            // ......
        }
    }
    // ......

    updateDevicesAndOutputs();
}

其中 mpClientInterface->openOutput() 最终会调用到 AudioFlinger::openOutput():打开输出流设备,并创建 PlaybackThread 对象:

status_t AudioFlinger::openOutput(audio_module_handle_t module,
                                  audio_io_handle_t *output,
                                  audio_config_t *config,
                                  audio_devices_t *devices,
                                  const String8& address,
                                  uint32_t *latencyMs,
                                  audio_output_flags_t flags)
{
    // ......

    Mutex::Autolock _l(mLock);

    sp<PlaybackThread> thread = openOutput_l(module, output, config, *devices, address, flags);
    // ......
}

sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_t module,
                                                            audio_io_handle_t *output,
                                                            audio_config_t *config,
                                                            audio_devices_t devices,
                                                            const String8& address,
                                                            audio_output_flags_t flags)
{
    // ......
    // 分配全局唯一的 audio_io_handle_t,可以理解它是回放线程的索引号
    if (*output == AUDIO_IO_HANDLE_NONE) {
        *output = nextUniqueId(); 
    }

    mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;

    //......

    // 打开音频输出流设备,HAL 层根据 flags 选择打开相关类型的输出流设备
    AudioStreamOut *outputStream = NULL;
    status_t status = outHwDev->openOutputStream(
            &outputStream,
            *output,
            devices,
            flags,
            config,
            address.string());

    mHardwareStatus = AUDIO_HW_IDLE;

    if (status == NO_ERROR) {

        PlaybackThread *thread;
        if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
            // AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 音频流,创建 OffloadThread 实例
            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
            ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread);
        } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                || !isValidPcmSinkFormat(config->format)
                || !isValidPcmSinkChannelMask(config->channel_mask)) {
            // AUDIO_OUTPUT_FLAG_DIRECT 音频流,创建 DirectOutputThread 实例
            thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
            ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread);
        } else {
            // 其他标识的音频流,创建 MixerThread 实例
            thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
            ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread);
        }
        // 把 audio_io_handle_t 和 PlaybackThread 添加到键值对向量 mPlaybackThreads 中
        // 键值对向量 mPlaybackThreads 中,由于 audio_io_handle_t 和 PlaybackThread 是一
        // 一对应的关系,所以拿到一个 audio_io_handle_t,就能找到它对应的 PlaybackThread
        // 所以可以理解 audio_io_handle_t 为 PlaybackThread 的索引号
        mPlaybackThreads.add(*output, thread);
        return thread;
    }

    return 0;
}


12.2.2.3 AudioFlinger 音频流管理

AudioFlinger 音频流管理由 AudioFlinger::PlaybackThread::Track 实现,
Track 与 AudioTrack 是一对一的关系,一个 AudioTrack 创建后,那么 AudioFlinger 会创建一个 Track 与之对应;
PlaybackThread 与 AudioTrack/Track 是一对多的关系,一个 PlaybackThread 可以挂着多个 Track。

具体来说:
AudioTrack 创建后,AudioPolicyManager 根据 AudioTrack 的输出标识和流类型,找到对应的输出流设备和 PlaybackThread
(如果没有找到的话,则系统会打开对应的输出流设备并新建一个 PlaybackThread),
然后创建一个 Track 并挂到这个 PlaybackThread 下面。


PlaybackThread 有两个私有成员向量与此强相关:

  1. mTracks
    该 PlaybackThread 创建的所有 Track 均添加保存到这个向量中。

  2. mActiveTracks
    只有需要播放(设置了 ACTIVE 状态)的 Track 会添加到这个向量中;
    PlaybackThread 会从该向量上找到所有设置了 ACTIVE 状态的 Track,把这些 Track 数据混音后写到输出流设备。


音频流控制最常用的三个接口:

  • AudioFlinger::PlaybackThread::Track::start:开始播放:
    把该 Track 置 ACTIVE 状态,然后添加到 mActiveTracks 向量中,
    最后调用 AudioFlinger::PlaybackThread::broadcast_l() 告知 PlaybackThread 情况有变

  • AudioFlinger::PlaybackThread::Track::stop:停止播放:
    把该 Track 置 STOPPED 状态,
    最后调用 AudioFlinger::PlaybackThread::broadcast_l() 告知 PlaybackThread 情况有变

  • AudioFlinger::PlaybackThread::Track::pause:暂停播放:
    把该 Track 置 PAUSING 状态,
    最后调用 AudioFlinger::PlaybackThread::broadcast_l() 告知 PlaybackThread 情况有变

  • AudioFlinger::PlaybackThread::threadLoop()
    得悉情况有变后,调用 prepareTracks_l() 重新准备音频流和混音器:
    ACTIVE 状态的 Track 会添加到 mActiveTracks,此外的 Track 会从 mActiveTracks 上移除出来,
    然后重新准备 AudioMixer。

可见这三个音频流控制接口是非常简单的,主要是设置一下 Track 的状态,然后发个事件通知 PlaybackThread 就行,
复杂的处理都在 AudioFlinger::PlaybackThread::threadLoop() 中了。






参考资料(特别感谢各位前辈的分析和图示):

特别感谢 - 林学森的Android专栏
特别感谢 - Yangwen123 - 深入剖析Android音频系统
特别感谢 - Zyuanyun - Android 音频系统:从 AudioTrack 到 AudioFlinger

发布了329 篇原创文章 · 获赞 66 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Ciellee/article/details/101781567