mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-20 00:57:49 +01:00
Android audio manager: Move responsibility of OpenSLES engine
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 <magjed@webrtc.org> Reviewed-by: Paulina Hensman <phensman@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22661}
This commit is contained in:
parent
1a18e0ac46
commit
e2971ec2ab
9 changed files with 121 additions and 114 deletions
|
@ -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,
|
||||
JNIEnv* env,
|
||||
jobject application_context) {
|
||||
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());
|
||||
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);
|
||||
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<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));
|
||||
}
|
||||
#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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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().
|
||||
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -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<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_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
|
Loading…
Reference in a new issue