AudioTrack播放pcm格式音頻
package com.zero.demo;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
import com.zero.demo.util.FileUtils;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by yingkun_che on 19-6-18.
* 使用AudioTrack 播放pcm音頻測試
*/
public class DemoPlay {
private String TAG="DemoPlay";
/**
* 採樣率,現在能夠保證在所有設備上使用的採樣率是44100Hz, 但是其他的採樣率(22050, 16000, 11025)在一些設備上也可以使用。
*/
private static final int SAMPLE_RATE_INHZ = 44100;
/**
* 聲道數。CHANNEL_IN_MONO and CHANNEL_IN_STEREO. 其中CHANNEL_IN_MONO是可以保證在所有設備能夠使用的。
*/
private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
/**
* 返回的音頻數據的格式。 ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, and ENCODING_PCM_FLOAT.
*/
private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
AudioTrack audioTrack;
private Context context;
public DemoPlay(Context context) {
this.context = context;
}
/**
* 播放,使用stream模式
*/
public void playInModeStream() {
/*
* SAMPLE_RATE_INHZ 對應pcm音頻的採樣率
* channelConfig 對應pcm音頻的聲道
* AUDIO_FORMAT 對應pcm音頻的格式
* */
int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
final int minBufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE_INHZ, channelConfig, AUDIO_FORMAT);
audioTrack=createAudioTrackTo();
audioTrack.play();
// File file = new File("/storage/emulated/0/Android/data/com.zero.demo/files/zero_editor_kuato/resources/themes/satura/Stratosphere.aac");
File externalAssetsDir = null;
try {
externalAssetsDir = FileUtils.getResourcesRootDir();
} catch (IOException e) {
e.printStackTrace();
}
File pcmFile = new File(externalAssetsDir, "test.pcm");
try {
FileInputStream fileInputStream = new FileInputStream(pcmFile);
final DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(fileInputStream));
new Thread(new Runnable() {
@Override public void run() {
try {
byte[] tempBuffer = new byte[minBufferSize];
while (dataInputStream.available() > 0) {
int readCount = dataInputStream.read(tempBuffer);
if (readCount == AudioTrack.ERROR_INVALID_OPERATION ||
readCount == AudioTrack.ERROR_BAD_VALUE) {
continue;
}
if (readCount != 0 && readCount != -1) {
audioTrack.write(tempBuffer, 0, readCount);
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (dataInputStream!=null){
dataInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
} catch (IOException e) {
e.printStackTrace();
}
}
private AudioTrack createAudioTrackTo() throws IllegalStateException{
int mBufferSizeInBytes = AudioTrack.getMinBufferSize(SAMPLE_RATE_INHZ, AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT);
if (mBufferSizeInBytes <= 0) {
throw new IllegalStateException("AudioTrack is not available " + mBufferSizeInBytes);
}
AudioTrack mAudioTrack;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAudioTrack = new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setLegacyStreamType(AudioManager.STREAM_MUSIC)
.build())
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AUDIO_FORMAT)
.setSampleRate(SAMPLE_RATE_INHZ)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build())
.setTransferMode(AudioTrack.MODE_STREAM)
.setBufferSizeInBytes(mBufferSizeInBytes)
.build();
} else {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE_INHZ, AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT,
mBufferSizeInBytes, AudioTrack.MODE_STREAM);
}
return mAudioTrack;
}
byte [] audioData;
/**
* 播放,使用static模式
*/
public void playInModeStatic() {
// static模式,需要將音頻數據一次性write到AudioTrack的內部緩衝區
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
InputStream in = context.getResources().openRawResource(R.raw.test);
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
for (int b; (b = in.read()) != -1; ) {
out.write(b);
}
Log.d(TAG, "Got the data");
audioData = out.toByteArray();
} finally {
in.close();
}
} catch (IOException e) {
Log.wtf(TAG, "Failed to read", e);
}
return null;
}
@Override
protected void onPostExecute(Void v) {
Log.i(TAG, "Creating track...audioData.length = " + audioData.length);
// R.raw.ding鈴聲文件的相關屬性爲 22050Hz, 8-bit, Mono
if (Build.VERSION.SDK_INT >Build.VERSION_CODES.KITKAT) {
audioTrack = new AudioTrack(
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build(),
new AudioFormat.Builder().setSampleRate(48000)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build(),
audioData.length,
AudioTrack.MODE_STATIC,
AudioManager.AUDIO_SESSION_ID_GENERATE);
} else {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
48000,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
audioData.length,
AudioTrack.MODE_STREAM);
}
Log.d(TAG, "Writing audio data...");
audioTrack.write(audioData, 0, audioData.length);
Log.d(TAG, "Starting playback");
audioTrack.play();
Log.d(TAG, "Playing");
}
}.execute();
}
}