AudioTrack的使用
- 簡介
- 使用
- 測驗
簡介
AudioTrack類為Java應用程式管理和播放單個音瞥澩,它允許PCM音頻緩沖區流到音頻接收器進行播放,
AudioTrack有兩個模式
| 模式 | 解釋 | 作用范圍 |
|---|---|---|
| 靜態模式(MODE_STATIC) | 這種模式下,在play之前只需要把所有資料通過一次write呼叫傳遞到AudioTrack中的內部緩沖區 | 在處理適合記憶體的短聲音以及需要以盡可能小的延遲播放時,應選擇靜態模式 |
| 流模式(MODE_STREAM) | 以流的形式持續把音頻資料寫到AudioTrack內部的Buffer中 | 由于音頻資料的特性(高采樣率、每采樣位數…)太大而無法放入記憶體的 等等 |
使用
1、加上讀取檔案的權限
<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE" />
2、因用到系統的檔案做耗時操作所以需要用到AsyncTask
3、最主要的是public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes)方法
第一個引數是 保存要播放的資料的陣列
第二個引數是 在音頻資料中,以位元組表示的偏移量,其中要寫入的資料 (我也不是清楚,希望有大佬能解釋一下,建議寫0就好)
第三個引數是 寫入音頻資料的位元組數
4、具體解釋請看下面的代碼
package com.audioandvideo.two.Activity;
import androidx.appcompat.app.AppCompatActivity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.audioandvideo.R;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/**
* MODE_STATIC:這種模式下,在play之前只需要把所有資料通過一次write呼叫傳遞到AudioTrack中的內部緩沖區
* MODE_STREAM:以流的形式持續把音頻資料寫到AudioTrack內部的Buffer中
*/
public class AudioTrackActivity extends AppCompatActivity implements View.OnClickListener{
private Button btnStatic;
private Button btnStream;
private AudioTrack audioTrack;
private byte[] audioData;
// 采樣率:音頻的采樣頻率,每秒鐘能夠采樣的次數,采樣率越高,音質越高
// 44100是目前的標準,但是某些設備仍然支持22050,16000,11025
// 采樣頻率一般共分為22.05KHz、44.1KHz、48KHz三個等級
private final int AUDIO_SAMPLE_RATE = 44100;
// 聲道設定:android支持雙聲道立體聲和單聲道,MONO單聲道,STEREO立體聲
private final int AUDIO_CHANNEL = AudioFormat.CHANNEL_OUT_STEREO;
// 編碼制式和采樣大小:采集來的資料當然使用PCM編碼
// (脈沖代碼調制編碼,即PCM編碼,PCM通過抽樣、量化、編碼三個步驟將連續變化的模擬信號轉換為數字編碼,)
// android支持的采樣大小16bit 或者8bit,當然采樣大小越大,那么資訊量越多,音質也越高,現在主流的采樣
// 大小都是16bit,在低質量的語音傳輸的時候8bit 足夠了,
private final int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
//要播放的pcm檔案的儲存位置及檔案名
private final String pcmFileName = Environment.getExternalStorageDirectory() + "/Download/record.pcm";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_audio_track);
btnStatic = findViewById(R.id.btn_static);
btnStream = findViewById(R.id.btn_stream);
btnStatic.setOnClickListener(this);
btnStream.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_static:
new AsyncStatic().execute();
break;
case R.id.btn_stream:
new AsyncStream().execute();
break;
}
}
/**
*MODE_STATIC:這種模式下,在play之前只需要把所有資料通過一次write呼叫傳遞到AudioTrack中的內部緩沖區
*/
private class AsyncStatic extends AsyncTask{
/**
* 后臺執行,比較耗時的操作都可以放在這里,注意這里不能直接操作UI,
* 此方法在后臺執行緒執行,完成任務的主要作業,通常需要較長的時間,
* @param objects
* @return
*/
@Override
protected Object doInBackground(Object[] objects) {
try {
InputStream in = new FileInputStream(new File(pcmFileName));
try {
//位元組陣列輸出流在記憶體中創建一個位元組陣列緩沖區,所有發送到輸出流的資料保存在該位元組陣列緩沖區中,
ByteArrayOutputStream out = new ByteArrayOutputStream();
for (int b; (b = in.read()) != -1; ) {
out.write(b);
}
//創建一個新分配的位元組陣列,陣列的大小和當前輸出流的大小,內容是當前輸出流的拷貝,
audioData = out.toByteArray();
} finally {
//最后關閉檔案
in.close();
}
} catch (IOException e) {
}
return null;
}
/**
* 相當于Handler 處理UI的方式,在這里面可以使用在doInBackground
* 得到的結果處理操作UI, 此方法在主執行緒執行,任務執行的結果作為此方法的引數回傳
* @param o
*/
@Override
protected void onPostExecute(Object o) {
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, AUDIO_SAMPLE_RATE,
AUDIO_CHANNEL, AUDIO_ENCODING, audioData.length,AudioTrack.MODE_STATIC);
audioTrack.write(audioData, 0, audioData.length); //將音頻資料寫入音頻接收器以便播放
audioTrack.play();//開始播放
}
}
/**
* MODE_STREAM:以流的形式持續把音頻資料寫到AudioTrack內部的Buffer中
*/
private class AsyncStream extends AsyncTask{
@Override
protected Object doInBackground(Object[] objects) {
final int minBufferSize = AudioTrack.getMinBufferSize(AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, AUDIO_SAMPLE_RATE,
AUDIO_CHANNEL, AUDIO_ENCODING, minBufferSize, AudioTrack.MODE_STREAM);//最后一個引數為audioTrack的模式
audioTrack.play();
File file = new File(pcmFileName);
//從檔案系統中的某個檔案中獲得輸入位元組
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte[] tempBuffer = new byte[minBufferSize];
while (true) {
try {
if (!(fileInputStream.available() > 0)) {
stop(); //停止播放
break;
}
// fileInputStream.read(tempBuffer)回傳讀入緩沖區的總位元組數;如果因為已經到達流末尾而不再有資料可用,則回傳 -1,
int readCount = fileInputStream.read(tempBuffer);
Log.d("TAG", "doInBackground:"+String.valueOf(readCount));
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();
}
}
return null;
}
}
//停止播放
private void stop(){
if(audioTrack.getState() != AudioTrack.STATE_UNINITIALIZED){
audioTrack.stop();
audioTrack.release();
}
}
}
測驗
界面只有兩個簡單的按鈕進行測驗,均能播放,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/264762.html
標籤:其他
