08.音频系统:第006课_音频系统HAL分析:第001节_HAL之框架

该小节开始,分析音频系统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<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;
        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对象

下面是配的框图:在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43013761/article/details/89705968