diff --git a/sdk/android/native_api/audio_device_module/audio_device_android.cc b/sdk/android/native_api/audio_device_module/audio_device_android.cc index 2649aa7217..93407f5427 100644 --- a/sdk/android/native_api/audio_device_module/audio_device_android.cc +++ b/sdk/android/native_api/audio_device_module/audio_device_android.cc @@ -28,59 +28,72 @@ namespace webrtc { -namespace { - -// This template function takes care of some boiler plate. -template -rtc::scoped_refptr CreateAudioDeviceModuleTemplate( - AudioDeviceModule::AudioLayer audio_layer, - JNIEnv* env, - jobject application_context) { - auto audio_manager = rtc::MakeUnique( - env, audio_layer, JavaParamRef(application_context)); - auto audio_input = rtc::MakeUnique(audio_manager.get()); - auto audio_output = rtc::MakeUnique(audio_manager.get()); - return CreateAudioDeviceModuleFromInputAndOutput( - audio_layer, std::move(audio_manager), std::move(audio_input), - std::move(audio_output)); -} - -} // namespace - #if defined(AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO) rtc::scoped_refptr CreateAAudioAudioDeviceModule( JNIEnv* env, jobject application_context) { RTC_LOG(INFO) << __FUNCTION__; - return CreateAudioDeviceModuleTemplate( - AudioDeviceModule::kAndroidAAudioAudio, env, application_context); + const AudioDeviceModule::AudioLayer audio_layer = + AudioDeviceModule::kAndroidAAudioAudio; + auto audio_manager = rtc::MakeUnique( + env, audio_layer, JavaParamRef(application_context)); + auto audio_input = + rtc::MakeUnique(audio_manager.get()); + auto audio_output = + rtc::MakeUnique(audio_manager.get()); + return CreateAudioDeviceModuleFromInputAndOutput( + audio_layer, std::move(audio_manager), std::move(audio_input), + std::move(audio_output)); } #endif rtc::scoped_refptr CreateJavaAudioDeviceModule( JNIEnv* env, jobject application_context) { - return CreateAudioDeviceModuleTemplate( - AudioDeviceModule::kAndroidJavaAudio, env, application_context); + const AudioDeviceModule::AudioLayer audio_layer = + AudioDeviceModule::kAndroidJavaAudio; + auto audio_manager = rtc::MakeUnique( + env, audio_layer, JavaParamRef(application_context)); + auto audio_input = + rtc::MakeUnique(audio_manager.get()); + auto audio_output = + rtc::MakeUnique(audio_manager.get()); + return CreateAudioDeviceModuleFromInputAndOutput( + audio_layer, std::move(audio_manager), std::move(audio_input), + std::move(audio_output)); } rtc::scoped_refptr CreateOpenSLESAudioDeviceModule( JNIEnv* env, jobject application_context) { - return CreateAudioDeviceModuleTemplate( - AudioDeviceModule::kAndroidJavaAudio, env, application_context); + const AudioDeviceModule::AudioLayer audio_layer = + AudioDeviceModule::kAndroidOpenSLESAudio; + auto engine_manager = rtc::MakeUnique(); + auto audio_manager = rtc::MakeUnique( + env, audio_layer, JavaParamRef(application_context)); + auto audio_input = rtc::MakeUnique( + audio_manager.get(), engine_manager.get()); + auto audio_output = rtc::MakeUnique( + audio_manager.get(), std::move(engine_manager)); + return CreateAudioDeviceModuleFromInputAndOutput( + audio_layer, std::move(audio_manager), std::move(audio_input), + std::move(audio_output)); } rtc::scoped_refptr CreateJavaInputAndOpenSLESOutputAudioDeviceModule(JNIEnv* env, jobject application_context) { - return CreateAudioDeviceModuleTemplate( - AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio, env, - application_context); + const AudioDeviceModule::AudioLayer audio_layer = + AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio; + auto audio_manager = rtc::MakeUnique( + env, audio_layer, JavaParamRef(application_context)); + auto audio_input = + rtc::MakeUnique(audio_manager.get()); + auto audio_output = rtc::MakeUnique( + audio_manager.get(), rtc::MakeUnique()); + return CreateAudioDeviceModuleFromInputAndOutput( + audio_layer, std::move(audio_manager), std::move(audio_input), + std::move(audio_output)); } } // namespace webrtc diff --git a/sdk/android/src/jni/audio_device/audio_manager.cc b/sdk/android/src/jni/audio_device/audio_manager.cc index 41943dca6d..39f83e38a6 100644 --- a/sdk/android/src/jni/audio_device/audio_manager.cc +++ b/sdk/android/src/jni/audio_device/audio_manager.cc @@ -73,47 +73,6 @@ AudioManager::~AudioManager() { Close(); } -SLObjectItf AudioManager::GetOpenSLEngine() { - RTC_LOG(INFO) << "GetOpenSLEngine"; - RTC_DCHECK(thread_checker_.CalledOnValidThread()); - // Only allow usage of OpenSL ES if such an audio layer has been specified. - if (audio_layer_ != AudioDeviceModule::kAndroidOpenSLESAudio && - audio_layer_ != - AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio) { - RTC_LOG(INFO) - << "Unable to create OpenSL engine for the current audio layer: " - << audio_layer_; - return nullptr; - } - // OpenSL ES for Android only supports a single engine per application. - // If one already has been created, return existing object instead of - // creating a new. - if (engine_object_.Get() != nullptr) { - RTC_LOG(WARNING) << "The OpenSL ES engine object has already been created"; - return engine_object_.Get(); - } - // Create the engine object in thread safe mode. - const SLEngineOption option[] = { - {SL_ENGINEOPTION_THREADSAFE, static_cast(SL_BOOLEAN_TRUE)}}; - SLresult result = - slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL); - if (result != SL_RESULT_SUCCESS) { - RTC_LOG(LS_ERROR) << "slCreateEngine() failed: " - << GetSLErrorString(result); - engine_object_.Reset(); - return nullptr; - } - // Realize the SL Engine in synchronous mode. - result = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE); - if (result != SL_RESULT_SUCCESS) { - RTC_LOG(LS_ERROR) << "Realize() failed: " << GetSLErrorString(result); - engine_object_.Reset(); - return nullptr; - } - // Finally return the SLObjectItf interface of the engine object. - return engine_object_.Get(); -} - bool AudioManager::Init() { RTC_LOG(INFO) << "Init"; RTC_DCHECK(thread_checker_.CalledOnValidThread()); diff --git a/sdk/android/src/jni/audio_device/audio_manager.h b/sdk/android/src/jni/audio_device/audio_manager.h index 5f32e2a2a1..c826402271 100644 --- a/sdk/android/src/jni/audio_device/audio_manager.h +++ b/sdk/android/src/jni/audio_device/audio_manager.h @@ -38,18 +38,6 @@ class AudioManager { const JavaParamRef& application_context); ~AudioManager(); - // 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. - // Subsequent calls returns the already created engine. The SL engine object - // is destroyed when the AudioManager object is deleted. It means that the - // engine object will be the first OpenSL ES object to be created and last - // object to be destroyed. - // Note that NULL will be returned unless the audio layer is specified as - // AudioDeviceModule::kAndroidOpenSLESAudio or - // AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio. - SLObjectItf GetOpenSLEngine(); - // Initializes the audio manager and stores the current audio mode. bool Init(); // Revert any setting done by Init(). @@ -96,13 +84,6 @@ class AudioManager { // in the AudioDeviceModule class. 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 - // SLEngineItf interface. This interface contains creation methods for all - // the other object types in the API. None of these interface are realized - // by this class. It only provides access to the global engine object. - ScopedSLObjectItf engine_object_; - // Set to true by Init() and false by Close(). bool initialized_; diff --git a/sdk/android/src/jni/audio_device/opensles_common.cc b/sdk/android/src/jni/audio_device/opensles_common.cc index 72ba56ff65..59ade32908 100644 --- a/sdk/android/src/jni/audio_device/opensles_common.cc +++ b/sdk/android/src/jni/audio_device/opensles_common.cc @@ -102,6 +102,42 @@ SLDataFormat_PCM CreatePCMConfiguration(size_t channels, return format; } +OpenSLEngineManager::OpenSLEngineManager() { + thread_checker_.DetachFromThread(); +} + +SLObjectItf OpenSLEngineManager::GetOpenSLEngine() { + RTC_LOG(INFO) << "GetOpenSLEngine"; + RTC_DCHECK(thread_checker_.CalledOnValidThread()); + // OpenSL ES for Android only supports a single engine per application. + // If one already has been created, return existing object instead of + // creating a new. + if (engine_object_.Get() != nullptr) { + RTC_LOG(WARNING) << "The OpenSL ES engine object has already been created"; + return engine_object_.Get(); + } + // Create the engine object in thread safe mode. + const SLEngineOption option[] = { + {SL_ENGINEOPTION_THREADSAFE, static_cast(SL_BOOLEAN_TRUE)}}; + SLresult result = + slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL); + if (result != SL_RESULT_SUCCESS) { + RTC_LOG(LS_ERROR) << "slCreateEngine() failed: " + << GetSLErrorString(result); + engine_object_.Reset(); + return nullptr; + } + // Realize the SL Engine in synchronous mode. + result = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE); + if (result != SL_RESULT_SUCCESS) { + RTC_LOG(LS_ERROR) << "Realize() failed: " << GetSLErrorString(result); + engine_object_.Reset(); + return nullptr; + } + // Finally return the SLObjectItf interface of the engine object. + return engine_object_.Get(); +} + } // namespace android_adm } // namespace webrtc diff --git a/sdk/android/src/jni/audio_device/opensles_common.h b/sdk/android/src/jni/audio_device/opensles_common.h index bba8ce780a..da14a50305 100644 --- a/sdk/android/src/jni/audio_device/opensles_common.h +++ b/sdk/android/src/jni/audio_device/opensles_common.h @@ -15,6 +15,8 @@ #include #include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/thread_checker.h" namespace webrtc { @@ -59,6 +61,27 @@ class ScopedSLObject { typedef ScopedSLObject ScopedSLObjectItf; +// 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. +// Subsequent calls returns the already created engine. +// Note: This class must be used single threaded and this is enfored by a thread +// checker. +class OpenSLEngineManager { + public: + OpenSLEngineManager(); + SLObjectItf GetOpenSLEngine(); + + private: + rtc::ThreadChecker thread_checker_; + // This object is the global entry point of the OpenSL ES API. + // After creating the engine object, the application can obtain this object‘s + // SLEngineItf interface. This interface contains creation methods for all + // the other object types in the API. None of these interface are realized + // by this class. It only provides access to the global engine object. + ScopedSLObjectItf engine_object_; +}; + } // namespace android_adm } // namespace webrtc diff --git a/sdk/android/src/jni/audio_device/opensles_player.cc b/sdk/android/src/jni/audio_device/opensles_player.cc index d2b42997ab..e2c1d75ed8 100644 --- a/sdk/android/src/jni/audio_device/opensles_player.cc +++ b/sdk/android/src/jni/audio_device/opensles_player.cc @@ -42,13 +42,15 @@ namespace webrtc { namespace android_adm { -OpenSLESPlayer::OpenSLESPlayer(AudioManager* audio_manager) - : audio_manager_(audio_manager), - audio_parameters_(audio_manager->GetPlayoutAudioParameters()), +OpenSLESPlayer::OpenSLESPlayer( + AudioManager* audio_manager, + std::unique_ptr engine_manager) + : audio_parameters_(audio_manager->GetPlayoutAudioParameters()), audio_device_buffer_(nullptr), initialized_(false), playing_(false), buffer_index_(0), + engine_manager_(std::move(engine_manager)), engine_(nullptr), player_(nullptr), simple_buffer_queue_(nullptr), @@ -233,7 +235,7 @@ bool OpenSLESPlayer::ObtainEngineInterface() { return true; // Get access to (or create if not already existing) the global OpenSL Engine // object. - SLObjectItf engine_object = audio_manager_->GetOpenSLEngine(); + SLObjectItf engine_object = engine_manager_->GetOpenSLEngine(); if (engine_object == nullptr) { ALOGE("Failed to access the global OpenSL engine"); return false; diff --git a/sdk/android/src/jni/audio_device/opensles_player.h b/sdk/android/src/jni/audio_device/opensles_player.h index 34d3c5366a..e4da19769b 100644 --- a/sdk/android/src/jni/audio_device/opensles_player.h +++ b/sdk/android/src/jni/audio_device/opensles_player.h @@ -60,7 +60,8 @@ class OpenSLESPlayer : public AudioOutput { // TODO(henrika): perhaps set this value dynamically based on OS version. static const int kNumOfOpenSLESBuffers = 2; - explicit OpenSLESPlayer(AudioManager* audio_manager); + OpenSLESPlayer(AudioManager* audio_manager, + std::unique_ptr engine_manager); ~OpenSLESPlayer() override; int Init() override; @@ -125,12 +126,6 @@ class OpenSLESPlayer : public AudioOutput { // Detached during construction of this object. rtc::ThreadChecker thread_checker_opensles_; - // Raw pointer to the audio manager injected at construction. Used to cache - // audio parameters and to access the global SL engine object needed by the - // ObtainEngineInterface() method. The audio manager outlives any instance of - // this class. - AudioManager* audio_manager_; - // Contains audio parameters provided to this class at construction by the // AudioManager. const AudioParameters audio_parameters_; @@ -168,6 +163,7 @@ class OpenSLESPlayer : public AudioOutput { // Example (kNumOfOpenSLESBuffers = 2): counts 0, 1, 0, 1, ... int buffer_index_; + std::unique_ptr engine_manager_; // This interface exposes creation methods for all the OpenSL ES object types. // It is the OpenSL ES API entry point. SLEngineItf engine_; diff --git a/sdk/android/src/jni/audio_device/opensles_recorder.cc b/sdk/android/src/jni/audio_device/opensles_recorder.cc index 270d18d7aa..e77e62eb5d 100644 --- a/sdk/android/src/jni/audio_device/opensles_recorder.cc +++ b/sdk/android/src/jni/audio_device/opensles_recorder.cc @@ -43,12 +43,13 @@ namespace webrtc { namespace android_adm { -OpenSLESRecorder::OpenSLESRecorder(AudioManager* audio_manager) - : audio_manager_(audio_manager), - audio_parameters_(audio_manager->GetRecordAudioParameters()), +OpenSLESRecorder::OpenSLESRecorder(AudioManager* audio_manager, + OpenSLEngineManager* engine_manager) + : audio_parameters_(audio_manager->GetRecordAudioParameters()), audio_device_buffer_(nullptr), initialized_(false), recording_(false), + engine_manager_(engine_manager), engine_(nullptr), recorder_(nullptr), simple_buffer_queue_(nullptr), @@ -214,7 +215,7 @@ bool OpenSLESRecorder::ObtainEngineInterface() { return true; // Get access to (or create if not already existing) the global OpenSL Engine // object. - SLObjectItf engine_object = audio_manager_->GetOpenSLEngine(); + SLObjectItf engine_object = engine_manager_->GetOpenSLEngine(); if (engine_object == nullptr) { ALOGE("Failed to access the global OpenSL engine"); return false; diff --git a/sdk/android/src/jni/audio_device/opensles_recorder.h b/sdk/android/src/jni/audio_device/opensles_recorder.h index 81efcb865e..f1b0cbfd6e 100644 --- a/sdk/android/src/jni/audio_device/opensles_recorder.h +++ b/sdk/android/src/jni/audio_device/opensles_recorder.h @@ -63,7 +63,8 @@ class OpenSLESRecorder : public AudioInput { // TODO(henrika): perhaps set this value dynamically based on OS version. static const int kNumOfOpenSLESBuffers = 2; - explicit OpenSLESRecorder(AudioManager* audio_manager); + OpenSLESRecorder(AudioManager* audio_manager, + OpenSLEngineManager* engine_manager); ~OpenSLESRecorder() override; int Init() override; @@ -133,12 +134,6 @@ class OpenSLESRecorder : public AudioInput { // Detached during construction of this object. rtc::ThreadChecker thread_checker_opensles_; - // Raw pointer to the audio manager injected at construction. Used to cache - // audio parameters and to access the global SL engine object needed by the - // ObtainEngineInterface() method. The audio manager outlives any instance of - // this class. - AudioManager* const audio_manager_; - // Contains audio parameters provided to this class at construction by the // AudioManager. const AudioParameters audio_parameters_; @@ -155,6 +150,7 @@ class OpenSLESRecorder : public AudioInput { bool initialized_; bool recording_; + OpenSLEngineManager* const engine_manager_; // This interface exposes creation methods for all the OpenSL ES object types. // It is the OpenSL ES API entry point. SLEngineItf engine_;