AudioRecord類優(yōu)點(diǎn)是能錄制到緩沖區(qū),能夠?qū)崿F(xiàn)邊錄邊播(AudioRecord + AudioTrack)以及對音頻的實(shí)時處理(如QQ電話)。缺點(diǎn)是輸出是PCM格式的原始采集數(shù)據(jù),如果直接保存成音頻文件,不能夠被播放器播放,所以必須用代碼實(shí)現(xiàn)數(shù)據(jù)編碼以及壓縮。
使用AudioRecord錄音的基本步驟是:確定錄音參數(shù)、申請緩沖區(qū)、創(chuàng)建AudioRecord對象、開始錄制、循環(huán)讀取數(shù)據(jù)到緩沖區(qū)并處理數(shù)據(jù)、停止錄制、釋放資源。
需要確定的錄音參數(shù)包括:采樣率、聲道、格式。申請緩沖區(qū)時需要根據(jù)錄音參數(shù)計算最小緩沖區(qū)大小。有了緩沖區(qū)以后才能創(chuàng)建AudioRecord對象。錄制過程中,需要不停地讀取采樣到的音頻數(shù)據(jù),并進(jìn)行處理。流程和對應(yīng)的代碼如下圖:
下面編寫一個例子,用AudioRecord采集音頻數(shù)據(jù),并以原始PCM格式存入文件。讀取數(shù)據(jù)和處理數(shù)據(jù)是需要循環(huán)進(jìn)行的操作,所以放入單獨(dú)線程執(zhí)行。例子運(yùn)行在Android8.0以上。
例子界面和主要代碼如下:
因?yàn)橐浺簦栽谂渲梦募镄枰暶麂浺魴?quán)限。同時,Android將文件寫入應(yīng)用在外部存儲上的私有目錄不需要再申請讀寫存儲的權(quán)限。
<uses-permission android:name="android.permission.RECORD_AUDIO" />
同時,使用AudioRecord錄音需要動態(tài)申請權(quán)限,即在實(shí)際錄音時需要檢查用戶是否允許應(yīng)用使用錄音權(quán)限。如果沒有允許,就彈出一個對話框詢問用戶。代碼如下:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
return;
}
這里用到的AudioRecord類的主要方法有:
1)構(gòu)造函數(shù):AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)?
- audioSource:音頻來源,一般取麥克風(fēng)MediaRecorder.AudioSource.MIC
- sampleRateInHz:采樣率
- channelConfig:聲道配置,一般取AudioFormat.CHANNEL_IN_MONO 、CHANNEL_IN_DEFAULT、CHANNEL_IN_STEREO等
- audioFormat:音頻格式,取AudioFormat.ENCODING_PCM_16BIT、AudioFormat.ENCODING_PCM_8BIT
- bufferSizeInBytes:緩沖區(qū)字節(jié)數(shù),不得小于getMinBufferSize計算出的最小緩沖區(qū)大小
2)static int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat):計算最小緩沖區(qū)大小,參數(shù)同構(gòu)造函數(shù)中三個參數(shù)。
3)從硬件讀取音頻數(shù)據(jù)保存到緩沖區(qū)有三個方法,都返回讀取的數(shù)據(jù)個數(shù)
- int read(byte[] audioData, int offsetInBytes, int sizeInBytes)?
- int read(ByteBuffer audioBuffer, int sizeInBytes)?
- int read(short[] audioData, int offsetInShorts, int sizeInShorts)
4)void startRecording():開始錄制
5)void stop():停止錄制
6)void release():釋放資源
從AudioRecord讀取的數(shù)據(jù)是PCM格式,可以用AudioTrack類播放。用AudioTrack類播放音頻的基本流程是:創(chuàng)建AudioTrack對象、開始播放、循環(huán)寫入數(shù)據(jù)到緩沖區(qū)、停止播放、釋放資源。創(chuàng)建AudioTrack對象時需給出參數(shù):采樣率、聲道、格式。流程和對應(yīng)的代碼如下圖:
下面就為前面的例子加上播放音頻的功能。用AudioTrack播放AudioRecord錄制的PCM音頻文件時需要注意:寫入數(shù)據(jù)后不能馬上release,因?yàn)椴シ攀钱惒降?,此時還剛開始播放,一旦release就不播放了。用AudioTrack還可以實(shí)現(xiàn)變音效果:以采樣率a錄制,以采樣率b播放。主要代碼如下:
AudioTrack類的主要方法有:
1)構(gòu)造函數(shù):AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)?
- streamType: 流類型,取值為AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, AudioManager.STREAM_ALARM
- sampleRateInHz:采樣率
- channelConfig:聲道配置,一般取AudioFormat.CHANNEL_OUT_DEFAULT、CHANNEL_OUT_STEREO等
- audioFormat:音頻格式,取AudioFormat.ENCODING_PCM_16BIT、AudioFormat.ENCODING_PCM_8BIT
- bufferSizeInBytes:緩沖區(qū)字節(jié)數(shù),不得小于getMinBufferSize計算出的最小緩沖區(qū)大小
- mode:緩沖區(qū)類型,MODE_STATIC、MODE_STREAM?
2)void play() :開始播放
3)寫入音頻數(shù)據(jù)到硬件有兩個方法,返回成功寫入的數(shù)據(jù)個數(shù)
- int write(byte[] audioData, int offsetInBytes, int sizeInBytes)?
- int write(short[] audioData, int offsetInShorts, int sizeInShorts)?
4)void stop() :停止播放
5)void pause():暫停播放
6)void release():釋放資源
例子的完整代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-407146.html
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.*;
import java.io.*;
public class MainActivity extends AppCompatActivity {
File soundFile; // 存放錄音的文件
boolean isRecording;
int frequency = 11025;
int inChannelConfig = AudioFormat.CHANNEL_IN_MONO;
int outChannelConfig = AudioFormat.CHANNEL_OUT_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
setContentView(ll);
// 錄制到文件:Android/data/<package-name>/files/audioRecord.pcm
soundFile = new File(getExternalFilesDir(null), "audioRecord.pcm");
Button btnRecord = new Button(this);
btnRecord.setText("Record");
ll.addView(btnRecord);
btnRecord.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
Thread t = new Thread() {
public void run() {
try {
record();
} catch (IOException e) {
e.printStackTrace();
}
}
};
t.start();
}
});
Button btnStop = new Button(this);
btnStop.setText("Stop");
ll.addView(btnStop);
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
isRecording = false;
}
});
Button btnPlay = new Button(this);
btnPlay.setText("Play");
ll.addView(btnPlay);
btnPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (soundFile.exists()) {
try {
play(frequency);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Button btnPlayFast = new Button(this);
btnPlayFast.setText("Play Fast");
ll.addView(btnPlayFast);
btnPlayFast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (soundFile.exists()) {
try {
play(frequency * 4 / 3);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Button btnPlaySlow = new Button(this);
btnPlaySlow.setText("Play Slow");
ll.addView(btnPlaySlow);
btnPlaySlow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
if (soundFile.exists()) {
try {
play(frequency * 3 / 4);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Button btnSpeak = new Button(this);
btnSpeak.setText("Press to Speak");
ll.addView(btnSpeak);
btnSpeak.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
switch (arg1.getAction()) {
case MotionEvent.ACTION_DOWN:
Thread t = new Thread() {
public void run() {
try {
record();
} catch (IOException e) {
e.printStackTrace();
}
}
};
t.start();
break;
case MotionEvent.ACTION_UP:
isRecording = false;
break;
}
return false;
}
});
}
void record() throws IOException {
// 動態(tài)權(quán)限申請
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
return;
}
if (soundFile.exists()) soundFile.delete();
soundFile.createNewFile();
FileOutputStream fos = new FileOutputStream(soundFile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream dos = new DataOutputStream(bos);
int bufferSize = AudioRecord.getMinBufferSize(frequency, inChannelConfig, audioFormat);
short[] buffer = new short[bufferSize];
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, inChannelConfig, audioFormat, bufferSize);
audioRecord.startRecording();
isRecording = true;
while(isRecording){
int bufferRead = audioRecord.read(buffer, 0, bufferSize);
for(int i=0; i<bufferRead; i++){
dos.writeShort(buffer[i]);
}
}
audioRecord.stop();
audioRecord.release();
dos.close();
bos.close();
fos.close();
}
void play(int frq) throws IOException{
int length = (int)soundFile.length()/2;
if(!soundFile.exists() || length==0) {
Toast.makeText(getBaseContext(), "音頻文件不存在或?yàn)榭?, Toast.LENGTH_SHORT).show();
return;
}
short[] data = new short[length];
FileInputStream fis = new FileInputStream(soundFile);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
int i=0;
while(dis.available()>0) {
data[i] = dis.readShort();
i++;
}
dis.close();
bis.close();
fis.close();
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frq, outChannelConfig, audioFormat, length*2, AudioTrack.MODE_STREAM);
audioTrack.play();
audioTrack.write(data, 0, length);
audioTrack.stop();
//audioTrack.release(); // 不能馬上release,因?yàn)閣rite后是異步播放,此時還剛開始播放,release就不播放了
}
}
Android多媒體功能開發(fā)-使用AudioRecord類錄制音頻的例子?文章來源地址http://www.zghlxwxcb.cn/news/detail-407146.html
到了這里,關(guān)于Android多媒體功能開發(fā)(11)——使用AudioRecord類錄制音頻的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!