最近在做语音相关的开发如Siri 智能音箱等都会经过下图的流程:

1.RecordManager类 对录音功能进行封装
public class RecordManager {
private final static String TAG = "RecordManager";
private static RecordManager mInstance;
// 音频获取源
private int audioSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
// 设置音频采样率
private int sampleRateInHz = 48000;
// 设置音频的录制的声道 CHANNEL_IN_STEREO为双声道
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
// 音频数据格式:PCM 16位每个样本
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
// 缓冲区字节大小
private int bufferSizeInBytes = 0;
private AudioRecord audioRecord;
// 设置正在录制的状态
private boolean isRecord = false;
private static String sdFilePath = Environment.getExternalStorageDirectory().getPath() + "/RecordPcm/";
private File pcmFile;
private RecordManager() {
}
public static RecordManager getInstance() {
if (mInstance == null) {
synchronized (RecordManager.class) {
if (mInstance == null) {
mInstance = new RecordManager();
}
}
}
return mInstance;
}
/**
* 初始化AudioRecord
*/
public void init() {
bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);
}
/**
* 停止录制
*/
public void stopRecord() {
if (audioRecord != null) {
Log.d(TAG, "Record Close...");
isRecord = false;//停止文件写入
audioRecord.stop();
audioRecord.release();//释放资源
audioRecord = null;
}
}
/**
* 开始录制
*/
public void startRecord() {
if (isRecord) {
Log.e(TAG, "正在录制中....." + audioRecord.getState());
return;
}
if (audioRecord == null) {
init();
}
if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "AudioRecord创建失败" + audioRecord.getState());
return;
}
isRecord = true;
pcmFile = createFile(System.currentTimeMillis() + "abc.pcm");
audioRecord.startRecording();
// 开启音频文件写入线程
new Thread(new Runnable() {
@Override
public void run() {
byte[] audioData = new byte[bufferSizeInBytes];
FileOutputStream fos = null;
try {
fos = new FileOutputStream(pcmFile.getAbsoluteFile());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int readSize;
while (isRecord == true) {
readSize = audioRecord.read(audioData, 0, bufferSizeInBytes);
if (AudioRecord.ERROR_INVALID_OPERATION != readSize) {
try {
fos.write(audioData);
Log.v(TAG, "readSize:" + readSize);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
private File createFile(String name) {
File file = new File(sdFilePath);
if (!file.exists()) {
file.mkdirs();
}
String filePath = sdFilePath + name;
File objFile = new File(filePath);
if (!objFile.exists()) {
try {
objFile.createNewFile();
return objFile;
} catch (IOException e) {
e.printStackTrace();
}
}
return objFile;
}
二、TrackManager 封装了pcm播放的功能
final private static String TAG = "TrackManager";
private static TrackManager mInstance;
private AudioTrack mAudioTrack;
private int mOutChannelConfig = AudioFormat.CHANNEL_OUT_MONO;//播放声道
private int mTrackBufferSize;
private int mSampleRateInHZ = 48000; //采样率
private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; //位数
private static String sdFilePath = Environment.getExternalStorageDirectory().getPath() + "/RecordPcm/";
private File file;
private volatile boolean isLife;
private TrackManager() {
}
public static TrackManager getInstance() {
if (mInstance == null) {
synchronized (TrackManager.class) {
mInstance = new TrackManager();
}
}
return mInstance;
}
/**
* 初始化AudioTrack
*/
private void init() {
mTrackBufferSize = AudioTrack.getMinBufferSize(mSampleRateInHZ, mOutChannelConfig, mAudioFormat);// 获得音频缓冲区大小
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, mSampleRateInHZ, mOutChannelConfig, mAudioFormat, mTrackBufferSize, AudioTrack.MODE_STREAM);
}
/**
* 开始播放 pcm文件
*/
public void startTrack() {
if (isLife) {
Log.d(TAG, "正在播放...");
return;
}
if (mAudioTrack == null) {
init();
}
isLife = true;
new Thread((new Runnable() {
@Override
public void run() {
byte[] tempBuffer = new byte[mTrackBufferSize];
FileInputStream fileInputStream;
File folder = new File(sdFilePath);
if (!folder.isDirectory()) {
return;
}
for (File folderFile : folder.listFiles()) {
Log.e(TAG, "STATUS:" + mAudioTrack.getState());
if (!isLife) {
return;
}
String folderName = folderFile.getName();
file = new File(sdFilePath, folderName);
Log.d(TAG, "path:" + sdFilePath + " -folderName:" + folderName);
if (!file.exists()) {
continue;
}
try {
mAudioTrack.play();
fileInputStream = new FileInputStream(file);
while (fileInputStream.available() > 0) {
int readCount = fileInputStream.read(tempBuffer);
if (readCount == AudioTrack.ERROR_INVALID_OPERATION ||
readCount == AudioTrack.ERROR_BAD_VALUE) {
continue;
}
Log.v(TAG, "readCount:" + readCount);
if (readCount != 0 && readCount != -1) {
mAudioTrack.write(tempBuffer, 0, readCount);
}
}
fileInputStream.close();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
stopTrack();
}
})).start();
}
/**
* 停止播放
*/
public void stopTrack() {
Log.d(TAG, "stopTrack");
if (mAudioTrack != null) {
isLife = false;
mAudioTrack.stop();
}
}
MainActivity
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.btn_start_record:
RecordManager.getInstance().startRecord();
break;
case R.id.btn_stop_record:
RecordManager.getInstance().stopRecord();
break;
case R.id.btn_start_track:
TrackManager.getInstance().startTrack();
break;
case R.id.btn_stop_track:
TrackManager.getInstance().stopTrack();
break;
}

github:代码查看地址
网友评论