javaee论坛

普通会员

225648

帖子

341

回复

355

积分

楼主
发表于 2019-10-30 14:58:33 | 查看: 98 | 回复: 1

该小节开始,分析音频系统HAL分析,在前面有一章节:第004课_Android音频系统详解。详细的分析了Android音频系统的源码,但是那些都是系统集成的,一般来说,我们在移植的时候,都不需要去理会的,只需要修改HAL层即可。

首先我们来讲解一下音频系统HAL的框架,我们要分析HAL层,那么他的相关文件由那些呢?

audio_hw_hal.cpp(hardware\rockchip\audio\legacy_hal\)AudioHardwareInterface.cpp(hardware\rockchip\audio\legacy_hal\)AudioHardware.cpp(hardware\rockchip\audio\legacy_hal\)

通过08.音频系统:第004课_Android音频系统详解:第005节_AudioFlinger启动过程分析小节,我们知道其最终会生成audio.primary.default.so文件,通过08.音频系统:第004课_Android音频系统详解:第004节_AudioPolicyService启动过程分析章节我们知道,AudioPolicyService会去加载配置文件/system/etc/audio_policy.conf,在这个配置文件中,描述了一个或者多个modle,后面会根据这个modle加载对应的.so文件,在配置文件中有一个叫primary的modle,所以其会去加载audio.primary.default.so。

为了更好的分析源码,我们先讲解一下他的框架:注意图中的HAL层,其中右边audio_policy_module已经废弃了,现在使用的是audio_module,HAL层对上要提供统一的接口,对下面(硬件)的操作,一般会抽象出一个类。在android系统中,使用的是面向对象的方式去编程,会把一个模块,或者单独的功能封装成一个类。

1.打开文件audio_hw_hal.cpp找到:

structlegacy_audio_device{------------------------------------------------------structaudio_hw_devicedevice;------------------------------------------------------structAudioHardwareInterface*hwif;};staticintlegacy_adev_open(consthw_module_t*module,constchar*name,hw_device_t**device){structlegacy_audio_device*ladev;ladev->device.init_check=adev_init_check;ladev->device.set_voice_volume=adev_set_voice_volume;......ladev->device.open_input_stream=adev_open_input_stream;ladev->device.close_input_stream=adev_close_input_stream;ladev->hwif=createAudioHardware();*device=&ladev->device.common;

其中的structaudio_hw_devicedevice就是HAL向上提供的接口,被封装成了一个结构体。AudioFlinger可以通过这个接口来访问硬件。从上面我们也能看到,其设置了一系列的函数。我们随便打开几个函数如adev_set_voice_volume:

staticintadev_set_voice_volume(structaudio_hw_device*dev,floatvolume){structlegacy_audio_device*ladev=to_ladev(dev);returnladev->hwif->setVoiceVolume(volume);}staticintadev_set_master_volume(structaudio_hw_device*dev,floatvolume){structlegacy_audio_device*ladev=to_ladev(dev);returnladev->hwif->setMasterVolume(volume);}......

可以看到,其最终都是调用ladev->hwif中的函数,在legacy_adev_open函数中我们看到了:

/*创建音频硬件*/ladev->hwif=createAudioHardware();

我们打开AudioHardware.cpp:

extern"C"AudioHardwareInterface*createAudioHardware(void){returnnewAudioHardware();}

可以看到,其创建了一个AudioHardware对象,该对象用来表示一个声卡。这个是厂家提供的类,即audio_hw_hal会通过AudioHardware向下访问硬件,当然,在这个类中,其会调用tinyalsa,在前面贴出的框图中,我们也可以看出。

既然是厂家编写的,那么他肯定不能随便写,需要遵循一定的接口,我们看看AudioHardware的定义:

classAudioHardware:publicAudioHardwareBase

可以知道,其派生于AudioHardwareBase:

classAudioHardwareBase:publicAudioHardwareInterface

AudioHardwareBase又派生于AudioHardwareInterface,则两个就是AudioHardwareInterface.cpp文件的由来。

现在我们来总结一下:HAL层向上由audio_hw_device(audio_hw_hal中legacy_adev_open函数)提供接口,向下通过AudioHardware访问硬件。

那么我们来看看audio_hw_device中是否有读写函数:

staticintlegacy_adev_open(consthw_module_t*module,constchar*name,hw_device_t**device){structlegacy_audio_device*ladev;intret;if(strcmp(name,AUDIO_HARDWARE_INTERFACE)!=0)return-EINVAL;ladev=(structlegacy_audio_device*)calloc(1,sizeof(*ladev));if(!ladev)return-ENOMEM;ladev->device.common.tag=HARDWARE_DEVICE_TAG;ladev->device.common.version=AUDIO_DEVICE_API_VERSION_2_0;ladev->device.common.module=const_cast<hw_module_t*>(module);ladev->device.common.close=legacy_adev_close;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;ladev->device.set_mode=adev_set_mode;ladev->device.set_mic_mute=adev_set_mic_mute;ladev->device.get_mic_mute=adev_get_mic_mute;ladev->device.set_parameters=adev_set_parameters;ladev->device.get_parameters=adev_get_parameters;ladev->device.get_input_buffer_size=adev_get_input_buffer_size;ladev->device.open_output_stream=adev_open_output_stream;ladev->device.close_output_stream=adev_close_output_stream;ladev->device.open_input_stream=adev_open_input_stream;ladev->device.close_input_stream=adev_close_input_stream;ladev->device.dump=adev_dump;ladev->hwif=createAudioHardware();if(!ladev->hwif){ret=-EIO;gotoerr_create_audio_hw;}*device=&ladev->device.common;return0;err_create_audio_hw:free(ladev);returnret;}

从上面我们似乎并没有找到读写的函数,我们播放声音,肯定是需要写入硬件的,但是上面我们可以看看:

/*打开输出流*/ladev->device.open_output_stream=adev_open_output_stream;.......out->stream.common.dump=out_dump;out->stream.common.set_parameters=out_set_parameters;out->stream.common.get_parameters=out_get_parameters;out->stream.common.add_audio_effect=out_add_audio_effect;out->stream.common.remove_audio_effect=......./*打开输入流*/ladev->device.open_input_stream=adev_open_input_stream;......in->stream.common.set_format=in_set_format;in->stream.common.standby=in_standby;in->stream.common.dump=in_dump;in->stream.common.set_parameters=in_set_parameters;in->stream.common.get_parameters=in_get_parameters;in->stream.common.add_audio_effect=in_add_audio_effect;......

可以看到两个open函数,我们可以看到其中有很多的stream,在这里我们要引入几个概念,其上的stream类型:

structlegacy_stream_out{structaudio_stream_outstream;AudioStreamOut*legacy_out;};structlegacy_stream_in{structaudio_stream_instream;AudioStreamIn*legacy_in;};

中前面的分析,我们知道使用AudioHardware代表一个声卡,那么这个声卡的输出功能用什么表示呢?,就是其上的legacy_stream_out与legacy_stream_in:既然legacy_stream_out表示输出,那么其中肯定含有输出函数(wirte),legacy_stream_in则含有输入函数(read),就不进行贴图了,audio_stream_out(向上提供输出功能)与audio_stream_in(向上提供输入功能)结构体都有定义。

我们进入ladev->device.open_output_stream=adev_open_output_stream函数:

staticintadev_open_output_stream(structaudio_hw_device*dev,audio_io_handle_thandle,audio_devices_tdevices,audio_output_flags_tflags,structaudio_config*config,structaudio_stream_out**stream_out,constchar*address__unused)/*设置一系列的函数*/......out->stream.write=out_write;/*返回一个audio_stream_out*/*stream_out=&out->stream;

之前我们提到legacy_adev_open中会构建一个legacy_audio_device结构体,其会借助AudioHardware完成那些函数肚饿功能。

staticintadev_set_voice_volume(structaudio_hw_device*dev,floatvolume){structlegacy_audio_device*ladev=to_ladev(dev);returnladev->hwif->setVoiceVolume(volume);}staticintadev_set_master_volume(structaudio_hw_device*dev,floatvolume){structlegacy_audio_device*ladev=to_ladev(dev);returnladev->hwif->setMasterVolume(volume);}......

所在open函数中:

staticintadev_set_voice_volume(structaudio_hw_device*dev,floatvolume){structlegacy_audio_device*ladev=to_ladev(dev);

定义了legacy_audio_device结构体

structlegacy_audio_device{/*向上提供的接口,使用AudioHardware实现相应的功能*/structaudio_hw_devicedevice;/*指向厂家代码提供的AudioHardware,*/structAudioHardwareInterface*hwif;};

在来查看一下:

structlegacy_stream_out{/*规范了向上提供的接口,其功能实现依赖于AudioStreamOut*/structaudio_stream_outstream;/*由厂家提供的AudioStreamOut类实现*/AudioStreamOut*legacy_out;};/*同上*/structlegacy_stream_in{structaudio_stream_instream;AudioStreamIn*legacy_in;};

下面我们追踪一下源码:

staticintadev_open_output_stream(structaudio_hw_device*dev,audio_io_handle_thandle,audio_devices_tdevices,audio_output_flags_tflags,structaudio_config*config,structaudio_stream_out**stream_out,constchar*address__unused)out->legacy_out=ladev->hwif->openOutputStreamWithFlags(devices,flags,(int*)&config->format,&config->channel_mask,&config->sample_rate,&status);openOutputStream(devices,format,channels,sampleRate,status);openOutputStream(devices,format,channels,sampleRate,status);

其中的openOutputStream在厂家提供AudioHardware.cpp中实现:

android_audio_legacy::AudioStreamOut*AudioHardware::openOutputStream(uint32_tdevices,int*format,uint32_t*channels,uint32_t*sampleRate,status_t*status)out=newAudioStreamOutALSA();

输入流也是一样的原理,能存在:

in=newAudioStreamInALSA();

其分析过程,下面是总结的笔记:

b.框架audioHAL中:b.1向上提供统一接口:audio_hw_device里面设置了各种函数b.2这些函数要借助声卡的代码才能实现,声卡的功能抽象为AudioHardware对象b.3audio_hw_device中的函数只看到各种set,get没有看到wirte,read怎么播放声音、录制声音?b.4要播放声音,b.4.1要先openoutput在audio_hw_device中有open_output_stream函数指针b.4.2open_output_stream返回一个audio_stream_out结构体,它是向上提供的"播放接口"b.4.3audio_stream_out也需要厂家提供的代码才能实现厂家提供的代码抽象为AudioStreamOutALSA对象b.5对于录制声音b.5.1要先openinput在audio_hw_device中有open_input_stream函数指针b.5.2open_input_stream返回一个audio_stream_in结构体,它是向上提供的"录制接口"b.5.3audio_stream_in也需要厂家提供的代码才能实现厂家提供的代码抽象为AudioStreamInALSA对象

下面是配的框图:


普通会员

0

帖子

312

回复

320

积分
沙发
发表于 2021-04-20 19:26:08

楼主说得对

您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017