zhaohuarong 发表于 2017-12-7 17:05:08

Android(海思平台)实现HDMI和I2S同时输出音频

本帖最后由 zhaohuarong 于 2017-12-7 17:05 编辑

最近工作中需要在Android板上HDMI和I2S(喇叭)做声音切换输出。基本思路就是不使用Android原生的AudioTrack进行声音输出。使用封装的类进行声音的播放,进行两路同时输出,然后切换的时候每次将一个设备设置为静音即可。搞了一个星期才搞定这个事情,写篇文章记录一下,绝对一个字一个字的敲出来的。辛苦啊!

原有的声音播放方式使用的是AudioTrack,专门用于播放声音码流。基本的用法就是不断的去调用AudioTrack.write(byteBuffer, sizeInBytes, AudioTrack.WRITE_BLOCKING);缓冲区中的数据会自动进行播放。但是这个方法无法设置外部声音设备,即无法指定输出设备。

原生的AudioTrack在Android源码中的位置




下面介绍一下实现AudioTrack的write的替代方法,只是可以同时进行双输出。

1.进入厂商的目录下的frameworks目录,可以看见厂商为Android额外增加的一些模块。


2. 我选择将新功能放到hiaudio模块中去。进入hiaudio,我们可以看见该模块的代码结构分类,java中存放该模块面向应用的Java接口,jni中存放的是jni接口,libs中存放的是cpp实现。现在需要按照这个顺序依次将接口从Java层引入到cpp中。


3.打开java目录中的HiAudioManager.java,在该类中添加如下代码

分别表示设置HDMI静音、设置I2S静音、初始化、写入数据。简单的几行代码就定义了在APP中的调用接口。

4.打开jni目录中的cpp文件,该cpp文件为刚才定义的Java接口的jni类型定义,作用相当于一个翻译人员,负责将Java接口翻译成本地化的cpp接口。函数体类调用的都是后面需要实现的cpp接口。



5.下面在进入到libs目录下的虚函数接口类中。在头文件中添加如下声明。

相应的在CPP文件中添加函数体。


6.下面进入到真正的函数执行部分了,上面的步骤都只是为了数据传递,将接口一步一步的向上暴露给Android程序调用,现在我们已经进入Android底层CPP代码。在头文件中添加函数体声明。

然后在CPP中对每个函数进行实现,此时不再是像上面那样固定的编码格式,而是业务逻辑代码。实现具体功能。

这两个函数相对比较简单,直接调用厂商的底层接口即可完成相应的功能。不做过多的介绍了。

初始化函数非常的长,就不全部截图了。目的就是将声音设备初始化,然后绑定到两个物理音频设备上去,这样就可以同时发出声音了。

这个writeData函数是反复调用的,在线音频或者本地音频,通过每次读取固定的长度的内存到缓冲区进行播放。



7.最后一步就是在Android app中调用了。
先import HiAudioManager这个包。这里我播放的是一个音频文件,在线音频码流原理是一样的。

小甲鱼 发表于 2017-12-12 19:01:53

干货!支持!

zhaohuarong 发表于 2017-12-7 22:13:08

{:10_257:}

zhaohuarong 发表于 2017-12-7 22:13:21

{:10_266:}

像番茄加两个蛋 发表于 2017-12-12 20:32:52

感谢楼主分享

xpp2013 发表于 2017-12-19 08:27:12

好帖,干货,谢谢楼主

zhangpeng96 发表于 2018-11-16 12:33:03

楼主可以私发一下初始化那里的代码吗?我i2s一直没有输出QQ:1091074137谢谢
页: [1]
查看完整版本: Android(海思平台)实现HDMI和I2S同时输出音频