77import android .media .audiofx .AcousticEchoCanceler ;
88import android .media .audiofx .AutomaticGainControl ;
99import android .os .Handler ;
10+ import android .os .HandlerThread ;
11+ import android .os .Looper ;
1012import android .os .Message ;
1113import android .text .TextUtils ;
1214import android .util .Log ;
1719import com .tencent .iot .thirdparty .flv .FLVPacker ;
1820import com .tencent .xnet .XP2P ;
1921
22+ import org .jetbrains .annotations .NotNull ;
2023import org .json .JSONException ;
2124import org .json .JSONObject ;
2225
2629import java .io .IOException ;
2730import java .util .ArrayList ;
2831import java .util .List ;
32+ import java .util .concurrent .CountDownLatch ;
2933import java .util .concurrent .ExecutorService ;
3034import java .util .concurrent .Executors ;
3135import java .util .concurrent .LinkedBlockingDeque ;
32- import java .util .concurrent .atomic .AtomicInteger ;
3336
3437import com .iot .gvoice .interfaces .GvoiceJNIBridge ;
3538
36- import tv .danmaku .ijk .media .player .IjkMediaPlayer ;
3739
38-
39- public class AudioRecordUtil implements EncoderListener , FLVListener {
40+ public class AudioRecordUtil implements EncoderListener , FLVListener , Handler .Callback {
4041 private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat .CHANNEL_IN_STEREO ; //设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
4142 private static final int DEFAULT_AUDIO_FORMAT = AudioFormat .ENCODING_PCM_16BIT ; //音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
42- private static final String TAG = AudioRecordUtil .class .getName ();;
43+ private static final String TAG = AudioRecordUtil .class .getName ();
44+ private static final int MSG_START = 1 ;
45+ private static final int MSG_STOP = 2 ;
46+ private static final int MSG_ENCODE = 3 ;
47+ private static final int MSG_RELEASE = 4 ;
48+ private final HandlerThread readThread ;
49+ private final ReadHandler mReadHandler ;
4350 private volatile boolean recorderState = true ; //录制状态
4451 private byte [] buffer ;
4552 private AudioRecord audioRecord ;
46- private AcousticEchoCanceler canceler ;
47- private AutomaticGainControl control ;
53+ private volatile AcousticEchoCanceler canceler ;
54+ private volatile AutomaticGainControl control ;
4855 private volatile PCMEncoder pcmEncoder ;
4956 private volatile FLVPacker flvPacker ;
5057 private Context context ;
@@ -73,8 +80,27 @@ public class AudioRecordUtil implements EncoderListener, FLVListener {
7380
7481 private static final int SAVE_PCM_DATA = 1 ;
7582
76- private IjkMediaPlayer player ;
7783 private LinkedBlockingDeque <Byte > playPcmData = new LinkedBlockingDeque <>(); // 内存队列,用于缓存获取到的播放器音频pcm
84+ private AudioRecordUtilListener audioRecordUtilListener = null ;
85+
86+ @ Override
87+ public boolean handleMessage (@ NotNull Message msg ) {
88+ switch (msg .what ) {
89+ case MSG_START :
90+ startInternal ();
91+ break ;
92+ case MSG_STOP :
93+ stopInternal ();
94+ break ;
95+ case MSG_ENCODE :
96+ // renderInternal((TRTCCloudDef.TRTCVideoFrame) msg.obj);
97+ break ;
98+ case MSG_RELEASE :
99+ releaseInternal ();
100+ break ;
101+ }
102+ return false ;
103+ }
78104
79105 private class MyHandler extends Handler {
80106
@@ -114,24 +140,36 @@ public AudioRecordUtil(Context ctx, String id, int sampleRate) {
114140 context = ctx ;
115141 deviceId = id ;
116142 init (sampleRate , DEFAULT_CHANNEL_CONFIG , DEFAULT_AUDIO_FORMAT );
143+ readThread = new HandlerThread (TAG );
144+ readThread .start ();
145+ mReadHandler = new ReadHandler (readThread .getLooper (), this );
117146 }
118147 public AudioRecordUtil (Context ctx , String id , int sampleRate , int channel , int bitDepth ) {
119148 context = ctx ;
120149 deviceId = id ;
121150 init (sampleRate , channel , bitDepth );
151+ readThread = new HandlerThread (TAG );
152+ readThread .start ();
153+ mReadHandler = new ReadHandler (readThread .getLooper (), this );
122154 }
123155 public AudioRecordUtil (Context ctx , String id , int sampleRate , int channel , int bitDepth , int pitch ) {
124156 context = ctx ;
125157 deviceId = id ;
126158 this .pitch = pitch ;
127159 init (sampleRate , channel , bitDepth );
160+ readThread = new HandlerThread (TAG );
161+ readThread .start ();
162+ mReadHandler = new ReadHandler (readThread .getLooper (), this );
128163 }
129164 public AudioRecordUtil (Context ctx , String id , int sampleRate , int channel , int bitDepth , boolean enableAEC , boolean enableAGC ) {
130165 context = ctx ;
131166 deviceId = id ;
132167 this .enableAEC = enableAEC ;
133168 this .enableAGC = enableAGC ;
134169 init (sampleRate , channel , bitDepth );
170+ readThread = new HandlerThread (TAG );
171+ readThread .start ();
172+ mReadHandler = new ReadHandler (readThread .getLooper (), this );
135173 }
136174 public AudioRecordUtil (Context ctx , String id , int sampleRate , int channel , int bitDepth , int pitch , boolean enableAEC , boolean enableAGC ) {
137175 context = ctx ;
@@ -140,6 +178,21 @@ public AudioRecordUtil(Context ctx, String id, int sampleRate, int channel, int
140178 this .enableAEC = enableAEC ;
141179 this .enableAGC = enableAGC ;
142180 init (sampleRate , channel , bitDepth );
181+ readThread = new HandlerThread (TAG );
182+ readThread .start ();
183+ mReadHandler = new ReadHandler (readThread .getLooper (), this );
184+ }
185+ public AudioRecordUtil (Context ctx , String id , int sampleRate , int channel , int bitDepth , int pitch , AudioRecordUtilListener audioRecordUtilListener ) {
186+ context = ctx ;
187+ deviceId = id ;
188+ this .pitch = pitch ;
189+ this .enableAEC = false ;
190+ this .enableAGC = false ;
191+ this .audioRecordUtilListener = audioRecordUtilListener ;
192+ init (sampleRate , channel , bitDepth );
193+ readThread = new HandlerThread (TAG );
194+ readThread .start ();
195+ mReadHandler = new ReadHandler (readThread .getLooper (), this );
143196 }
144197
145198 private void init (int sampleRate , int channel , int bitDepth ) {
@@ -229,14 +282,15 @@ public void setMode(VoiceChangerMode mode) {
229282 }
230283 }
231284
232- public void setPlayer (IjkMediaPlayer player ) {
233- this .player = player ;
234- }
235-
236285 /**
237286 * 开始录制
238287 */
239288 public void start () {
289+ Log .i (TAG , "start" );
290+ mReadHandler .obtainMessage (MSG_START ).sendToTarget ();
291+ }
292+
293+ private void startInternal () {
240294 if (isRecord ) {
241295 fos1 = createFiles ("near" );
242296 fos2 = createFiles ("far" );
@@ -256,9 +310,12 @@ public void start() {
256310 VoiceChangerJNIBridge .setMode (this .mode .getValue ());
257311 }
258312 recorderState = true ;
313+ Log .e (TAG , "turn recorderState : " + recorderState );
259314 audioRecord .startRecording ();
260315 new RecordThread ().start ();
261- new WriteThread ().start ();
316+ if (audioRecordUtilListener != null ) {
317+ new WriteThread ().start ();
318+ }
262319 }
263320
264321 private void reset () {
@@ -283,43 +340,57 @@ private void reset() {
283340 * 停止录制
284341 */
285342 public void stop () {
286- recorderState = false ;
287- if (audioRecord != null ) {
288- audioRecord .stop ();
289- }
290-
291- executor .shutdown ();
292- audioRecord = null ;
293- pcmEncoder = null ;
294- if (flvPacker != null ) {
295- flvPacker .release ();
296- flvPacker = null ;
297- }
298- if (canceler != null ) {
299- canceler .setEnabled (false );
300- canceler .release ();
301- canceler = null ;
302- }
303- if (control != null ) {
304- control .setEnabled (false );
305- control .release ();
306- control = null ;
307- }
343+ Log .i (TAG , "stop" );
344+ mReadHandler .obtainMessage (MSG_STOP ).sendToTarget ();
345+ }
308346
309- if (!VoiceChangerJNIBridge .isAvailable ()) {
310- if (st != null ) {
311- st .finish ();
312- st .clearBuffer (0 );
313- st = null ;
347+ private void stopInternal () {
348+ recorderState = false ;
349+ Log .e (TAG , "turn recorderState : " + recorderState );
350+ mReadHandler .postDelayed (new Runnable () {
351+ @ Override
352+ public void run () {
353+ Log .e (TAG , "mReadHandler.postDelayed 200 turn recorderState : " + recorderState );
354+ if (audioRecord != null ) {
355+ audioRecord .stop ();
356+ }
357+ executor .shutdown ();
358+ audioRecord = null ;
359+ pcmEncoder = null ;
360+ if (flvPacker != null ) {
361+ flvPacker .release ();
362+ flvPacker = null ;
363+ }
364+ if (canceler != null ) {
365+ canceler .setEnabled (false );
366+ canceler .release ();
367+ canceler = null ;
368+ }
369+ if (control != null ) {
370+ control .setEnabled (false );
371+ control .release ();
372+ control = null ;
373+ }
374+ if (!VoiceChangerJNIBridge .isAvailable ()) {
375+ if (st != null ) {
376+ st .finish ();
377+ st .clearBuffer (0 );
378+ st = null ;
379+ }
380+ } else {
381+ VoiceChangerJNIBridge .destory ();
382+ }
383+ // GvoiceJNIBridge.destory();
314384 }
315- } else {
316- VoiceChangerJNIBridge .destory ();
317- }
318-
319- GvoiceJNIBridge .destory ();
385+ }, 200 );
320386 }
321387
322388 public void release () {
389+ Log .i (TAG , "release" );
390+ mReadHandler .obtainMessage (MSG_STOP ).sendToTarget ();
391+ }
392+
393+ private void releaseInternal () {
323394 audioRecord .release ();
324395 }
325396
@@ -336,7 +407,7 @@ public void encodeG711(byte[] data) { }
336407 @ Override
337408 public void onFLV (byte [] data ) {
338409 if (recorderState ) {
339- Log .d (TAG , "===== XP2P.dataSend dataLen:" + data .length );
410+ // Log.d(TAG, "===== XP2P.dataSend dataLen:" + data.length);
340411 XP2P .dataSend (deviceId , data , data .length );
341412
342413 if (executor .isShutdown ()) return ;
@@ -373,7 +444,7 @@ private class RecordThread extends Thread {
373444 public void run () {
374445 while (recorderState ) {
375446 int read = audioRecord .read (buffer , 0 , buffer .length );
376- Log .e (TAG , "audioRecord.read: " +read + ", buffer.length: " + buffer .length );
447+ Log .e (TAG , "audioRecord.read: " +read + ", buffer.length: " + buffer .length + ", recorderState: " + recorderState );
377448 if (!VoiceChangerJNIBridge .isAvailable ()) {
378449 if (pitch != 0 && st != null ) {
379450 st .putBytes (buffer );
@@ -387,7 +458,7 @@ public void run() {
387458 if (AudioRecord .ERROR_INVALID_OPERATION != read ) {
388459 //获取到的pcm数据就是buffer了
389460 if (buffer != null && pcmEncoder != null ) {
390- if (player != null && player . isPlaying () ) {
461+ if (audioRecordUtilListener != null ) {
391462 byte [] playerPcmBytes = onReadPlayerPlayPcm (buffer .length );
392463 byte [] aecPcmBytes = GvoiceJNIBridge .cancellation (buffer , playerPcmBytes );
393464 if (isRecord ) {
@@ -460,14 +531,12 @@ private class WriteThread extends Thread {
460531 @ Override
461532 public void run () {
462533 while (recorderState ) {
463- if (player != null && player .isPlaying ()) {
464- byte [] data = new byte [204800 ];
465- int len = player ._getPcmData (data );
466- if (len > 0 ) {
467- byte [] playerBytes = new byte [len ];
468- System .arraycopy (data , 0 , playerBytes , 0 , len );
534+ if (audioRecordUtilListener != null ) {
535+ byte [] data = audioRecordUtilListener .onReadPlayerPcmByte ();
536+ if (data != null && data .length > 0 ) {
537+ Log .e (TAG , "data.length: " + data .length + " , recorderState : " + recorderState );
469538 List <Byte > tmpList = new ArrayList <>();
470- for (byte b : playerBytes ) {
539+ for (byte b : data ) {
471540 tmpList .add (b );
472541 }
473542 playPcmData .addAll (tmpList );
@@ -476,4 +545,25 @@ public void run() {
476545 }
477546 }
478547 }
548+
549+ public static class ReadHandler extends Handler {
550+
551+ public ReadHandler (Looper looper , Callback callback ) {
552+ super (looper , callback );
553+ }
554+
555+ public void runAndWaitDone (final Runnable runnable ) {
556+ final CountDownLatch countDownLatch = new CountDownLatch (1 );
557+ post (() -> {
558+ runnable .run ();
559+ countDownLatch .countDown ();
560+ });
561+
562+ try {
563+ countDownLatch .await ();
564+ } catch (InterruptedException e ) {
565+ e .printStackTrace ();
566+ }
567+ }
568+ }
479569}
0 commit comments