08.音频系统:第006课_音频系统HAL分析:第002节_HAL之调用流程源码分析

在上小节中,分析了android音频系统中,HAL代码的框架,该小节我们根据源代码查看一下流程,加深一下理解。在分析源代码之前,我们先俩看看HAL在整个音频系统中,他处于什么位置,下面是一个框图,相关知识点,在前面的小节中,都已经讲解过:

在这里插入图片描述

现在我们来回顾一下,假设有一个android手机,他上面有喇叭,我们在听音乐的时候,声音会中喇叭中播放出来,当插上耳机的时候,声音就从耳机中播放出来,那么这整个过程会涉及什么东西?
在这里插入图片描述
1.优先从耳机播放,其由AudioPolicyService决定
2.如果有多个APP要播放声音,AudioFlinger负责混合多个APP的声音,当然除此之外还有其他的许多功能。
3.最终要操作硬件,有多种声卡,可以动态的拔插(USB声卡,蓝牙声卡),对于每一种声卡由一个模块(so文件)来操控他,即HAL
4.为简化声卡的操作,有一个tinyalsa库。只需要pcm_open,pcm_wirte,pcm_read就能进行播放录音。
5.pcm_open,pcm_wirte,pcm_read通过标准的open,wirte,read访问驱动,进而控制驱动访问硬件。

现在我们来看看HAL的代码是怎么被调用的,其又是怎么调用tinyalsa的。下面是流程图:
在这里插入图片描述
我们先来看下HAL的操作流程:
1.从/system/etc/audio_policy.conf配置文件中确定so文件的名字。
2.加载so文件
3.HAL文件中的open函数构造并且返回一个audio_hw_device_t 结构体,其中包含了adev_open_output_stream,adev_open_input_stream。
然后AudioFlinger使用audio_hw_device_t 构造成AudioHwDevice对象,每个声卡对应一个audio_hw_device_t 与AudioHwDevice。放入数组mAudioHwDeviceS中。
4.调用hal文件中audio_hw_device_t 结构体中的adev_open_output_stream会构建一个audio_stream_out结构体,返回给AudioFlinger,AudioFlinger使用根据他创建一个MixerThread线程。

根据图示,最终会调用到adev_open_output_stream。

5.write写入给声卡,

以上步骤的对应函数都已经和流程图连接,之前讲解过的函数,就不再次进行讲解了,我们知道每个module中都有一个,如audio_hw_hal.cpp 中:

static int legacy_adev_open(const hw_module_t* module, const char* name,hw_device_t** device){
	*device = &ladev->device.common;
}

static struct hw_module_methods_t legacy_audio_module_methods = {
        open: legacy_adev_open
};

struct legacy_audio_module HAL_MODULE_INFO_SYM = {
    module: {
        common: {
            tag: HARDWARE_MODULE_TAG,
            module_api_version: AUDIO_MODULE_API_VERSION_0_1,
            hal_api_version: HARDWARE_HAL_API_VERSION,
            id: AUDIO_HARDWARE_MODULE_ID,
            name: "LEGACY Audio HW HAL",
            author: "The Android Open Source Project",
            methods: &legacy_audio_module_methods,
            dso : NULL,
            reserved : {0},
        },
    },
};

这个module中有一个方法methods legacy_audio_module_methods,methods 中包含了open函数,那么他是在什么时候被调用呢?从流程图可以知道load_audio_interface,打开AudioFlinger.cpp:

static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
	/*获得一个audio_hw_device_t **dev结构体指针*/
	rc = audio_hw_device_open(mod, dev);
	

audio_hw_device_t 最终在AudioFlinger中被构建成一个AudioHwDevice对象,

现在我们看看最终调用到的adev_open_output_stream函数:

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)
	out->stream.write = out_write;
	*stream_out = &out->stream;

可以知道其返回一个audio_stream_out结构体。其中的out_write函数又对应谁呢?其对应AudioHardware.cpp(厂家提供)中的write函数。当然,引起该函数的调用流程如下:
在这里插入图片描述
也就是说MixerThread线程被创建之后,一直在等待数据,当接受到数据之后最终引起AudioHardware.cpp(厂家提供)中的write函数被调用。

下面是该小节的要点总结:

HAL之调用流程源码分析
a. 确定HAL文件的名字:
   AudioPolicyManager的构造函数读取配置文件/system/etc/audio_policy.conf
   确定名字

b. 加载HAL对应的so文件
c. 打开HAL文件中的open函数
   在HAL中会构造audio_hw_device结构体, 
   该结构体中有各类函数, 特别是 open_output_stream / open_input_stream
   
   AudioFlinger根据audio_hw_device结构体构造一个AudioHwDev对象并放入mAudioHwDevs

d. open output stream:
   调用hal结构体audio_hw_device的open_output_stream,
   它会构造出一个audio_stream_out结构体, 里面有write函数
   
   AudioFlinger根据audio_stream_out结构体构造一个MixerThread

e. 播放声音(这时才真正打开声卡驱动): 
   thread->threadLoopg_write  => stream.write ==> pcm_open, pcm_write
  • 9
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

江南才尽,年少无知!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值