录音器 AudioRecorder
实现录音器有两种方式可以选择:
1.AudioRecord(基于字节流录音)
优点:可以实现语音的实时处理,进行边录边播,对音频的实时处理。
缺点:输出的是PCM的语音数据,如果保存成音频文件是不能被播放器播放的。要用到AudioTrack这个去进行处理。
2.MediaRecorder(基于文件录音)
已集成了录音,编码,压缩等,支持少量的音频格式文件。
优点:封装度很高,操作简单
缺点:无法实现实时处理音频,输出的音频格式少。
权限:
<uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
AudioRecorder录音工具类代码如下:
package com.example.m_evolution.Utils; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Environment; import android.os.Handler; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; public class AudioRecoderUtils { //文件路径 private String filePath; //文件夹路径 private String FolderPath; //录音的线程 private Thread mThread; // private MediaRecorder mMediaRecorder; private AudioRecord audioRecord; private boolean isRecording; private int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; private int sampleRate = 44100; private int bufferSizeInBytes; private final String TAG = "fan"; public static final int MAX_LENGTH = 1000 * 60 * 10;// 最大录音时长1000*60*10; private OnAudioStatusUpdateListener audioStatusUpdateListener; /** * 文件存储默认sdcard/record */ public AudioRecoderUtils(){ //默认保存路径为/sdcard/record/下 FolderPath = Environment.getExternalStorageDirectory()+"/record/"; bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate, channelConfiguration, audioEncoding); // need to be larger than size of a frame audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfiguration, audioEncoding, bufferSizeInBytes); //麦克风 } public void startRecord(){ mThread = new Thread(new Runnable() { @Override public void run() { /* 获取开始时间* */ startTime = System.currentTimeMillis(); //设置录制指标 isRecording = true; //自动更新界面 updateMicStatus(); //设置存储路径 filePath = FolderPath+getCurrentDate("yyyyMMddHHmmss") + ".wav"; File recordingFile = new File(filePath); OutputStream out = null; ByteArrayOutputStream baos = null; try { baos = new ByteArrayOutputStream(); audioRecord.startRecording(); byte[] buffer = new byte[bufferSizeInBytes]; int bufferReadResult = 0; while (isRecording) { bufferReadResult = audioRecord.read(buffer, 0, bufferSizeInBytes); if(bufferReadResult>0){ baos.write(buffer, 0, bufferReadResult); } } Log.i(TAG, "stop recording,file=" + recordingFile.getAbsolutePath()); buffer = baos.toByteArray(); Log.i(TAG, "audio byte len="+buffer.length); out = new FileOutputStream(recordingFile); out.write(getWavHeader(buffer.length)); out.write(buffer); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if(baos!=null){ try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }); mThread.start(); } public void stopRecord(){ stopRecording(); audioStatusUpdateListener.onStop(filePath); filePath = ""; } public byte[] getWavHeader(long totalAudioLen){ int mChannels = 1; long totalDataLen = totalAudioLen + 36; long longSampleRate = sampleRate; long byteRate = sampleRate * 2 * mChannels; byte[] header = new byte[44]; header[0] = 'R'; // RIFF/WAVE header header[1] = 'I'; header[2] = 'F'; header[3] = 'F'; header[4] = (byte) (totalDataLen & 0xff); header[5] = (byte) ((totalDataLen >> 8) & 0xff); header[6] = (byte) ((totalDataLen >> 16) & 0xff); header[7] = (byte) ((totalDataLen >> 24) & 0xff); header[8] = 'W'; header[9] = 'A'; header[10] = 'V'; header[11] = 'E'; header[12] = 'f'; // 'fmt ' chunk header[13] = 'm'; header[14] = 't'; header[15] = ' '; header[16] = 16; // 4 bytes: size of 'fmt ' chunk header[17] = 0; header[18] = 0; header[19] = 0; header[20] = 1; // format = 1 header[21] = 0; header[22] = (byte) mChannels; header[23] = 0; header[24] = (byte) (longSampleRate & 0xff); header[25] = (byte) ((longSampleRate >> 8) & 0xff); header[26] = (byte) ((longSampleRate >> 16) & 0xff); header[27] = (byte) ((longSampleRate >> 24) & 0xff); header[28] = (byte) (byteRate & 0xff); header[29] = (byte) ((byteRate >> 8) & 0xff); header[30] = (byte) ((byteRate >> 16) & 0xff); header[31] = (byte) ((byteRate >> 24) & 0xff); header[32] = (byte) (2 * mChannels); // block align header[33] = 0; header[34] = 16; // bits per sample header[35] = 0; header[36] = 'd'; header[37] = 'a'; header[38] = 't'; header[39] = 'a'; header[40] = (byte) (totalAudioLen & 0xff); header[41] = (byte) ((totalAudioLen >> 8) & 0xff); header[42] = (byte) ((totalAudioLen >> 16) & 0xff); header[43] = (byte) ((totalAudioLen >> 24) & 0xff); return header; } private long startTime; private long endTime; public static String getCurrentDate(String pattern) { SimpleDateFormat formatter = new SimpleDateFormat(pattern); Date curDate = new Date(System.currentTimeMillis());// 获取当前时间 String timestamp = formatter.format(curDate); return timestamp; } public void stopRecording() { try { isRecording = false; audioRecord.stop(); audioRecord.release(); audioRecord = null; audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfiguration, audioEncoding, bufferSizeInBytes); //麦克风 } catch (Exception e) { e.printStackTrace(); } } private final Handler mHandler = new Handler(); private Runnable mUpdateMicStatusTimer = new Runnable() { public void run() { updateMicStatus(); } }; private int SPACE = 100;//显示时间的间隔时间 public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) { this.audioStatusUpdateListener = audioStatusUpdateListener; } /** * 更新麦克状态 */ private void updateMicStatus() { if (isRecording) { if(null != audioStatusUpdateListener) { audioStatusUpdateListener.onUpdate(System.currentTimeMillis()-startTime); } mHandler.postDelayed(mUpdateMicStatusTimer, SPACE); } } public interface OnAudioStatusUpdateListener { /** * 录音中... * @param db 当前声音分贝 * @param time 录音时长 */ public void onUpdate(long time); /** * 停止录音 * @param filePath 保存路径 */ public void onStop(String filePath); } }