android语音播放
Ⅰ Android音频播放
最近需要在Android的客户端中使用PCM声音播放和录制,简单学习了一下。有不正确的地方还请指出。
首先有几个概念需要了解一下:采样频率、声道数、采样位数。
采样频率一般是sample rate, 代表的是数字化音频时每秒采样的次数。常见的有44.1KHz(CD品质)、48KHz等。
这个很好理解,单声道Mono就是声音从一个方向传出来;双声道Stereo也叫立体声,声音是从两个方向传来。通常的流行音乐中,仔细听能发现每个声道可能侧重不同的乐曲声部,比如左声道吉他,右声道钢琴,人声似乎两个声道都有,听起来就像站在中间一样。(这里没有考证,随便举例)
每一个采样都是一个数据点,采样位数是指这个数据点使用了几位来记录。AudioTrack类只支持8位和16位的PCM音频。8位就是2的8次方,即256个值;而16位则是2的16次方,有65536个值。
这个在音频的编解码中还是比较常用的。在PCM格式中,1秒钟音频的数据大小是SampleRate×Channel×Bit/8,单位是byte字节。由于PCM本身没有音频帧的概念,所以通过这个公式就能计算出任意时长音频的大小,或者得到任意大小音频的时长。如果规定1个音频帧是“每个声道256个采样”,双声道下就是512个采样,那么1帧的数据量就是256×Channel×Bit/8,同理可以推断出1秒钟有多少音频帧等等。音频帧的概念在各种编解码中各有不同,但计算公式大同小异,这里不展开。
Android中音频的播放使用的是AudioTrack类,具体用法非常简单。
首先设置buffer大小。AudioTrack播放时需要先写入buffer,如果这个buffer没有写满,那么这部分是不会播放的。所以buffer不能设置太小,这样会导致播放不连贯;而buffer也不能设置太小,这样不间断写入会消耗许多CPU资源。AudioTrack自带了getMinBufferSize方法可以给出一个最小buffer,一般用这个值就可以。getMinBufferSize方法三个参数分别是sample rate、channel和bit。
设置完buffer size就可以实例化一个AudioTrack。其中第一个参数streamType是指不同的音频流类型,包括STREAM_MUSIC、STREAM_ALARM、STREAM_VOICE_CALL、STREAM_RING等,是Android对不同音频的分类。中间三个参数很好理解,第四个是buffer size,刚刚计算出来了。最后一个参数mode有两种:MODE_STREAM和MODE_STATIC。前者是以流形式播放,后者则是一次性全部写入然后播放。
调用实例的play()方法就可以开始播放了。不过播放得要有数据吧?要填写数据就要用到write()方法。write方法中第一个参数是一个byte[]类型,是要写入的数据源,可以是从文件流中读取出来的;第二个参数offset是初始位移,即从source的哪个位置开始;第三个参数则是输入长度。
当write方法写满一个AudioTrack的buffer时,就会有声音播放出来了。
当播放完成后记得要把AudioTrack停止并释放。
Ⅱ Android音视频【十二】使用OpenSLES和AudioTrack进行播放PCM
本节我们学习下如何播放pcm数据,在Android中有两种方法:一种是使用java层的 AudioTrack 方法,一种是使用底层的 OpenSLES 直接在 jni 层调用系统的 OpenSLES的c方法 实现。
两种使用场景不一样:
AudioTrack 一般用于 比如本地播放一个pcm文件/流,又或者播放解码后的音频的pcm流,API较简单。
OpenSLES 一般用于一些播放器中开发中,比如音频/视频播放器,声音/音频的播放采用的OpenSLES,一是播放器一般是c/c++实现,便于直接在c层调用OpenSLES的API,二也是如果用AudioTrack进行播放,务必会带来java和jni层的反射调用的开销,API较复杂。
可以根据业务自行决定来进行选择。
AudioTrack的方式使用较简单,直接在java层。
指定采样率,采样位数,声道数进行创建。
其中44100是采样率, AudioFormat.CHANNEL_OUT_STEREO 为双声道,还有 CHANNEL_OUT_MONO 单声道。 AudioFormat.ENCODING_PCM_16BIT 为采样位数16位,还有 ENCODING_PCM_8BIT 8位。 minBufferSize 是播放器缓冲的大小,也是根据采样率和采样位数,声道数 进行获取,只有满足最小的buffer才去操作底层进程播放。
最后一个参数mode。可以指定的值有 AudioTrack.MODE_STREAM 和 AudioTrack.MODE_STATIC 。
MODE_STREAM 适用于大多数的场景,比如动态的处理audio buffer,或者播放很长的音频文件,它是将audio buffers从java层传递到native层。音频播放时音频数据从Java流式传输到native层的创建模式。
MODE_STATIC 适用场景,比如播放很短的音频,它是一次性将全部的音频资源从java传递到native层。音频数据在音频开始播放前仅从Java传输到native层的创建模式。
是的,就这么一个方法。注意此方法是同步方法,是个耗时方法,一般是开启一个线程循环调用 write 方法进行写入。
注意在调用 write 方法前需要调用 audioTrack.play() 方法开始播放。
因为是pcm裸数据,无法像mediaplayer一样提供了API。所以需要自己处理下。可以利用 getPlaybackHeadPosition 方法。
getPlaybackHeadPosition() 的意思是返回以帧为单位表示的播放头位置
getPlaybackRate() 的意思是返回以Hz为单位返回当前播放采样率。
所以当前播放时间可以通过如下方式获取
OpenSLES:(Open Sound Library for Embedded Systems).
OpenSLES是跨平台是针对嵌入式系统精心优化的硬件音频加速API。使用OpenSLES进行音频播放的好处是可以不依赖第三方。比如一些音频或者视频播放器中都是用OpenSLES进行播放解码后的pcm的,这样免去了和java层的交互。
在Android中使用OpenSLES首先需要把Android 系统提供的so链接到外面自己的so。在CMakeLists.txt脚本中添加链接库OpenSLES。库的名字可以在 类似如下目录中
需要去掉lib
然后导入头文件即可使用了OpenSLES提供的底层方法了。
创建&使用的步骤大致分为:
一个 SLObjectItf 里面可能包含了多个Interface,获取Interface通过 GetInterface 方法,而 GetInterface 方法的地2个参数 SLInterfaceID 参数来指定到的需要获取Object里面的那个Interface。比如通过指定 SL_IID_ENGINE 的类型来获取 SLEngineItf 。我们可以通过 SLEngineItf 去创建各种Object,例如播放器、录音器、混音器的Object,然后在用这些Object去获取各种Interface去实现各种功能。
如上所说,SLEngineItf可以创建混音器的Object。
在创建播放器前需要创建音频的配置信息(比如采样率,声道数,每个采样的位数等)
开始播放后会不断的回调这个 pcmBufferCallBack 函数将音频数据压入队列
(*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, this);
如果想要暂停播放参数直接设置为SL_PLAYSTATE_PAUSED,若暂停后继续播放设置参数为SL_PLAYSTATE_PLAYING即可。若想要停止播放参数设置为SL_PLAYSTATE_STOPPED即可。
首先获取播放器的用于控制音量的接口SLVolumeItf pcmVolumePlay
然后动态设置
首先也是获取播放器的用于控制音量的接口SLMuteSoloItf pcmMutePlay
然后动态设置
看起来控制还是蛮简单的哈。先熟悉这么多,OpenSLES还是蛮强大的。
https://github.com/ta893115871/PCMPlay
Ⅲ android 实现实时语音功能选择接入哪个音视频sdk好
可以考虑接入即构科技的音视频sdk,他们的音视频sdk平台兼容性强,可覆盖 iOS、Android、Windows、macOS、Web、小程序并支持平台间互通,支持 32 路实时音视频互动,能够为开发者提供便捷接入、高清流畅、低延迟、高并发的音视频服务,而且4 行代码极速接入, 30 分钟内即可构建完毕。