混音播放

2022-04-10  本文已影响0人  进击的杰爷

前言

公司今年开始设置了创新奖,分享奖等各种大奖,不由得动力满满的,是时候拿些压箱底来冲击下奖项了。

正所谓,博一博,单车变摩托。

1,音频API

安卓sdk里,播放音频有 SoundPool,MediaPlayer, AudioTrack 三种方案。

SoundPool,明显不适合技术选型,因为它比较适合播放短促音效,文件小的音频。

MediaPlayer,使用频繁的方案,自带解码,支持mp3,wav等音频文件,但只支持单一音频播放。同样不适合。

AudioTrack,偏底层的音频播放方案,只支持pcm文件。所以,需要将音频文件解码成PCM(byte[] ),再将数据读取到固定的buffer缓存块里,然后再写入 AudioTrack ,就可以播放声音。

由于前面两个选项已被否决。那么,AudioTrack适不适合混和播放呢?暂不做确认,先看看什么是混和播放。

2,混音播放

混和播放,也就是多音轨同时播放,暂停,seekTo 等操作。

MediaPlayer 也不是不行。新建多个MediaPlayer实例,然后同时操作,该方案其实也是项目里Loop最初的实现方案,曲谱的实现方案。

虽然项目里的重点模块-曲谱都用上该方案,说明可行性还是有的。但终究不是终极方案。

比如所有音轨播放之前,播放一段前置节拍。此时会出现衔接间断的问题。

由于MediaPlayer是对AudioTrack的封装,所以,这个方案的逻辑,其实是系统针对多应用同时播放声音的方案。

所以,简单的将MediaPlayer替换成AudioTrack,通过多个AudioTrack实例来实现,原理上是一模一样的。

那还有没有其他方案呢。

这里就不得不探讨下声音的数字化的原理:在单位时间内对声波进行采样,最后量化成pcm数据。

同理,混音的原理是是:各个声音波形的叠加,也就是pcm数据的叠加。

而安卓sdk提供的音频API里,唯一能够针对pcm数据进行播放的,就只有AudioTrack。

结合上述的分析,具体的方案如下图:

所以,该方案可行?

这里抛开其他一些额外处理(比如不同采样率的音频混音,混音后的溢出),理论上是可行的,但其实有个致命的问题。

那就是多音轨时,jvm内存可能会爆掉。

这笔帐是可以算清楚的,

假如采样率为 44100HZ,位深为 16bit,声道数为 2 的 pcm,60 秒大小应为

44100×16bit×2×60s÷8bit=10,584,000Byte=10.0936889648MB 

而 Loop 单轨最高录制 5分钟,即单轨大小为 50M,8轨共计 400M

对于一些低端机型,怕是要承受不来的。

但实际场景并没有这么极限。所以,应该是可行的。

实际上,恩雅APP采用了Google Oboe的方案,比AudioTrack更加底层,更加高效以及低延迟。

但混音原理是一样的,至于不同采样率的音频混音,混音后的溢出同样是存在的,这些还未完善。

而内存溢出方面,由于JNI 没有内存限制,所以比AudioTrack更加放心。实测录制8条5分钟的音轨,整个应用占用的将近1G,1+3机型也不会出现内存溢出的问题。

至于为何一开始没有在AudioTrack下功夫,只是项目前期已经接入Google Oboe,也就不再考虑范围。

所以,接下来,则是重头戏 Oboe 的混音实现了。由于篇幅太长,只能下集解说了。

上一篇下一篇

猜你喜欢

热点阅读