From 17fa15084fc7f9b2c31525946e326d3ca24dc23d Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson Date: Sat, 8 Oct 2022 15:11:10 -0400 Subject: [PATCH] RecorderThread: Use non-blocking reads from AudioRecord On Samsung devices, when a call ends, AudioRecord.read() blocks until another call becomes active, which prevents recordings from stopping at the correct time. This behavior does not happen in AOSP. To work around this, use non-blocking reads with a sleep interval of the AudioRecord minimum buffer size. This gives the recording loop a chance to check if recording has been cancelled. Issue: #143 Signed-off-by: Andrew Gunnerson --- .../main/java/com/chiller3/bcr/RecorderThread.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/chiller3/bcr/RecorderThread.kt b/app/src/main/java/com/chiller3/bcr/RecorderThread.kt index 4ab065fa2..873f26c6c 100644 --- a/app/src/main/java/com/chiller3/bcr/RecorderThread.kt +++ b/app/src/main/java/com/chiller3/bcr/RecorderThread.kt @@ -496,7 +496,7 @@ class RecorderThread( * * @param audioRecord [AudioRecord.startRecording] must have been called * @param encoder [Encoder.start] must have been called - * @param bufSize Size of buffer to use for each [AudioRecord.read] operation + * @param bufSize Minimum buffer size for each [AudioRecord.read] operation * * @throws Exception if the audio recorder or encoder encounters an error */ @@ -508,10 +508,14 @@ class RecorderThread( val buffer = ByteBuffer.allocateDirect(bufSize * 2) val bufferFrames = buffer.capacity().toLong() / frameSize val bufferNs = bufferFrames * 1_000_000_000L / audioRecord.sampleRate + Log.d(tag, "Buffer is ${buffer.capacity()} bytes, $bufferFrames frames, ${bufferNs}ns") while (!isCancelled) { val begin = System.nanoTime() - val n = audioRecord.read(buffer, buffer.remaining()) + // We do a non-blocking read because on Samsung devices, when the call ends, the audio + // device immediately stops producing data and blocks forever until the next call is + // active. + val n = audioRecord.read(buffer, buffer.remaining(), AudioRecord.READ_NON_BLOCKING) val recordElapsed = System.nanoTime() - begin var encodeElapsed = 0L @@ -520,8 +524,9 @@ class RecorderThread( isCancelled = true captureFailed = true } else if (n == 0) { - Log.e(tag, "Unexpected EOF from AudioRecord") - isCancelled = true + // Wait for half of buffer size + sleep(bufferNs / 1_000_000L / 2) + continue } else { buffer.limit(n)