From b93d030b5513a37691c572cc045df215552027f0 Mon Sep 17 00:00:00 2001 From: Magnus Jedvert Date: Wed, 28 Mar 2018 15:50:16 +0200 Subject: [PATCH] Android: Update RecordedAudioToFileController This CL refactors the way RecordedAudioToFileController is connected to AudioRecord. Instead of allowing to dynamically set and update the AudioSamplesCallback, it's set once at start time and then stopping is implemented in RecordedAudioToFileController by simply ignoring calls to onWebRtcAudioRecordSamplesReady. The reason for this CL is to reduce the amount of methods we need to add to the future AudioDeviceModule interface. The more functionality we can move to creation time in the ctor, the less methods we need to have in the interface. Bug: webrtc:7452 Change-Id: I462df275d8579c848e1d2c86cbd8e881da89cbf3 Reviewed-on: https://webrtc-review.googlesource.com/64988 Reviewed-by: Magnus Jedvert Reviewed-by: Paulina Hensman Commit-Queue: Magnus Jedvert Cr-Commit-Position: refs/heads/master@{#22653} --- .../appspot/apprtc/PeerConnectionClient.java | 19 +++--- .../apprtc/RecordedAudioToFileController.java | 66 +++++-------------- 2 files changed, 28 insertions(+), 57 deletions(-) diff --git a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java index d88db10586..93343a0d3f 100644 --- a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java +++ b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java @@ -476,12 +476,6 @@ public class PeerConnectionClient { preferIsac = peerConnectionParameters.audioCodec != null && peerConnectionParameters.audioCodec.equals(AUDIO_CODEC_ISAC); - if (peerConnectionParameters.useLegacyAudioDevice) { - setupAudioDeviceLegacy(); - } else { - setupAudioDevice(); - } - // It is possible to save a copy in raw PCM format on a file by checking // the "Save input audio to file" checkbox in the Settings UI. A callback // interface is set when this flag is enabled. As a result, a copy of recorded @@ -490,14 +484,19 @@ public class PeerConnectionClient { if (peerConnectionParameters.saveInputAudioToFile) { if (!peerConnectionParameters.useOpenSLES) { Log.d(TAG, "Enable recording of microphone input audio to file"); - saveRecordedAudioToFile = new RecordedAudioToFileController( - executor, peerConnectionParameters.useLegacyAudioDevice); + saveRecordedAudioToFile = new RecordedAudioToFileController(executor); } else { // TODO(henrika): ensure that the UI reflects that if OpenSL ES is selected, // then the "Save inut audio to file" option shall be grayed out. Log.e(TAG, "Recording of input audio is not supported for OpenSL ES"); } } + + if (peerConnectionParameters.useLegacyAudioDevice) { + setupAudioDeviceLegacy(); + } else { + setupAudioDevice(); + } // Create peer connection factory. if (options != null) { Log.d(TAG, "Factory networkIgnoreMask option: " + options.networkIgnoreMask); @@ -546,6 +545,8 @@ public class PeerConnectionClient { WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(false); } + WebRtcAudioRecord.setOnAudioSamplesReady(saveRecordedAudioToFile); + // Set audio record error callbacks. WebRtcAudioRecord.setErrorCallback(new WebRtcAudioRecordErrorCallback() { @Override @@ -616,6 +617,8 @@ public class PeerConnectionClient { AudioDeviceModule.setWebRtcBasedNoiseSuppressor(false); } + AudioDeviceModule.setOnAudioSamplesReady(saveRecordedAudioToFile); + // Set audio record error callbacks. AudioDeviceModule.setErrorCallback(new AudioDeviceModule.AudioRecordErrorCallback() { @Override diff --git a/examples/androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java b/examples/androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java index 89ff360640..d9ddce44d5 100644 --- a/examples/androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java +++ b/examples/androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java @@ -38,13 +38,12 @@ public class RecordedAudioToFileController private final ExecutorService executor; @Nullable private OutputStream rawAudioFileOutputStream = null; + private boolean isRunning; private long fileSizeInBytes = 0; - private boolean useLegacyAudioDevice; - public RecordedAudioToFileController(ExecutorService executor, boolean useLegacyAudioDevice) { + public RecordedAudioToFileController(ExecutorService executor) { Log.d(TAG, "ctor"); this.executor = executor; - this.useLegacyAudioDevice = useLegacyAudioDevice; } /** @@ -57,11 +56,8 @@ public class RecordedAudioToFileController Log.e(TAG, "Writing to external media is not possible"); return false; } - // Register this class as receiver of recorded audio samples for storage. - if (useLegacyAudioDevice) { - WebRtcAudioRecord.setOnAudioSamplesReady(this); - } else { - AudioDeviceModule.setOnAudioSamplesReady(this); + synchronized (lock) { + isRunning = true; } return true; } @@ -72,13 +68,8 @@ public class RecordedAudioToFileController */ public void stop() { Log.d(TAG, "stop"); - // De-register this class as receiver of recorded audio samples for storage. - if (useLegacyAudioDevice) { - WebRtcAudioRecord.setOnAudioSamplesReady(null); - } else { - AudioDeviceModule.setOnAudioSamplesReady(null); - } synchronized (lock) { + isRunning = false; if (rawAudioFileOutputStream != null) { try { rawAudioFileOutputStream.close(); @@ -116,6 +107,13 @@ public class RecordedAudioToFileController Log.d(TAG, "Opened file for recording: " + fileName); } + // Called when new audio samples are ready. + @Override + public void onWebRtcAudioRecordSamplesReady(WebRtcAudioRecord.AudioSamples samples) { + onWebRtcAudioRecordSamplesReady(new AudioDeviceModule.AudioSamples(samples.getAudioFormat(), + samples.getChannelCount(), samples.getSampleRate(), samples.getData())); + } + // Called when new audio samples are ready. @Override public void onWebRtcAudioRecordSamplesReady(AudioDeviceModule.AudioSamples samples) { @@ -124,43 +122,13 @@ public class RecordedAudioToFileController Log.e(TAG, "Invalid audio format"); return; } - // Open a new file for the first callback only since it allows us to add - // audio parameters to the file name. synchronized (lock) { - if (rawAudioFileOutputStream == null) { - openRawAudioOutputFile(samples.getSampleRate(), samples.getChannelCount()); - fileSizeInBytes = 0; + // Abort early if stop() has been called. + if (!isRunning) { + return; } - } - // Append the recorded 16-bit audio samples to the open output file. - executor.execute(() -> { - if (rawAudioFileOutputStream != null) { - try { - // Set a limit on max file size. 58348800 bytes corresponds to - // approximately 10 minutes of recording in mono at 48kHz. - if (fileSizeInBytes < MAX_FILE_SIZE_IN_BYTES) { - // Writes samples.getData().length bytes to output stream. - rawAudioFileOutputStream.write(samples.getData()); - fileSizeInBytes += samples.getData().length; - } - } catch (IOException e) { - Log.e(TAG, "Failed to write audio to file: " + e.getMessage()); - } - } - }); - } - - // Called when new audio samples are ready. - @Override - public void onWebRtcAudioRecordSamplesReady(WebRtcAudioRecord.AudioSamples samples) { - // The native audio layer on Android should use 16-bit PCM format. - if (samples.getAudioFormat() != AudioFormat.ENCODING_PCM_16BIT) { - Log.e(TAG, "Invalid audio format"); - return; - } - // Open a new file for the first callback only since it allows us to add - // audio parameters to the file name. - synchronized (lock) { + // Open a new file for the first callback only since it allows us to add audio parameters to + // the file name. if (rawAudioFileOutputStream == null) { openRawAudioOutputFile(samples.getSampleRate(), samples.getChannelCount()); fileSizeInBytes = 0;