AudioTrack

之前我们讲过MediaPlayer,MediaPlayer就相当于AudioTrack的包装层,它可以播放MP3,WAV,OGG,AAC,MIDI等,而AudioTrack只能播放PCM数据流

AudioTrack的构造方法


public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) { ... }


 

streamType 音频流类型



AudioManager.STREAM_MUSIC:用于音乐播放的音频流。
AudioManager.STREAM_SYSTEM:用于系统声音的音频流。
AudioManager.STREAM_RING:用于电话铃声的音频流。
AudioManager.STREAM_VOICE_CALL:用于电话通话的音频流。
AudioManager.STREAM_ALARM:用于警报的音频流。
AudioManager.STREAM_NOTIFICATION:用于通知的音频流。
AudioManager.STREAM_BLUETOOTH_SCO:用于连接到蓝牙电话时的手机音频流。
AudioManager.STREAM_SYSTEM_ENFORCED:在某些国家实施的系统声音的音频流。
AudioManager.STREAM_DTMF:DTMF音调的音频流。
AudioManager.STREAM_TTS:文本到语音转换(TTS)的音频流。
 

sampleRateInHz 采样率
播放的音频每秒钟会有多少次采样,MediaRecoder 的采样率通常是8000Hz AAC的通常是44100Hz。 设置采样率为44100,目前为常用的采样率
channelConfig 声道数(通道数)
一般可选的就两种,单声道CHANNEL_IN_MONO,双声道CHANNEL_IN_STEREO,建议选择单声道
audioFormat 数据位宽
只支持AudioFormat.ENCODING_PCM_8BIT(8bit)和AudioFormat.ENCODING_PCM_16BIT(16bit)两种,后者支持所有Android手机
bufferSizeInBytes 音频缓冲区大小
建议使用AudioTrack.getMinBufferSize()这个方法获取,参数如上
mode 播放模式
Android 提供了两种播放模式:
MODE_STATIC,一次性将所有数据都写入播放缓冲区中,简单高效,一般用于铃声,系统提醒音,内存比较小的。
MODE_STREAM,需要按照一定的时间间隔,不断的写入音频数据,理论上它可以应用于任何音频播放的场景。
 

public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,int mode, int sessionId) { ... }


 

静态播放

// ************ 静态播放模式 ************ 
 // 直接获取文件大小
 InputStream in = getResources().openRawResource(R.raw.ding);
 try {
    try {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        for (int b; (b = in.read()) != -1; ) {
            out.write(b);
        }
        audioData = out.toByteArray();
    } finally {
        in.close();
    }
 } catch (IOException ioe) {
    ioe.printStackTrace();
    Log.d(TAG, "读取数据失败!");
 }
 //构造AudioTrack对象,写入数据并播放
 audioTrack = new AudioTrack(
 new AudioAttributes.Builder()
         .setUsage(AudioAttributes.USAGE_MEDIA)
         .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
         .build(),
 new AudioFormat.Builder().setSampleRate(22050)
         .setEncoding(AudioFormat.ENCODING_PCM_8BIT)
         .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
         .build(),
 audioData.length,
 AudioTrack.MODE_STATIC,
 AudioManager.AUDIO_SESSION_ID_GENERATE);
 audioTrack.write(audioData, 0, audioData.length);
 if(audioTrack.getState() == AudioTrack.STATE_UNINITIALIZED){
     Toast.makeText(this,"AudioTrack初始化失败!",Toast.LENGTH_SHORT).show();
     return;
 } 
 audioTrack.play();

流播放模式

// ************ 流播放 ************ 
final int minBufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE_INHZ, AudioFormat.CHANNEL_OUT_MONO, AUDIO_FORMAT);
// 创建 AudioTrack 对象
audioTrack = new AudioTrack(
 new AudioAttributes.Builder()
         .setUsage(AudioAttributes.USAGE_MEDIA)
         .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
         .build(),
 new AudioFormat.Builder().setSampleRate(SAMPLE_RATE_INHZ)
         .setEncoding(AUDIO_FORMAT)
         .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
         .build(),
 minBufferSize,
 AudioTrack.MODE_STREAM,
 AudioManager.AUDIO_SESSION_ID_GENERATE
);
// 检查初始化是否成功
if(audioTrack.getState() == AudioTrack.STATE_UNINITIALIZED){
    Toast.makeText(this,"AudioTrack初始化失败!",Toast.LENGTH_SHORT).show();
    return;
} 
// 播放
audioTrack.play();
//子线程中文件流写入
workHandler.post(new Runnable() {
   @Override
   public void run() {
       try {
           final File file = new File(getExternalFilesDir(Environment.DIRECTORY_MUSIC), "test.pcm");
           FileInputStream fileInputStream = new FileInputStream(file);
           byte[] tempBuffer = new byte[minBufferSize];
           while (fileInputStream.available() > 0) {
               int readCount = fileInputStream.read(tempBuffer);
               if (readCount == AudioTrack.ERROR_INVALID_OPERATION ||
                       readCount == AudioTrack.ERROR_BAD_VALUE) {
                   continue;
               }
               if (readCount != 0 && readCount != -1) {
                   audioTrack.write(tempBuffer, 0, readCount);
               }
           }
           fileInputStream.close();
       } catch (IOException ioe) {
           ioe.printStackTrace();
       }
   }
});

停止播放,销毁资源

// 停止线程
 handlerThread.quit();
 workHandler.removeCallbacksAndMessages(null);
 if(audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED){
     audioTrack.stop();
     audioTrack.release();
 }