Android 11音频服务创建以及播放的流程

1、音频服务初始化流程

当前版本:Android 11

大致的创建流程如下:

1
2
3
4
5
6 和AudioFlinger交互
7
8 返回加载结果
9
main_audioserver
AudioFlinger
AudioPolicyService
AudioPolicyManager
解析包含设备的xml配置
初始化Engine并解析策略xml
加载xml解析出的模块
打开输入输出流

经过上面的流程系统音频服务已经启动处于待命状态,如果有应用需要播放则会通过服务最终选择合适的硬件将声音播出,接下来按照上面的流程进行进一步的细分。

1.1 开机启动音频服务

音频服务在frameworks/av/media/audioserver/main_audioserver.cpp中,这里会启动音频的AudioFlingerAudioPolicyService两大组件,简单的流程如下:

1 instantiate
2 instantiate
main_audioserver
AudioFlinger
AudioPolicyService

经过上面流程之后音频系统中会启动AudioFlinger用于处理后面所有的音频播放,AudioFlinger具体的功能后面再详细分析,AudioPolicyService负责后面的音频策略的处理等流程,AudioFlingerAudioPolicyService之间进行交互

1.2 AudioFlinger模块加载

通过上面流程会调用到AudioFlinger的构造函数,进行AudioFlinger模块的处理,流程如下:

onFirstRef
构造函数
DevicesFactoryHalInterface.cpp
1
2
DevicesFactoryHalCallbackImpl
EffectsFactoryHalInterface::create
DevicesFactoryHalInterface::create
create
AudioFlinger

在上面的构造函数中实例化了设备接口以及音效接口,此时AudioFlinger模块已经成功创建出来,后面即使AudioPolicyService创建出来后和AudioFlinger之间的交互过程

1.3 AudioPolicyService模块加载

AudioPolicyService负责音频的一些策略管理以及命令处理,具体的启动流程如下:

Engine
xml文件解析
AudioPolicyManager
AudioPolicyService
1 启动音频命令处理线程
2 启动output活跃命令线程
3
4
5
2
1 传入APM持有的AudioPolicyConfig对象,解析出来放在这里
解析xml配置文件
这里是一个模板,会解析出所有的内容
1 加载音频engine库
2 根据前面加载的库调用该函数创建Engine对象
3 设置APM为监听者
4 初始化检查
5 打开访问附加设备所需的所有输出流
和AudioFlinger交互
load
createEngine
setObserver
initCheck
deserializeAudioPolicyXmlConfig
deserializeAudioPolicyFile
PolicySerializer::deserialize
deserializeCollection
deserialize
AudioPolicyManagerSPRD构造
AudioPolicyManager构造
loadConfig
initialize
onNewAudioModulesAvailableInt
APS构造函数
onFirstRef
new-AudioCommandThread
new1-AudioCommandThread
new-AudioPolicyClient
createAudioPolicyManager
new-AudioPolicyEffects
AudioFlinger
  • 这里调用的createAudioPolicyManager定义在vendor/sprd/modules/audio/newapm/R.x/AudioPolicyManagerSPRD.cpp
  • 解析的配置文件包含audio_policy_configuration.xml,用于解析包含音频策略在内的一些配置文件
  • deserializeAudioPolicyFile方法定义在frameworks/av/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp文件中
  • primary_audio_policy_configuration.xml文件解析流程配置解析
  • Engine配置分析

总结:

  1. 首先分析了从AudioPolicyService创建AudioPolicyManager的流程,这里涉及到第三方自己的AudioPolicyManager,所以中间多了一个AudioPolicyManagerSPRD的创建
  2. 有了AudioPolicyManager对象之后需要加载音频的一些配置文件,包括描述所有外部设备以及设备之间路由情况的primary_audio_policy_configuration.xml,这个xml文件解析之后会将内容存放到AudioPolicyManager持有的AudioPolicyConfig对象中,具体的作用我们后面分析
  3. 加载完xml之后就是进行Engine对象的创建,这个Engine对象负责管理音频策略相关的内容
  4. Engine对象创建完毕之后需要对xml解析出来的内容进行处理,这部分涉及和AudioFlinger的交互,放在后面一节讲述

1.3.1 AudioPolicyServiceAudioFlinger交互流程

audio_hw
DevicesFactoryHalLocal
AudioFlinger
AudioPolicyManager
1
1 mDevicesFactoryHal->openDevice
2 new AudioHwDevice
3 add添加到mAudioHwDevs
1
2
1 调用hardware.c中内容打开相应音频HAL层库
2 hardware/audio.h
这里会根据前面加载的库文件进行最终调用
2 将已经成功加载的模块添加到该容器中
3
adev_open
openDevice
load_audio_interface
new-DeviceHalLocal
loadHwModule
loadHwModule_l
onNewAudioModulesAvailableInt
mHwModules
打开访问连接设备的所有输入输出流
AudioHwDevice构造
mAudioHwDevs
hw_get_module_byclass
audio_hw_device_open

这里涉及几个重要的文件位置:

frameworks/av/services/audiopolicy/common/managerdefinitions/include/HwModule.h

hardware/libhardware/include/hardware/audio.h

hardware/libhardware/hardware.c

frameworks/av/media/libaudiohal/impl/DeviceHalLocal.cpp

分析:在hw_get_module_by_class的时候会加载音频库,这里会加载第三方自己实现的库,一般第三方的库中都有对open函数指针的赋值,这里赋的是adev_open;然后调用audio_hw_device_open最终调用到adev_open之后会打开相应的模块,并将所有的操作指针进行赋值,如果成功返回再创建DeviceHalLocal对象,在这里也是为以后调用open_output_stream/open_input_stream等函数做准备,这些函数就包含在这个对象中

1.3.1.1 输入输出设备的打开和线程创建

在前面流程图AudioPolicyManager的第三步,具体代码如下:

void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
{
    for (const auto& hwModule : mHwModulesAll) {
        if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
            continue;
        }
        hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
        if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
            ALOGW("could not open HW module %s", hwModule->getName());
            continue;
        }
        mHwModules.push_back(hwModule);
       // 打开访问附加设备所需的所有输出流,除了仅在应用程序实际需
       // 要时才打开的直接输出流。这也验证了 mAvailableOutputDevices 列表 
        for (const auto& outProfile : hwModule->getOutputProfiles()) {
            if (!outProfile->canOpenNewIo()) {
                ALOGE("Invalid Output profile max open count %u for profile %s",
                      outProfile->maxOpenCount, outProfile->getTagName().c_str());
                continue;
            }
            if (!outProfile->hasSupportedDevices()) {
                ALOGW("Output profile contains no device on module %s", hwModule->getName());
                continue;
            }
            // 这里和primary_audio_policy_coinfiguration.xml中给hifi音源加的flag进行对应
            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
                mTtsOutputAvailable = true;
            }

            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
            DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
            sp<DeviceDescriptor> supportedDevice = 0;
            if (supportedDevices.contains(mDefaultOutputDevice)) {
                supportedDevice = mDefaultOutputDevice;
            } else {
                // 选择配置文件的 SupportedDevices 中存在的第一个设备,
                // 也是 mAvailableOutputDevices 的一部分。 
                if (availProfileDevices.isEmpty()) {
                    continue;
                }
                supportedDevice = availProfileDevices.itemAt(0);
            }
            if (!mOutputDevicesAll.contains(supportedDevice)) {
                continue;
            }
            // 根据outProfile 得到一个描述符,设置mpClientInterface
            // 描述了source和sink之间的关系
            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
                                                                                 mpClientInterface);
            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
            // 在这里最终调用AudioFlinger的openOutput函数打开这个输出流,并返回表示这个设备的输出流
            // 的句柄audio_io_handle_t用于后面AudioTrack创建的时候查找具体的线程使用
            status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
                                               AUDIO_STREAM_DEFAULT,
                                               AUDIO_OUTPUT_FLAG_NONE, &output);
            if (status != NO_ERROR) {
                ALOGW("Cannot open output stream for devices %s on hw module %s",
                      // 表示失败,不能打开profile对应的device的输出流
                      supportedDevice->toString().c_str(), hwModule->getName());
                continue;
            }
            for (const auto &device : availProfileDevices) {
                // 一旦确认连接的设备可以访问,就为它提供一个有效的 ID 
                if (!device->isAttached()) {
                    device->attach(hwModule);
                    mAvailableOutputDevices.add(device); // 添加到可用的输出设备中
                    device->setEncapsulationInfoFromHal(mpClientInterface);
                    if (newDevices) newDevices->add(device);
                    setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
                }
            }
            if (mPrimaryOutput == 0 &&
                    outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                mPrimaryOutput = outputDesc; // 设置主音频输出
            }
            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                outputDesc->close(); // 如果是直接输出流则先关闭
            } else {
                // 将这个添加到打开的输出描述符列表mOutputs中(SwAudioOutputCollection类型)
                addOutput(output, outputDesc);
                // 设置适合当前Source的输出设备,这一部分内容和修改的pfw文件有关
                setOutputDevices(outputDesc,
                                 DeviceVector(supportedDevice),
                                 true,
                                 0,
                                 NULL);
            }
        }
        // 打开访问附加设备所需的输入流以验证 mAvailableInputDevices 列表 
        for (const auto& inProfile : hwModule->getInputProfiles()) {
            if (!inProfile->canOpenNewIo()) {
                ALOGE("Invalid Input profile max open count %u for profile %s",
                      inProfile->maxOpenCount, inProfile->getTagName().c_str());
                continue;
            }
            // 如果当前sink没有相应的设备支持则结束
            if (!inProfile->hasSupportedDevices()) {
                ALOGW("Input profile contains no device on module %s", hwModule->getName());
                continue;
            }
            // 选择配置文件中存在的第一个设备支持的设备也是可用输入设备的一部分 
            const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
            DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
            if (availProfileDevices.isEmpty()) {
                ALOGE("%s: Input device list is empty!", __FUNCTION__);
                continue;
            }
            // 根据inProfile 得到一个描述符,设置mpClientInterface
            sp<AudioInputDescriptor> inputDesc =
                    new AudioInputDescriptor(inProfile, mpClientInterface);

            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
            // 这里最终调用到AudioFlinger的openIntput打开输入流
            status_t status = inputDesc->open(nullptr,
                                              availProfileDevices.itemAt(0),
                                              AUDIO_SOURCE_MIC,
                                              AUDIO_INPUT_FLAG_NONE,
                                              &input);
            if (status != NO_ERROR) {
                ALOGW("Cannot open input stream for device %s on hw module %s",
                      availProfileDevices.toString().c_str(),
                      hwModule->getName());
                continue;
            }
            for (const auto &device : availProfileDevices) {
                // 一旦确认连接的设备可以访问,就为它提供一个有效的 ID 
                if (!device->isAttached()) {
                    device->attach(hwModule);
                    device->importAudioPortAndPickAudioProfile(inProfile, true);
                    mAvailableInputDevices.add(device);
                    if (newDevices) newDevices->add(device);
                    setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
                }
            }
            inputDesc->close();
        }
    }
}

上面代码中提到在AudioFlinger中打开了输入和输出设备,下面是输出流打开流程包括线程的创建:

Threads
AudioFlinger
AudioOutputDescriptor
AudioPolicyManager
1 new SwAudioOutputDescriptor
2
mClientInterface->openOutput
该函数会返回创建的输出线程
1
2 outHwDev->openOutputStream
1 new AudioStreamOut
2
1 这里调用的是函数指针实际指向adev_open_output_stream
2 new StreamOutHalLocal
3 使用打开的输出流创建线程
4 将创建的线程添加到成员中
MixerThread构造
openOutput
openOutput_l
findSuitableHwDev_l
mPlaybackThreads.add
Output构造
open
onNewAudioModulesAvailableInt
AudioHwDevice::openOutputStream
AudioStreamOut构造
AudioStreamOut::open
DeviceHalLocal::openOutputStream
open_output_stream
StreamOutHalLocal构造

上图findSuitableHwDev_l会返回AudioFlinger::loadHwModule_l中根据Module加载的AudioHwDevice

接下来继续分析输入流的打开流程以及线程的创建:

Threads
DeviceHalLocal.cpp
AudioFlinger
AudioInputDescriptor
AudioPolicyManager
1
2
mClientInterface->openInput
1
2
实际是audio_hw.c中的adev_open_input_stream
3
4创建线程
5 创建的线程添加到成员中
RecordThread构造
openInputStream
openInput
openInput_l
findSuitableHwDev_l
mRecordThreads.add
Input构造
open
onNewAudioModulesAvailableInt
open_input_stream
StreamInHalLocal构造
AudioStreamIn构造

上面讲输入和输出的线程创建已经分析完毕,现在我们的Android系统中已经存在了一些播放线程了,后面就是一个应用如果通过AudioTrack开始播放音频该怎么将这段音频对应到相应的线程中去的问题

整个第一节音频服务初始化到这里结束,音频服务启动之后加载相应的音频库,扫描了配置文件中的一些模块和连接的外设,并打开这些外设创建了相应的工作线程,比如最常用的MixerThread线程和录音的RecordThread,现在整个音频系统已经启动,剩下的就是其他应用等访问音频服务的过程。

2、 Engine的创建流程

前面分析Engine的时候没有进行详细的分析,Engine作为音频后期统筹管理的模块,是如何将策略加载进去的,以及后面设备切换的时候怎么进行修改,这些内容在这一节进行分析

2.1 音频策略加载

在前面1.2节中AudioPolicyManagerinitialize方法中涉及到了Engine的创建,接着这个内容进一步详细分析:

ProductStrategy
EngineConfig
EngineBase
Engine
EngineLibrary
1 传入了Engine库的名字
1
2 传入Engine库名字
解析出Engine创建函数到mCreateEngineInstance
2
1该分支不重要
2
创建出mPfwConnector
创建出_pParameterMgr
1
1
解析出来的内容放到这里
2
1 添加新的音量组
2 创建音量曲线
3
4
设定默认策略
2
ProductStrategy构造
initialize
getDefault
parse
struct-Config
B/loadAudioPolicyEngineConfig
loadVolumeConfig
Engine构造
loadAudioPolicyEngineConfig
追加自定义XML解析
load
EngineLibrary构造
init
createEngine
AudioPolicyManager
dlsym
EngineInstance::createEngineInstance
ParameterManagerWrapper构造
CParameterMgrPlatformConnector构造
CParameterMgr构造
VolumeGroup构造
VolumeCurve构造

音频策略加载的时候有一个比较重要的函数,这个函数EngineBase里面的loadAudioPolicyEngineConfig,代码如下:

engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
{
    auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
        // 确保名称唯一性以防止重复 
        LOG_ALWAYS_FATAL_IF(std::any_of(std::begin(volumeGroups), std::end(volumeGroups),
                                     [&volumeConfig](const auto &volumeGroup) {
                return volumeConfig.name == volumeGroup.second->getName(); }),
                            "group name %s defined twice, review the configuration",
                            volumeConfig.name.c_str());

        // 表示当前VolumeGroup还没有被加载过,开始创建加载加载
        sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
                                                      volumeConfig.indexMax);
        volumeGroups[volumeGroup->getId()] = volumeGroup;

        for (auto &configCurve : volumeConfig.volumeCurves) {
            device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
            if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
                ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
                continue;
            }
            sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
            for (auto &point : configCurve.curvePoints) {
                curve->add({point.index, point.attenuationInMb});
            }
            volumeGroup->add(curve);
        }
        return volumeGroup;
    };
    auto addSupportedAttributesToGroup = [](auto &group, auto &volumeGroup, auto &strategy) {
        for (const auto &attr : group.attributesVect) {
            strategy->addAttributes({group.stream, volumeGroup->getId(), attr});
            volumeGroup->addSupportedAttributes(attr);
        }
    };
    auto checkStreamForGroups = [](auto streamType, const auto &volumeGroups) {
        const auto &iter = std::find_if(std::begin(volumeGroups), std::end(volumeGroups),
                                     [&streamType](const auto &volumeGroup) {
            const auto& streams = volumeGroup.second->getStreamTypes();
            return std::find(std::begin(streams), std::end(streams), streamType) !=
                    std::end(streams);
        });
        return iter != end(volumeGroups);
    };

    // 前面三个lambda表达式后面会用到,实际是从这里开始的
    
    // 这里开始进行解析,最终会解析出来策略、标准、标准类型以及音量组四个内容
    // struct Config {
    // 	float version;
    // 	ProductStrategies productStrategies;
    // 	Criteria criteria;
    // 	CriterionTypes criterionTypes;
   	// 	VolumeGroups volumeGroups;
	// };
    auto result = engineConfig::parse();
    if (result.parsedConfig == nullptr) { // 如果上面没有解析成功表示没有找到配置,所以使用默认的配置
        ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
        engineConfig::Config config = gDefaultEngineConfig;
        android::status_t ret = engineConfig::parseLegacyVolumes(config.volumeGroups);
        result = {std::make_unique<engineConfig::Config>(config),
                  static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
    } 
    
	...
        
    ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement); // 这里是解析的时候跳过的无效策略数

    engineConfig::VolumeGroup defaultVolumeConfig;
    engineConfig::VolumeGroup defaultSystemVolumeConfig;
    // 循环解析所有的音量组
    for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
        // 保存未在配置中定义的流的默认音量配置 讲music和patch作为未定义流类型的默认配置
        if (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {
            defaultVolumeConfig = volumeConfig;
        }
        if (volumeConfig.name.compare("AUDIO_STREAM_PATCH") == 0) {
            defaultSystemVolumeConfig = volumeConfig;
        }
        // 这里调用上面第一个lamabda表达式
        // 这里定义的mVolumeGroups是一个map容器,其中second是VolumeGroup指针,定义在VolumeGroup.h中
        // 这里调用这个lambda表达式是为了讲volumeConfig中包含的volumeGroups解析到mVolumeGroups中
        loadVolumeConfig(mVolumeGroups, volumeConfig);
    }
    // 循环遍历所有的音频策略
    for (auto& strategyConfig : result.parsedConfig->productStrategies) {
        sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
        for (const auto &group : strategyConfig.attributesGroups) {
            // 查找该策略是否有相应的音量组
            const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
                                         [&group](const auto &volumeGroup) {
                    return group.volumeGroup == volumeGroup.second->getName(); });
            sp<VolumeGroup> volumeGroup = nullptr;
            // 如果没有为此策略提供音量组,则使用音乐音量组配置创建一个新的音量组(视为默认设置) 
            if (iter == end(mVolumeGroups)) {
                engineConfig::VolumeGroup volumeConfig;
                if (group.stream >= AUDIO_STREAM_PUBLIC_CNT) {
                    volumeConfig = defaultSystemVolumeConfig;
                } else {
                    volumeConfig = defaultVolumeConfig;
                }
                ALOGW("%s: No configuration of %s found, using default volume configuration"
                        , __FUNCTION__, group.volumeGroup.c_str());
                volumeConfig.name = group.volumeGroup;
                volumeGroup = loadVolumeConfig(mVolumeGroups, volumeConfig);
            } else {
                volumeGroup = iter->second;
            }
            if (group.stream != AUDIO_STREAM_DEFAULT) {
                // 可以将旧流一次分配给卷组 
                LOG_ALWAYS_FATAL_IF(checkStreamForGroups(group.stream, mVolumeGroups),
                                    "stream %s already assigned to a volume group, "
                                    "review the configuration", toString(group.stream).c_str());
                volumeGroup->addSupportedStream(group.stream);
            }
            // 为策略添加相应的属性
            addSupportedAttributesToGroup(group, volumeGroup, strategy);
        }
        // 将新创建的strategy保存到mProductStrategies中并分配一个单独的ID
        product_strategy_t strategyId = strategy->getId();
        mProductStrategies[strategyId] = strategy;
    }
    mProductStrategies.initialize();
    return result;
}

3、 应用播放音频

应用播放音频是通过创建AudioTrack的方式进行播放的,每一个音频流对应着一个AudioTrack的实例,每个AudioTrack会在创建的时候注册到AudioFlinger中,由AudioFlinger将所有的AudioTrack进行混合再传入到HAL中进行播放。

通过前面的分析流程知道了AudioPolicyService启动时加载了系统支持的所有音频接口,并且打开了默认的音频输出,并且为该输出创建了一个播放线程,同时为该线程分配了一个全局唯一的audio_io_handle_t值,任何Track想要发声都需要去查找相应的audio_io_handle_t值找到对应的播放线程才能最终将音频数据传输到HAL层进行播放,大致的播放框图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lHvPE4uC-1642646395284)(./TN1.11.7870音频文档/应用播放流程.png)]

3.1 应用创建Track流程

  1. 调用AudioTrack::getMinBufferSize接口传入音频参数获取最小缓冲区大小,调用到HAL层判断当前硬件是否支持该种类型的音频播放,如果不支持后续也不会创建Track
  2. new AudioTrack
  3. AudioTrack::write
  4. AudioTrack::play

需要注意的是音频播放的时候有两种模式:

  • static模式,一次性将音频加载进内存中供AudioFlinger读取,这种方式适用于对时延要求高且内存较小的音频
  • stream模式,这种是AudioTrack向内存中不断的写数据,AudioFlinger去内存中读数据,动态的进行,一般情况下遇到的都是这种情况

static模式下需要先调用write方法,后调用play方法
stream模式下先调用play方法,后调用write方法

AudioTrack.cpp
Native
AudioTrack.java
native_setup
1 new AudioTrack
3 根据播放模式调用set
和AudioFlinger交互
2 申请共享内存
native_get_min_buff_size进入native是为了确认硬件是否支持这些参数
会和AF交互计算出最小帧数用于确定缓冲区大小
AudioTrack构造
getMinFrameCount
set
createTrack_l
android_media_AudioTrack_setup
android_media_AudioTrack_get_min_buff_size
AudioTrackJniStorage构造
AudioTrack
getMinBufferSize
AudioFlinger

在这里创建共享内存的时候会用到getMinBufferSize获取的值最终创建缓冲区大小,这一步最终会进入到HAL层使用应用的采样率等一些参数来判断当前硬件是否支持该种类型的音频播放。

在set函数中会和AudioFlinger以及AudioPolicyManager进行互动,主要是找到给当前Track播放的设备以及该设备使用的线程,最终实现播放音频的目的。

3.2 策略查找流程

AudioPolicyMix
Engine
AudioPolicyManager
AudioFlinger
AudioTrack
1
1
2 new TrackClientDescriptor
1 通过应用attr获取流类型
2 mPolicyMixes.getOutputForAttr
3
4 Engine策略
1
2
3
4 返回输出设备
getOutputForAttr
getStreamTypeForAttributes
getOutputDevicesForAttributes
AP::getOutputForAttr
getOutputForAttrInt
getAvailableOutputDevices
getOutputs
如果有显式路由优先显式路由其次动态路由
AF::createTrack
set
AT::createTrack_l
TrackClientDescriptor构造
getProductStrategyForAttributes
findPreferredDevice

AudioPolicyManager种获取output的候可以选择主设备和次设备输出,但是次设备都是通过动态策略进行选择的,Engine不支持选中次设备,主要都是通过这里的APM从前面解析xml之后得到的一些结果中去查询需要的数据

3.3 播放线程和HAL的交互

将输出设备选中之后就需要针对该输出设备创建相应的线程进行数据的写入了,前面部分已经获取了当前应用要播放的流类型应该打开的output的所有信息,剩下的工作就是怎么找到当前output所对应的播放线程:

3.3.1 播放线程的选择以及Track创建

Threads
AudioFlinger
2 根据当前的outputID找到对应的播放线程
3 调用上一步返回的线程的该函数
4 是Track对象的代理支持binder通讯
1 创建Track
2
createTrack_l
将Track添加进线程持有的mTracks
AF::createTrack
checkPlaybackThread_l
TrackHandler构造
PlaybackTracks::Track

这里首先根据当前找到的outputId查找对应的播放线程,这个播放线程是在一开始创建AudioFlingerAudioPolicyManager的时候就打开的,然后在该线程中为当前要播放的音频创建一个Track并将该Track添加进当前线程持有的Track容器中。

到此从应用发起创建AudioTrack的请求到AudioFlinger最终创建AudioTrack已经结束,剩下的事情就是应用开始往共享内存中写入内容,AudioFlinger获取内容并发送到HAL层中通过tinyALSA驱动打开硬件进行最终的播放。

3.3.1 AudioTrack打开输出源

上面的内容是找到了当前AudioTrack相关的output以及相应的工作线程,接下来就需要打开这个output,然后开始往里面写数据,也就是应用调用writeplay之后开始写数据的内容,直接从AudioTrack.cpp中开始看

AudioPolicyManager
AudioTrack
第三方的函数
在这里有对TTS流的处理
1 重新选择device?
2 最终选择的设备看这里
APMS::startOutput
APM::startOutput
startSource
getNewOutputDevices
setOutputDevices
start

在上面调用startSource的时候需要进行一些判断来决定最终是否打开该输出源,如果不能打开是不会向底层写数据的,调试的时候需要重点关注这部分内容,判断是否所有情况都准备就绪再去看数据处理的部分。

3.3.2 AudioFlingerHAL层写数据

这里AudioTrack向共享内存写入数据,AudioFlinger从共享内存中读取数据,我们这里直接从AudioFlinger里面的线程开始分析,假设是MixerThread(大部分情况都是这种)过程如下:

audio_hifi
audio_hw
AudioStreamOut
Threads
首先启动mFastMixer
mOutput->write
stream->write
mStream->write
1
1
2
3
2
3
out_hifi_write
start_hifi_output_stream
out_write
start_output_stream
write
MIX::threadLoop_write
PLAY::threadLoop_write
streamHalLocal::write
pcm_open
pcm_mmap_write
  • 18
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值