Android: Simplify moved audio device module
This CL performs some simplifications and cleanups of the moved audio code. * All JNI interaction now goes from the C++ audio manager calling into the Java audio manager. The calls back from the Java code to the C++ audio manager are removed (this was related to caching audio parameters). It's simpler this way because the Java code is now unaware of the C++ layer and it will be easier to make this into a Java interface. * A bunch of state was removed that was related to caching the audio parameters. * Some unused functions from audio manager was removed. * The Java audio manager no longer depends on ContextUtils, and the context has to be passed in externally instead. This is done because we want to get rid of ContextUtils eventually. * The selection of what AudioDeviceModule to create (AAudio, OpenSLES input/output is now exposed in the interface. The reason is that client should decide and create what they need explicitly instead of setting blacklists in static global WebRTC classes. This will be more modular long term. * Selection of what audio device module to create (OpenSLES combinations) no longer requires instantiating a C++ AudioManager and is done with static enumeration methods instead. Bug: webrtc:7452 Change-Id: Iba29cf7447a1f6063abd9544d7315e10095167c8 Reviewed-on: https://webrtc-review.googlesource.com/63760 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@{#22542}
This commit is contained in:
committed by
Commit Bot
parent
2955d82eca
commit
32362a6729
@ -62,8 +62,12 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
NUM_STATUSES = 4
|
||||
};
|
||||
|
||||
explicit AudioDeviceTemplateAndroid(AudioDeviceModule::AudioLayer audio_layer)
|
||||
: audio_layer_(audio_layer), initialized_(false) {
|
||||
AudioDeviceTemplateAndroid(JNIEnv* env,
|
||||
const JavaParamRef<jobject>& application_context,
|
||||
AudioDeviceModule::AudioLayer audio_layer)
|
||||
: audio_layer_(audio_layer),
|
||||
audio_manager_(env, audio_layer, application_context),
|
||||
initialized_(false) {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
thread_checker_.DetachFromThread();
|
||||
}
|
||||
@ -85,24 +89,22 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
int32_t Init() override {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
audio_manager_ = rtc::MakeUnique<AudioManager>();
|
||||
output_ = rtc::MakeUnique<OutputType>(audio_manager_.get());
|
||||
input_ = rtc::MakeUnique<InputType>(audio_manager_.get());
|
||||
audio_manager_->SetActiveAudioLayer(audio_layer_);
|
||||
output_ = rtc::MakeUnique<OutputType>(&audio_manager_);
|
||||
input_ = rtc::MakeUnique<InputType>(&audio_manager_);
|
||||
audio_device_buffer_ = rtc::MakeUnique<AudioDeviceBuffer>();
|
||||
AttachAudioBuffer();
|
||||
if (initialized_) {
|
||||
return 0;
|
||||
}
|
||||
InitStatus status;
|
||||
if (!audio_manager_->Init()) {
|
||||
if (!audio_manager_.Init()) {
|
||||
status = InitStatus::OTHER_ERROR;
|
||||
} else if (output_->Init() != 0) {
|
||||
audio_manager_->Close();
|
||||
audio_manager_.Close();
|
||||
status = InitStatus::PLAYOUT_ERROR;
|
||||
} else if (input_->Init() != 0) {
|
||||
output_->Terminate();
|
||||
audio_manager_->Close();
|
||||
audio_manager_.Close();
|
||||
status = InitStatus::RECORDING_ERROR;
|
||||
} else {
|
||||
initialized_ = true;
|
||||
@ -125,7 +127,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
int32_t err = input_->Terminate();
|
||||
err |= output_->Terminate();
|
||||
err |= !audio_manager_->Close();
|
||||
err |= !audio_manager_.Close();
|
||||
initialized_ = false;
|
||||
RTC_DCHECK_EQ(err, 0);
|
||||
return err;
|
||||
@ -248,7 +250,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
return 0;
|
||||
}
|
||||
audio_device_buffer_->StartPlayout();
|
||||
if (!audio_manager_->IsCommunicationModeEnabled()) {
|
||||
if (!audio_manager_.IsCommunicationModeEnabled()) {
|
||||
RTC_LOG(WARNING)
|
||||
<< "The application should use MODE_IN_COMMUNICATION audio mode!";
|
||||
}
|
||||
@ -286,7 +288,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
if (Recording()) {
|
||||
return 0;
|
||||
}
|
||||
if (!audio_manager_->IsCommunicationModeEnabled()) {
|
||||
if (!audio_manager_.IsCommunicationModeEnabled()) {
|
||||
RTC_LOG(WARNING)
|
||||
<< "The application should use MODE_IN_COMMUNICATION audio mode!";
|
||||
}
|
||||
@ -471,7 +473,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
int32_t StereoPlayoutIsAvailable(bool* available) const override {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
CHECKinitialized_();
|
||||
*available = audio_manager_->IsStereoPlayoutSupported();
|
||||
*available = audio_manager_.IsStereoPlayoutSupported();
|
||||
RTC_LOG(INFO) << "output: " << *available;
|
||||
return 0;
|
||||
}
|
||||
@ -483,7 +485,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
RTC_LOG(WARNING) << "recording in stereo is not supported";
|
||||
return -1;
|
||||
}
|
||||
bool available = audio_manager_->IsStereoPlayoutSupported();
|
||||
bool available = audio_manager_.IsStereoPlayoutSupported();
|
||||
// Android does not support changes between mono and stero on the fly.
|
||||
// Instead, the native audio layer is configured via the audio manager
|
||||
// to either support mono or stereo. It is allowed to call this method
|
||||
@ -503,7 +505,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
int32_t StereoPlayout(bool* enabled) const override {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
CHECKinitialized_();
|
||||
*enabled = audio_manager_->IsStereoPlayoutSupported();
|
||||
*enabled = audio_manager_.IsStereoPlayoutSupported();
|
||||
RTC_LOG(INFO) << "output: " << *enabled;
|
||||
return 0;
|
||||
}
|
||||
@ -512,7 +514,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
CHECKinitialized_();
|
||||
bool isAvailable = false;
|
||||
if (audio_manager_->IsStereoRecordSupported() == -1) {
|
||||
if (audio_manager_.IsStereoRecordSupported() == -1) {
|
||||
return -1;
|
||||
}
|
||||
*available = isAvailable;
|
||||
@ -527,7 +529,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
RTC_LOG(WARNING) << "recording in stereo is not supported";
|
||||
return -1;
|
||||
}
|
||||
bool available = audio_manager_->IsStereoRecordSupported();
|
||||
bool available = audio_manager_.IsStereoRecordSupported();
|
||||
// Android does not support changes between mono and stero on the fly.
|
||||
// Instead, the native audio layer is configured via the audio manager
|
||||
// to either support mono or stereo. It is allowed to call this method
|
||||
@ -547,7 +549,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
int32_t StereoRecording(bool* enabled) const override {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
CHECKinitialized_();
|
||||
*enabled = audio_manager_->IsStereoRecordSupported();
|
||||
*enabled = audio_manager_.IsStereoRecordSupported();
|
||||
RTC_LOG(INFO) << "output: " << *enabled;
|
||||
return 0;
|
||||
}
|
||||
@ -555,7 +557,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
int32_t PlayoutDelay(uint16_t* delay_ms) const override {
|
||||
CHECKinitialized_();
|
||||
// Best guess we can do is to use half of the estimated total delay.
|
||||
*delay_ms = audio_manager_->GetDelayEstimateInMilliseconds() / 2;
|
||||
*delay_ms = audio_manager_.GetDelayEstimateInMilliseconds() / 2;
|
||||
RTC_DCHECK_GT(*delay_ms, 0);
|
||||
return 0;
|
||||
}
|
||||
@ -575,7 +577,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
bool BuiltInAECIsAvailable() const override {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
CHECKinitialized__BOOL();
|
||||
bool isAvailable = audio_manager_->IsAcousticEchoCancelerSupported();
|
||||
bool isAvailable = audio_manager_.IsAcousticEchoCancelerSupported();
|
||||
RTC_LOG(INFO) << "output: " << isAvailable;
|
||||
return isAvailable;
|
||||
}
|
||||
@ -587,7 +589,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
bool BuiltInAGCIsAvailable() const override {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
CHECKinitialized__BOOL();
|
||||
bool isAvailable = audio_manager_->IsAutomaticGainControlSupported();
|
||||
bool isAvailable = false;
|
||||
RTC_LOG(INFO) << "output: " << isAvailable;
|
||||
return isAvailable;
|
||||
}
|
||||
@ -599,7 +601,7 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
bool BuiltInNSIsAvailable() const override {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
CHECKinitialized__BOOL();
|
||||
bool isAvailable = audio_manager_->IsNoiseSuppressorSupported();
|
||||
bool isAvailable = audio_manager_.IsNoiseSuppressorSupported();
|
||||
RTC_LOG(INFO) << "output: " << isAvailable;
|
||||
return isAvailable;
|
||||
}
|
||||
@ -634,11 +636,6 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
return result;
|
||||
}
|
||||
|
||||
AudioDeviceModule::AudioLayer PlatformAudioLayer() const {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
return audio_layer_;
|
||||
}
|
||||
|
||||
int32_t AttachAudioBuffer() {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
output_->AttachAudioBuffer(audio_device_buffer_.get());
|
||||
@ -646,16 +643,12 @@ class AudioDeviceTemplateAndroid : public AudioDeviceModule {
|
||||
return 0;
|
||||
}
|
||||
|
||||
AudioDeviceBuffer* GetAudioDeviceBuffer() {
|
||||
return audio_device_buffer_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
|
||||
AudioDeviceModule::AudioLayer audio_layer_;
|
||||
const AudioDeviceModule::AudioLayer audio_layer_;
|
||||
|
||||
std::unique_ptr<AudioManager> audio_manager_;
|
||||
AudioManager audio_manager_;
|
||||
std::unique_ptr<OutputType> output_;
|
||||
std::unique_ptr<InputType> input_;
|
||||
std::unique_ptr<AudioDeviceBuffer> audio_device_buffer_;
|
||||
|
||||
@ -16,61 +16,111 @@
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/platform_thread.h"
|
||||
#include "rtc_base/ptr_util.h"
|
||||
#include "rtc_base/refcount.h"
|
||||
#include "rtc_base/refcountedobject.h"
|
||||
|
||||
#include "sdk/android/generated_audio_jni/jni/WebRtcAudioManager_jni.h"
|
||||
#include "sdk/android/src/jni/audio_device/audio_common.h"
|
||||
#include "sdk/android/src/jni/jni_helpers.h"
|
||||
|
||||
#if defined(AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
|
||||
#include "sdk/android/src/jni/audio_device/aaudio_player.h"
|
||||
#include "sdk/android/src/jni/audio_device/aaudio_recorder.h"
|
||||
#endif
|
||||
#include "sdk/android/src/jni/audio_device/audio_device_template_android.h"
|
||||
#include "sdk/android/src/jni/audio_device/audio_manager.h"
|
||||
#include "sdk/android/src/jni/audio_device/audio_record_jni.h"
|
||||
#include "sdk/android/src/jni/audio_device/audio_track_jni.h"
|
||||
#include "sdk/android/src/jni/audio_device/opensles_player.h"
|
||||
#include "sdk/android/src/jni/audio_device/opensles_recorder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace android_adm {
|
||||
|
||||
// AudioManager::JavaAudioManager implementation
|
||||
AudioManager::JavaAudioManager::JavaAudioManager(
|
||||
const ScopedJavaLocalRef<jobject>& audio_manager)
|
||||
: env_(audio_manager.env()), audio_manager_(audio_manager) {
|
||||
RTC_LOG(INFO) << "JavaAudioManager::ctor";
|
||||
#if defined(AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
|
||||
rtc::scoped_refptr<AudioDeviceModule>
|
||||
AudioManager::CreateAAudioAudioDeviceModule(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& application_context) {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
return new rtc::RefCountedObject<android_adm::AudioDeviceTemplateAndroid<
|
||||
android_adm::AAudioRecorder, android_adm::AAudioPlayer>>(
|
||||
env, AudioDeviceModule::kAndroidAAudioAudio);
|
||||
}
|
||||
#endif
|
||||
|
||||
rtc::scoped_refptr<AudioDeviceModule> AudioManager::CreateAudioDeviceModule(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& application_context) {
|
||||
const bool use_opensles_output =
|
||||
!Java_WebRtcAudioManager_isDeviceBlacklistedForOpenSLESUsage(env) &&
|
||||
Java_WebRtcAudioManager_isLowLatencyOutputSupported(env,
|
||||
application_context);
|
||||
const bool use_opensles_input =
|
||||
use_opensles_output && Java_WebRtcAudioManager_isLowLatencyInputSupported(
|
||||
env, application_context);
|
||||
return CreateAudioDeviceModule(env, application_context, use_opensles_input,
|
||||
use_opensles_output);
|
||||
}
|
||||
|
||||
AudioManager::JavaAudioManager::~JavaAudioManager() {
|
||||
RTC_LOG(INFO) << "JavaAudioManager::~dtor";
|
||||
}
|
||||
rtc::scoped_refptr<AudioDeviceModule> AudioManager::CreateAudioDeviceModule(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& application_context,
|
||||
bool use_opensles_input,
|
||||
bool use_opensles_output) {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
|
||||
bool AudioManager::JavaAudioManager::Init() {
|
||||
thread_checker_.CalledOnValidThread();
|
||||
return Java_WebRtcAudioManager_init(env_, audio_manager_);
|
||||
}
|
||||
|
||||
void AudioManager::JavaAudioManager::Close() {
|
||||
thread_checker_.CalledOnValidThread();
|
||||
Java_WebRtcAudioManager_dispose(env_, audio_manager_);
|
||||
}
|
||||
|
||||
bool AudioManager::JavaAudioManager::IsCommunicationModeEnabled() {
|
||||
thread_checker_.CalledOnValidThread();
|
||||
return Java_WebRtcAudioManager_isCommunicationModeEnabled(env_,
|
||||
audio_manager_);
|
||||
}
|
||||
|
||||
bool AudioManager::JavaAudioManager::IsDeviceBlacklistedForOpenSLESUsage() {
|
||||
thread_checker_.CalledOnValidThread();
|
||||
return Java_WebRtcAudioManager_isDeviceBlacklistedForOpenSLESUsage(
|
||||
env_, audio_manager_);
|
||||
if (use_opensles_output) {
|
||||
if (use_opensles_input) {
|
||||
// Use OpenSL ES for both playout and recording.
|
||||
return new rtc::RefCountedObject<android_adm::AudioDeviceTemplateAndroid<
|
||||
android_adm::OpenSLESRecorder, android_adm::OpenSLESPlayer>>(
|
||||
env, application_context, AudioDeviceModule::kAndroidOpenSLESAudio);
|
||||
} else {
|
||||
// Use OpenSL ES for output and AudioRecord API for input. This
|
||||
// combination provides low-latency output audio and at the same
|
||||
// time support for HW AEC using the AudioRecord Java API.
|
||||
return new rtc::RefCountedObject<android_adm::AudioDeviceTemplateAndroid<
|
||||
android_adm::AudioRecordJni, android_adm::OpenSLESPlayer>>(
|
||||
env, application_context,
|
||||
AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio);
|
||||
}
|
||||
} else {
|
||||
RTC_DCHECK(!use_opensles_input)
|
||||
<< "Combination of OpenSLES input and Java-based output not supported";
|
||||
// Use Java-based audio in both directions.
|
||||
return new rtc::RefCountedObject<android_adm::AudioDeviceTemplateAndroid<
|
||||
android_adm::AudioRecordJni, android_adm::AudioTrackJni>>(
|
||||
env, application_context, AudioDeviceModule::kAndroidJavaAudio);
|
||||
}
|
||||
}
|
||||
|
||||
// AudioManager implementation
|
||||
AudioManager::AudioManager()
|
||||
: audio_layer_(AudioDeviceModule::kPlatformDefaultAudio),
|
||||
initialized_(false),
|
||||
hardware_aec_(false),
|
||||
hardware_agc_(false),
|
||||
hardware_ns_(false),
|
||||
low_latency_playout_(false),
|
||||
low_latency_record_(false),
|
||||
delay_estimate_in_milliseconds_(0) {
|
||||
AudioManager::AudioManager(JNIEnv* env,
|
||||
AudioDeviceModule::AudioLayer audio_layer,
|
||||
const JavaParamRef<jobject>& application_context)
|
||||
: j_audio_manager_(
|
||||
Java_WebRtcAudioManager_Constructor(env, application_context)),
|
||||
audio_layer_(audio_layer),
|
||||
initialized_(false) {
|
||||
RTC_LOG(INFO) << "ctor";
|
||||
j_audio_manager_.reset(
|
||||
new JavaAudioManager(Java_WebRtcAudioManager_Constructor(
|
||||
AttachCurrentThreadIfNeeded(), jni::jlongFromPointer(this))));
|
||||
const int sample_rate =
|
||||
Java_WebRtcAudioManager_getSampleRate(env, j_audio_manager_);
|
||||
const size_t output_channels =
|
||||
Java_WebRtcAudioManager_getStereoOutput(env, j_audio_manager_) ? 2 : 1;
|
||||
const size_t input_channels =
|
||||
Java_WebRtcAudioManager_getStereoInput(env, j_audio_manager_) ? 2 : 1;
|
||||
const size_t output_buffer_size =
|
||||
Java_WebRtcAudioManager_getOutputBufferSize(env, j_audio_manager_);
|
||||
const size_t input_buffer_size =
|
||||
Java_WebRtcAudioManager_getInputBufferSize(env, j_audio_manager_);
|
||||
playout_parameters_.reset(sample_rate, static_cast<size_t>(output_channels),
|
||||
static_cast<size_t>(output_buffer_size));
|
||||
record_parameters_.reset(sample_rate, static_cast<size_t>(input_channels),
|
||||
static_cast<size_t>(input_buffer_size));
|
||||
thread_checker_.DetachFromThread();
|
||||
}
|
||||
|
||||
AudioManager::~AudioManager() {
|
||||
@ -79,25 +129,6 @@ AudioManager::~AudioManager() {
|
||||
Close();
|
||||
}
|
||||
|
||||
void AudioManager::SetActiveAudioLayer(
|
||||
AudioDeviceModule::AudioLayer audio_layer) {
|
||||
RTC_LOG(INFO) << "SetActiveAudioLayer: " << audio_layer;
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(!initialized_);
|
||||
// Store the currently utilized audio layer.
|
||||
audio_layer_ = audio_layer;
|
||||
// The delay estimate can take one of two fixed values depending on if the
|
||||
// device supports low-latency output or not. However, it is also possible
|
||||
// that the user explicitly selects the high-latency audio path, hence we use
|
||||
// the selected |audio_layer| here to set the delay estimate.
|
||||
delay_estimate_in_milliseconds_ =
|
||||
(audio_layer == AudioDeviceModule::kAndroidJavaAudio)
|
||||
? kHighLatencyModeDelayEstimateInMilliseconds
|
||||
: kLowLatencyModeDelayEstimateInMilliseconds;
|
||||
RTC_LOG(INFO) << "delay_estimate_in_milliseconds: "
|
||||
<< delay_estimate_in_milliseconds_;
|
||||
}
|
||||
|
||||
SLObjectItf AudioManager::GetOpenSLEngine() {
|
||||
RTC_LOG(INFO) << "GetOpenSLEngine";
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
@ -144,7 +175,8 @@ bool AudioManager::Init() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(!initialized_);
|
||||
RTC_DCHECK_NE(audio_layer_, AudioDeviceModule::kPlatformDefaultAudio);
|
||||
if (!j_audio_manager_->Init()) {
|
||||
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
||||
if (!Java_WebRtcAudioManager_init(env, j_audio_manager_)) {
|
||||
RTC_LOG(LS_ERROR) << "Init() failed";
|
||||
return false;
|
||||
}
|
||||
@ -157,60 +189,31 @@ bool AudioManager::Close() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
if (!initialized_)
|
||||
return true;
|
||||
j_audio_manager_->Close();
|
||||
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
||||
Java_WebRtcAudioManager_dispose(env, j_audio_manager_);
|
||||
initialized_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioManager::IsCommunicationModeEnabled() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return j_audio_manager_->IsCommunicationModeEnabled();
|
||||
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
||||
return Java_WebRtcAudioManager_isCommunicationModeEnabled(env,
|
||||
j_audio_manager_);
|
||||
}
|
||||
|
||||
bool AudioManager::IsAcousticEchoCancelerSupported() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return hardware_aec_;
|
||||
}
|
||||
|
||||
bool AudioManager::IsAutomaticGainControlSupported() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return hardware_agc_;
|
||||
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
||||
return Java_WebRtcAudioManager_isAcousticEchoCancelerSupported(
|
||||
env, j_audio_manager_);
|
||||
}
|
||||
|
||||
bool AudioManager::IsNoiseSuppressorSupported() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return hardware_ns_;
|
||||
}
|
||||
|
||||
bool AudioManager::IsLowLatencyPlayoutSupported() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
// Some devices are blacklisted for usage of OpenSL ES even if they report
|
||||
// that low-latency playout is supported. See b/21485703 for details.
|
||||
return j_audio_manager_->IsDeviceBlacklistedForOpenSLESUsage()
|
||||
? false
|
||||
: low_latency_playout_;
|
||||
}
|
||||
|
||||
bool AudioManager::IsLowLatencyRecordSupported() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
return low_latency_record_;
|
||||
}
|
||||
|
||||
bool AudioManager::IsProAudioSupported() const {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
// TODO(henrika): return the state independently of if OpenSL ES is
|
||||
// blacklisted or not for now. We could use the same approach as in
|
||||
// IsLowLatencyPlayoutSupported() but I can't see the need for it yet.
|
||||
return pro_audio_;
|
||||
}
|
||||
|
||||
// TODO(henrika): improve comments...
|
||||
bool AudioManager::IsAAudioSupported() const {
|
||||
#if defined(AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
|
||||
return a_audio_;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
JNIEnv* env = AttachCurrentThreadIfNeeded();
|
||||
return Java_WebRtcAudioManager_isNoiseSuppressorSupported(env,
|
||||
j_audio_manager_);
|
||||
}
|
||||
|
||||
bool AudioManager::IsStereoPlayoutSupported() const {
|
||||
@ -224,49 +227,9 @@ bool AudioManager::IsStereoRecordSupported() const {
|
||||
}
|
||||
|
||||
int AudioManager::GetDelayEstimateInMilliseconds() const {
|
||||
return delay_estimate_in_milliseconds_;
|
||||
}
|
||||
|
||||
void AudioManager::CacheAudioParameters(JNIEnv* env,
|
||||
const JavaParamRef<jobject>& j_caller,
|
||||
jint sample_rate,
|
||||
jint output_channels,
|
||||
jint input_channels,
|
||||
jboolean hardware_aec,
|
||||
jboolean hardware_agc,
|
||||
jboolean hardware_ns,
|
||||
jboolean low_latency_output,
|
||||
jboolean low_latency_input,
|
||||
jboolean pro_audio,
|
||||
jboolean a_audio,
|
||||
jint output_buffer_size,
|
||||
jint input_buffer_size) {
|
||||
RTC_LOG(INFO)
|
||||
<< "OnCacheAudioParameters: "
|
||||
<< "hardware_aec: " << static_cast<bool>(hardware_aec)
|
||||
<< ", hardware_agc: " << static_cast<bool>(hardware_agc)
|
||||
<< ", hardware_ns: " << static_cast<bool>(hardware_ns)
|
||||
<< ", low_latency_output: " << static_cast<bool>(low_latency_output)
|
||||
<< ", low_latency_input: " << static_cast<bool>(low_latency_input)
|
||||
<< ", pro_audio: " << static_cast<bool>(pro_audio)
|
||||
<< ", a_audio: " << static_cast<bool>(a_audio)
|
||||
<< ", sample_rate: " << static_cast<int>(sample_rate)
|
||||
<< ", output_channels: " << static_cast<int>(output_channels)
|
||||
<< ", input_channels: " << static_cast<int>(input_channels)
|
||||
<< ", output_buffer_size: " << static_cast<int>(output_buffer_size)
|
||||
<< ", input_buffer_size: " << static_cast<int>(input_buffer_size);
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
hardware_aec_ = hardware_aec;
|
||||
hardware_agc_ = hardware_agc;
|
||||
hardware_ns_ = hardware_ns;
|
||||
low_latency_playout_ = low_latency_output;
|
||||
low_latency_record_ = low_latency_input;
|
||||
pro_audio_ = pro_audio;
|
||||
a_audio_ = a_audio;
|
||||
playout_parameters_.reset(sample_rate, static_cast<size_t>(output_channels),
|
||||
static_cast<size_t>(output_buffer_size));
|
||||
record_parameters_.reset(sample_rate, static_cast<size_t>(input_channels),
|
||||
static_cast<size_t>(input_buffer_size));
|
||||
return audio_layer_ == AudioDeviceModule::kAndroidJavaAudio
|
||||
? kHighLatencyModeDelayEstimateInMilliseconds
|
||||
: kLowLatencyModeDelayEstimateInMilliseconds;
|
||||
}
|
||||
|
||||
const AudioParameters& AudioManager::GetPlayoutAudioParameters() {
|
||||
|
||||
@ -30,37 +30,32 @@ namespace android_adm {
|
||||
// relies on the AudioManager in android.media. It also populates an
|
||||
// AudioParameter structure with native audio parameters detected at
|
||||
// construction. This class does not make any audio-related modifications
|
||||
// unless Init() is called. Caching audio parameters makes no changes but only
|
||||
// reads data from the Java side.
|
||||
// unless Init() is called.
|
||||
class AudioManager {
|
||||
public:
|
||||
// Wraps the Java specific parts of the AudioManager into one helper class.
|
||||
// Stores method IDs for all supported methods at construction and then
|
||||
// allows calls like JavaAudioManager::Close() while hiding the Java/JNI
|
||||
// parts that are associated with this call.
|
||||
class JavaAudioManager {
|
||||
public:
|
||||
explicit JavaAudioManager(const ScopedJavaLocalRef<jobject>& audio_manager);
|
||||
~JavaAudioManager();
|
||||
#if defined(AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
|
||||
static rtc::scoped_refptr<AudioDeviceModule> CreateAAudioAudioDeviceModule(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& application_context);
|
||||
#endif
|
||||
|
||||
bool Init();
|
||||
void Close();
|
||||
bool IsCommunicationModeEnabled();
|
||||
bool IsDeviceBlacklistedForOpenSLESUsage();
|
||||
static rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceModule(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& application_context,
|
||||
bool use_opensles_input,
|
||||
bool use_opensles_output);
|
||||
|
||||
private:
|
||||
JNIEnv* const env_;
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
ScopedJavaGlobalRef<jobject> audio_manager_;
|
||||
};
|
||||
// This function has internal logic checking if OpenSLES is blacklisted and
|
||||
// whether it's supported.
|
||||
static rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceModule(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& application_context);
|
||||
|
||||
AudioManager();
|
||||
AudioManager(JNIEnv* env,
|
||||
AudioDeviceModule::AudioLayer audio_layer,
|
||||
const JavaParamRef<jobject>& application_context);
|
||||
~AudioManager();
|
||||
|
||||
// Sets the currently active audio layer combination. Must be called before
|
||||
// Init().
|
||||
void SetActiveAudioLayer(AudioDeviceModule::AudioLayer audio_layer);
|
||||
|
||||
// Creates and realizes the main (global) Open SL engine object and returns
|
||||
// a reference to it. The engine object is only created at the first call
|
||||
// since OpenSL ES for Android only supports a single engine per application.
|
||||
@ -91,14 +86,8 @@ class AudioManager {
|
||||
// Can currently only be used in combination with a Java based audio backend
|
||||
// for the recoring side (i.e. using the android.media.AudioRecord API).
|
||||
bool IsAcousticEchoCancelerSupported() const;
|
||||
bool IsAutomaticGainControlSupported() const;
|
||||
bool IsNoiseSuppressorSupported() const;
|
||||
|
||||
// Returns true if the device supports the low-latency audio paths in
|
||||
// combination with OpenSL ES.
|
||||
bool IsLowLatencyPlayoutSupported() const;
|
||||
bool IsLowLatencyRecordSupported() const;
|
||||
|
||||
// Returns true if the device supports (and has been configured for) stereo.
|
||||
// Call the Java API WebRtcAudioManager.setStereoOutput/Input() with true as
|
||||
// paramter to enable stereo. Default is mono in both directions and the
|
||||
@ -107,49 +96,23 @@ class AudioManager {
|
||||
bool IsStereoPlayoutSupported() const;
|
||||
bool IsStereoRecordSupported() const;
|
||||
|
||||
// Returns true if the device supports pro-audio features in combination with
|
||||
// OpenSL ES.
|
||||
bool IsProAudioSupported() const;
|
||||
|
||||
// Returns true if the device supports AAudio.
|
||||
bool IsAAudioSupported() const;
|
||||
|
||||
// Returns the estimated total delay of this device. Unit is in milliseconds.
|
||||
// The vaule is set once at construction and never changes after that.
|
||||
// Possible values are webrtc::kLowLatencyModeDelayEstimateInMilliseconds and
|
||||
// webrtc::kHighLatencyModeDelayEstimateInMilliseconds.
|
||||
int GetDelayEstimateInMilliseconds() const;
|
||||
|
||||
// Called from Java side so we can cache the native audio parameters.
|
||||
// This method will be called by the WebRtcAudioManager constructor, i.e.
|
||||
// on the same thread that this object is created on.
|
||||
void CacheAudioParameters(JNIEnv* env,
|
||||
const JavaParamRef<jobject>& j_caller,
|
||||
jint sample_rate,
|
||||
jint output_channels,
|
||||
jint input_channels,
|
||||
jboolean hardware_aec,
|
||||
jboolean hardware_agc,
|
||||
jboolean hardware_ns,
|
||||
jboolean low_latency_output,
|
||||
jboolean low_latency_input,
|
||||
jboolean pro_audio,
|
||||
jboolean a_audio,
|
||||
jint output_buffer_size,
|
||||
jint input_buffer_size);
|
||||
|
||||
private:
|
||||
// Stores thread ID in the constructor.
|
||||
// We can then use ThreadChecker::CalledOnValidThread() to ensure that
|
||||
// other methods are called from the same thread.
|
||||
// This class is single threaded except that construction might happen on a
|
||||
// different thread.
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
|
||||
// Wraps the Java specific parts of the AudioManager.
|
||||
std::unique_ptr<AudioManager::JavaAudioManager> j_audio_manager_;
|
||||
ScopedJavaGlobalRef<jobject> j_audio_manager_;
|
||||
|
||||
// Contains the selected audio layer specified by the AudioLayer enumerator
|
||||
// in the AudioDeviceModule class.
|
||||
AudioDeviceModule::AudioLayer audio_layer_;
|
||||
const AudioDeviceModule::AudioLayer audio_layer_;
|
||||
|
||||
// This object is the global entry point of the OpenSL ES API.
|
||||
// After creating the engine object, the application can obtain this object‘s
|
||||
@ -161,32 +124,8 @@ class AudioManager {
|
||||
// Set to true by Init() and false by Close().
|
||||
bool initialized_;
|
||||
|
||||
// True if device supports hardware (or built-in) AEC.
|
||||
bool hardware_aec_;
|
||||
// True if device supports hardware (or built-in) AGC.
|
||||
bool hardware_agc_;
|
||||
// True if device supports hardware (or built-in) NS.
|
||||
bool hardware_ns_;
|
||||
|
||||
// True if device supports the low-latency OpenSL ES audio path for output.
|
||||
bool low_latency_playout_;
|
||||
|
||||
// True if device supports the low-latency OpenSL ES audio path for input.
|
||||
bool low_latency_record_;
|
||||
|
||||
// True if device supports the low-latency OpenSL ES pro-audio path.
|
||||
bool pro_audio_;
|
||||
|
||||
// True if device supports the low-latency AAudio audio path.
|
||||
bool a_audio_;
|
||||
|
||||
// The delay estimate can take one of two fixed values depending on if the
|
||||
// device supports low-latency output or not.
|
||||
int delay_estimate_in_milliseconds_;
|
||||
|
||||
// Contains native parameters (e.g. sample rate, channel configuration).
|
||||
// Set at construction in OnCacheAudioParameters() which is called from
|
||||
// Java on the same thread as this object is created on.
|
||||
// Contains native parameters (e.g. sample rate, channel configuration). Set
|
||||
// at construction.
|
||||
AudioParameters playout_parameters_;
|
||||
AudioParameters record_parameters_;
|
||||
};
|
||||
|
||||
@ -26,8 +26,8 @@
|
||||
#include "rtc_base/stringutils.h"
|
||||
#include "rtc_base/thread.h"
|
||||
#include "sdk/android/generated_peerconnection_jni/jni/PeerConnectionFactory_jni.h"
|
||||
#include "sdk/android/native_api/audio_device_module/audio_device_android.h"
|
||||
#include "sdk/android/native_api/jni/java_types.h"
|
||||
#include "sdk/android/src/jni/audio_device/audio_manager.h"
|
||||
#include "sdk/android/src/jni/jni_helpers.h"
|
||||
#include "sdk/android/src/jni/pc/androidnetworkmonitor.h"
|
||||
#include "sdk/android/src/jni/pc/audio.h"
|
||||
@ -102,7 +102,6 @@ void PeerConnectionFactorySignalingThreadReady() {
|
||||
static void JNI_PeerConnectionFactory_InitializeAndroidGlobals(
|
||||
JNIEnv* jni,
|
||||
const JavaParamRef<jclass>&,
|
||||
const JavaParamRef<jobject>& context,
|
||||
jboolean video_hw_acceleration) {
|
||||
video_hw_acceleration_enabled = video_hw_acceleration;
|
||||
if (!factory_static_initialized) {
|
||||
@ -173,6 +172,7 @@ static void JNI_PeerConnectionFactory_ShutdownInternalTracer(
|
||||
|
||||
jlong CreatePeerConnectionFactoryForJava(
|
||||
JNIEnv* jni,
|
||||
const JavaParamRef<jobject>& jcontext,
|
||||
const JavaParamRef<jobject>& joptions,
|
||||
const JavaParamRef<jobject>& jencoder_factory,
|
||||
const JavaParamRef<jobject>& jdecoder_factory,
|
||||
@ -217,7 +217,7 @@ jlong CreatePeerConnectionFactoryForJava(
|
||||
|
||||
rtc::scoped_refptr<AudioDeviceModule> adm =
|
||||
field_trial::IsEnabled(kExternalAndroidAudioDeviceFieldTrialName)
|
||||
? CreateAndroidAudioDeviceModule()
|
||||
? android_adm::AudioManager::CreateAudioDeviceModule(jni, jcontext)
|
||||
: nullptr;
|
||||
rtc::scoped_refptr<AudioMixer> audio_mixer = nullptr;
|
||||
std::unique_ptr<CallFactoryInterface> call_factory(CreateCallFactory());
|
||||
@ -295,6 +295,7 @@ jlong CreatePeerConnectionFactoryForJava(
|
||||
static jlong JNI_PeerConnectionFactory_CreatePeerConnectionFactory(
|
||||
JNIEnv* jni,
|
||||
const JavaParamRef<jclass>&,
|
||||
const JavaParamRef<jobject>& jcontext,
|
||||
const JavaParamRef<jobject>& joptions,
|
||||
const JavaParamRef<jobject>& jencoder_factory,
|
||||
const JavaParamRef<jobject>& jdecoder_factory,
|
||||
@ -306,7 +307,7 @@ static jlong JNI_PeerConnectionFactory_CreatePeerConnectionFactory(
|
||||
reinterpret_cast<FecControllerFactoryInterface*>(
|
||||
native_fec_controller_factory));
|
||||
return CreatePeerConnectionFactoryForJava(
|
||||
jni, joptions, jencoder_factory, jdecoder_factory,
|
||||
jni, jcontext, joptions, jencoder_factory, jdecoder_factory,
|
||||
audio_processor ? audio_processor : CreateAudioProcessing(),
|
||||
std::move(fec_controller_factory));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user