NIMSDK-AOS  10.5.0
AudioRecorder.java
浏览该文件的文档.
1 package com.netease.nimlib.sdk.media.record;
2 
3 import android.content.Context;
4 import android.media.AudioManager;
5 import android.os.Handler;
6 import android.os.HandlerThread;
7 import android.os.Looper;
8 import android.os.Message;
9 import android.text.TextUtils;
10 
11 import com.netease.nimlib.SDKCache;
12 import com.netease.nimlib.log.NimLog;
13 import com.netease.nimlib.net.http.util.AttachmentStore;
14 import com.netease.nimlib.util.NetworkUtil;
15 import com.netease.nimlib.util.StringUtil;
16 import com.netease.nimlib.util.storage.NimStorageType;
17 import com.netease.nimlib.util.storage.NimStorageUtil;
18 import com.netease.share.media.AudioRecord;
19 import com.netease.share.media.OnInfoListener;
20 
21 import java.io.File;
22 import java.util.concurrent.atomic.AtomicBoolean;
23 
28 public class AudioRecorder {
29 
30  public static final int DEFAULT_MAX_AUDIO_RECORD_TIME_SECOND = 120;
31  private static final int MSG_START_RECORD = 1;
32  private static final int MSG_STOP_RECORD = 2;
33  private static final int MSG_END_RECORD = 3; // 录音超时等异常结束
34 
35  private static final int RECORD_FAILED = 1;
36  private static final int RECORD_READY = 2;
37  private static final int RECORD_START = 3;
38  private static final int RECORD_SUCCESS = 4;
39  private static final int RECORD_CANCELED = 5;
40  private static final String TAG = "AudioRecordManager";
41 
42  private AudioRecord mAudioRecorder;
43  private AudioManager audioManager;
44 
45  private Context context;
46  private int networkClass = NetworkUtil.NETWORK_CLASS_UNKNOWN;
47 
48  private File audioFile;
49  private RecordType recordType;
50  private int maxDuration;
51  private AtomicBoolean isRecording = new AtomicBoolean(false);
52  private AtomicBoolean cancelRecord = new AtomicBoolean(false);
53  private IAudioRecordCallback cb;
54 
55  private RecordHandler mHandler;
56  private Handler mEventHandler = new Handler(Looper.getMainLooper());
57  private HandlerThread handlerThread;
58 
59  private class RecordHandler extends Handler {
60 
61  public RecordHandler(Looper looper) {
62  super(looper);
63  }
64 
65  @Override
66  public void handleMessage(Message msg) {
67  switch (msg.what) {
68  case MSG_START_RECORD:
69  onStartRecord();
70  break;
71  case MSG_STOP_RECORD:
72  boolean cancel = (Boolean) msg.obj;
73  onCompleteRecord(cancel);
74  break;
75  case MSG_END_RECORD:
76  boolean success = (Boolean) msg.obj;
77  int duration = msg.arg1;
78  onHandleEndRecord(success, duration);
79  break;
80  }
81  }
82  }
83 
92  public AudioRecorder(
93  Context context,
94  RecordType recordType,
95  int maxDuration,
97  ) {
98  this.context = context.getApplicationContext();
99  this.recordType = recordType;
100  if (maxDuration <= 0) {
101  this.maxDuration = DEFAULT_MAX_AUDIO_RECORD_TIME_SECOND;
102  } else {
103  this.maxDuration = maxDuration;
104  }
105  this.cb = cb;
106 
107  audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
108  handlerThread = new HandlerThread("audio_recorder");
109  handlerThread.start();
110  mHandler = new RecordHandler(handlerThread.getLooper());
111  }
112 
118  public void startRecord() {
119  // 移除队列中的 开始任务
120  mHandler.removeMessages(MSG_START_RECORD);
121  mHandler.obtainMessage(MSG_START_RECORD).sendToTarget();
122  }
123 
124  private void onStartRecord() {
125  audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
126 
127  if (isRecording.get()) {
128  NimLog.audio(TAG + " startRecord false, as current state is isRecording");
129  callBackRecordState(RECORD_FAILED);
130  return;
131  }
132 
133  if (!NimStorageUtil.hasEnoughSpaceForWrite(NimStorageType.TYPE_AUDIO)) {
134  NimLog.audio(TAG + " startRecord false, as has no enough space to write");
135  callBackRecordState(RECORD_FAILED);
136  return;
137  }
138 
139  int outputFormat = recordType.getOutputFormat();
140 
141  String outputFilePath = NimStorageUtil.getWritePath(SDKCache.getContext(), StringUtil.get36UUID() + outputFormat,
142  NimStorageType.TYPE_AUDIO);
143  if (TextUtils.isEmpty(outputFilePath)) {
144  NimLog.audio(TAG + " startRecord false, as outputFilePath is empty");
145  callBackRecordState(RECORD_FAILED);
146  return;
147  } else {
148  outputFilePath = outputFilePath + recordType.getFileSuffix();
149  audioFile = new File(outputFilePath);
150  }
151 
152  cancelRecord.set(false);
153 
154  try {
155  mAudioRecorder = new AudioRecord(context, outputFilePath, maxDuration * 1000);
156  mAudioRecorder.setAudioCodec(outputFormat);
157  networkClass = NetworkUtil.getNetworkClass(context);
158  if (networkClass == NetworkUtil.NETWORK_CLASS_3_G)
159  mAudioRecorder.setMaxSampleRateInHz(22050);
160  else if (networkClass == NetworkUtil.NETWORK_CLASS_2_G)
161  mAudioRecorder.setMaxSampleRateInHz(16000);
162  mAudioRecorder.setOnInfoListener(infoListener);
163 
164  if (!cancelRecord.get()) {
165  callBackRecordState(RECORD_READY);
166  if (mAudioRecorder.startRecording()) {
167  isRecording.set(true);
168  callBackRecordState(RECORD_START);
169  }
170  }
171  } catch (Exception e) {
172  e.printStackTrace();
173  onCompleteRecord(false);
174  }
175  if (!isRecording.get()) {
176  callBackRecordState(RECORD_FAILED);
177  }
178  }
179 
186  public void completeRecord(boolean cancel) {
187  Message message = mHandler.obtainMessage(MSG_STOP_RECORD);
188  message.obj = cancel;
189  message.sendToTarget();
190  }
191 
192  private void onCompleteRecord(boolean cancel) {
193  if (!isRecording.get()) {
194  return;
195  }
196  cancelRecord.set(cancel);
197  audioManager.abandonAudioFocus(null);
198  try {
199  if (mAudioRecorder != null) {
200  mAudioRecorder.stopRecording();
201  onHandleEndRecord(true, mAudioRecorder.duration());
202  mAudioRecorder = null;
203  }
204  } catch (Exception e) {
205  e.printStackTrace();
206  }
207  }
208 
212  public void destroyAudioRecorder() {
213  if (mHandler != null) {
214  mHandler.removeCallbacksAndMessages(null);
215  }
216  if (handlerThread != null && handlerThread.isAlive()) {
217  Looper looper = handlerThread.getLooper();
218  looper.quit();
219  }
220  }
221 
225  public boolean isRecording() {
226  return isRecording.get();
227  }
228 
229  public void handleEndRecord(boolean isSuccess, int duration) {
230  Message message = mHandler.obtainMessage(MSG_END_RECORD);
231  message.obj = isSuccess;
232  message.arg1 = duration;
233  message.sendToTarget();
234  }
235 
236  private void onHandleEndRecord(boolean isSuccess, final int duration) {
237  if (cancelRecord.get()) {
238  // cancel
239  AttachmentStore.deleteOnExit(audioFile.getAbsolutePath());
240 
241  callBackRecordState(RECORD_CANCELED);
242  } else if (!isSuccess) {
243  // failed
244  AttachmentStore.deleteOnExit(audioFile.getAbsolutePath());
245  callBackRecordState(RECORD_FAILED);
246  } else {
247  // error
248  if (audioFile == null || !audioFile.exists() || audioFile.length() <= 0) {
249  callBackRecordState(RECORD_FAILED);
250  } else {
251  // success
252  mEventHandler.post(new Runnable() {
253  @Override
254  public void run() {
255  cb.onRecordSuccess(audioFile, duration, recordType);
256  }
257  });
258  }
259  }
260  isRecording.set(false);
261  }
262 
263  private void callBackRecordState(final int recordState) {
264  mEventHandler.post(new Runnable() {
265  @Override
266  public void run() {
267  switch (recordState) {
268  case RECORD_FAILED:
269  cb.onRecordFail();
270  break;
271  case RECORD_READY:
272  cb.onRecordReady();
273  break;
274  case RECORD_START:
275  cb.onRecordStart(audioFile, recordType);
276  break;
277  case RECORD_CANCELED:
278  cb.onRecordCancel();
279  default:
280  break;
281  }
282  }
283  });
284  }
285 
292  if (mAudioRecorder != null) {
293  return mAudioRecorder.getMaxAmplitude();
294  }
295 
296  return 0;
297  }
298 
299  private void handleReachedMaxRecordTime(int duration) {
300  cb.onRecordReachedMaxTime(duration);
301  }
302 
303  // UI线程回调
304  private OnInfoListener infoListener = new OnInfoListener() {
305 
306  @Override
307  public void onInfo(int session, int what, int extra) {
308  if (what == OnInfoListener.MEDIA_RECORDER_INFO_ERROR) {
309  handleEndRecord(false, 0);
310  } else if (what == OnInfoListener.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
311  mHandler.post(new Runnable() {
312  @Override
313  public void run() {
314  isRecording.set(false);
315  }
316  });
317  handleReachedMaxRecordTime(extra);
318  } else if (what == OnInfoListener.MEDIA_RECORDER_INFO_STARTED) {
319  //
320 
321  }
322  }
323  };
324 
325 }
void completeRecord(boolean cancel)
完成(结束)录音,根据参数cancel,做不同的回调。 如果cancel为true,回调onRecordCancel, 为false,回调onRecordSuccess
高清语音录制工具类 Created by huangjun on 2015/4/1.
录音类型,支持AAC、AMR格式输出
Definition: RecordType.java:11
void startRecord()
启动(开始)录音,如果成功,会按照顺序回调onRecordReady和onRecordStart
AudioRecorder(Context context, RecordType recordType, int maxDuration, IAudioRecordCallback cb)
构造函数
void handleEndRecord(boolean isSuccess, int duration)
void onRecordStart(File audioFile, RecordType recordType)
开始录音回调
void onRecordReachedMaxTime(int maxTime)
到达指定的最长录音时间
void onRecordCancel()
录音结束, 用户主动取消录音
void onRecordReady()
录音器已就绪,提供此接口用于在录音前关闭本地音视频播放(可选)
int getCurrentRecordMaxAmplitude()
获取当前录音时最大振幅, 40ms更新一次数据。 每次获取后数值会重置。
void onRecordSuccess(File audioFile, long audioLength, RecordType recordType)
录音结束,成功