audio_native层 | 获取音频输出getOutput和设置

本文参考了TaigaComplex求职中的博文,结合自己目前看的代码,分析下getoutput的调用流程。

参考文章:Audio系统中声音输出设备的getOutput函数的调用流程图
注意:这篇文章版本太旧,执行代码不同,比如它的getoutput函数直接调到audiosystem中,但是我看的代码里面就只有一个返回值。

目录

    • AudioTrack获取moutput
    • AudioTrack的moutput初始化
      • AudioSystem::getOutputForAttr
      • AudioPolicyService::getOutputForAttr
      • AudioPolicyManager::getOutputForAttr
      • AudioPolicyManager::getOutputForDevice
      • AudioPolicyService::AudioPolicyClient::openOutput
      • AudioFlinger::openOutput
      • AudioFlinger::openOutput_l
  • 总结

audio_native层 | 获取音频输出getOutput和设置_第1张图片

每创建一个AudioTrack,代表需要新增一个输出实例,即需要根据音频流的的stream type,音频流的音轨数量,采样率,位宽等数据来重新构建buffer,而且输出的设备也可能会有变化,由于Android设备支持的输出设备各种各样,如线控耳机,喇叭,蓝牙耳机,midi设备等,因此如果该设备是第一次被使用时,则会被初始化。

下文描述的打开输出设置并非真正的打开linux设备文件,而是输出设备相关的初始化操作

AudioTrack获取moutput

@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的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进行赋值,我们来看看该函数做了些什么

AudioSystem::getOutputForAttr

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这一块我也很懵,姑且这样理解,如果发现我理解错了希望可以一起探讨下。)

AudioPolicyService::getOutputForAttr

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 的部分功能使用。
(这一块还是很懵,先这样,等过段时间再细看)

AudioPolicyManager::getOutputForAttr

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是在如下函数中

AudioPolicyManager::getOutputForDevice

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里

AudioPolicyService::AudioPolicyClient::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

@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(),我们去看下。

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);

	//······
	

}

AudioFlinger::openOutput_l

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获取到初始化,整个调用流程如图。
audio_native层 | 获取音频输出getOutput和设置_第2张图片

attribute -> strategy -> device -> output

整个获取output的流程就在AudioPolicyManager::getOutputForAttr()函数内@AudioPolicyManager.cpp。

有问题可以结合我参考的文章进行理解,那篇文章思路特别清晰。
最后,膜拜、感谢大佬。

续集

你可能感兴趣的:(audio)