本文参考了TaigaComplex求职中的博文,结合自己目前看的代码,分析下getoutput的调用流程。
参考文章:Audio系统中声音输出设备的getOutput函数的调用流程图
注意:这篇文章版本太旧,执行代码不同,比如它的getoutput函数直接调到audiosystem中,但是我看的代码里面就只有一个返回值。
每创建一个AudioTrack,代表需要新增一个输出实例,即需要根据音频流的的stream type,音频流的音轨数量,采样率,位宽等数据来重新构建buffer,而且输出的设备也可能会有变化,由于Android设备支持的输出设备各种各样,如线控耳机,喇叭,蓝牙耳机,midi设备等,因此如果该设备是第一次被使用时,则会被初始化。
下文描述的打开输出设置并非真正的打开linux设备文件,而是输出设备相关的初始化操作
@AudioTrack.cpp
//参数mOutput
audio_io_handle_t mOutput; // returned by AudioSystem::getOutput()
audio_io_handle_t AudioTrack::getOutput() const
{
AutoMutex lock(mLock);
return mOutput;
}
audio_io_handle_t 是与 PlaybackThread 是一一对应的(一对键值对),由已知的 audio_io_handle_t 就能找到对应的 PlaybackThread。audio_io_handle_t 在创建 PlaybackThread 时由系统分配,这个值是全局唯一的。
通过moutput可以获取该AudioTrack对应的PlaybackThread 。
该函数的作用只是返回moutput这个变量的值,我们查看下该变量是在哪里被赋值的。
->AudioTrack::createTrack_l
|- AudioSystem::getOutputForAttr
|- AudioPolicyService::getOutputForAttr
|- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
|- AudioPolicyManager::getOutputForDevice
|- AudioPolicyService::AudioPolicyClient::openOutput
|- AudioFlinger::openOutput
|- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
@AudioTrack.cpp
status_t AudioTrack::createTrack_l()
{
//定义变量output
audio_io_handle_t output;
//getOutputForAttr中对output进行赋值
status = AudioSystem::getOutputForAttr( attr,
&output, //传入地址,用于赋值传出
mSessionId,
&streamType,
mClientUid,
&config,
mFlags,
&mRoutedDeviceId,
&mPortId);
//赋值给mOutput,这里是存放到audiotrack类中的参数,之后可以通过AudioSystem::getOutput直接获取到output
mOutput = output;
}
getOutputForAttr()函数中对output进行赋值,我们来看看该函数做了些什么
AudioTrack::createTrack_l
-> |- AudioSystem::getOutputForAttr
|- AudioPolicyService::getOutputForAttr
|- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
|- AudioPolicyManager::getOutputForDevice
|- AudioPolicyService::AudioPolicyClient::openOutput
|- AudioFlinger::openOutput
|- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
@AudioSystem.cpp
status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
uid_t uid,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return NO_INIT;
return aps->getOutputForAttr(attr, output, session, stream, uid,
config,
flags, selectedDeviceId, portId);
}
这里的调用是通过binder,AudioPolicyService作为service,IAudioPolicyService作为client,调用IAudioPolicyService实际调到的就是AudioPolicyService的操作,具体实现在如下文件中。
(binder这一块我也很懵,姑且这样理解,如果发现我理解错了希望可以一起探讨下。)
AudioTrack::createTrack_l
|- AudioSystem::getOutputForAttr
-> |- AudioPolicyService::getOutputForAttr
|- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
|- AudioPolicyManager::getOutputForDevice
|- AudioPolicyService::AudioPolicyClient::openOutput
|- AudioFlinger::openOutput
|- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
@AudioPolicyIntefaceImpl.cpp
status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
uid_t uid,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId)
{
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
"%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
uid = callingUid;
}
return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
config,
flags, selectedDeviceId, portId);
}
mAudioPolicyManager是AudioPolicyManager的部分操作的集成(想象成这样),mAudioPolicyManager的类型是AudioPolicyInterface,看该类的定义有这句话(Audio Policy Manager Interface)
//AudioPolicyManager 类的定义
class AudioPolicyManager : public AudioPolicyInterface, public AudioPolicyManagerObserver
上述代码,表明了AudioPolicyManager 是由AudioPolicyInterface继承而来,故当AudioPolicyManager “转回去”,那就只有AudioPolicyInterface中定义的那部分功能。
想象成封装了AudioPolicyManager 的部分功能使用。
(这一块还是很懵,先这样,等过段时间再细看)
AudioTrack::createTrack_l
|- AudioSystem::getOutputForAttr
|- AudioPolicyService::getOutputForAttr
-> |- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
|- AudioPolicyManager::getOutputForDevice
|- AudioPolicyService::AudioPolicyClient::openOutput
|- AudioFlinger::openOutput
|- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
@AudioPolicyManager.cpp
status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
uid_t uid,
const audio_config_t *config,
audio_output_flags_t flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId)
{
//······
//根据attributes获取策略strategy
routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
//根据strategy获取策略device
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
//······
//根据device打开output
*output = getOutputForDevice(device, session, *stream,
config->sample_rate, config->format, config->channel_mask,
flags, &config->offload_info);
if (*output == AUDIO_IO_HANDLE_NONE) {
mOutputRoutes.removeRoute(session);
return INVALID_OPERATION;
}
//······
}
这里注意下,真正获取output是在如下函数中
AudioTrack::createTrack_l
|- AudioSystem::getOutputForAttr
|- AudioPolicyService::getOutputForAttr
|- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
-> |- AudioPolicyManager::getOutputForDevice
|- AudioPolicyService::AudioPolicyClient::openOutput
|- AudioFlinger::openOutput
|- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
@AudioPolicyManager.cpp
audio_io_handle_t AudioPolicyManager::getOutputForDevice(
audio_devices_t device,
audio_session_t session,
audio_stream_type_t stream,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo)
{
//······
//这里就是真正的获取output
status = mpClientInterface->openOutput(profile->getModuleHandle(),
&output,
&config,
&outputDesc->mDevice,
address,
&outputDesc->mLatency,
outputDesc->mFlags);
//······
}
mpClientInterface变量和之前的相似,直接看对应的文件
(注:这篇文章的openOutput部分详细讲述了调用过程
注意事项:我的代码里找不到这位大佬的,应该是版本问题,具体结合代码看吧,但是最终都调到了AudioFlinger里)
AudioTrack::createTrack_l
|- AudioSystem::getOutputForAttr
|- AudioPolicyService::getOutputForAttr
|- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
|- AudioPolicyManager::getOutputForDevice
-> |- AudioPolicyService::AudioPolicyClient::openOutput
|- AudioFlinger::openOutput
|- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
@AudioPolicyClientImpl.cpp
status_t AudioPolicyService::AudioPolicyClient::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)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED;
}
return af->openOutput(module, output, config, devices, address, latencyMs, flags);
}
终于要到熟悉的AudioFlinger了。
这个函数简单,就是获取了AudioFlinger,然后通过binder调到了AudioFlinger的openOutput(),我们去看下。
AudioTrack::createTrack_l
|- AudioSystem::getOutputForAttr
|- AudioPolicyService::getOutputForAttr
|- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
|- AudioPolicyManager::getOutputForDevice
|- AudioPolicyService::AudioPolicyClient::openOutput
-> |- AudioFlinger::openOutput
|- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
@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)
{
//······
sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags);
//······
}
AudioTrack::createTrack_l
|- AudioSystem::getOutputForAttr
|- AudioPolicyService::getOutputForAttr
|- AudioPolicyManager::getOutputForAttr
|- getStrategyForAttr
|- getDeviceForStrategy
|- AudioPolicyManager::getOutputForDevice
|- AudioPolicyService::AudioPolicyClient::openOutput
|- AudioFlinger::openOutput
-> |- AudioFlinger::openOutput_l
|- findSuitableHwDev_l
|- openOutputStream
|- new MixerThread
openOutput_l内的函数调用参考我另一篇文章AudioFlinger::openOutput
//@AudioFlinger.cpp
sp<AudioFlinger::ThreadBase> 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)
{
//查硬件模块,加载硬件设备
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
//······
//打开音频流
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
//······
//嘿嘿,到了创建播放线程实例的地方了,舒服
if (status == NO_ERROR) {
//这里是打开流失败的
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
sp<MmapPlaybackThread> thread =
new MmapPlaybackThread(this, *output, outHwDev, outputStream,
devices, AUDIO_DEVICE_NONE, mSystemReady);
mMmapThreads.add(*output, thread);
ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
*output, thread.get());
return thread;
} else {
//成功打开音频流,创建线程。yep!!!
sp<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.get());
} 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.get());
} else {
//创建MixerThread
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p",
*output, thread.get());
}
//加入mPlaybackThreads进行管理
mPlaybackThreads.add(*output, thread);
return thread;
}
}
至此,成功的创建并获取了播放线程实例的key(output)。具体还有很多细节等后续再完善吧。
本文简要介绍了AudioTrack的output获取到初始化,整个调用流程如图。
attribute -> strategy -> device -> output
整个获取output的流程就在AudioPolicyManager::getOutputForAttr()函数内@AudioPolicyManager.cpp。
有问题可以结合我参考的文章进行理解,那篇文章思路特别清晰。
最后,膜拜、感谢大佬。
续集