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

下面是配的框图:

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

  1. 08.音频系统:第003课_Linux音频驱动程序:第002节_ASoC音频驱动框架

    通过上小节alsa音频驱动框架的分析,知道如果要去写一个声卡驱动,我们需要分配,设置,注册snd_card结构体: 定义一个struct snd_card *card; snd_card_new // ...

  2. 新风系统风速推荐表_新风系统风速标准及与噪音的关系

    原标题:新风系统风速标准及与噪音的关系 如今,新风系统不仅能够对室内空气进行净化,还能够为室内提供源源不断的新鲜空气,真可谓空净产品的实力担当.新风系统不同于其它空气净化设备,只有进行合理的选择安装才 ...

  3. 西门子dcs系统组态手册下载_“DCS系统组态”是什么意思?其步骤方法又有哪些?...

    "DCS系统组态"是什么意思? DCS组态通俗来讲就是就是控制回路程序. 控制回路通常是针对模拟量的控制来说,一个控制器根据一个输入量,按照一定的规则和算法来决定一个输出量,这样, ...

  4. 安卓系统怎么安装软件_这些系统帮助我们实现了在PC上安装安卓系统!

    要是说在早期智能手机还不是那么的普及的时候,个人电脑应该就是我们最了解的智能设备了吧.那个时候,个人PC的上安装的操作系统就分为Windows操作系统.MAC OS操作系统.Linux 操作系统以及其 ...

  5. 新风系统风速推荐表_新风系统出风口风速—新风系统出风口风速选择规范介绍...

    大家一听到新风系统这个词就会想到其是有关于风的.新风系统简单地说是一个换气系统,所以其会有进风口以及出风口.不同的新风系统就会不一样的出风口风速.那么大家知道怎么选择新风系统出风口风速吗?下面就跟着小 ...

  6. 08.音频系统:第003课_Linux音频驱动程序:第003节_耳麦拔插事件调用流程分析

    在前面的小节中,我们编写了一个驱动程序,模拟耳机的插拔事件,其可以上报耳机的拔插事件,并且修改了android的源代码,可以根据耳机的拔插事件,在状态栏上现实或者消除耳麦的图标,这节视频我们讲解耳麦插 ...

  7. 08.音频系统:第003课_Linux音频驱动程序:第001节_alsa音频驱动框架

    在上小节我们分析了Adndroid系统音频的框架,这么一个复杂的系统我们怎么去学习呢?我们从下往上学,先分析音频的驱动程序,看看linux系统中驱动程序是怎么编写的,他的结构是怎么样的,然后在琢磨Ti ...

  8. 08.音频系统:第003课_Linux音频驱动程序:第005节_DAPM_widget_route_path

    DAPM是Dynamic Audio PowerManagement的缩写,译过来就是动态音频电源管理的意思.DAPM是为了使基于linux的移动设备上的音频驱动子系统,在任何时候都工作在最小功耗状态 ...

  9. 08.音频系统:第003课_Linux音频驱动程序:第003节_RK3399声卡驱动移植_combine

    该小节我们讲解一下开发板RK3399声卡rt5651的移植,主要分为4个部分,platfrom,codec,machine,dts(设备树). 首先我们从设备树开始讲起,当然在讲解之前,我们先来体验下 ...

  10. 嵌入式系统串口解析二进制数_嵌入式系统Bootloader分析及DSP56F800串口加载功能实现...

    嵌入式系统 Bootloader 分析及 DSP56F800 串口加载功 能实现 张小平 ; 谷勇 ; 丰新龙 [期刊名称] <海军航空工程学院学报> [年 ( 卷 ), 期] 2010( ...

最新文章

  1. 点云配准的端到端深度神经网络:ICCV2019论文解读
  2. 如何将简单CMS后台管理系统示例转换为Java、Php等不同后台语言的版本
  3. ASP.NET Core 1.0 使用 MySQL for EF Core 1.0 (.NET Core 1.0)
  4. 美团北京,今日起无人驾驶送外卖
  5. 5-29 vscode占位
  6. FineReport连接多维数据库示例及操作
  7. Github 优秀开源项目 Best Open Source Projects
  8. 玻璃体混浊不要转眼球
  9. SharePoint 2013 RBS(Remote BLOB Storag) 安装、部署、垃圾回收
  10. PowerShell远程连接到Windows
  11. 2015推荐的Android框架
  12. # JDK7+ MethodHandle
  13. 基于词嵌入技术的微博博文情感分析系统设计实现
  14. window Jconsole链接到CenOS 监控Tomcat
  15. 《操作系统真象还原》——0.17 先有的语言,还是先有的编译器,第1个编译器是怎么产生的...
  16. JVM基础思维导图(持续更新中)
  17. 短信验证码功能(阿里云版)
  18. 图像插值-双三次插值(bicubic)
  19. java sql编写教务系统_教务管理系统的设计与实现(SQLServer)
  20. 问题:During startup program exited with code 0xc0000135

热门文章

  1. “目标-用户-指标”——企业开源运营之道|瞰道@谭中意
  2. Gossip 协议详解
  3. 一致性算法-Gossip协议详解
  4. 英语知识点整理day02
  5. 编写程序,求柱体的体积:
  6. 用于fast scnn的cityscape数据集制作
  7. termux自动启动ssh
  8. soul—产品体验报告
  9. 水处理过滤器:常见水处理过滤器的种类大全
  10. Revisiting Time Series Outlier Detection: Definitions and Benchmarks