blob: a4f54bccaa9f53f3b748c33ae82484f3f85eccd6 [file] [log] [blame]
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_device/android/audio_manager.h"
#include <android/log.h>
#include "webrtc/base/arraysize.h"
#include "webrtc/base/checks.h"
#include "webrtc/modules/audio_device/android/audio_common.h"
#include "webrtc/modules/utility/interface/helpers_android.h"
#define TAG "AudioManager"
#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
namespace webrtc {
static JavaVM* g_jvm = NULL;
static jobject g_context = NULL;
static jclass g_audio_manager_class = NULL;
void AudioManager::SetAndroidAudioDeviceObjects(void* jvm, void* context) {
ALOGD("SetAndroidAudioDeviceObjects%s", GetThreadInfo().c_str());
CHECK(jvm);
CHECK(context);
g_jvm = reinterpret_cast<JavaVM*>(jvm);
JNIEnv* jni = GetEnv(g_jvm);
CHECK(jni) << "AttachCurrentThread must be called on this tread";
g_context = NewGlobalRef(jni, reinterpret_cast<jobject>(context));
jclass local_class = FindClass(
jni, "org/webrtc/voiceengine/WebRtcAudioManager");
g_audio_manager_class = reinterpret_cast<jclass>(
NewGlobalRef(jni, local_class));
CHECK_EXCEPTION(jni);
// Register native methods with the WebRtcAudioManager class. These methods
// are declared private native in WebRtcAudioManager.java.
JNINativeMethod native_methods[] = {
{"nativeCacheAudioParameters", "(IIJ)V",
reinterpret_cast<void*>(&webrtc::AudioManager::CacheAudioParameters)}};
jni->RegisterNatives(g_audio_manager_class,
native_methods, arraysize(native_methods));
CHECK_EXCEPTION(jni) << "Error during RegisterNatives";
}
void AudioManager::ClearAndroidAudioDeviceObjects() {
ALOGD("ClearAndroidAudioDeviceObjects%s", GetThreadInfo().c_str());
JNIEnv* jni = GetEnv(g_jvm);
CHECK(jni) << "AttachCurrentThread must be called on this tread";
jni->UnregisterNatives(g_audio_manager_class);
CHECK_EXCEPTION(jni) << "Error during UnregisterNatives";
DeleteGlobalRef(jni, g_audio_manager_class);
g_audio_manager_class = NULL;
DeleteGlobalRef(jni, g_context);
g_context = NULL;
g_jvm = NULL;
}
AudioManager::AudioManager()
: j_audio_manager_(NULL),
initialized_(false) {
ALOGD("ctor%s", GetThreadInfo().c_str());
CHECK(HasDeviceObjects());
CreateJavaInstance();
}
AudioManager::~AudioManager() {
ALOGD("~dtor%s", GetThreadInfo().c_str());
DCHECK(thread_checker_.CalledOnValidThread());
Close();
AttachThreadScoped ats(g_jvm);
JNIEnv* jni = ats.env();
jni->DeleteGlobalRef(j_audio_manager_);
j_audio_manager_ = NULL;
DCHECK(!initialized_);
}
bool AudioManager::Init() {
ALOGD("Init%s", GetThreadInfo().c_str());
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!initialized_);
AttachThreadScoped ats(g_jvm);
JNIEnv* jni = ats.env();
jmethodID initID = GetMethodID(jni, g_audio_manager_class, "init", "()Z");
jboolean res = jni->CallBooleanMethod(j_audio_manager_, initID);
CHECK_EXCEPTION(jni);
if (!res) {
ALOGE("init failed!");
return false;
}
initialized_ = true;
return true;
}
bool AudioManager::Close() {
ALOGD("Close%s", GetThreadInfo().c_str());
DCHECK(thread_checker_.CalledOnValidThread());
if (!initialized_)
return true;
AttachThreadScoped ats(g_jvm);
JNIEnv* jni = ats.env();
jmethodID disposeID = GetMethodID(
jni, g_audio_manager_class, "dispose", "()V");
jni->CallVoidMethod(j_audio_manager_, disposeID);
CHECK_EXCEPTION(jni);
initialized_ = false;
return true;
}
void JNICALL AudioManager::CacheAudioParameters(JNIEnv* env, jobject obj,
jint sample_rate, jint channels, jlong nativeAudioManager) {
webrtc::AudioManager* this_object =
reinterpret_cast<webrtc::AudioManager*> (nativeAudioManager);
this_object->OnCacheAudioParameters(env, sample_rate, channels);
}
void AudioManager::OnCacheAudioParameters(
JNIEnv* env, jint sample_rate, jint channels) {
ALOGD("OnCacheAudioParameters%s", GetThreadInfo().c_str());
ALOGD("sample_rate: %d", sample_rate);
ALOGD("channels: %d", channels);
DCHECK(thread_checker_.CalledOnValidThread());
// TODO(henrika): add support stereo output.
playout_parameters_.reset(sample_rate, channels);
record_parameters_.reset(sample_rate, channels);
}
AudioParameters AudioManager::GetPlayoutAudioParameters() const {
CHECK(playout_parameters_.is_valid());
return playout_parameters_;
}
AudioParameters AudioManager::GetRecordAudioParameters() const {
CHECK(record_parameters_.is_valid());
return record_parameters_;
}
bool AudioManager::HasDeviceObjects() {
return (g_jvm && g_context && g_audio_manager_class);
}
void AudioManager::CreateJavaInstance() {
ALOGD("CreateJavaInstance");
AttachThreadScoped ats(g_jvm);
JNIEnv* jni = ats.env();
jmethodID constructorID = GetMethodID(
jni, g_audio_manager_class, "<init>", "(Landroid/content/Context;J)V");
j_audio_manager_ = jni->NewObject(g_audio_manager_class,
constructorID,
g_context,
reinterpret_cast<intptr_t>(this));
CHECK_EXCEPTION(jni) << "Error during NewObject";
CHECK(j_audio_manager_);
j_audio_manager_ = jni->NewGlobalRef(j_audio_manager_);
CHECK_EXCEPTION(jni) << "Error during NewGlobalRef";
CHECK(j_audio_manager_);
}
} // namespace webrtc