前一篇講了如何錄制wav音頻文件,,本篇就來(lái)講講如何播放wav文件,,這里就是使用AudioTrack來(lái)播放音頻,,確切的說(shuō)是播放pcm格式數(shù)據(jù),,使用AudioTrack播放也沒(méi)什么難度,主要就是將數(shù)據(jù)寫(xiě)入到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可以為空,。先是通過(guò)readWavHeader()方法讀取wav文件的文件頭信息,,返回AudioParams,這個(gè)類(lèi)是我前一篇文章有列出來(lái),,可以得到一些需要的數(shù)據(jù),。 關(guān)于讀數(shù)據(jù)頭部信息,可以參考這里,,讀取重要數(shù)據(jù),。 AudioTrack.getMinBufferSize(simpleRate, channelConfig, audioFormat)可以獲取最小緩存大小。 AudioTrack的構(gòu)造方法中,,第一個(gè)參數(shù)為播放流的類(lèi)型,,有下面幾種 AudioManager.STREAM_MUSIC //音樂(lè) AudioManager.STREAM_VOICE_CALL //電話(huà) AudioManager.STREAM_RING //鈴聲 AudioManager.STREAM_ALARM //鬧鐘 AudioManager.STREAM_NOTIFICATION //通知 最后了個(gè)參數(shù)是流寫(xiě)入的方式,有兩種 AudioTrack.MODE_STREAM // 流寫(xiě)入 AudioTrack.MODE_STATIC //靜態(tài)寫(xiě)入 AudioTrack.MODE_STREAM看名字大概就能知道是流的方式寫(xiě)入,,邊寫(xiě)邊播,。 AudioTrack.MODE_STATIC就是一次寫(xiě)完,然后播放,,這種方式更適合比較短的聲音播放,,比如通知聲音 開(kāi)始播放時(shí),先調(diào)用AudioTrack.play(),,然后從wav文件的數(shù)據(jù)塊開(kāi)始讀,,即第44個(gè)字節(jié)開(kāi)始,,讀完調(diào)用audioTrack.write寫(xiě)入pcm數(shù)據(jù)。當(dāng)讀不到數(shù)據(jù)時(shí),,停止AudioTrack,,釋放資源即可。 通過(guò)RandomAccessFile方式讀取文件,,可以記錄讀取的位置,,并通過(guò)seek方法跳轉(zhuǎn)到指定位置,可實(shí)現(xiàn)播放,、暫停,、繼續(xù)播放的功能。 |
|
來(lái)自: 小仙女本仙人 > 《待分類(lèi)》