[AndroidAudioRecord] Added audio format parameter to configure AudioRecord - JavaAudioDeviceModule
Added audio format field and set method to Builder. - WebRTCAudioRecord. Added audio format field, added to constructor. Default audio format value AudioFormat.ENCODING_PCM_16BIT. initRecord(), added how to calculate bytesPerFrame, depends on audioFormat. First commit and contribution, updated AUTHORS file Bug: None Change-Id: I16f660d42350ec9ce2e329b239bd7f6324e76dfe Reviewed-on: https://webrtc-review.googlesource.com/c/122302 Commit-Queue: Magnus Jedvert <magjed@webrtc.org> Reviewed-by: Magnus Jedvert <magjed@webrtc.org> Reviewed-by: Artem Titov <titovartem@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26775}
This commit is contained in:

committed by
Commit Bot

parent
5341aaccdb
commit
ce27875b83
1
AUTHORS
1
AUTHORS
@ -108,3 +108,4 @@ Vewd Software AS <*@vewd.com>
|
|||||||
Highfive, Inc. <*@highfive.com>
|
Highfive, Inc. <*@highfive.com>
|
||||||
CoSMo Software Consulting, Pte Ltd <*@cosmosoftware.io>
|
CoSMo Software Consulting, Pte Ltd <*@cosmosoftware.io>
|
||||||
Tuple, LLC <*@tuple.app>
|
Tuple, LLC <*@tuple.app>
|
||||||
|
Videona Socialmedia <*@videona.com>
|
||||||
|
@ -31,6 +31,7 @@ public class JavaAudioDeviceModule implements AudioDeviceModule {
|
|||||||
private final AudioManager audioManager;
|
private final AudioManager audioManager;
|
||||||
private int sampleRate;
|
private int sampleRate;
|
||||||
private int audioSource = WebRtcAudioRecord.DEFAULT_AUDIO_SOURCE;
|
private int audioSource = WebRtcAudioRecord.DEFAULT_AUDIO_SOURCE;
|
||||||
|
private int audioFormat = WebRtcAudioRecord.DEFAULT_AUDIO_FORMAT;
|
||||||
private AudioTrackErrorCallback audioTrackErrorCallback;
|
private AudioTrackErrorCallback audioTrackErrorCallback;
|
||||||
private AudioRecordErrorCallback audioRecordErrorCallback;
|
private AudioRecordErrorCallback audioRecordErrorCallback;
|
||||||
private SamplesReadyCallback samplesReadyCallback;
|
private SamplesReadyCallback samplesReadyCallback;
|
||||||
@ -65,6 +66,17 @@ public class JavaAudioDeviceModule implements AudioDeviceModule {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this to change the audio format. The argument should be one of the values from
|
||||||
|
* android.media.AudioFormat ENCODING_PCM_8BIT, ENCODING_PCM_16BIT or ENCODING_PCM_FLOAT.
|
||||||
|
* Default audio data format is PCM 16 bit per sample.
|
||||||
|
* Guaranteed to be supported by all devices.
|
||||||
|
*/
|
||||||
|
public Builder setAudioFormat(int audioFormat) {
|
||||||
|
this.audioFormat = audioFormat;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a callback to retrieve errors from the AudioTrack.
|
* Set a callback to retrieve errors from the AudioTrack.
|
||||||
*/
|
*/
|
||||||
@ -154,9 +166,9 @@ public class JavaAudioDeviceModule implements AudioDeviceModule {
|
|||||||
}
|
}
|
||||||
Logging.d(TAG, "HW AEC will not be used.");
|
Logging.d(TAG, "HW AEC will not be used.");
|
||||||
}
|
}
|
||||||
final WebRtcAudioRecord audioInput =
|
final WebRtcAudioRecord audioInput = new WebRtcAudioRecord(context, audioManager, audioSource,
|
||||||
new WebRtcAudioRecord(context, audioManager, audioSource, audioRecordErrorCallback,
|
audioFormat, audioRecordErrorCallback, samplesReadyCallback,
|
||||||
samplesReadyCallback, useHardwareAcousticEchoCanceler, useHardwareNoiseSuppressor);
|
useHardwareAcousticEchoCanceler, useHardwareNoiseSuppressor);
|
||||||
final WebRtcAudioTrack audioOutput =
|
final WebRtcAudioTrack audioOutput =
|
||||||
new WebRtcAudioTrack(context, audioManager, audioTrackErrorCallback);
|
new WebRtcAudioTrack(context, audioManager, audioTrackErrorCallback);
|
||||||
return new JavaAudioDeviceModule(context, audioManager, audioInput, audioOutput, sampleRate,
|
return new JavaAudioDeviceModule(context, audioManager, audioInput, audioOutput, sampleRate,
|
||||||
|
@ -32,10 +32,6 @@ import org.webrtc.audio.JavaAudioDeviceModule.SamplesReadyCallback;
|
|||||||
class WebRtcAudioRecord {
|
class WebRtcAudioRecord {
|
||||||
private static final String TAG = "WebRtcAudioRecordExternal";
|
private static final String TAG = "WebRtcAudioRecordExternal";
|
||||||
|
|
||||||
// Default audio data format is PCM 16 bit per sample.
|
|
||||||
// Guaranteed to be supported by all devices.
|
|
||||||
private static final int BITS_PER_SAMPLE = 16;
|
|
||||||
|
|
||||||
// Requested size of each recorded buffer provided to the client.
|
// Requested size of each recorded buffer provided to the client.
|
||||||
private static final int CALLBACK_BUFFER_SIZE_MS = 10;
|
private static final int CALLBACK_BUFFER_SIZE_MS = 10;
|
||||||
|
|
||||||
@ -53,9 +49,14 @@ class WebRtcAudioRecord {
|
|||||||
|
|
||||||
public static final int DEFAULT_AUDIO_SOURCE = AudioSource.VOICE_COMMUNICATION;
|
public static final int DEFAULT_AUDIO_SOURCE = AudioSource.VOICE_COMMUNICATION;
|
||||||
|
|
||||||
|
// Default audio data format is PCM 16 bit per sample.
|
||||||
|
// Guaranteed to be supported by all devices.
|
||||||
|
public static final int DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final AudioManager audioManager;
|
private final AudioManager audioManager;
|
||||||
private final int audioSource;
|
private final int audioSource;
|
||||||
|
private final int audioFormat;
|
||||||
|
|
||||||
private long nativeAudioRecord;
|
private long nativeAudioRecord;
|
||||||
|
|
||||||
@ -145,13 +146,14 @@ class WebRtcAudioRecord {
|
|||||||
|
|
||||||
@CalledByNative
|
@CalledByNative
|
||||||
WebRtcAudioRecord(Context context, AudioManager audioManager) {
|
WebRtcAudioRecord(Context context, AudioManager audioManager) {
|
||||||
this(context, audioManager, DEFAULT_AUDIO_SOURCE, null /* errorCallback */,
|
this(context, audioManager, DEFAULT_AUDIO_SOURCE, DEFAULT_AUDIO_FORMAT,
|
||||||
null /* audioSamplesReadyCallback */, WebRtcAudioEffects.isAcousticEchoCancelerSupported(),
|
null /* errorCallback */, null /* audioSamplesReadyCallback */,
|
||||||
|
WebRtcAudioEffects.isAcousticEchoCancelerSupported(),
|
||||||
WebRtcAudioEffects.isNoiseSuppressorSupported());
|
WebRtcAudioEffects.isNoiseSuppressorSupported());
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebRtcAudioRecord(Context context, AudioManager audioManager, int audioSource,
|
public WebRtcAudioRecord(Context context, AudioManager audioManager, int audioSource,
|
||||||
@Nullable AudioRecordErrorCallback errorCallback,
|
int audioFormat, @Nullable AudioRecordErrorCallback errorCallback,
|
||||||
@Nullable SamplesReadyCallback audioSamplesReadyCallback,
|
@Nullable SamplesReadyCallback audioSamplesReadyCallback,
|
||||||
boolean isAcousticEchoCancelerSupported, boolean isNoiseSuppressorSupported) {
|
boolean isAcousticEchoCancelerSupported, boolean isNoiseSuppressorSupported) {
|
||||||
if (isAcousticEchoCancelerSupported && !WebRtcAudioEffects.isAcousticEchoCancelerSupported()) {
|
if (isAcousticEchoCancelerSupported && !WebRtcAudioEffects.isAcousticEchoCancelerSupported()) {
|
||||||
@ -163,6 +165,7 @@ class WebRtcAudioRecord {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.audioManager = audioManager;
|
this.audioManager = audioManager;
|
||||||
this.audioSource = audioSource;
|
this.audioSource = audioSource;
|
||||||
|
this.audioFormat = audioFormat;
|
||||||
this.errorCallback = errorCallback;
|
this.errorCallback = errorCallback;
|
||||||
this.audioSamplesReadyCallback = audioSamplesReadyCallback;
|
this.audioSamplesReadyCallback = audioSamplesReadyCallback;
|
||||||
this.isAcousticEchoCancelerSupported = isAcousticEchoCancelerSupported;
|
this.isAcousticEchoCancelerSupported = isAcousticEchoCancelerSupported;
|
||||||
@ -203,7 +206,7 @@ class WebRtcAudioRecord {
|
|||||||
reportWebRtcAudioRecordInitError("InitRecording called twice without StopRecording.");
|
reportWebRtcAudioRecordInitError("InitRecording called twice without StopRecording.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
final int bytesPerFrame = channels * (BITS_PER_SAMPLE / 8);
|
final int bytesPerFrame = channels * getBytesPerSample(audioFormat);
|
||||||
final int framesPerBuffer = sampleRate / BUFFERS_PER_SECOND;
|
final int framesPerBuffer = sampleRate / BUFFERS_PER_SECOND;
|
||||||
byteBuffer = ByteBuffer.allocateDirect(bytesPerFrame * framesPerBuffer);
|
byteBuffer = ByteBuffer.allocateDirect(bytesPerFrame * framesPerBuffer);
|
||||||
if (!(byteBuffer.hasArray())) {
|
if (!(byteBuffer.hasArray())) {
|
||||||
@ -221,8 +224,7 @@ class WebRtcAudioRecord {
|
|||||||
// an AudioRecord object, in byte units.
|
// an AudioRecord object, in byte units.
|
||||||
// Note that this size doesn't guarantee a smooth recording under load.
|
// Note that this size doesn't guarantee a smooth recording under load.
|
||||||
final int channelConfig = channelCountToConfiguration(channels);
|
final int channelConfig = channelCountToConfiguration(channels);
|
||||||
int minBufferSize =
|
int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
|
||||||
AudioRecord.getMinBufferSize(sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT);
|
|
||||||
if (minBufferSize == AudioRecord.ERROR || minBufferSize == AudioRecord.ERROR_BAD_VALUE) {
|
if (minBufferSize == AudioRecord.ERROR || minBufferSize == AudioRecord.ERROR_BAD_VALUE) {
|
||||||
reportWebRtcAudioRecordInitError("AudioRecord.getMinBufferSize failed: " + minBufferSize);
|
reportWebRtcAudioRecordInitError("AudioRecord.getMinBufferSize failed: " + minBufferSize);
|
||||||
return -1;
|
return -1;
|
||||||
@ -235,8 +237,8 @@ class WebRtcAudioRecord {
|
|||||||
int bufferSizeInBytes = Math.max(BUFFER_SIZE_FACTOR * minBufferSize, byteBuffer.capacity());
|
int bufferSizeInBytes = Math.max(BUFFER_SIZE_FACTOR * minBufferSize, byteBuffer.capacity());
|
||||||
Logging.d(TAG, "bufferSizeInBytes: " + bufferSizeInBytes);
|
Logging.d(TAG, "bufferSizeInBytes: " + bufferSizeInBytes);
|
||||||
try {
|
try {
|
||||||
audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig,
|
audioRecord =
|
||||||
AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes);
|
new AudioRecord(audioSource, sampleRate, channelConfig, audioFormat, bufferSizeInBytes);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
reportWebRtcAudioRecordInitError("AudioRecord ctor error: " + e.getMessage());
|
reportWebRtcAudioRecordInitError("AudioRecord ctor error: " + e.getMessage());
|
||||||
releaseAudioResources();
|
releaseAudioResources();
|
||||||
@ -363,4 +365,23 @@ class WebRtcAudioRecord {
|
|||||||
errorCallback.onWebRtcAudioRecordError(errorMessage);
|
errorCallback.onWebRtcAudioRecordError(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reference from Android code, AudioFormat.getBytesPerSample. BitPerSample / 8
|
||||||
|
// Default audio data format is PCM 16 bits per sample.
|
||||||
|
// Guaranteed to be supported by all devices
|
||||||
|
private static int getBytesPerSample(int audioFormat) {
|
||||||
|
switch (audioFormat) {
|
||||||
|
case AudioFormat.ENCODING_PCM_8BIT:
|
||||||
|
return 1;
|
||||||
|
case AudioFormat.ENCODING_PCM_16BIT:
|
||||||
|
case AudioFormat.ENCODING_IEC61937:
|
||||||
|
case AudioFormat.ENCODING_DEFAULT:
|
||||||
|
return 2;
|
||||||
|
case AudioFormat.ENCODING_PCM_FLOAT:
|
||||||
|
return 4;
|
||||||
|
case AudioFormat.ENCODING_INVALID:
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Bad audio format " + audioFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user