From 3d8838409f3120dcfea0fcfb3d70a728014673e3 Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Wed, 31 Jul 2019 17:19:58 +0200 Subject: [PATCH] Replace zero buffer with sample noise --- .../video/encoding/AudioConfig.java | 2 +- .../video/encoding/AudioMediaEncoder.java | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioConfig.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioConfig.java index 3d09b51e..1a01d756 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioConfig.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioConfig.java @@ -20,7 +20,7 @@ public class AudioConfig { final int encoding = AudioFormat.ENCODING_PCM_16BIT; // Determines the sampleSizePerChannel // The 44.1KHz frequency is the only setting guaranteed to be available on all devices. final int samplingFrequency = 44100; // samples/sec - final int sampleSizePerChannel = 2; // byte/sample/channel [16bit] + final int sampleSizePerChannel = 2; // byte/sample/channel [16bit]. If this changes, review noise introduction final int byteRatePerChannel = samplingFrequency * sampleSizePerChannel; // byte/sec/channel @NonNull diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioMediaEncoder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioMediaEncoder.java index 62a060f1..4aa9c5cf 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioMediaEncoder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/video/encoding/AudioMediaEncoder.java @@ -1,6 +1,5 @@ package com.otaliastudios.cameraview.video.encoding; -import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaCodec; import android.media.MediaCodecInfo; @@ -17,6 +16,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; +import java.util.Random; import java.util.concurrent.LinkedBlockingQueue; /** @@ -31,11 +31,16 @@ public class AudioMediaEncoder extends MediaEncoder { private static final boolean PERFORMANCE_DEBUG = false; private static final boolean PERFORMANCE_FILL_GAPS = true; + private final static Random NOISE = new Random(); + + private static short noise() { + return (short) NOISE.nextInt(300); + } + private boolean mRequestStop = false; private AudioEncodingThread mEncoder; private AudioRecordingThread mRecorder; private ByteBufferPool mByteBufferPool; - private ByteBuffer mZeroBuffer; private final AudioTimestamp mTimestamp; private AudioConfig mConfig; private InputBufferPool mInputBufferPool = new InputBufferPool(); @@ -76,7 +81,6 @@ public class AudioMediaEncoder extends MediaEncoder { mMediaCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mMediaCodec.start(); mByteBufferPool = new ByteBufferPool(mConfig.frameSize(), mConfig.bufferPoolMaxSize()); - mZeroBuffer = ByteBuffer.allocateDirect(mConfig.frameSize()); } @EncoderThread @@ -253,16 +257,21 @@ public class AudioMediaEncoder extends MediaEncoder { long frameUs = AudioTimestamp.bytesToUs(mConfig.frameSize(), mConfig.byteRate()); LOG.w("read thread - GAPS: trying to add", gaps, "zeroed buffers"); for (int i = 0; i < gaps; i++) { - ByteBuffer zeroBuffer = mByteBufferPool.get(); - if (zeroBuffer == null) { + ByteBuffer noiseBuffer = mByteBufferPool.get(); + if (noiseBuffer == null) { LOG.e("read thread - GAPS: aborting because we have no free buffer."); break; } - ; - zeroBuffer.position(0); - zeroBuffer.put(mZeroBuffer); - zeroBuffer.clear(); - enqueue(zeroBuffer, gapStart, false); + noiseBuffer.clear(); + while (noiseBuffer.hasRemaining()) { + // Assume remaining() is not an odd number! + // Also assuming byte order is little endian in Android. + short noise = noise(); + noiseBuffer.put((byte) noise); + noiseBuffer.put((byte) (noise >> 8)); + } + noiseBuffer.rewind(); + enqueue(noiseBuffer, gapStart, false); gapStart += frameUs; } } @@ -312,6 +321,7 @@ public class AudioMediaEncoder extends MediaEncoder { if (PERFORMANCE_DEBUG) { long sendEnd = System.nanoTime() / 1000000; Long sendStart = mSendStartMap.remove(inputBuffer.timestamp); + //noinspection StatementWithEmptyBody if (sendStart != null) { mAvgSendDelay = ((mAvgSendDelay * mSendCount) + (sendEnd - sendStart)) / (++mSendCount); LOG.v("send delay millis:", sendEnd - sendStart, "average:", mAvgSendDelay); @@ -357,7 +367,7 @@ public class AudioMediaEncoder extends MediaEncoder { // NOTE: can consider calling this drainOutput on yet another thread, which would let us // use an even smaller BUFFER_POOL_MAX_SIZE without losing audio frames. But this way // we can accumulate delay on this new thread without noticing (no pool getting empty). - drainOutput(buffer.isEndOfStream); + drainOutput(eos); if (PERFORMANCE_DEBUG) { long executeEnd = System.nanoTime() / 1000000;