/* * 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 #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(jvm); JNIEnv* jni = GetEnv(g_jvm); CHECK(jni) << "AttachCurrentThread must be called on this tread"; g_context = NewGlobalRef(jni, reinterpret_cast(context)); jclass local_class = FindClass( jni, "org/webrtc/voiceengine/WebRtcAudioManager"); g_audio_manager_class = reinterpret_cast( 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(&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 AudioManager::SetCommunicationMode(bool enable) { ALOGD("SetCommunicationMode(%d)%s", enable, GetThreadInfo().c_str()); DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(initialized_); AttachThreadScoped ats(g_jvm); JNIEnv* jni = ats.env(); jmethodID setcommID = GetMethodID( jni, g_audio_manager_class, "setCommunicationMode", "(Z)V"); jni->CallVoidMethod(j_audio_manager_, setcommID, enable); CHECK_EXCEPTION(jni); } void JNICALL AudioManager::CacheAudioParameters(JNIEnv* env, jobject obj, jint sample_rate, jint channels, jlong nativeAudioManager) { webrtc::AudioManager* this_object = reinterpret_cast (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, "", "(Landroid/content/Context;J)V"); j_audio_manager_ = jni->NewObject(g_audio_manager_class, constructorID, g_context, reinterpret_cast(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