1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/audio/android/audio_manager_android.h"
6
7 #include <memory>
8
9 #include "base/android/build_info.h"
10 #include "base/android/jni_array.h"
11 #include "base/android/jni_string.h"
12 #include "base/android/scoped_java_ref.h"
13 #include "base/bind.h"
14 #include "base/files/file_path.h"
15 #include "base/logging.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "media/audio/android/aaudio_output.h"
18 #include "media/audio/android/aaudio_stubs.h"
19 #include "media/audio/android/audio_track_output_stream.h"
20 #include "media/audio/android/opensles_input.h"
21 #include "media/audio/android/opensles_output.h"
22 #include "media/audio/audio_device_description.h"
23 #include "media/audio/audio_features.h"
24 #include "media/audio/audio_manager.h"
25 #include "media/audio/fake_audio_input_stream.h"
26 #include "media/base/android/media_jni_headers/AudioManagerAndroid_jni.h"
27 #include "media/base/audio_parameters.h"
28 #include "media/base/channel_layout.h"
29
30 using base::android::AppendJavaStringArrayToStringVector;
31 using base::android::AttachCurrentThread;
32 using base::android::ConvertJavaStringToUTF8;
33 using base::android::ConvertUTF8ToJavaString;
34 using base::android::JavaParamRef;
35 using base::android::JavaRef;
36 using base::android::ScopedJavaLocalRef;
37
38 using media_audio_android::InitializeStubs;
39 using media_audio_android::kModuleAaudio;
40 using media_audio_android::StubPathMap;
41
42 static const base::FilePath::CharType kAaudioLib[] =
43 FILE_PATH_LITERAL("libaaudio.so");
44
45 namespace media {
46 namespace {
47
AddDefaultDevice(AudioDeviceNames * device_names)48 void AddDefaultDevice(AudioDeviceNames* device_names) {
49 DCHECK(device_names->empty());
50 device_names->push_front(AudioDeviceName::CreateDefault());
51 }
52
53 // Maximum number of output streams that can be open simultaneously.
54 const int kMaxOutputStreams = 10;
55
56 const int kDefaultInputBufferSize = 1024;
57 const int kDefaultOutputBufferSize = 2048;
58
59 } // namespace
60
InitAAudio()61 static bool InitAAudio() {
62 StubPathMap paths;
63
64 // Check if the AAudio library is available.
65 paths[kModuleAaudio].push_back(kAaudioLib);
66 if (!InitializeStubs(paths)) {
67 VLOG(1) << "Failed on loading the AAudio library and symbols";
68 return false;
69 }
70 return true;
71 }
72
CreateAudioManager(std::unique_ptr<AudioThread> audio_thread,AudioLogFactory * audio_log_factory)73 std::unique_ptr<AudioManager> CreateAudioManager(
74 std::unique_ptr<AudioThread> audio_thread,
75 AudioLogFactory* audio_log_factory) {
76 return std::make_unique<AudioManagerAndroid>(std::move(audio_thread),
77 audio_log_factory);
78 }
79
AudioManagerAndroid(std::unique_ptr<AudioThread> audio_thread,AudioLogFactory * audio_log_factory)80 AudioManagerAndroid::AudioManagerAndroid(
81 std::unique_ptr<AudioThread> audio_thread,
82 AudioLogFactory* audio_log_factory)
83 : AudioManagerBase(std::move(audio_thread), audio_log_factory),
84 communication_mode_is_on_(false),
85 output_volume_override_set_(false),
86 output_volume_override_(0) {
87 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
88 }
89
90 AudioManagerAndroid::~AudioManagerAndroid() = default;
91
InitializeIfNeeded()92 void AudioManagerAndroid::InitializeIfNeeded() {
93 GetTaskRunner()->PostTask(
94 FROM_HERE, base::BindOnce(base::IgnoreResult(
95 &AudioManagerAndroid::GetJavaAudioManager),
96 base::Unretained(this)));
97 }
98
ShutdownOnAudioThread()99 void AudioManagerAndroid::ShutdownOnAudioThread() {
100 AudioManagerBase::ShutdownOnAudioThread();
101
102 // Destory java android manager here because it can only be accessed on the
103 // audio thread.
104 if (!j_audio_manager_.is_null()) {
105 DVLOG(2) << "Destroying Java part of the audio manager";
106 Java_AudioManagerAndroid_close(base::android::AttachCurrentThread(),
107 j_audio_manager_);
108 j_audio_manager_.Reset();
109 }
110 }
111
HasAudioOutputDevices()112 bool AudioManagerAndroid::HasAudioOutputDevices() {
113 return true;
114 }
115
HasAudioInputDevices()116 bool AudioManagerAndroid::HasAudioInputDevices() {
117 return true;
118 }
119
GetAudioInputDeviceNames(AudioDeviceNames * device_names)120 void AudioManagerAndroid::GetAudioInputDeviceNames(
121 AudioDeviceNames* device_names) {
122 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
123
124 // Always add default device parameters as first element.
125 DCHECK(device_names->empty());
126 AddDefaultDevice(device_names);
127
128 // Get list of available audio devices.
129 JNIEnv* env = AttachCurrentThread();
130 ScopedJavaLocalRef<jobjectArray> j_device_array =
131 Java_AudioManagerAndroid_getAudioInputDeviceNames(env,
132 GetJavaAudioManager());
133 if (j_device_array.is_null()) {
134 // Most probable reason for a NULL result here is that the process lacks
135 // MODIFY_AUDIO_SETTINGS or RECORD_AUDIO permissions.
136 return;
137 }
138 AudioDeviceName device;
139 for (auto j_device : j_device_array.ReadElements<jobject>()) {
140 ScopedJavaLocalRef<jstring> j_device_name =
141 Java_AudioDeviceName_name(env, j_device);
142 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name);
143 ScopedJavaLocalRef<jstring> j_device_id =
144 Java_AudioDeviceName_id(env, j_device);
145 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id);
146 device_names->push_back(device);
147 }
148
149 for (auto d : *device_names) {
150 DVLOG(1) << "device_name: " << d.device_name;
151 DVLOG(1) << "unique_id: " << d.unique_id;
152 }
153 }
154
GetAudioOutputDeviceNames(AudioDeviceNames * device_names)155 void AudioManagerAndroid::GetAudioOutputDeviceNames(
156 AudioDeviceNames* device_names) {
157 // TODO(henrika): enumerate using GetAudioInputDeviceNames().
158 AddDefaultDevice(device_names);
159 }
160
GetInputStreamParameters(const std::string & device_id)161 AudioParameters AudioManagerAndroid::GetInputStreamParameters(
162 const std::string& device_id) {
163 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
164
165 // Use mono as preferred number of input channels on Android to save
166 // resources. Using mono also avoids a driver issue seen on Samsung
167 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
168 JNIEnv* env = AttachCurrentThread();
169 ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
170 int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
171 env, GetNativeOutputSampleRate(),
172 ChannelLayoutToChannelCount(channel_layout));
173 buffer_size = buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size;
174 int effects = AudioParameters::NO_EFFECTS;
175 effects |= Java_AudioManagerAndroid_acousticEchoCancelerIsAvailable(env)
176 ? AudioParameters::ECHO_CANCELLER
177 : AudioParameters::NO_EFFECTS;
178
179 int user_buffer_size = GetUserBufferSize();
180 if (user_buffer_size)
181 buffer_size = user_buffer_size;
182
183 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
184 GetNativeOutputSampleRate(), buffer_size);
185 params.set_effects(effects);
186 DVLOG(1) << params.AsHumanReadableString();
187 return params;
188 }
189
GetName()190 const char* AudioManagerAndroid::GetName() {
191 return "Android";
192 }
193
MakeAudioOutputStream(const AudioParameters & params,const std::string & device_id,const LogCallback & log_callback)194 AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
195 const AudioParameters& params,
196 const std::string& device_id,
197 const LogCallback& log_callback) {
198 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
199 AudioOutputStream* stream = AudioManagerBase::MakeAudioOutputStream(
200 params, std::string(), AudioManager::LogCallback());
201 if (stream)
202 streams_.insert(static_cast<MuteableAudioOutputStream*>(stream));
203 return stream;
204 }
205
MakeAudioInputStream(const AudioParameters & params,const std::string & device_id,const LogCallback & log_callback)206 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
207 const AudioParameters& params,
208 const std::string& device_id,
209 const LogCallback& log_callback) {
210 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
211 bool has_no_input_streams = HasNoAudioInputStreams();
212 AudioInputStream* stream = AudioManagerBase::MakeAudioInputStream(
213 params, device_id, AudioManager::LogCallback());
214
215 // By default, the audio manager for Android creates streams intended for
216 // real-time VoIP sessions and therefore sets the audio mode to
217 // MODE_IN_COMMUNICATION. However, the user might have asked for a special
218 // mode where all audio input processing is disabled, and if that is the case
219 // we avoid changing the mode.
220 if (stream && has_no_input_streams &&
221 params.effects() != AudioParameters::NO_EFFECTS) {
222 communication_mode_is_on_ = true;
223 SetCommunicationAudioModeOn(true);
224 }
225 return stream;
226 }
227
ReleaseOutputStream(AudioOutputStream * stream)228 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
229 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
230 streams_.erase(static_cast<MuteableAudioOutputStream*>(stream));
231 AudioManagerBase::ReleaseOutputStream(stream);
232 }
233
ReleaseInputStream(AudioInputStream * stream)234 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
235 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
236 AudioManagerBase::ReleaseInputStream(stream);
237
238 // Restore the audio mode which was used before the first communication-
239 // mode stream was created.
240 if (HasNoAudioInputStreams() && communication_mode_is_on_) {
241 communication_mode_is_on_ = false;
242 SetCommunicationAudioModeOn(false);
243 }
244 }
245
MakeLinearOutputStream(const AudioParameters & params,const LogCallback & log_callback)246 AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
247 const AudioParameters& params,
248 const LogCallback& log_callback) {
249 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
250 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
251
252 if (UseAAudio())
253 return new AAudioOutputStream(this, params, AAUDIO_USAGE_MEDIA);
254
255 return new OpenSLESOutputStream(this, params, SL_ANDROID_STREAM_MEDIA);
256 }
257
MakeLowLatencyOutputStream(const AudioParameters & params,const std::string & device_id,const LogCallback & log_callback)258 AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
259 const AudioParameters& params,
260 const std::string& device_id,
261 const LogCallback& log_callback) {
262 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
263 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
264
265 if (UseAAudio()) {
266 const aaudio_usage_t usage = communication_mode_is_on_
267 ? AAUDIO_USAGE_VOICE_COMMUNICATION
268 : AAUDIO_USAGE_MEDIA;
269 return new AAudioOutputStream(this, params, usage);
270 }
271
272 // Set stream type which matches the current system-wide audio mode used by
273 // the Android audio manager.
274 const SLint32 stream_type = communication_mode_is_on_
275 ? SL_ANDROID_STREAM_VOICE
276 : SL_ANDROID_STREAM_MEDIA;
277 return new OpenSLESOutputStream(this, params, stream_type);
278 }
279
MakeBitstreamOutputStream(const AudioParameters & params,const std::string & device_id,const LogCallback & log_callback)280 AudioOutputStream* AudioManagerAndroid::MakeBitstreamOutputStream(
281 const AudioParameters& params,
282 const std::string& device_id,
283 const LogCallback& log_callback) {
284 DCHECK(params.IsBitstreamFormat());
285 return new AudioTrackOutputStream(this, params);
286 }
287
MakeLinearInputStream(const AudioParameters & params,const std::string & device_id,const LogCallback & log_callback)288 AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
289 const AudioParameters& params,
290 const std::string& device_id,
291 const LogCallback& log_callback) {
292 // TODO(henrika): add support for device selection if/when any client
293 // needs it.
294 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
295 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
296 return new OpenSLESInputStream(this, params);
297 }
298
MakeLowLatencyInputStream(const AudioParameters & params,const std::string & device_id,const LogCallback & log_callback)299 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
300 const AudioParameters& params,
301 const std::string& device_id,
302 const LogCallback& log_callback) {
303 DVLOG(1) << "MakeLowLatencyInputStream: " << params.effects();
304 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
305 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
306 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
307
308 // Use the device ID to select the correct input device.
309 // Note that the input device is always associated with a certain output
310 // device, i.e., this selection does also switch the output device.
311 // All input and output streams will be affected by the device selection.
312 if (!SetAudioDevice(device_id)) {
313 LOG(ERROR) << "Unable to select audio device!";
314 return NULL;
315 }
316
317 // Create a new audio input stream and enable or disable all audio effects
318 // given |params.effects()|.
319 return new OpenSLESInputStream(this, params);
320 }
321
322 // static
SupportsPerformanceModeForOutput()323 bool AudioManagerAndroid::SupportsPerformanceModeForOutput() {
324 return base::android::BuildInfo::GetInstance()->sdk_int() >=
325 base::android::SDK_VERSION_NOUGAT_MR1;
326 }
327
SetMute(JNIEnv * env,const JavaParamRef<jobject> & obj,jboolean muted)328 void AudioManagerAndroid::SetMute(JNIEnv* env,
329 const JavaParamRef<jobject>& obj,
330 jboolean muted) {
331 GetTaskRunner()->PostTask(
332 FROM_HERE, base::BindOnce(&AudioManagerAndroid::DoSetMuteOnAudioThread,
333 base::Unretained(this), muted));
334 }
335
SetOutputVolumeOverride(double volume)336 void AudioManagerAndroid::SetOutputVolumeOverride(double volume) {
337 GetTaskRunner()->PostTask(
338 FROM_HERE, base::BindOnce(&AudioManagerAndroid::DoSetVolumeOnAudioThread,
339 base::Unretained(this), volume));
340 }
341
HasOutputVolumeOverride(double * out_volume) const342 bool AudioManagerAndroid::HasOutputVolumeOverride(double* out_volume) const {
343 if (output_volume_override_set_) {
344 *out_volume = output_volume_override_;
345 }
346 return output_volume_override_set_;
347 }
348
GetOutputLatency()349 base::TimeDelta AudioManagerAndroid::GetOutputLatency() {
350 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
351 JNIEnv* env = AttachCurrentThread();
352 return base::TimeDelta::FromMilliseconds(
353 Java_AudioManagerAndroid_getOutputLatency(env, GetJavaAudioManager()));
354 }
355
GetPreferredOutputStreamParameters(const std::string & output_device_id,const AudioParameters & input_params)356 AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
357 const std::string& output_device_id,
358 const AudioParameters& input_params) {
359 DVLOG(1) << __FUNCTION__;
360 // TODO(tommi): Support |output_device_id|.
361 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
362 DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
363 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
364 int sample_rate = GetNativeOutputSampleRate();
365 int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2);
366 if (input_params.IsValid()) {
367 // Use the client's input parameters if they are valid.
368 sample_rate = input_params.sample_rate();
369
370 // Pre-Lollipop devices don't support > stereo OpenSLES output and the
371 // AudioManager APIs for GetOptimalOutputFrameSize() don't support channel
372 // layouts greater than stereo unless low latency audio is supported.
373 if (input_params.channels() <= 2 ||
374 (base::android::BuildInfo::GetInstance()->sdk_int() >=
375 base::android::SDK_VERSION_LOLLIPOP &&
376 IsAudioLowLatencySupported())) {
377 channel_layout = input_params.channel_layout();
378 }
379
380 // For high latency playback on supported platforms, pass through the
381 // requested buffer size; this provides significant power savings (~25%) and
382 // reduces the potential for glitches under load.
383 if (SupportsPerformanceModeForOutput() &&
384 input_params.latency_tag() == AudioLatency::LATENCY_PLAYBACK) {
385 buffer_size = input_params.frames_per_buffer();
386 } else {
387 buffer_size = GetOptimalOutputFrameSize(
388 sample_rate, ChannelLayoutToChannelCount(channel_layout));
389 }
390 }
391
392 int user_buffer_size = GetUserBufferSize();
393 if (user_buffer_size)
394 buffer_size = user_buffer_size;
395
396 return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
397 sample_rate, buffer_size);
398 }
399
HasNoAudioInputStreams()400 bool AudioManagerAndroid::HasNoAudioInputStreams() {
401 return input_stream_count() == 0;
402 }
403
GetJavaAudioManager()404 const JavaRef<jobject>& AudioManagerAndroid::GetJavaAudioManager() {
405 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
406 if (j_audio_manager_.is_null()) {
407 // Create the Android audio manager on the audio thread.
408 DVLOG(2) << "Creating Java part of the audio manager";
409 j_audio_manager_.Reset(Java_AudioManagerAndroid_createAudioManagerAndroid(
410 base::android::AttachCurrentThread(),
411 reinterpret_cast<intptr_t>(this)));
412
413 // Prepare the list of audio devices and register receivers for device
414 // notifications.
415 Java_AudioManagerAndroid_init(base::android::AttachCurrentThread(),
416 j_audio_manager_);
417 }
418 return j_audio_manager_;
419 }
420
SetCommunicationAudioModeOn(bool on)421 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
422 DVLOG(1) << __FUNCTION__ << ": " << on;
423 Java_AudioManagerAndroid_setCommunicationAudioModeOn(
424 base::android::AttachCurrentThread(), GetJavaAudioManager(), on);
425 }
426
SetAudioDevice(const std::string & device_id)427 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
428 DVLOG(1) << __FUNCTION__ << ": " << device_id;
429 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
430
431 // Send the unique device ID to the Java audio manager and make the
432 // device switch. Provide an empty string to the Java audio manager
433 // if the default device is selected.
434 JNIEnv* env = AttachCurrentThread();
435 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
436 env, device_id == AudioDeviceDescription::kDefaultDeviceId ? std::string()
437 : device_id);
438 return Java_AudioManagerAndroid_setDevice(env, GetJavaAudioManager(),
439 j_device_id);
440 }
441
GetNativeOutputSampleRate()442 int AudioManagerAndroid::GetNativeOutputSampleRate() {
443 return Java_AudioManagerAndroid_getNativeOutputSampleRate(
444 base::android::AttachCurrentThread(), GetJavaAudioManager());
445 }
446
IsAudioLowLatencySupported()447 bool AudioManagerAndroid::IsAudioLowLatencySupported() {
448 return Java_AudioManagerAndroid_isAudioLowLatencySupported(
449 base::android::AttachCurrentThread(), GetJavaAudioManager());
450 }
451
GetAudioLowLatencyOutputFrameSize()452 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
453 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
454 base::android::AttachCurrentThread(), GetJavaAudioManager());
455 }
456
GetOptimalOutputFrameSize(int sample_rate,int channels)457 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
458 int channels) {
459 if (IsAudioLowLatencySupported())
460 return GetAudioLowLatencyOutputFrameSize();
461
462 return std::max(kDefaultOutputBufferSize,
463 Java_AudioManagerAndroid_getMinOutputFrameSize(
464 base::android::AttachCurrentThread(),
465 sample_rate, channels));
466 }
467
DoSetMuteOnAudioThread(bool muted)468 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
469 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
470 for (OutputStreams::iterator it = streams_.begin();
471 it != streams_.end(); ++it) {
472 (*it)->SetMute(muted);
473 }
474 }
475
DoSetVolumeOnAudioThread(double volume)476 void AudioManagerAndroid::DoSetVolumeOnAudioThread(double volume) {
477 output_volume_override_set_ = true;
478 output_volume_override_ = volume;
479
480 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
481 for (OutputStreams::iterator it = streams_.begin(); it != streams_.end();
482 ++it) {
483 (*it)->SetVolume(volume);
484 }
485 }
486
UseAAudio()487 bool AudioManagerAndroid::UseAAudio() {
488 if (!base::FeatureList::IsEnabled(features::kUseAAudioDriver))
489 return false;
490
491 if (base::android::BuildInfo::GetInstance()->sdk_int() <
492 base::android::SDK_VERSION_P) {
493 // We need APIs that weren't added until API Level 28.
494 return false;
495 }
496
497 if (!is_aaudio_available_.has_value())
498 is_aaudio_available_ = InitAAudio();
499
500 return is_aaudio_available_.value();
501 }
502
503 } // namespace media
504