前一篇讲了如何录制wav音频文件,本篇就来讲讲如何播放wav文件,这里就是使用AudioTrack来播放音频,确切的说是播放pcm格式数据,使用AudioTrack播放也没什么难度,主要就是将数据写入到AudioTrack中就可以了,先贴代码
package cn.sskbskdrin.record.audio; import android.media.AudioManager; import android.media.AudioTrack; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; /** * @author sskbskdrin * @date 2019/April/3 */ public class AudioTrackManager { private AudioTrack audioTrack; private boolean playing = false; public AudioParams 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 = new AudioTrack(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(); return params; } public static AudioParams readWavHeader(RandomAccessFile file) throws IOException { 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 new AudioParams(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方法跳转到指定位置,可实现播放、暂停、继续播放的功能。
原文地址:https://www.cnblogs.com/sskbskdrin/p/10649591.html