前一篇讲了如何录制wav音频文件,本篇就来讲讲如何播放wav文件,这里就是使用AudioTrack来播放音频,确切的说是播放pcm格式数据,使用AudioTrack播放也没什么难度,主要就是将数据写入到AudioTrack中就可以了,先贴代码
packagecn.sskbskdrin.record.audio;importandroid.media.AudioManager;importandroid.media.AudioTrack;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.RandomAccessFile;/***@authorsskbskdrin
* @date 2019/April/3*/
public classAudioTrackManager {privateAudioTrack audioTrack;private boolean playing = false;publicAudioParams playWav(String filepath, AudioRecordManager.RecordCallback callback) {
RandomAccessFile file= null;
AudioParams params= null;try{
file= new RandomAccessFile(filepath, "r");
params=readWavHeader(file);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}if (params == null) {return null;
}int simpleRate =params.simpleRate;int channelConfig =params.getOutChannelConfig();int audioFormat =params.getEncodingFormat();int minBufSize =AudioTrack.getMinBufferSize(simpleRate, channelConfig, audioFormat);
audioTrack= newAudioTrack(AudioManager.STREAM_MUSIC, simpleRate, channelConfig, audioFormat, minBufSize,
AudioTrack.MODE_STREAM);final RandomAccessFile finalFile =file;new Thread(() ->{
playing= true;
audioTrack.play();byte[] buffer = new byte[minBufSize];try{
finalFile.seek(44);while(playing) {int read =finalFile.read(buffer);if (read > 0) {
audioTrack.write(buffer,0, read);
}else{
finalFile.close();
playing= false;
audioTrack.stop();
audioTrack.release();
}if (callback != null) {
callback.onRecord(buffer, read);
}
}
}catch(IOException e) {
e.printStackTrace();
}
}).start();returnparams;
}public static AudioParams readWavHeader(RandomAccessFile file) throwsIOException {
file.seek(22);byte channelCount =file.readByte();
file.seek(24);int sampleRate = file.readByte() & 0xff;
sampleRate|= (file.readByte() & 0xff) << 8;
sampleRate|= (file.readByte() & 0xff) << 16;
sampleRate|= (file.readByte() & 0xff) << 24;
file.seek(34);byte bits =file.readByte();return newAudioParams(sampleRate, channelCount, bits);
}
}
播放的方法,是传入文件路径,AudioRecordManager.RecordCallback可以为空。先是通过readWavHeader()方法读取wav文件的文件头信息,返回AudioParams,这个类是我前一篇文章有列出来,可以得到一些需要的数据。
关于读数据头部信息,可以参考这里,读取重要数据。
AudioTrack.getMinBufferSize(simpleRate, channelConfig, audioFormat)可以获取最小缓存大小。
AudioTrack的构造方法中,第一个参数为播放流的类型,有下面几种
AudioManager.STREAM_MUSIC //音乐
AudioManager.STREAM_VOICE_CALL //电话
AudioManager.STREAM_RING //铃声
AudioManager.STREAM_ALARM //闹钟
AudioManager.STREAM_NOTIFICATION //通知
最后了个参数是流写入的方式,有两种
AudioTrack.MODE_STREAM // 流写入
AudioTrack.MODE_STATIC //静态写入
AudioTrack.MODE_STREAM看名字大概就能知道是流的方式写入,边写边播。
AudioTrack.MODE_STATIC就是一次写完,然后播放,这种方式更适合比较短的声音播放,比如通知声音
开始播放时,先调用AudioTrack.play(),然后从wav文件的数据块开始读,即第44个字节开始,读完调用audioTrack.write写入pcm数据。当读不到数据时,停止AudioTrack,释放资源即可。
通过RandomAccessFile方式读取文件,可以记录读取的位置,并通过seek方法跳转到指定位置,可实现播放、暂停、继续播放的功能。