1 package com.netease.nimlib.sdk.media.record;
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;
22 import java.util.concurrent.atomic.AtomicBoolean;
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;
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";
42 private AudioRecord mAudioRecorder;
43 private AudioManager audioManager;
45 private Context context;
46 private int networkClass = NetworkUtil.NETWORK_CLASS_UNKNOWN;
48 private File audioFile;
50 private int maxDuration;
51 private AtomicBoolean
isRecording =
new AtomicBoolean(
false);
52 private AtomicBoolean cancelRecord =
new AtomicBoolean(
false);
55 private RecordHandler mHandler;
56 private Handler mEventHandler =
new Handler(Looper.getMainLooper());
57 private HandlerThread handlerThread;
59 private class RecordHandler
extends Handler {
61 public RecordHandler(Looper looper) {
66 public void handleMessage(Message msg) {
68 case MSG_START_RECORD:
72 boolean cancel = (Boolean) msg.obj;
73 onCompleteRecord(cancel);
76 boolean success = (Boolean) msg.obj;
77 int duration = msg.arg1;
78 onHandleEndRecord(success, duration);
98 this.context = context.getApplicationContext();
99 this.recordType = recordType;
100 if (maxDuration <= 0) {
103 this.maxDuration = maxDuration;
107 audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
108 handlerThread =
new HandlerThread(
"audio_recorder");
109 handlerThread.start();
110 mHandler =
new RecordHandler(handlerThread.getLooper());
120 mHandler.removeMessages(MSG_START_RECORD);
121 mHandler.obtainMessage(MSG_START_RECORD).sendToTarget();
124 private void onStartRecord() {
125 audioManager.requestAudioFocus(null, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
127 if (isRecording.get()) {
128 NimLog.audio(TAG +
" startRecord false, as current state is isRecording");
129 callBackRecordState(RECORD_FAILED);
133 if (!NimStorageUtil.hasEnoughSpaceForWrite(NimStorageType.TYPE_AUDIO)) {
134 NimLog.audio(TAG +
" startRecord false, as has no enough space to write");
135 callBackRecordState(RECORD_FAILED);
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);
148 outputFilePath = outputFilePath + recordType.
getFileSuffix();
149 audioFile =
new File(outputFilePath);
152 cancelRecord.set(
false);
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);
164 if (!cancelRecord.get()) {
165 callBackRecordState(RECORD_READY);
166 if (mAudioRecorder.startRecording()) {
167 isRecording.set(
true);
168 callBackRecordState(RECORD_START);
171 }
catch (Exception e) {
173 onCompleteRecord(
false);
175 if (!isRecording.get()) {
176 callBackRecordState(RECORD_FAILED);
187 Message message = mHandler.obtainMessage(MSG_STOP_RECORD);
188 message.obj = cancel;
189 message.sendToTarget();
192 private void onCompleteRecord(
boolean cancel) {
193 if (!isRecording.get()) {
196 cancelRecord.set(cancel);
197 audioManager.abandonAudioFocus(null);
199 if (mAudioRecorder != null) {
200 mAudioRecorder.stopRecording();
201 onHandleEndRecord(
true, mAudioRecorder.duration());
202 mAudioRecorder = null;
204 }
catch (Exception e) {
213 if (mHandler != null) {
214 mHandler.removeCallbacksAndMessages(null);
216 if (handlerThread != null && handlerThread.isAlive()) {
217 Looper looper = handlerThread.getLooper();
226 return isRecording.get();
230 Message message = mHandler.obtainMessage(MSG_END_RECORD);
231 message.obj = isSuccess;
232 message.arg1 = duration;
233 message.sendToTarget();
236 private void onHandleEndRecord(
boolean isSuccess,
final int duration) {
237 if (cancelRecord.get()) {
239 AttachmentStore.deleteOnExit(audioFile.getAbsolutePath());
241 callBackRecordState(RECORD_CANCELED);
242 }
else if (!isSuccess) {
244 AttachmentStore.deleteOnExit(audioFile.getAbsolutePath());
245 callBackRecordState(RECORD_FAILED);
248 if (audioFile == null || !audioFile.exists() || audioFile.length() <= 0) {
249 callBackRecordState(RECORD_FAILED);
252 mEventHandler.post(
new Runnable() {
260 isRecording.set(
false);
263 private void callBackRecordState(
final int recordState) {
264 mEventHandler.post(
new Runnable() {
267 switch (recordState) {
277 case RECORD_CANCELED:
292 if (mAudioRecorder != null) {
293 return mAudioRecorder.getMaxAmplitude();
299 private void handleReachedMaxRecordTime(
int duration) {
304 private OnInfoListener infoListener =
new OnInfoListener() {
307 public void onInfo(
int session,
int what,
int extra) {
308 if (what == OnInfoListener.MEDIA_RECORDER_INFO_ERROR) {
310 }
else if (what == OnInfoListener.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
311 mHandler.post(
new Runnable() {
314 isRecording.set(
false);
317 handleReachedMaxRecordTime(extra);
318 }
else if (what == OnInfoListener.MEDIA_RECORDER_INFO_STARTED) {