该小节开始,分析音频系统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找到:
struct legacy_audio_device {
------------------------------------------------------
struct audio_hw_device device;
------------------------------------------------------
struct AudioHardwareInterface *hwif;
};
static int legacy_adev_open(const hw_module_t* module, const char* name,hw_device_t** device)
{
struct legacy_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;
其中的struct audio_hw_device device就是HAL向上提供的接口,被封装成了一个结构体。AudioFlinger可以通过这个接口来访问硬件。从上面我们也能看到,其设置了一系列的函数。 我们随便打开几个函数如adev_set_voice_volume:
static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
{
struct legacy_audio_device *ladev = to_ladev(dev);
return ladev->hwif->setVoiceVolume(volume);
}
static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
{
struct legacy_audio_device *ladev = to_ladev(dev);
return ladev->hwif->setMasterVolume(volume);
}
......
可以看到,其最终都是调用ladev->hwif中的函数,在legacy_adev_open函数中我们看到了:
/*创建音频硬件*/
ladev->hwif = createAudioHardware();
我们打开AudioHardware.cpp:
extern "C" AudioHardwareInterface* createAudioHardware(void) {
return new AudioHardware();
}
可以看到,其创建了一个AudioHardware对象,该对象用来表示一个声卡。这个是厂家提供的类,即audio_hw_hal会通过AudioHardware向下访问硬件,当然,在这个类中,其会调用tinyalsa,在前面贴出的框图中,我们也可以看出。
既然是厂家编写的,那么他肯定不能随便写,需要遵循一定的接口,我们看看AudioHardware的定义:
class AudioHardware : public AudioHardwareBase
可以知道,其派生于AudioHardwareBase:
class AudioHardwareBase : public AudioHardwareInterface
AudioHardwareBase 又派生于AudioHardwareInterface,则两个就是AudioHardwareInterface.cpp文件的由来。
现在我们来总结一下: HAL层向上由audio_hw_device(audio_hw_hal中legacy_adev_open函数)提供接口,向下通过AudioHardware访问硬件。
那么我们来看看audio_hw_device中是否有读写函数:
static int legacy_adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct legacy_audio_device *ladev;
int ret;
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
return -EINVAL;
ladev = (struct legacy_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(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;
goto err_create_audio_hw;
}
*device = &ladev->device.common;
return 0;
err_create_audio_hw:
free(ladev);
return ret;
}
从上面我们似乎并没有找到读写的函数,我们播放声音,肯定是需要写入硬件的,但是上面我们可以看看:
/*打开输出流*/
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类型:
struct legacy_stream_out {
struct audio_stream_out stream;
AudioStreamOut *legacy_out;
};
struct legacy_stream_in {
struct audio_stream_in stream;
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函数:
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;
/*返回一个audio_stream_out*/
*stream_out = &out->stream;
之前我们提到legacy_adev_open中会构建一个legacy_audio_device 结构体,其会借助AudioHardware完成那些函数肚饿功能。
static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
{
struct legacy_audio_device *ladev = to_ladev(dev);
return ladev->hwif->setVoiceVolume(volume);
}
static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
{
struct legacy_audio_device *ladev = to_ladev(dev);
return ladev->hwif->setMasterVolume(volume);
}
......
所在open函数中:
static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
{
struct legacy_audio_device *ladev = to_ladev(dev);
定义了legacy_audio_device结构体
struct legacy_audio_device {
/*向上提供的接口,使用AudioHardware实现相应的功能*/
struct audio_hw_device device;
/*指向厂家代码提供的AudioHardware,*/
struct AudioHardwareInterface *hwif;
};
在来查看一下:
struct legacy_stream_out {
/*规范了向上提供的接口,其功能实现依赖于AudioStreamOut */
struct audio_stream_out stream;
/*由厂家提供的AudioStreamOut类实现*/
AudioStreamOut *legacy_out;
};
/*同上*/
struct legacy_stream_in {
struct audio_stream_in stream;
AudioStreamIn *legacy_in;
};
下面我们追踪一下源码:
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->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_t devices, int *format, uint32_t *channels,uint32_t *sampleRate, status_t *status)
out = new AudioStreamOutALSA();
输入流也是一样的原理,能存在:
in = new AudioStreamInALSA();
其分析过程,下面是总结的笔记:
b. 框架
audio HAL中:
b.1 向上提供统一接口: audio_hw_device
里面设置了各种函数
b.2 这些函数要借助声卡的代码才能实现,
声卡的功能抽象为AudioHardware对象
b.3 audio_hw_device中的函数只看到各种set, get
没有看到wirte, read
怎么播放声音、录制声音?
b.4 要播放声音,
b.4.1 要先open output
在audio_hw_device中有open_output_stream函数指针
b.4.2 open_output_stream返回一个audio_stream_out结构体,
它是向上提供的"播放接口"
b.4.3 audio_stream_out也需要厂家提供的代码才能实现
厂家提供的代码抽象为AudioStreamOutALSA对象
b.5 对于录制声音
b.5.1 要先open input
在audio_hw_device中有open_input_stream函数指针
b.5.2 open_input_stream返回一个audio_stream_in结构体,
它是向上提供的"录制接口"
b.5.3 audio_stream_in也需要厂家提供的代码才能实现
厂家提供的代码抽象为AudioStreamInALSA对象
下面是配的框图: