1/*
2 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/audio_device/android/audio_manager.h"
12
13#include <utility>
14
15#include <android/log.h>
16
17#include "webrtc/base/arraysize.h"
18#include "webrtc/base/checks.h"
19#include "webrtc/base/scoped_ptr.h"
20#include "webrtc/modules/audio_device/android/audio_common.h"
21#include "webrtc/modules/utility/include/helpers_android.h"
22
23#define TAG "AudioManager"
24#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
25#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
26#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
27#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
28#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
29
30namespace webrtc {
31
32// AudioManager::JavaAudioManager implementation
33AudioManager::JavaAudioManager::JavaAudioManager(
34    NativeRegistration* native_reg,
35    rtc::scoped_ptr<GlobalRef> audio_manager)
36    : audio_manager_(std::move(audio_manager)),
37      init_(native_reg->GetMethodId("init", "()Z")),
38      dispose_(native_reg->GetMethodId("dispose", "()V")),
39      is_communication_mode_enabled_(
40          native_reg->GetMethodId("isCommunicationModeEnabled", "()Z")),
41      is_device_blacklisted_for_open_sles_usage_(
42          native_reg->GetMethodId("isDeviceBlacklistedForOpenSLESUsage",
43                                  "()Z")) {
44  ALOGD("JavaAudioManager::ctor%s", GetThreadInfo().c_str());
45}
46
47AudioManager::JavaAudioManager::~JavaAudioManager() {
48  ALOGD("JavaAudioManager::dtor%s", GetThreadInfo().c_str());
49}
50
51bool AudioManager::JavaAudioManager::Init() {
52  return audio_manager_->CallBooleanMethod(init_);
53}
54
55void AudioManager::JavaAudioManager::Close() {
56  audio_manager_->CallVoidMethod(dispose_);
57}
58
59bool AudioManager::JavaAudioManager::IsCommunicationModeEnabled() {
60  return audio_manager_->CallBooleanMethod(is_communication_mode_enabled_);
61}
62
63bool AudioManager::JavaAudioManager::IsDeviceBlacklistedForOpenSLESUsage() {
64  return audio_manager_->CallBooleanMethod(
65      is_device_blacklisted_for_open_sles_usage_);
66}
67
68// AudioManager implementation
69AudioManager::AudioManager()
70    : j_environment_(JVM::GetInstance()->environment()),
71      audio_layer_(AudioDeviceModule::kPlatformDefaultAudio),
72      initialized_(false),
73      hardware_aec_(false),
74      hardware_agc_(false),
75      hardware_ns_(false),
76      low_latency_playout_(false),
77      delay_estimate_in_milliseconds_(0) {
78  ALOGD("ctor%s", GetThreadInfo().c_str());
79  RTC_CHECK(j_environment_);
80  JNINativeMethod native_methods[] = {
81      {"nativeCacheAudioParameters",
82       "(IIZZZZIIJ)V",
83       reinterpret_cast<void*>(&webrtc::AudioManager::CacheAudioParameters)}};
84  j_native_registration_ = j_environment_->RegisterNatives(
85      "org/webrtc/voiceengine/WebRtcAudioManager",
86      native_methods, arraysize(native_methods));
87  j_audio_manager_.reset(new JavaAudioManager(
88      j_native_registration_.get(),
89      j_native_registration_->NewObject(
90          "<init>", "(Landroid/content/Context;J)V",
91          JVM::GetInstance()->context(), PointerTojlong(this))));
92}
93
94AudioManager::~AudioManager() {
95  ALOGD("~dtor%s", GetThreadInfo().c_str());
96  RTC_DCHECK(thread_checker_.CalledOnValidThread());
97  Close();
98}
99
100void AudioManager::SetActiveAudioLayer(
101    AudioDeviceModule::AudioLayer audio_layer) {
102  ALOGD("SetActiveAudioLayer(%d)%s", audio_layer, GetThreadInfo().c_str());
103  RTC_DCHECK(thread_checker_.CalledOnValidThread());
104  RTC_DCHECK(!initialized_);
105  // Store the currenttly utilized audio layer.
106  audio_layer_ = audio_layer;
107  // The delay estimate can take one of two fixed values depending on if the
108  // device supports low-latency output or not. However, it is also possible
109  // that the user explicitly selects the high-latency audio path, hence we use
110  // the selected |audio_layer| here to set the delay estimate.
111  delay_estimate_in_milliseconds_ =
112      (audio_layer == AudioDeviceModule::kAndroidJavaAudio) ?
113      kHighLatencyModeDelayEstimateInMilliseconds :
114      kLowLatencyModeDelayEstimateInMilliseconds;
115  ALOGD("delay_estimate_in_milliseconds: %d", delay_estimate_in_milliseconds_);
116}
117
118bool AudioManager::Init() {
119  ALOGD("Init%s", GetThreadInfo().c_str());
120  RTC_DCHECK(thread_checker_.CalledOnValidThread());
121  RTC_DCHECK(!initialized_);
122  RTC_DCHECK_NE(audio_layer_, AudioDeviceModule::kPlatformDefaultAudio);
123  if (!j_audio_manager_->Init()) {
124    ALOGE("init failed!");
125    return false;
126  }
127  initialized_ = true;
128  return true;
129}
130
131bool AudioManager::Close() {
132  ALOGD("Close%s", GetThreadInfo().c_str());
133  RTC_DCHECK(thread_checker_.CalledOnValidThread());
134  if (!initialized_)
135    return true;
136  j_audio_manager_->Close();
137  initialized_ = false;
138  return true;
139}
140
141bool AudioManager::IsCommunicationModeEnabled() const {
142  ALOGD("IsCommunicationModeEnabled()");
143  RTC_DCHECK(thread_checker_.CalledOnValidThread());
144  return j_audio_manager_->IsCommunicationModeEnabled();
145}
146
147bool AudioManager::IsAcousticEchoCancelerSupported() const {
148  RTC_DCHECK(thread_checker_.CalledOnValidThread());
149  return hardware_aec_;
150}
151
152bool AudioManager::IsAutomaticGainControlSupported() const {
153  RTC_DCHECK(thread_checker_.CalledOnValidThread());
154  return hardware_agc_;
155}
156
157bool AudioManager::IsNoiseSuppressorSupported() const {
158  RTC_DCHECK(thread_checker_.CalledOnValidThread());
159  return hardware_ns_;
160}
161
162bool AudioManager::IsLowLatencyPlayoutSupported() const {
163  RTC_DCHECK(thread_checker_.CalledOnValidThread());
164  ALOGD("IsLowLatencyPlayoutSupported()");
165  // Some devices are blacklisted for usage of OpenSL ES even if they report
166  // that low-latency playout is supported. See b/21485703 for details.
167  return j_audio_manager_->IsDeviceBlacklistedForOpenSLESUsage() ?
168      false : low_latency_playout_;
169}
170
171int AudioManager::GetDelayEstimateInMilliseconds() const {
172  return delay_estimate_in_milliseconds_;
173}
174
175void JNICALL AudioManager::CacheAudioParameters(JNIEnv* env,
176                                                jobject obj,
177                                                jint sample_rate,
178                                                jint channels,
179                                                jboolean hardware_aec,
180                                                jboolean hardware_agc,
181                                                jboolean hardware_ns,
182                                                jboolean low_latency_output,
183                                                jint output_buffer_size,
184                                                jint input_buffer_size,
185                                                jlong native_audio_manager) {
186  webrtc::AudioManager* this_object =
187      reinterpret_cast<webrtc::AudioManager*>(native_audio_manager);
188  this_object->OnCacheAudioParameters(
189      env, sample_rate, channels, hardware_aec, hardware_agc, hardware_ns,
190      low_latency_output, output_buffer_size, input_buffer_size);
191}
192
193void AudioManager::OnCacheAudioParameters(JNIEnv* env,
194                                          jint sample_rate,
195                                          jint channels,
196                                          jboolean hardware_aec,
197                                          jboolean hardware_agc,
198                                          jboolean hardware_ns,
199                                          jboolean low_latency_output,
200                                          jint output_buffer_size,
201                                          jint input_buffer_size) {
202  ALOGD("OnCacheAudioParameters%s", GetThreadInfo().c_str());
203  ALOGD("hardware_aec: %d", hardware_aec);
204  ALOGD("hardware_agc: %d", hardware_agc);
205  ALOGD("hardware_ns: %d", hardware_ns);
206  ALOGD("low_latency_output: %d", low_latency_output);
207  ALOGD("sample_rate: %d", sample_rate);
208  ALOGD("channels: %d", channels);
209  ALOGD("output_buffer_size: %d", output_buffer_size);
210  ALOGD("input_buffer_size: %d", input_buffer_size);
211  RTC_DCHECK(thread_checker_.CalledOnValidThread());
212  hardware_aec_ = hardware_aec;
213  hardware_agc_ = hardware_agc;
214  hardware_ns_ = hardware_ns;
215  low_latency_playout_ = low_latency_output;
216  // TODO(henrika): add support for stereo output.
217  playout_parameters_.reset(sample_rate, static_cast<size_t>(channels),
218                            static_cast<size_t>(output_buffer_size));
219  record_parameters_.reset(sample_rate, static_cast<size_t>(channels),
220                           static_cast<size_t>(input_buffer_size));
221}
222
223const AudioParameters& AudioManager::GetPlayoutAudioParameters() {
224  RTC_CHECK(playout_parameters_.is_valid());
225  RTC_DCHECK(thread_checker_.CalledOnValidThread());
226  return playout_parameters_;
227}
228
229const AudioParameters& AudioManager::GetRecordAudioParameters() {
230  RTC_CHECK(record_parameters_.is_valid());
231  RTC_DCHECK(thread_checker_.CalledOnValidThread());
232  return record_parameters_;
233}
234
235}  // namespace webrtc
236