1.1、什么是PCM
脉冲编码调制(Pulse Code Modulation,PCM),它的作用是把一个时间连续,取值连续的模拟信号变换成时间离散,取值离散的数字信号后在信道中传输。脉冲编码调制就是对模拟信号先抽样,再对样值幅度量化,编码的过程。
pcm是一个通信上的概念,脉冲编码调制,是编码。wav是媒体概念,体现的是封装。wav文件可以封装pcm编码信息,也可以封装其他编码格式,例如mp3等
从手机麦克风采集的数据就是pcm原始数据。
1.2、AudioTrck
首先它可以直接播放pcm音频数据,但是不能播放其它的格式如MP3,AAC,WAV等,不过更加上层的API如MediaPlay却可以播放这些格式,但是同时MediaPlay也失去了对底层数据流的一些操作,如AudioTrack可以控制每一帧数据,可以自己转化任意格式,自由性比较强大,而MediaPlay却不行。
AudioTrack播放有两种模式:
MODE_STREAM:
在这种模式下,需要先play,然后通过write一次次把音频数据写到AudioTrack中(我在试验中可以先write再play,可能是数据太小了的原因)。每次都需要把数据从用户提供的Buffer中拷贝到AudioTrack内部的Buffer中,这在一定程度上会使引入延时。
适用于大多数的场景,将audio buffers从java层传递到native层即返回。
如果audio buffers占用内存多,应该使用MODE_STREAM。
比如播放时间很长的声音文件,
比如音频文件使用高采样率,
比如动态的处理audio buffer等
MODE_STATIC:
这种模式下,需要先write,再play.。先把所有数据通过一次write调用传递到AudioTrack中的内部缓冲区,后续就不必再传递数据了。但它也有一个缺点,就是一次write的数据不能太多,否则系统无法分配足够的内存来存储全部数据。
一次性将全部的音频资源从java传递到native层,这种方式延迟低,但也有局限性。
音频文件短且占用内存小。
适用于短促的游戏音效,并且对播放延迟真的有很高要求。
PS:以上两种模式比对摘抄如下文章
1.3、介绍
在看播放之前,先来了解一下AudioTrack是如何构造出来的。
在AudioTrack构造函数中,会接触到AudioManager.STREAM_MUSIC这个参数。
Android将系统的声音streamType分为好几种流类型,下面是几个常见的:
- STREAM_ALARM:警告声
- STREAM_MUSIC:音乐声,例如music等
- STREAM_RING:铃声
- STREAM_SYSTEM:系统声音,例如低电提示音,锁屏音等
- STREAM_VOCIE_CALL:通话声
注意:上面这些类型的划分和音频数据本身并没有关系。例如MUSIC和RING类型都可以是某首MP3歌曲。另外,声音流类型的选择没有固定的标准,例如,铃声预览中的铃声可以设置为MUSIC类型。音频流类型的划分和Audio系统对音频的管理策略有关。(也就是播放时调用的哪种流格式而已,Android对不同流格式处理的有些不同而已)
构造有多种:
下面两种对于低版本api可以用:
1. AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,int bufferSizeInBytes, int mode)
2. AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,int bufferSizeInBytes, int mode, int sessionId)
streamType(音频流类型AudioManager.STREAM_XXX),sampleRateInHz(采样率,不同音频的采样率不一样,比如可以16000,也可以说44100),channelConfig(通道数目,目前最多只支持双声道),audioFormat(音频量化位数,只支持8bit和16bit,也就是AudioFormat.ENCODING_PCM_8BIT和AudioFormat.ENCODING_PCM_16BIT),bufferSizeInBytes(取决于采样率、声道数和采样深度三个属性),mode(仅支持MODE_STREAM和MODE_STATIC,上面有介绍)
sessionId:音频会话的ID AudioTrack必须附加。AudioManager.AUDIO_SESSION_ID_GENERATE if the session isn't known at construction time。就是说在创建的时候不知道会话可以传入这个值AudioManager.AUDIO_SESSION_ID_GENERATE 。
文档中也给出了提示:https://developer.android.google.cn/reference/android/media/AudioTrack.html#AudioTrack(int,%20int,%20int,%20int,%20int,%20int)
This constructor was deprecated in API level 26.use AudioTrack.Builder or AudioTrack(AudioAttributes, AudioFormat, int, int, int) to specify the AudioAttributes instead of the stream type which is only for volume control.
另外一种:
3. AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,int mode, int sessionId)
后面三个int参数就不用介绍了,上面有,介绍前两个参数(not null)。
format实例描述将通过此AudioTrack播放的数据的格式。见AudioFormat.Builder用于配置音频格式参数,如编码数据格式、通道和采样率,就是将之前的api的三个参数(数据格式,通道,采样率)合为一体,很容易理解。
attributes则是对之前的api的streamType的 一个改进,具体请查阅AudioAttributes 。
本文摘抄《Android-音视频(3):用AudioTrack播放音频PCM》、《音频播放AudioTrack之入门篇》和《AudioTrack中MODE_STATIC和MODE_STREAM的差异》自己整理得出。不懂的可访问相关链接。
后面还有一篇关于如何使用,谢谢。
https://www.biumall.com/ 笔友城堡,为你导航!