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