1、简介
Android 中用于播放音频的API有三种,分别是:MediaPlayer,SoundPool,AudioTrack。MediaPlayer适合长时间在后台播放媒体音乐,包括本地音乐或在线流媒体资源。SoundPool适合播放比较短的音频片段,比如游戏音效、铃声片段等,它可以同时播放多个音频。AudioTrack更接近底层,它提供了强大的音频控制能力,支持低延迟播放,适合流媒体播放等。AudioTrack播放的音频必须是解码后的PCM数据。
2、MediaPlayer的创建
public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
int bufferSizeInBytes, int mode)
-
streamType 这个参数代表当前应用使用哪种音频管理策略。当系统有多个进程需要播放音频时,这个策略会决定最终展示的效果。该参数值在AudioManager类中,主要包括:
STREAM_VOCIE_CALL:电话声音
STREAM_SYSTEM:系统声音
STREAM_RING:铃声
STREAM_MUSCI:音乐声
STREAM_ALARM:警告声
STREAM_NOTIFICATION:通知声 -
sampleRateInHz 该参数表示采样率。44100Hz是科学家给出的最佳采样频率,并且在Android中也是多所有Android设备兼容最好的采样频率。
-
channelConfig 通道数,也就是声道数。常量定义在AudioFormat类中,CHANNEL_OUT_MONO表示单声道,CHANNEL_OUT_STEREO表示双声道。
-
audioFormat 指音频采样精度,或者说是音频位宽。常量定义在AudioFormat类中,可选AudioFormat.ENCODING_PCM_16BIT或AudioFormat.ENCODING_PCM_8BIT等。16位将占用更多的空间,但采集的音频也更加接近原声。AudioFormat.ENCODING_PCM_16BIT目前兼容性更好。
-
bufferSizeInBytes 这个参数是AudioRecoder内部音频缓冲区的大小。该缓冲区的大小不能小于一个“音频帧”的大小。音频帧的计算方法为:int size = 采样率 x 位宽 x 采样时间 x 声道数。
采样时间是指采集一帧数据所用的时间,它的取值一般在2.5ms~120ms 之间,根据手机厂商等因素决定。每一帧采样的时间越短,产生的延时就越小,但是碎片化的数据也就越多。
AudioRecoder类中提供了一个静态方法int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)来获取缓冲区大小。音频缓冲区大小必须是“音频帧”大小的2~N倍。这里强烈建议使用该方法去计算缓冲区大小,而不是手动去计算。 -
mode AudioTrack提供两种播放方式,一种是static,另外一种是stream。static方式需要一次性的将所有的音频数据全部写入音频缓冲区,这样简单高效,适用于铃声、系统提示音等比较短的音频片段。stream方式是按一定的时间间隔将音频数据不断的写入到缓存区,比如音频通话,视频直播的声音播放,理论上适用于所有的音频播放场景。
3、音频播放
AudioTrack创建完成后,就可以在一个新的线程中,调用以下方法将数据写入到缓存区进行播放
AudioTrack.write(byte[] audioData, int offsetInBytes, int sizeInBytes)
AudioTrack.write方法需要在子线程中调用。
4、代码示例
private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;
private static final int DEFAULT_PLAY_MODE = AudioTrack.MODE_STREAM;
private static final int DEFAULT_CHANNEL = AudioFormat.CHANNEL_OUT_MONO;
/**
* 缓存的音频大小
*/
private int mBufferSize;
private boolean isPlaying = false;
private AudioTrack audioTrack;
/**
* @param sampleRate sample rate、采样率
* @param encoding Audio data format、音频格式
*/
AudioPlayer(int sampleRate, int encoding) {
this.mSampleRate = sampleRate;
this.mBufferSize = AudioTrack.getMinBufferSize(sampleRate, DEFAULT_CHANNEL, encoding);
if (mBufferSize == AudioTrack.ERROR_BAD_VALUE) {
Log.e(TAG, "获取BufferSize失败");
return;
}
this.audioTrack = new AudioTrack(DEFAULT_STREAM_TYPE, sampleRate, DEFAULT_CHANNEL, encoding, mBufferSize, DEFAULT_PLAY_MODE);
isPlaying = false;
}
/**
* 播放音频
*
* @param audioData
*/
public void startPlay(final byte[] audioData) {
if (isPlaying) {
return;
}
if (audioData.length < mBufferSize) {
Log.e(TAG, "startPlay: 录音太短");
return;
}
new Thread(new Runnable() {
@Override
public void run() {
if (audioTrack.write(audioData, 0, audioData.length) != audioData.length) {
Log.e(TAG, "startPlay: 播放出错");
}
audioTrack.play();
}
}).start();
}
/**
* 停止播放
*/
public void stopPlay() {
if (!isPlaying) {
return;
}
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.stop();
}
audioTrack.release();
isPlaying = false;
}
这里只是介绍了使用AudioTrack进行音频的播放,示例代码只是部分代码。在这里记录一下自己学习的过程。
网友评论