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 <magjed@webrtc.org>
Reviewed-by: Paulina Hensman <phensman@webrtc.org>
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22653}
This commit is contained in:
Magnus Jedvert
2018-03-28 15:50:16 +02:00
committed by Commit Bot
parent ac9365ed64
commit b93d030b55
2 changed files with 28 additions and 57 deletions

View File

@ -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

View File

@ -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;
}
}
// 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");
// Abort early if stop() has been called.
if (!isRunning) {
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;