Android WebRTC 对 AudioRecord 的使用( 二 )

在该方法中,首先启动了 audioRecord,接着判断了读取线程事都正在录制中 。
读数据 private class AudioRecordThread extends Thread {private volatile boolean keepAlive = true;public AudioRecordThread(String name) {super(name);}// TODO(titovartem) make correct fix during webrtc:9175@SuppressWarnings("ByteBufferBackingArray")@Overridepublic void run() {Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);Logging.d(TAG, "AudioRecordThread" + WebRtcAudioUtils.getThreadInfo());assertTrue(audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING);long lastTime = System.nanoTime();while (keepAlive) {int bytesRead = audioRecord.read(byteBuffer, byteBuffer.capacity());if (bytesRead == byteBuffer.capacity()) {if (microphoneMute) {byteBuffer.clear();byteBuffer.put(emptyBytes);}// It's possible we've been shut down during the read, and stopRecording() tried and// failed to join this thread. To be a bit safer, try to avoid calling any native methods// in case they've been unregistered after stopRecording() returned.if (keepAlive) {nativeDataIsRecorded(bytesRead, nativeAudioRecord);}if (audioSamplesReadyCallback != null) {// Copy the entire byte buffer array.Assume that the start of the byteBuffer is// at index 0.byte[] data = https://www.isolves.com/it/cxkf/ydd/Android/2022-01-13/Arrays.copyOf(byteBuffer.array(), byteBuffer.capacity());audioSamplesReadyCallback.onWebRtcAudioRecordSamplesReady(new AudioSamples(audioRecord, data));}} else {String errorMessage = "AudioRecord.read failed: " + bytesRead;Logging.e(TAG, errorMessage);if (bytesRead == AudioRecord.ERROR_INVALID_OPERATION) {keepAlive = false;reportWebRtcAudioRecordError(errorMessage);}}if (DEBUG) {long nowTime = System.nanoTime();long durationInMs = TimeUnit.NANOSECONDS.toMillis((nowTime - lastTime));lastTime = nowTime;Logging.d(TAG, "bytesRead[" + durationInMs + "] " + bytesRead);}}try {if (audioRecord != null) {audioRecord.stop();}} catch (IllegalStateException e) {Logging.e(TAG, "AudioRecord.stop failed: " + e.getMessage());}}// Stops the inner thread loop and also calls AudioRecord.stop().// Does not block the calling thread.public void stopThread() {Logging.d(TAG, "stopThread");keepAlive = false;}}从 AudioRecord去数据的逻辑在 AudioRecordThread 线程的 Run函数中 。

  1. 在线程启动的地方,先设置线程的优先级为URGENT_AUDIO,这里调用的是Process.setThreadPriority 。
  2. 在一个循环中不停地调用audioRecord.read读取数据,把采集到的数据读到ByteBuffer中,然后调用nativeDataIsRecorded JNI函数通知native层数据已经读到,进行下一步处理 。
停止和销毁private boolean stopRecording() {Logging.d(TAG, "stopRecording");assertTrue(audioThread != null);audioThread.stopThread();if (!ThreadUtils.joinUninterruptibly(audioThread, AUDIO_RECORD_THREAD_JOIN_TIMEOUT_MS)) {Logging.e(TAG, "Join of AudioRecordJavaThread timed out");WebRtcAudioUtils.logAudioState(TAG);}audioThread = null;if (effects != null) {effects.release();}releaseAudioResources();return true;}可以看到,这里首先把AudioRecordThread读数据循环的keepAlive条件置为false,接着调用
ThreadUtils.joinUninterruptibly等待AudioRecordThread线程退出 。
这里有一点值得一提,keepAlive变量加了volatile关键字进行修饰,这是因为修改和读取这个变量的操作可能发生在不同的线程,使用volatile关键字进行修饰,可以保证修改之后能被立即读取到 。
AudioRecordThread线程退出循环后,会调用audioRecord.stop()停止采集;线程退出之后,会调用audioRecord.release()释放AudioRecord对象 。
以上,就是 Android WebRTC 音频采集 Java 层的大致流程 。
 
参考《WebRTC 开发实战》
【Android WebRTC 对 AudioRecord 的使用】https://chromium.googlesource.com/external/webrtc/+/HEAD/sdk/android/src/java/org/webrtc/audio/WebRtcAudioRecord.java




推荐阅读