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 "modules/audio_device/android/audio_manager.h"
12
13 #include <utility>
14
15 #include "modules/audio_device/android/audio_common.h"
16 #include "modules/utility/include/helpers_android.h"
17 #include "rtc_base/arraysize.h"
18 #include "rtc_base/checks.h"
19 #include "rtc_base/logging.h"
20 #include "rtc_base/platform_thread.h"
21
22 namespace webrtc {
23
24 // AudioManager::JavaAudioManager implementation
JavaAudioManager(NativeRegistration * native_reg,std::unique_ptr<GlobalRef> audio_manager)25 AudioManager::JavaAudioManager::JavaAudioManager(
26 NativeRegistration* native_reg,
27 std::unique_ptr<GlobalRef> audio_manager)
28 : audio_manager_(std::move(audio_manager)),
29 init_(native_reg->GetMethodId("init", "()Z")),
30 dispose_(native_reg->GetMethodId("dispose", "()V")),
31 is_communication_mode_enabled_(
32 native_reg->GetMethodId("isCommunicationModeEnabled", "()Z")),
33 is_device_blacklisted_for_open_sles_usage_(
34 native_reg->GetMethodId("isDeviceBlacklistedForOpenSLESUsage",
35 "()Z")) {
36 RTC_LOG(INFO) << "JavaAudioManager::ctor";
37 }
38
~JavaAudioManager()39 AudioManager::JavaAudioManager::~JavaAudioManager() {
40 RTC_LOG(INFO) << "JavaAudioManager::~dtor";
41 }
42
Init()43 bool AudioManager::JavaAudioManager::Init() {
44 return audio_manager_->CallBooleanMethod(init_);
45 }
46
Close()47 void AudioManager::JavaAudioManager::Close() {
48 audio_manager_->CallVoidMethod(dispose_);
49 }
50
IsCommunicationModeEnabled()51 bool AudioManager::JavaAudioManager::IsCommunicationModeEnabled() {
52 return audio_manager_->CallBooleanMethod(is_communication_mode_enabled_);
53 }
54
IsDeviceBlacklistedForOpenSLESUsage()55 bool AudioManager::JavaAudioManager::IsDeviceBlacklistedForOpenSLESUsage() {
56 return audio_manager_->CallBooleanMethod(
57 is_device_blacklisted_for_open_sles_usage_);
58 }
59
60 // AudioManager implementation
AudioManager()61 AudioManager::AudioManager()
62 : j_environment_(JVM::GetInstance()->environment()),
63 audio_layer_(AudioDeviceModule::kPlatformDefaultAudio),
64 initialized_(false),
65 hardware_aec_(false),
66 hardware_agc_(false),
67 hardware_ns_(false),
68 low_latency_playout_(false),
69 low_latency_record_(false),
70 delay_estimate_in_milliseconds_(0) {
71 RTC_LOG(INFO) << "ctor";
72 RTC_CHECK(j_environment_);
73 JNINativeMethod native_methods[] = {
74 {"nativeCacheAudioParameters", "(IIIZZZZZZZIIJ)V",
75 reinterpret_cast<void*>(&webrtc::AudioManager::CacheAudioParameters)}};
76 j_native_registration_ = j_environment_->RegisterNatives(
77 "org/webrtc/voiceengine/WebRtcAudioManager", native_methods,
78 arraysize(native_methods));
79 j_audio_manager_.reset(
80 new JavaAudioManager(j_native_registration_.get(),
81 j_native_registration_->NewObject(
82 "<init>", "(J)V", PointerTojlong(this))));
83 }
84
~AudioManager()85 AudioManager::~AudioManager() {
86 RTC_LOG(INFO) << "dtor";
87 RTC_DCHECK(thread_checker_.IsCurrent());
88 Close();
89 }
90
SetActiveAudioLayer(AudioDeviceModule::AudioLayer audio_layer)91 void AudioManager::SetActiveAudioLayer(
92 AudioDeviceModule::AudioLayer audio_layer) {
93 RTC_LOG(INFO) << "SetActiveAudioLayer: " << audio_layer;
94 RTC_DCHECK(thread_checker_.IsCurrent());
95 RTC_DCHECK(!initialized_);
96 // Store the currently utilized audio layer.
97 audio_layer_ = audio_layer;
98 // The delay estimate can take one of two fixed values depending on if the
99 // device supports low-latency output or not. However, it is also possible
100 // that the user explicitly selects the high-latency audio path, hence we use
101 // the selected |audio_layer| here to set the delay estimate.
102 delay_estimate_in_milliseconds_ =
103 (audio_layer == AudioDeviceModule::kAndroidJavaAudio)
104 ? kHighLatencyModeDelayEstimateInMilliseconds
105 : kLowLatencyModeDelayEstimateInMilliseconds;
106 RTC_LOG(INFO) << "delay_estimate_in_milliseconds: "
107 << delay_estimate_in_milliseconds_;
108 }
109
GetOpenSLEngine()110 SLObjectItf AudioManager::GetOpenSLEngine() {
111 RTC_LOG(INFO) << "GetOpenSLEngine";
112 RTC_DCHECK(thread_checker_.IsCurrent());
113 // Only allow usage of OpenSL ES if such an audio layer has been specified.
114 if (audio_layer_ != AudioDeviceModule::kAndroidOpenSLESAudio &&
115 audio_layer_ !=
116 AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio) {
117 RTC_LOG(INFO)
118 << "Unable to create OpenSL engine for the current audio layer: "
119 << audio_layer_;
120 return nullptr;
121 }
122 // OpenSL ES for Android only supports a single engine per application.
123 // If one already has been created, return existing object instead of
124 // creating a new.
125 if (engine_object_.Get() != nullptr) {
126 RTC_LOG(WARNING) << "The OpenSL ES engine object has already been created";
127 return engine_object_.Get();
128 }
129 // Create the engine object in thread safe mode.
130 const SLEngineOption option[] = {
131 {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
132 SLresult result =
133 slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL);
134 if (result != SL_RESULT_SUCCESS) {
135 RTC_LOG(LS_ERROR) << "slCreateEngine() failed: "
136 << GetSLErrorString(result);
137 engine_object_.Reset();
138 return nullptr;
139 }
140 // Realize the SL Engine in synchronous mode.
141 result = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE);
142 if (result != SL_RESULT_SUCCESS) {
143 RTC_LOG(LS_ERROR) << "Realize() failed: " << GetSLErrorString(result);
144 engine_object_.Reset();
145 return nullptr;
146 }
147 // Finally return the SLObjectItf interface of the engine object.
148 return engine_object_.Get();
149 }
150
Init()151 bool AudioManager::Init() {
152 RTC_LOG(INFO) << "Init";
153 RTC_DCHECK(thread_checker_.IsCurrent());
154 RTC_DCHECK(!initialized_);
155 RTC_DCHECK_NE(audio_layer_, AudioDeviceModule::kPlatformDefaultAudio);
156 if (!j_audio_manager_->Init()) {
157 RTC_LOG(LS_ERROR) << "Init() failed";
158 return false;
159 }
160 initialized_ = true;
161 return true;
162 }
163
Close()164 bool AudioManager::Close() {
165 RTC_LOG(INFO) << "Close";
166 RTC_DCHECK(thread_checker_.IsCurrent());
167 if (!initialized_)
168 return true;
169 j_audio_manager_->Close();
170 initialized_ = false;
171 return true;
172 }
173
IsCommunicationModeEnabled() const174 bool AudioManager::IsCommunicationModeEnabled() const {
175 RTC_DCHECK(thread_checker_.IsCurrent());
176 return j_audio_manager_->IsCommunicationModeEnabled();
177 }
178
IsAcousticEchoCancelerSupported() const179 bool AudioManager::IsAcousticEchoCancelerSupported() const {
180 RTC_DCHECK(thread_checker_.IsCurrent());
181 return hardware_aec_;
182 }
183
IsAutomaticGainControlSupported() const184 bool AudioManager::IsAutomaticGainControlSupported() const {
185 RTC_DCHECK(thread_checker_.IsCurrent());
186 return hardware_agc_;
187 }
188
IsNoiseSuppressorSupported() const189 bool AudioManager::IsNoiseSuppressorSupported() const {
190 RTC_DCHECK(thread_checker_.IsCurrent());
191 return hardware_ns_;
192 }
193
IsLowLatencyPlayoutSupported() const194 bool AudioManager::IsLowLatencyPlayoutSupported() const {
195 RTC_DCHECK(thread_checker_.IsCurrent());
196 // Some devices are blacklisted for usage of OpenSL ES even if they report
197 // that low-latency playout is supported. See b/21485703 for details.
198 return j_audio_manager_->IsDeviceBlacklistedForOpenSLESUsage()
199 ? false
200 : low_latency_playout_;
201 }
202
IsLowLatencyRecordSupported() const203 bool AudioManager::IsLowLatencyRecordSupported() const {
204 RTC_DCHECK(thread_checker_.IsCurrent());
205 return low_latency_record_;
206 }
207
IsProAudioSupported() const208 bool AudioManager::IsProAudioSupported() const {
209 RTC_DCHECK(thread_checker_.IsCurrent());
210 // TODO(henrika): return the state independently of if OpenSL ES is
211 // blacklisted or not for now. We could use the same approach as in
212 // IsLowLatencyPlayoutSupported() but I can't see the need for it yet.
213 return pro_audio_;
214 }
215
216 // TODO(henrika): improve comments...
IsAAudioSupported() const217 bool AudioManager::IsAAudioSupported() const {
218 #if defined(WEBRTC_AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
219 return a_audio_;
220 #else
221 return false;
222 #endif
223 }
224
IsStereoPlayoutSupported() const225 bool AudioManager::IsStereoPlayoutSupported() const {
226 RTC_DCHECK(thread_checker_.IsCurrent());
227 return (playout_parameters_.channels() == 2);
228 }
229
IsStereoRecordSupported() const230 bool AudioManager::IsStereoRecordSupported() const {
231 RTC_DCHECK(thread_checker_.IsCurrent());
232 return (record_parameters_.channels() == 2);
233 }
234
GetDelayEstimateInMilliseconds() const235 int AudioManager::GetDelayEstimateInMilliseconds() const {
236 return delay_estimate_in_milliseconds_;
237 }
238
239 JNI_FUNCTION_ALIGN
CacheAudioParameters(JNIEnv * env,jobject obj,jint sample_rate,jint output_channels,jint input_channels,jboolean hardware_aec,jboolean hardware_agc,jboolean hardware_ns,jboolean low_latency_output,jboolean low_latency_input,jboolean pro_audio,jboolean a_audio,jint output_buffer_size,jint input_buffer_size,jlong native_audio_manager)240 void JNICALL AudioManager::CacheAudioParameters(JNIEnv* env,
241 jobject obj,
242 jint sample_rate,
243 jint output_channels,
244 jint input_channels,
245 jboolean hardware_aec,
246 jboolean hardware_agc,
247 jboolean hardware_ns,
248 jboolean low_latency_output,
249 jboolean low_latency_input,
250 jboolean pro_audio,
251 jboolean a_audio,
252 jint output_buffer_size,
253 jint input_buffer_size,
254 jlong native_audio_manager) {
255 webrtc::AudioManager* this_object =
256 reinterpret_cast<webrtc::AudioManager*>(native_audio_manager);
257 this_object->OnCacheAudioParameters(
258 env, sample_rate, output_channels, input_channels, hardware_aec,
259 hardware_agc, hardware_ns, low_latency_output, low_latency_input,
260 pro_audio, a_audio, output_buffer_size, input_buffer_size);
261 }
262
OnCacheAudioParameters(JNIEnv * env,jint sample_rate,jint output_channels,jint input_channels,jboolean hardware_aec,jboolean hardware_agc,jboolean hardware_ns,jboolean low_latency_output,jboolean low_latency_input,jboolean pro_audio,jboolean a_audio,jint output_buffer_size,jint input_buffer_size)263 void AudioManager::OnCacheAudioParameters(JNIEnv* env,
264 jint sample_rate,
265 jint output_channels,
266 jint input_channels,
267 jboolean hardware_aec,
268 jboolean hardware_agc,
269 jboolean hardware_ns,
270 jboolean low_latency_output,
271 jboolean low_latency_input,
272 jboolean pro_audio,
273 jboolean a_audio,
274 jint output_buffer_size,
275 jint input_buffer_size) {
276 RTC_LOG(INFO)
277 << "OnCacheAudioParameters: "
278 "hardware_aec: "
279 << static_cast<bool>(hardware_aec)
280 << ", hardware_agc: " << static_cast<bool>(hardware_agc)
281 << ", hardware_ns: " << static_cast<bool>(hardware_ns)
282 << ", low_latency_output: " << static_cast<bool>(low_latency_output)
283 << ", low_latency_input: " << static_cast<bool>(low_latency_input)
284 << ", pro_audio: " << static_cast<bool>(pro_audio)
285 << ", a_audio: " << static_cast<bool>(a_audio)
286 << ", sample_rate: " << static_cast<int>(sample_rate)
287 << ", output_channels: " << static_cast<int>(output_channels)
288 << ", input_channels: " << static_cast<int>(input_channels)
289 << ", output_buffer_size: " << static_cast<int>(output_buffer_size)
290 << ", input_buffer_size: " << static_cast<int>(input_buffer_size);
291 RTC_DCHECK(thread_checker_.IsCurrent());
292 hardware_aec_ = hardware_aec;
293 hardware_agc_ = hardware_agc;
294 hardware_ns_ = hardware_ns;
295 low_latency_playout_ = low_latency_output;
296 low_latency_record_ = low_latency_input;
297 pro_audio_ = pro_audio;
298 a_audio_ = a_audio;
299 playout_parameters_.reset(sample_rate, static_cast<size_t>(output_channels),
300 static_cast<size_t>(output_buffer_size));
301 record_parameters_.reset(sample_rate, static_cast<size_t>(input_channels),
302 static_cast<size_t>(input_buffer_size));
303 }
304
GetPlayoutAudioParameters()305 const AudioParameters& AudioManager::GetPlayoutAudioParameters() {
306 RTC_CHECK(playout_parameters_.is_valid());
307 RTC_DCHECK(thread_checker_.IsCurrent());
308 return playout_parameters_;
309 }
310
GetRecordAudioParameters()311 const AudioParameters& AudioManager::GetRecordAudioParameters() {
312 RTC_CHECK(record_parameters_.is_valid());
313 RTC_DCHECK(thread_checker_.IsCurrent());
314 return record_parameters_;
315 }
316
317 } // namespace webrtc
318