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.
5 #include "media/audio/android/audio_manager_android.h"
7 #include "base/android/build_info.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/android/scoped_java_ref.h"
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "jni/AudioManagerAndroid_jni.h"
16 #include "media/audio/android/audio_record_input.h"
17 #include "media/audio/android/opensles_input.h"
18 #include "media/audio/android/opensles_output.h"
19 #include "media/audio/audio_manager.h"
20 #include "media/audio/audio_parameters.h"
21 #include "media/audio/fake_audio_input_stream.h"
22 #include "media/base/channel_layout.h"
24 using base::android::AppendJavaStringArrayToStringVector
;
25 using base::android::AttachCurrentThread
;
26 using base::android::ConvertJavaStringToUTF8
;
27 using base::android::ConvertUTF8ToJavaString
;
28 using base::android::ScopedJavaLocalRef
;
33 void AddDefaultDevice(AudioDeviceNames
* device_names
) {
34 DCHECK(device_names
->empty());
35 device_names
->push_front(AudioDeviceName(AudioManager::GetDefaultDeviceName(),
36 AudioManagerBase::kDefaultDeviceId
));
39 // Maximum number of output streams that can be open simultaneously.
40 const int kMaxOutputStreams
= 10;
42 const int kDefaultInputBufferSize
= 1024;
43 const int kDefaultOutputBufferSize
= 2048;
47 AudioManager
* CreateAudioManager(AudioLogFactory
* audio_log_factory
) {
48 return new AudioManagerAndroid(audio_log_factory
);
51 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory
* audio_log_factory
)
52 : AudioManagerBase(audio_log_factory
),
53 communication_mode_is_on_(false),
54 output_volume_override_set_(false),
55 output_volume_override_(0) {
56 SetMaxOutputStreamsAllowed(kMaxOutputStreams
);
58 // WARNING: This is executed on the UI loop, do not add any code here which
59 // loads libraries or attempts to call out into the OS. Instead add such code
60 // to the InitializeOnAudioThread() method below.
62 // Task must be posted last to avoid races from handing out "this" to the
64 GetTaskRunner()->PostTask(FROM_HERE
, base::Bind(
65 &AudioManagerAndroid::InitializeOnAudioThread
,
66 base::Unretained(this)));
69 AudioManagerAndroid::~AudioManagerAndroid() {
70 // It's safe to post a task here since Shutdown() will wait for all tasks to
71 // complete before returning.
72 GetTaskRunner()->PostTask(FROM_HERE
, base::Bind(
73 &AudioManagerAndroid::ShutdownOnAudioThread
, base::Unretained(this)));
77 bool AudioManagerAndroid::HasAudioOutputDevices() {
81 bool AudioManagerAndroid::HasAudioInputDevices() {
85 void AudioManagerAndroid::GetAudioInputDeviceNames(
86 AudioDeviceNames
* device_names
) {
87 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
89 // Always add default device parameters as first element.
90 DCHECK(device_names
->empty());
91 AddDefaultDevice(device_names
);
93 // Get list of available audio devices.
94 JNIEnv
* env
= AttachCurrentThread();
95 ScopedJavaLocalRef
<jobjectArray
> j_device_array
=
96 Java_AudioManagerAndroid_getAudioInputDeviceNames(
97 env
, j_audio_manager_
.obj());
98 if (j_device_array
.is_null()) {
99 // Most probable reason for a NULL result here is that the process lacks
100 // MODIFY_AUDIO_SETTINGS or RECORD_AUDIO permissions.
103 jsize len
= env
->GetArrayLength(j_device_array
.obj());
104 AudioDeviceName device
;
105 for (jsize i
= 0; i
< len
; ++i
) {
106 ScopedJavaLocalRef
<jobject
> j_device(
107 env
, env
->GetObjectArrayElement(j_device_array
.obj(), i
));
108 ScopedJavaLocalRef
<jstring
> j_device_name
=
109 Java_AudioDeviceName_name(env
, j_device
.obj());
110 ConvertJavaStringToUTF8(env
, j_device_name
.obj(), &device
.device_name
);
111 ScopedJavaLocalRef
<jstring
> j_device_id
=
112 Java_AudioDeviceName_id(env
, j_device
.obj());
113 ConvertJavaStringToUTF8(env
, j_device_id
.obj(), &device
.unique_id
);
114 device_names
->push_back(device
);
118 void AudioManagerAndroid::GetAudioOutputDeviceNames(
119 AudioDeviceNames
* device_names
) {
120 // TODO(henrika): enumerate using GetAudioInputDeviceNames().
121 AddDefaultDevice(device_names
);
124 AudioParameters
AudioManagerAndroid::GetInputStreamParameters(
125 const std::string
& device_id
) {
126 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
128 // Use mono as preferred number of input channels on Android to save
129 // resources. Using mono also avoids a driver issue seen on Samsung
130 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
131 JNIEnv
* env
= AttachCurrentThread();
132 ChannelLayout channel_layout
= CHANNEL_LAYOUT_MONO
;
133 int buffer_size
= Java_AudioManagerAndroid_getMinInputFrameSize(
134 env
, GetNativeOutputSampleRate(),
135 ChannelLayoutToChannelCount(channel_layout
));
136 buffer_size
= buffer_size
<= 0 ? kDefaultInputBufferSize
: buffer_size
;
137 int effects
= AudioParameters::NO_EFFECTS
;
138 effects
|= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env
) ?
139 AudioParameters::ECHO_CANCELLER
: AudioParameters::NO_EFFECTS
;
141 int user_buffer_size
= GetUserBufferSize();
142 if (user_buffer_size
)
143 buffer_size
= user_buffer_size
;
145 AudioParameters
params(AudioParameters::AUDIO_PCM_LOW_LATENCY
, channel_layout
,
146 GetNativeOutputSampleRate(), 16, buffer_size
);
147 params
.set_effects(effects
);
151 AudioOutputStream
* AudioManagerAndroid::MakeAudioOutputStream(
152 const AudioParameters
& params
,
153 const std::string
& device_id
) {
154 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
155 AudioOutputStream
* stream
=
156 AudioManagerBase::MakeAudioOutputStream(params
, std::string());
157 streams_
.insert(static_cast<OpenSLESOutputStream
*>(stream
));
161 AudioInputStream
* AudioManagerAndroid::MakeAudioInputStream(
162 const AudioParameters
& params
, const std::string
& device_id
) {
163 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
164 bool has_no_input_streams
= HasNoAudioInputStreams();
165 AudioInputStream
* stream
=
166 AudioManagerBase::MakeAudioInputStream(params
, device_id
);
168 // The audio manager for Android creates streams intended for real-time
169 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
170 // If a Bluetooth headset is used, the audio stream will use the SCO
171 // channel and therefore have a limited bandwidth (8kHz).
172 if (stream
&& has_no_input_streams
) {
173 communication_mode_is_on_
= true;
174 SetCommunicationAudioModeOn(true);
179 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream
* stream
) {
180 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
181 streams_
.erase(static_cast<OpenSLESOutputStream
*>(stream
));
182 AudioManagerBase::ReleaseOutputStream(stream
);
185 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream
* stream
) {
186 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
187 DCHECK(!j_audio_manager_
.is_null());
188 AudioManagerBase::ReleaseInputStream(stream
);
190 // Restore the audio mode which was used before the first communication-
191 // mode stream was created.
192 if (HasNoAudioInputStreams()) {
193 communication_mode_is_on_
= false;
194 SetCommunicationAudioModeOn(false);
198 AudioOutputStream
* AudioManagerAndroid::MakeLinearOutputStream(
199 const AudioParameters
& params
) {
200 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
201 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
202 return new OpenSLESOutputStream(this, params
, SL_ANDROID_STREAM_MEDIA
);
205 AudioOutputStream
* AudioManagerAndroid::MakeLowLatencyOutputStream(
206 const AudioParameters
& params
,
207 const std::string
& device_id
) {
208 DLOG_IF(ERROR
, !device_id
.empty()) << "Not implemented!";
209 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
211 // Set stream type which matches the current system-wide audio mode used by
212 // the Android audio manager.
213 const SLint32 stream_type
= communication_mode_is_on_
?
214 SL_ANDROID_STREAM_VOICE
: SL_ANDROID_STREAM_MEDIA
;
215 return new OpenSLESOutputStream(this, params
, stream_type
);
218 AudioInputStream
* AudioManagerAndroid::MakeLinearInputStream(
219 const AudioParameters
& params
, const std::string
& device_id
) {
220 // TODO(henrika): add support for device selection if/when any client
222 DLOG_IF(ERROR
, !device_id
.empty()) << "Not implemented!";
223 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
224 return new OpenSLESInputStream(this, params
);
227 AudioInputStream
* AudioManagerAndroid::MakeLowLatencyInputStream(
228 const AudioParameters
& params
, const std::string
& device_id
) {
229 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
230 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
231 DLOG_IF(ERROR
, device_id
.empty()) << "Invalid device ID!";
233 // Use the device ID to select the correct input device.
234 // Note that the input device is always associated with a certain output
235 // device, i.e., this selection does also switch the output device.
236 // All input and output streams will be affected by the device selection.
237 if (!SetAudioDevice(device_id
)) {
238 LOG(ERROR
) << "Unable to select audio device!";
242 if (params
.effects() != AudioParameters::NO_EFFECTS
) {
243 // Platform effects can only be enabled through the AudioRecord path.
244 // An effect should only have been requested here if recommended by
245 // AudioManagerAndroid.shouldUse<Effect>.
247 // Creating this class requires Jelly Bean, which is already guaranteed by
248 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use
249 // the effect settings as a way to select the input path.
250 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16);
251 DVLOG(1) << "Creating AudioRecordInputStream";
252 return new AudioRecordInputStream(this, params
);
254 DVLOG(1) << "Creating OpenSLESInputStream";
255 return new OpenSLESInputStream(this, params
);
259 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv
* env
) {
260 return RegisterNativesImpl(env
);
263 void AudioManagerAndroid::SetMute(JNIEnv
* env
, jobject obj
, jboolean muted
) {
264 GetTaskRunner()->PostTask(
267 &AudioManagerAndroid::DoSetMuteOnAudioThread
,
268 base::Unretained(this),
272 void AudioManagerAndroid::SetOutputVolumeOverride(double volume
) {
273 GetTaskRunner()->PostTask(
276 &AudioManagerAndroid::DoSetVolumeOnAudioThread
,
277 base::Unretained(this),
281 bool AudioManagerAndroid::HasOutputVolumeOverride(double* out_volume
) const {
282 if (output_volume_override_set_
) {
283 *out_volume
= output_volume_override_
;
285 return output_volume_override_set_
;
288 AudioParameters
AudioManagerAndroid::GetPreferredOutputStreamParameters(
289 const std::string
& output_device_id
,
290 const AudioParameters
& input_params
) {
291 // TODO(tommi): Support |output_device_id|.
292 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
293 DLOG_IF(ERROR
, !output_device_id
.empty()) << "Not implemented!";
294 ChannelLayout channel_layout
= CHANNEL_LAYOUT_STEREO
;
295 int sample_rate
= GetNativeOutputSampleRate();
296 int buffer_size
= GetOptimalOutputFrameSize(sample_rate
, 2);
297 int bits_per_sample
= 16;
298 if (input_params
.IsValid()) {
299 // Use the client's input parameters if they are valid.
300 sample_rate
= input_params
.sample_rate();
301 bits_per_sample
= input_params
.bits_per_sample();
302 channel_layout
= input_params
.channel_layout();
303 buffer_size
= GetOptimalOutputFrameSize(
304 sample_rate
, ChannelLayoutToChannelCount(channel_layout
));
307 int user_buffer_size
= GetUserBufferSize();
308 if (user_buffer_size
)
309 buffer_size
= user_buffer_size
;
311 return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY
, channel_layout
,
312 sample_rate
, bits_per_sample
, buffer_size
);
315 bool AudioManagerAndroid::HasNoAudioInputStreams() {
316 return input_stream_count() == 0;
319 void AudioManagerAndroid::InitializeOnAudioThread() {
320 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
322 // Create the Android audio manager on the audio thread.
323 DVLOG(2) << "Creating Java part of the audio manager";
324 j_audio_manager_
.Reset(
325 Java_AudioManagerAndroid_createAudioManagerAndroid(
326 base::android::AttachCurrentThread(),
327 base::android::GetApplicationContext(),
328 reinterpret_cast<intptr_t>(this)));
330 // Prepare the list of audio devices and register receivers for device
332 Java_AudioManagerAndroid_init(
333 base::android::AttachCurrentThread(),
334 j_audio_manager_
.obj());
337 void AudioManagerAndroid::ShutdownOnAudioThread() {
338 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
339 DVLOG(2) << "Destroying Java part of the audio manager";
340 Java_AudioManagerAndroid_close(
341 base::android::AttachCurrentThread(),
342 j_audio_manager_
.obj());
343 j_audio_manager_
.Reset();
346 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on
) {
347 Java_AudioManagerAndroid_setCommunicationAudioModeOn(
348 base::android::AttachCurrentThread(),
349 j_audio_manager_
.obj(), on
);
352 bool AudioManagerAndroid::SetAudioDevice(const std::string
& device_id
) {
353 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
355 // Send the unique device ID to the Java audio manager and make the
356 // device switch. Provide an empty string to the Java audio manager
357 // if the default device is selected.
358 JNIEnv
* env
= AttachCurrentThread();
359 ScopedJavaLocalRef
<jstring
> j_device_id
= ConvertUTF8ToJavaString(
361 device_id
== AudioManagerBase::kDefaultDeviceId
?
362 std::string() : device_id
);
363 return Java_AudioManagerAndroid_setDevice(
364 env
, j_audio_manager_
.obj(), j_device_id
.obj());
367 int AudioManagerAndroid::GetNativeOutputSampleRate() {
368 return Java_AudioManagerAndroid_getNativeOutputSampleRate(
369 base::android::AttachCurrentThread(),
370 j_audio_manager_
.obj());
373 bool AudioManagerAndroid::IsAudioLowLatencySupported() {
374 return Java_AudioManagerAndroid_isAudioLowLatencySupported(
375 base::android::AttachCurrentThread(),
376 j_audio_manager_
.obj());
379 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
380 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
381 base::android::AttachCurrentThread(),
382 j_audio_manager_
.obj());
385 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate
,
387 if (IsAudioLowLatencySupported())
388 return GetAudioLowLatencyOutputFrameSize();
390 return std::max(kDefaultOutputBufferSize
,
391 Java_AudioManagerAndroid_getMinOutputFrameSize(
392 base::android::AttachCurrentThread(),
393 sample_rate
, channels
));
396 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted
) {
397 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
398 for (OutputStreams::iterator it
= streams_
.begin();
399 it
!= streams_
.end(); ++it
) {
400 (*it
)->SetMute(muted
);
404 void AudioManagerAndroid::DoSetVolumeOnAudioThread(double volume
) {
405 output_volume_override_set_
= true;
406 output_volume_override_
= volume
;
408 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
409 for (OutputStreams::iterator it
= streams_
.begin();
410 it
!= streams_
.end(); ++it
) {
411 (*it
)->SetVolume(volume
);