Skip to content

Commit

Permalink
Android audio manager: Move responsibility of OpenSLES engine
Browse files Browse the repository at this point in the history
The OpenSLES engine is currently managed by the AudioManager which is
a generic class shared between different kinds of audio input/output.
This CL moves the responsibility of the OpenSLES engine to the actual
OpenSLES implementations.

Bug: webrtc:7452
Change-Id: Iecccb03ec5cd12ce2f3fdc44daaedae27aecf88b
Reviewed-on: https://webrtc-review.googlesource.com/64520
Commit-Queue: Magnus Jedvert <[email protected]>
Reviewed-by: Paulina Hensman <[email protected]>
Cr-Commit-Position: refs/heads/master@{#22661}
  • Loading branch information
Hnoo112233 authored and Commit Bot committed Mar 28, 2018
1 parent 1a18e0a commit e2971ec
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 112 deletions.
73 changes: 43 additions & 30 deletions sdk/android/native_api/audio_device_module/audio_device_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,59 +28,72 @@

namespace webrtc {

namespace {

// This template function takes care of some boiler plate.
template <typename AudioInputT, typename AudioOutputT>
rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceModuleTemplate(
AudioDeviceModule::AudioLayer audio_layer,
#if defined(AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
rtc::scoped_refptr<AudioDeviceModule> CreateAAudioAudioDeviceModule(
JNIEnv* env,
jobject application_context) {
RTC_LOG(INFO) << __FUNCTION__;
const AudioDeviceModule::AudioLayer audio_layer =
AudioDeviceModule::kAndroidAAudioAudio;
auto audio_manager = rtc::MakeUnique<android_adm::AudioManager>(
env, audio_layer, JavaParamRef<jobject>(application_context));
auto audio_input = rtc::MakeUnique<AudioInputT>(audio_manager.get());
auto audio_output = rtc::MakeUnique<AudioOutputT>(audio_manager.get());
auto audio_input =
rtc::MakeUnique<android_adm::AAudioRecorder>(audio_manager.get());
auto audio_output =
rtc::MakeUnique<android_adm::AAudioPlayer>(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<AudioDeviceModule> CreateAAudioAudioDeviceModule(
JNIEnv* env,
jobject application_context) {
RTC_LOG(INFO) << __FUNCTION__;
return CreateAudioDeviceModuleTemplate<android_adm::AAudioRecorder,
android_adm::AAudioPlayer>(
AudioDeviceModule::kAndroidAAudioAudio, env, application_context);
}
#endif

rtc::scoped_refptr<AudioDeviceModule> CreateJavaAudioDeviceModule(
JNIEnv* env,
jobject application_context) {
return CreateAudioDeviceModuleTemplate<android_adm::AudioRecordJni,
android_adm::AudioTrackJni>(
AudioDeviceModule::kAndroidJavaAudio, env, application_context);
const AudioDeviceModule::AudioLayer audio_layer =
AudioDeviceModule::kAndroidJavaAudio;
auto audio_manager = rtc::MakeUnique<android_adm::AudioManager>(
env, audio_layer, JavaParamRef<jobject>(application_context));
auto audio_input =
rtc::MakeUnique<android_adm::AudioRecordJni>(audio_manager.get());
auto audio_output =
rtc::MakeUnique<android_adm::AudioTrackJni>(audio_manager.get());
return CreateAudioDeviceModuleFromInputAndOutput(
audio_layer, std::move(audio_manager), std::move(audio_input),
std::move(audio_output));
}

rtc::scoped_refptr<AudioDeviceModule> CreateOpenSLESAudioDeviceModule(
JNIEnv* env,
jobject application_context) {
return CreateAudioDeviceModuleTemplate<android_adm::OpenSLESRecorder,
android_adm::OpenSLESPlayer>(
AudioDeviceModule::kAndroidJavaAudio, env, application_context);
const AudioDeviceModule::AudioLayer audio_layer =
AudioDeviceModule::kAndroidOpenSLESAudio;
auto engine_manager = rtc::MakeUnique<android_adm::OpenSLEngineManager>();
auto audio_manager = rtc::MakeUnique<android_adm::AudioManager>(
env, audio_layer, JavaParamRef<jobject>(application_context));
auto audio_input = rtc::MakeUnique<android_adm::OpenSLESRecorder>(
audio_manager.get(), engine_manager.get());
auto audio_output = rtc::MakeUnique<android_adm::OpenSLESPlayer>(
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<AudioDeviceModule>
CreateJavaInputAndOpenSLESOutputAudioDeviceModule(JNIEnv* env,
jobject application_context) {
return CreateAudioDeviceModuleTemplate<android_adm::AudioRecordJni,
android_adm::OpenSLESPlayer>(
AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio, env,
application_context);
const AudioDeviceModule::AudioLayer audio_layer =
AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio;
auto audio_manager = rtc::MakeUnique<android_adm::AudioManager>(
env, audio_layer, JavaParamRef<jobject>(application_context));
auto audio_input =
rtc::MakeUnique<android_adm::AudioRecordJni>(audio_manager.get());
auto audio_output = rtc::MakeUnique<android_adm::OpenSLESPlayer>(
audio_manager.get(), rtc::MakeUnique<android_adm::OpenSLEngineManager>());
return CreateAudioDeviceModuleFromInputAndOutput(
audio_layer, std::move(audio_manager), std::move(audio_input),
std::move(audio_output));
}

} // namespace webrtc
41 changes: 0 additions & 41 deletions sdk/android/src/jni/audio_device/audio_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<SLuint32>(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());
Expand Down
19 changes: 0 additions & 19 deletions sdk/android/src/jni/audio_device/audio_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,6 @@ class AudioManager {
const JavaParamRef<jobject>& 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().
Expand Down Expand Up @@ -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_;

Expand Down
36 changes: 36 additions & 0 deletions sdk/android/src/jni/audio_device/opensles_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<SLuint32>(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
23 changes: 23 additions & 0 deletions sdk/android/src/jni/audio_device/opensles_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <stddef.h>

#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/thread_checker.h"

namespace webrtc {

Expand Down Expand Up @@ -59,6 +61,27 @@ class ScopedSLObject {

typedef ScopedSLObject<SLObjectItf, const SLObjectItf_*> 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
Expand Down
10 changes: 6 additions & 4 deletions sdk/android/src/jni/audio_device/opensles_player.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<OpenSLEngineManager> 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),
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 3 additions & 7 deletions sdk/android/src/jni/audio_device/opensles_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<OpenSLEngineManager> engine_manager);
~OpenSLESPlayer() override;

int Init() override;
Expand Down Expand Up @@ -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_;
Expand Down Expand Up @@ -168,6 +163,7 @@ class OpenSLESPlayer : public AudioOutput {
// Example (kNumOfOpenSLESBuffers = 2): counts 0, 1, 0, 1, ...
int buffer_index_;

std::unique_ptr<OpenSLEngineManager> engine_manager_;
// This interface exposes creation methods for all the OpenSL ES object types.
// It is the OpenSL ES API entry point.
SLEngineItf engine_;
Expand Down
9 changes: 5 additions & 4 deletions sdk/android/src/jni/audio_device/opensles_recorder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 3 additions & 7 deletions sdk/android/src/jni/audio_device/opensles_recorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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_;
Expand All @@ -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_;
Expand Down

0 comments on commit e2971ec

Please sign in to comment.