08.音频系统:第004课_Android音频系统详解:第005节_AudioFlinger启动过程分析

该小节讲解AudioFlinger启动的过程,作为一个硬件访问服务,其启动过程十分的简单,只需要向系统注册服务就可以了,然后被动的等待其他的客户端来访问。
在上一小节讲解了AudioPolicyService的启动过程,其除了注册本身的服务之外,还调用了AudioFlinger加载厂家提供的so文件。并且open某个output。在这小节的我们除了讲解AudioFlinger服务之外,还会讲解上小节遗留下来的两个问题:
a. 注册AudioFlinger服务
b. 被AudioPolicyService调用以打开厂家提供的so文件
c. 被AudioPolicyService调用来open output、创建playback thread

下面是AudioFlinger调用的时序图:
在这里插入图片描述
从图中我们可以知道其添加服务只通过BinderService.h中的:

    static status_t publish(bool allowIsolated = false) {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(
                String16(SERVICE::getServiceName()),
                new SERVICE(), allowIsolated);
    }

publish函数,所以前面提到的第一点,a. 注册AudioFlinger服务就已经解决。
我们下面来看看:c. 被AudioPolicyService调用来open output、创建playback thread 。在上小节我们已经分析过,在AudioPolicyManagerBase.cpp文件中:

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
	if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
        if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
            ALOGE("could not load audio policy configuration file, setting defaults");
            defaultAudioPolicyConfig();
        }
    }	
    audio_io_handle_t output = mpClientInterface->openOutput(outProfile->mModule->mHandle,&outputDesc->mDevice,&outputDesc->mSamplingRate,&outputDesc->mFormat,&outputDesc->mChannelMask,&outputDesc->mLatency,outputDesc->mFlags);

下面是之前小节讲解相关文件时画的图片,在此拷贝一下:
在这里插入图片描述
在讲解b. 被AudioPolicyService调用以打开厂家提供的so文件之前,有如下问题

b.1:加载哪个so文件?文件名是什么?文件从何而来?
	名字从/system/etc/audio_policy.conf文件中得到(该文件上小节分析,知道其有model:primary,a2dp,usb,r_submix)
	在开放版上执行ls /system/lib/hw/audio*可以看到文件如下:
	/system/lib/hw/audio.a2dp.default.so(蓝牙)    
	/system/lib/hw/audio.primary.default.so
	/system/lib/hw/audio.r_submix.default.so
	/system/lib/hw/audio.usb.default.so    
    /system/lib/hw/audio.vr_bee_hidraw.default.so
    /system/lib/hw/audio_policy.default.so  
	可以知道,其与我们的model一一对应。

b.2:改so文件由什么源文件组成?
	在上面贴出的框图中(AudioPolicyService边下面),我们可以看到起涉及andio_hw_hal.cpp(硬件抽象层)与AudioHardware.cpp(厂家提供),其最终编译成/system/lib/hw/audio.primary.default.so文件

查看源码hardware\rockchip\audio\legacy_hal\Android.mk:

LOCAL_SRC_FILES := \
    AudioHardwareInterface.cpp\
    AudioHardware.cpp \
    audio_hw_hal.cpp\
    alsa_mixer.c\
    alsa_route.c\
    alsa_pcm.c

LOCAL_MODULE := audio.primary.$(TARGET_BOARD_HARDWARE)

可以知道其会生成文件audio.primary.default.so,其他的so文件也是同理。其中audio_hw_hal.cpp就是厂家提供的。这样我们就知道了so文件的来源,回答了第一个问题。

现在我们反过来看看第一个问题,我们如何去加载这个文件。我们依旧打开AudioPolicyManagerBase.cpp的构造函数:

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
	loadAudioPolicyConfig
		/*对每一个Modules创建一个HwModule *module = new HwModule(root->name);
		然后通过mHwModules.add(module);添加到mHwModules*/
		loadHwModules(root);
	/*取出所有的module*/
	for (size_t i = 0; i < mHwModules.size(); i++) {
		/*根据名字,调用每个mpClientInterface的loadHwModule函数加载厂家提供的so文件(远程带调用)*/
		mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);

在上面我们可以看到,其使用的一个远程调用,该最终会导致AudioFlinger中的loadHwModule,进入AudioFlinger.cpp:

/*一下的name我们暂时都当做primary */
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
	loadHwModule_l(name)
		/*打开audio.primary.xxx文件,构造audio_hw_device_t结构体*/
		int rc = load_audio_interface(name, &dev);
		
			/*AUDIO_HARDWARE_MODULE_ID "audio"
			if_name "primary "
			及加载audio.primary.xxx文件,不继续深究,有兴趣可以自行了解
			*/
			rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
			/*得到so文件之后,调用so文件中的open函数,打开hw_device,这里的hw_device只是一个抽象,没有实质的与硬件打交道*/
			
			/*根据厂家提供的AudioHardware类,获得一个audio_hw_device_t **dev结构体。该结构体最终会保存在AudioFlinger.cpp中的AudioHwDevice类里面*/
			rc = audio_hw_device_open(mod, dev);

现在我们已经知道,其如何从系统中得到so文件。在继续深入讲解audio_hw_device_open函数之前我们先做一些总结:

对硬件的封装:
AudioFlinger : AudioHwDevice (放入mAudioHwDevs数组中)
audio_hw_hal.cpp : audio_hw_device
厂家 : AudioHardware (派生自: AudioHardwareInterface)

AudioHwDevice是对audio_hw_device的封装,
audio_hw_device中函数的实现要通过AudioHardware类对象

下面是硬件封装的框图:
在这里插入图片描述
AudioFlinger把硬件相关的封装成一个AudioHwDevice。其通过audio_hw_hal.cpp访问硬件,audio_hw_hal.cpp对硬件的操作封装成了audio_hw_device(可以看出AudioHwDevice中包含了audio_hw_hal)。audio_hw_hal.cpp只是一个接口,其需要依赖厂家提供的AudioHardware.cpp。其派生自AudioHardwareInterface,封装成AudioHardware类。

下面我们继续分析audio_hw_device_open(mod, dev);:

/*其会调调用so(audio_hw_hal.cpp)文件中的open函数*/
static inline int audio_hw_device_open(const struct hw_module_t* module,struct audio_hw_device** device)
	module->methods->open(module, AUDIO_HARDWARE_INTERFACE,(struct hw_device_t**)device);

上面的函数,最终会调用audio_hw_hal.cpp中的open函数legacy_adev_open:

static int legacy_adev_open(const hw_module_t* module, const char* name,hw_device_t** device)
	struct legacy_audio_device *ladev;
	/*以下为audio_hw_hal.cpp定义的函数,该些函数都会使用到厂家提供的AudioHardware类*/
	ladev->device.init_check = adev_init_check;
    ladev->device.set_voice_volume = adev_set_voice_volume;
    ladev->device.set_master_volume = adev_set_master_volume;
    ladev->device.get_master_volume = adev_get_master_volume;
    
	/*获得厂家提供的AudioHardware,保存在ladev->hwif中*/
	ladev->hwif = createAudioHardware();
		return new AudioHardwareStub();

这样b的问题我们就解决了,现在只剩下一个问题了:c. 被AudioPolicyService调用来open output、创建playback thread(可以从时序图的A2部分开始看),我们依旧打开AudioPolicyManagerBase.cpp,找到他的构造函数:

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)
	/*加载解析配置文件*/
	loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE)
	/*加载从配置文件得到的so(路径)文件*/
	mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
	/*配置文件的每一个modle都会被存放在mHwModules数组中,每个modle中存在一个或者多个ouput,其存放在mOutputProfiles数组中,mOutputProfiles为IOprofile类*/
	for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
		/*获得一个outProfile结构体 */
		const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
		/*根据outProfile结构体获得一个AudioOutputDescriptor描述符*/
		AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
		/*发起远程调用,调用AudioFlinger中的openOutput*/
	    audio_io_handle_t output = mpClientInterface->openOutput(outProfile->mModule->mHandle,&outputDesc->mDevice,&outputDesc->mSamplingRate,&outputDesc->mFormat,&outputDesc->mChannelMask,&outputDesc->mLatency,outputDesc->mFlags);

我们进入AudioFlinger.cpp找到openOutput函数:

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)
	/*该处返回一个线程,显然openOutput_l中会创建一个播放线程*/
	sp<PlaybackThread> thread = openOutput_l(module, output, config, *devices, address, flags);
		/*获得一个AudioHwDevice,前面提到AudioFlinger对应一个或者多个AudioHwDevice ,每一个AudioHwDevice都对应一个module(so文件),所支持的设备*/
		AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
		
		status_t status = outHwDev->openOutputStream(&outputStream,*output,devices,flags,config,address.string());
		/*根据类型不一样,创建不同的线程*/
       	thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
       	thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
       	/*一般创建该线程较多,表示声音来源多种多样,其会把这些声音混合起来*/
       	thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);     
        mPlaybackThreads.add(*output, thread);

下面我们做一些总结:

/*描述多个modules*/
audio_hw_modules {
  primary { //一个modules对应一个厂家提供的so文件
    outputs { //一个modules可以有多个output
      primary {//一个output表明他的参数(primary代表默认设备)
        ......
      }
      spdif_passthrough {   
        ......  
      }

      hdmi {
        ......
      }
    }
    inputs {//一个modules可以有多个input
      primary {
      }
    }
  }
  a2dp {
    outputs {
      a2dp {
        ......
      }
    }
  }
  usb {
    outputs {
      usb_accessory {
        ......
      }
      usb_device {
        ......
      }
    }
    inputs {
      usb_device {
        ......
      }
    }
  }
  r_submix {
    outputs {
      submix {
        ......
      }
    }
    inputs {
      submix {
        ......
      }
    }
  }
}

上面是我们之前讲解过的配置文件,其中primary,a2dp,usb,r_submix节点间我们称为modle,在primary中存在一个outputs与inputs结点。

1.在AudioPolicyService中存在一个mHwModules数组,其中有多个mHwModule,每个mHwModule包含.mName,.mOutputProfiles(对应一个output结点配置:IOProfiles类),.mInputProfiles(对应一个或者多个input结点配置:IOProfiles类).等成员。
2.由AudioFlinger实现,根据mHwModules数组中每个mHwModule的名字,打开厂家提供的so文件。然后构建硬件封装的对象mAudioHwDevice放入mAudioHwDevices数组中。mAudioHwDevice中含有audio_hw_device结构体,audio_hw_device又包含了厂家提供的AudioHardWare对象。
3.打开module中的output创建playbackTraad线程(由AudioFlinger实现,但是由AudioPolicyService调用):对每一个module中的每一个output Profiles,如果flog不是特殊的,则调用status_t status = outHwDev->openOutputStream(&outputStream,*output,devices,flags,config,address.string())。然后创建线程thread = new DirectOutputThread,在通过mPlaybackThreads.add(*output, thread)添加到mPlaybackThreads线程数组之中。所以,没一个Output都对应一个线程(猜测input也是如此)。

  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江南才尽,年少无知!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值