xref: /aosp_15_r20/external/webrtc/modules/audio_device/android/audio_manager.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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(LS_INFO) << "JavaAudioManager::ctor";
37 }
38 
~JavaAudioManager()39 AudioManager::JavaAudioManager::~JavaAudioManager() {
40   RTC_LOG(LS_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(LS_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(LS_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(LS_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(LS_INFO) << "delay_estimate_in_milliseconds: "
107                    << delay_estimate_in_milliseconds_;
108 }
109 
GetOpenSLEngine()110 SLObjectItf AudioManager::GetOpenSLEngine() {
111   RTC_LOG(LS_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(LS_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(LS_WARNING)
127         << "The OpenSL ES engine object has already been created";
128     return engine_object_.Get();
129   }
130   // Create the engine object in thread safe mode.
131   const SLEngineOption option[] = {
132       {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
133   SLresult result =
134       slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL);
135   if (result != SL_RESULT_SUCCESS) {
136     RTC_LOG(LS_ERROR) << "slCreateEngine() failed: "
137                       << GetSLErrorString(result);
138     engine_object_.Reset();
139     return nullptr;
140   }
141   // Realize the SL Engine in synchronous mode.
142   result = engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE);
143   if (result != SL_RESULT_SUCCESS) {
144     RTC_LOG(LS_ERROR) << "Realize() failed: " << GetSLErrorString(result);
145     engine_object_.Reset();
146     return nullptr;
147   }
148   // Finally return the SLObjectItf interface of the engine object.
149   return engine_object_.Get();
150 }
151 
Init()152 bool AudioManager::Init() {
153   RTC_LOG(LS_INFO) << "Init";
154   RTC_DCHECK(thread_checker_.IsCurrent());
155   RTC_DCHECK(!initialized_);
156   RTC_DCHECK_NE(audio_layer_, AudioDeviceModule::kPlatformDefaultAudio);
157   if (!j_audio_manager_->Init()) {
158     RTC_LOG(LS_ERROR) << "Init() failed";
159     return false;
160   }
161   initialized_ = true;
162   return true;
163 }
164 
Close()165 bool AudioManager::Close() {
166   RTC_LOG(LS_INFO) << "Close";
167   RTC_DCHECK(thread_checker_.IsCurrent());
168   if (!initialized_)
169     return true;
170   j_audio_manager_->Close();
171   initialized_ = false;
172   return true;
173 }
174 
IsCommunicationModeEnabled() const175 bool AudioManager::IsCommunicationModeEnabled() const {
176   RTC_DCHECK(thread_checker_.IsCurrent());
177   return j_audio_manager_->IsCommunicationModeEnabled();
178 }
179 
IsAcousticEchoCancelerSupported() const180 bool AudioManager::IsAcousticEchoCancelerSupported() const {
181   RTC_DCHECK(thread_checker_.IsCurrent());
182   return hardware_aec_;
183 }
184 
IsAutomaticGainControlSupported() const185 bool AudioManager::IsAutomaticGainControlSupported() const {
186   RTC_DCHECK(thread_checker_.IsCurrent());
187   return hardware_agc_;
188 }
189 
IsNoiseSuppressorSupported() const190 bool AudioManager::IsNoiseSuppressorSupported() const {
191   RTC_DCHECK(thread_checker_.IsCurrent());
192   return hardware_ns_;
193 }
194 
IsLowLatencyPlayoutSupported() const195 bool AudioManager::IsLowLatencyPlayoutSupported() const {
196   RTC_DCHECK(thread_checker_.IsCurrent());
197   // Some devices are blacklisted for usage of OpenSL ES even if they report
198   // that low-latency playout is supported. See b/21485703 for details.
199   return j_audio_manager_->IsDeviceBlacklistedForOpenSLESUsage()
200              ? false
201              : low_latency_playout_;
202 }
203 
IsLowLatencyRecordSupported() const204 bool AudioManager::IsLowLatencyRecordSupported() const {
205   RTC_DCHECK(thread_checker_.IsCurrent());
206   return low_latency_record_;
207 }
208 
IsProAudioSupported() const209 bool AudioManager::IsProAudioSupported() const {
210   RTC_DCHECK(thread_checker_.IsCurrent());
211   // TODO(henrika): return the state independently of if OpenSL ES is
212   // blacklisted or not for now. We could use the same approach as in
213   // IsLowLatencyPlayoutSupported() but I can't see the need for it yet.
214   return pro_audio_;
215 }
216 
217 // TODO(henrika): improve comments...
IsAAudioSupported() const218 bool AudioManager::IsAAudioSupported() const {
219 #if defined(WEBRTC_AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
220   return a_audio_;
221 #else
222   return false;
223 #endif
224 }
225 
IsStereoPlayoutSupported() const226 bool AudioManager::IsStereoPlayoutSupported() const {
227   RTC_DCHECK(thread_checker_.IsCurrent());
228   return (playout_parameters_.channels() == 2);
229 }
230 
IsStereoRecordSupported() const231 bool AudioManager::IsStereoRecordSupported() const {
232   RTC_DCHECK(thread_checker_.IsCurrent());
233   return (record_parameters_.channels() == 2);
234 }
235 
GetDelayEstimateInMilliseconds() const236 int AudioManager::GetDelayEstimateInMilliseconds() const {
237   return delay_estimate_in_milliseconds_;
238 }
239 
240 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)241 void JNICALL AudioManager::CacheAudioParameters(JNIEnv* env,
242                                                 jobject obj,
243                                                 jint sample_rate,
244                                                 jint output_channels,
245                                                 jint input_channels,
246                                                 jboolean hardware_aec,
247                                                 jboolean hardware_agc,
248                                                 jboolean hardware_ns,
249                                                 jboolean low_latency_output,
250                                                 jboolean low_latency_input,
251                                                 jboolean pro_audio,
252                                                 jboolean a_audio,
253                                                 jint output_buffer_size,
254                                                 jint input_buffer_size,
255                                                 jlong native_audio_manager) {
256   webrtc::AudioManager* this_object =
257       reinterpret_cast<webrtc::AudioManager*>(native_audio_manager);
258   this_object->OnCacheAudioParameters(
259       env, sample_rate, output_channels, input_channels, hardware_aec,
260       hardware_agc, hardware_ns, low_latency_output, low_latency_input,
261       pro_audio, a_audio, output_buffer_size, input_buffer_size);
262 }
263 
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)264 void AudioManager::OnCacheAudioParameters(JNIEnv* env,
265                                           jint sample_rate,
266                                           jint output_channels,
267                                           jint input_channels,
268                                           jboolean hardware_aec,
269                                           jboolean hardware_agc,
270                                           jboolean hardware_ns,
271                                           jboolean low_latency_output,
272                                           jboolean low_latency_input,
273                                           jboolean pro_audio,
274                                           jboolean a_audio,
275                                           jint output_buffer_size,
276                                           jint input_buffer_size) {
277   RTC_LOG(LS_INFO)
278       << "OnCacheAudioParameters: "
279          "hardware_aec: "
280       << static_cast<bool>(hardware_aec)
281       << ", hardware_agc: " << static_cast<bool>(hardware_agc)
282       << ", hardware_ns: " << static_cast<bool>(hardware_ns)
283       << ", low_latency_output: " << static_cast<bool>(low_latency_output)
284       << ", low_latency_input: " << static_cast<bool>(low_latency_input)
285       << ", pro_audio: " << static_cast<bool>(pro_audio)
286       << ", a_audio: " << static_cast<bool>(a_audio)
287       << ", sample_rate: " << static_cast<int>(sample_rate)
288       << ", output_channels: " << static_cast<int>(output_channels)
289       << ", input_channels: " << static_cast<int>(input_channels)
290       << ", output_buffer_size: " << static_cast<int>(output_buffer_size)
291       << ", input_buffer_size: " << static_cast<int>(input_buffer_size);
292   RTC_DCHECK(thread_checker_.IsCurrent());
293   hardware_aec_ = hardware_aec;
294   hardware_agc_ = hardware_agc;
295   hardware_ns_ = hardware_ns;
296   low_latency_playout_ = low_latency_output;
297   low_latency_record_ = low_latency_input;
298   pro_audio_ = pro_audio;
299   a_audio_ = a_audio;
300   playout_parameters_.reset(sample_rate, static_cast<size_t>(output_channels),
301                             static_cast<size_t>(output_buffer_size));
302   record_parameters_.reset(sample_rate, static_cast<size_t>(input_channels),
303                            static_cast<size_t>(input_buffer_size));
304 }
305 
GetPlayoutAudioParameters()306 const AudioParameters& AudioManager::GetPlayoutAudioParameters() {
307   RTC_CHECK(playout_parameters_.is_valid());
308   RTC_DCHECK(thread_checker_.IsCurrent());
309   return playout_parameters_;
310 }
311 
GetRecordAudioParameters()312 const AudioParameters& AudioManager::GetRecordAudioParameters() {
313   RTC_CHECK(record_parameters_.is_valid());
314   RTC_DCHECK(thread_checker_.IsCurrent());
315   return record_parameters_;
316 }
317 
318 }  // namespace webrtc
319