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
;
32 static void AddDefaultDevice(AudioDeviceNames
* device_names
) {
33 DCHECK(device_names
->empty());
34 device_names
->push_front(
35 AudioDeviceName(AudioManagerBase::kDefaultDeviceName
,
36 AudioManagerBase::kDefaultDeviceId
));
39 // Maximum number of output streams that can be open simultaneously.
40 static const int kMaxOutputStreams
= 10;
42 static const int kDefaultInputBufferSize
= 1024;
43 static const int kDefaultOutputBufferSize
= 2048;
45 AudioManager
* CreateAudioManager(AudioLogFactory
* audio_log_factory
) {
46 return new AudioManagerAndroid(audio_log_factory
);
49 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory
* audio_log_factory
)
50 : AudioManagerBase(audio_log_factory
),
51 communication_mode_is_on_(false),
52 output_volume_override_set_(false),
53 output_volume_override_(0) {
54 SetMaxOutputStreamsAllowed(kMaxOutputStreams
);
56 // WARNING: This is executed on the UI loop, do not add any code here which
57 // loads libraries or attempts to call out into the OS. Instead add such code
58 // to the InitializeOnAudioThread() method below.
60 // Task must be posted last to avoid races from handing out "this" to the
62 GetTaskRunner()->PostTask(FROM_HERE
, base::Bind(
63 &AudioManagerAndroid::InitializeOnAudioThread
,
64 base::Unretained(this)));
67 AudioManagerAndroid::~AudioManagerAndroid() {
68 // It's safe to post a task here since Shutdown() will wait for all tasks to
69 // complete before returning.
70 GetTaskRunner()->PostTask(FROM_HERE
, base::Bind(
71 &AudioManagerAndroid::ShutdownOnAudioThread
, base::Unretained(this)));
75 bool AudioManagerAndroid::HasAudioOutputDevices() {
79 bool AudioManagerAndroid::HasAudioInputDevices() {
83 void AudioManagerAndroid::GetAudioInputDeviceNames(
84 AudioDeviceNames
* device_names
) {
85 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
87 // Always add default device parameters as first element.
88 DCHECK(device_names
->empty());
89 AddDefaultDevice(device_names
);
91 // Get list of available audio devices.
92 JNIEnv
* env
= AttachCurrentThread();
93 ScopedJavaLocalRef
<jobjectArray
> j_device_array
=
94 Java_AudioManagerAndroid_getAudioInputDeviceNames(
95 env
, j_audio_manager_
.obj());
96 if (j_device_array
.is_null()) {
97 // Most probable reason for a NULL result here is that the process lacks
98 // MODIFY_AUDIO_SETTINGS or RECORD_AUDIO permissions.
101 jsize len
= env
->GetArrayLength(j_device_array
.obj());
102 AudioDeviceName device
;
103 for (jsize i
= 0; i
< len
; ++i
) {
104 ScopedJavaLocalRef
<jobject
> j_device(
105 env
, env
->GetObjectArrayElement(j_device_array
.obj(), i
));
106 ScopedJavaLocalRef
<jstring
> j_device_name
=
107 Java_AudioDeviceName_name(env
, j_device
.obj());
108 ConvertJavaStringToUTF8(env
, j_device_name
.obj(), &device
.device_name
);
109 ScopedJavaLocalRef
<jstring
> j_device_id
=
110 Java_AudioDeviceName_id(env
, j_device
.obj());
111 ConvertJavaStringToUTF8(env
, j_device_id
.obj(), &device
.unique_id
);
112 device_names
->push_back(device
);
116 void AudioManagerAndroid::GetAudioOutputDeviceNames(
117 AudioDeviceNames
* device_names
) {
118 // TODO(henrika): enumerate using GetAudioInputDeviceNames().
119 AddDefaultDevice(device_names
);
122 AudioParameters
AudioManagerAndroid::GetInputStreamParameters(
123 const std::string
& device_id
) {
124 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
126 // Use mono as preferred number of input channels on Android to save
127 // resources. Using mono also avoids a driver issue seen on Samsung
128 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
129 JNIEnv
* env
= AttachCurrentThread();
130 ChannelLayout channel_layout
= CHANNEL_LAYOUT_MONO
;
131 int buffer_size
= Java_AudioManagerAndroid_getMinInputFrameSize(
132 env
, GetNativeOutputSampleRate(),
133 ChannelLayoutToChannelCount(channel_layout
));
134 buffer_size
= buffer_size
<= 0 ? kDefaultInputBufferSize
: buffer_size
;
135 int effects
= AudioParameters::NO_EFFECTS
;
136 effects
|= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env
) ?
137 AudioParameters::ECHO_CANCELLER
: AudioParameters::NO_EFFECTS
;
139 int user_buffer_size
= GetUserBufferSize();
140 if (user_buffer_size
)
141 buffer_size
= user_buffer_size
;
143 AudioParameters
params(AudioParameters::AUDIO_PCM_LOW_LATENCY
, channel_layout
,
144 GetNativeOutputSampleRate(), 16, buffer_size
);
145 params
.set_effects(effects
);
149 AudioOutputStream
* AudioManagerAndroid::MakeAudioOutputStream(
150 const AudioParameters
& params
,
151 const std::string
& device_id
) {
152 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
153 AudioOutputStream
* stream
=
154 AudioManagerBase::MakeAudioOutputStream(params
, std::string());
155 streams_
.insert(static_cast<OpenSLESOutputStream
*>(stream
));
159 AudioInputStream
* AudioManagerAndroid::MakeAudioInputStream(
160 const AudioParameters
& params
, const std::string
& device_id
) {
161 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
162 bool has_no_input_streams
= HasNoAudioInputStreams();
163 AudioInputStream
* stream
=
164 AudioManagerBase::MakeAudioInputStream(params
, device_id
);
166 // The audio manager for Android creates streams intended for real-time
167 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
168 // If a Bluetooth headset is used, the audio stream will use the SCO
169 // channel and therefore have a limited bandwidth (8kHz).
170 if (stream
&& has_no_input_streams
) {
171 communication_mode_is_on_
= true;
172 SetCommunicationAudioModeOn(true);
177 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream
* stream
) {
178 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
179 streams_
.erase(static_cast<OpenSLESOutputStream
*>(stream
));
180 AudioManagerBase::ReleaseOutputStream(stream
);
183 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream
* stream
) {
184 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
185 DCHECK(!j_audio_manager_
.is_null());
186 AudioManagerBase::ReleaseInputStream(stream
);
188 // Restore the audio mode which was used before the first communication-
189 // mode stream was created.
190 if (HasNoAudioInputStreams()) {
191 communication_mode_is_on_
= false;
192 SetCommunicationAudioModeOn(false);
196 AudioOutputStream
* AudioManagerAndroid::MakeLinearOutputStream(
197 const AudioParameters
& params
) {
198 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
199 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
200 return new OpenSLESOutputStream(this, params
, SL_ANDROID_STREAM_MEDIA
);
203 AudioOutputStream
* AudioManagerAndroid::MakeLowLatencyOutputStream(
204 const AudioParameters
& params
,
205 const std::string
& device_id
) {
206 DLOG_IF(ERROR
, !device_id
.empty()) << "Not implemented!";
207 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
209 // Set stream type which matches the current system-wide audio mode used by
210 // the Android audio manager.
211 const SLint32 stream_type
= communication_mode_is_on_
?
212 SL_ANDROID_STREAM_VOICE
: SL_ANDROID_STREAM_MEDIA
;
213 return new OpenSLESOutputStream(this, params
, stream_type
);
216 AudioInputStream
* AudioManagerAndroid::MakeLinearInputStream(
217 const AudioParameters
& params
, const std::string
& device_id
) {
218 // TODO(henrika): add support for device selection if/when any client
220 DLOG_IF(ERROR
, !device_id
.empty()) << "Not implemented!";
221 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
222 return new OpenSLESInputStream(this, params
);
225 AudioInputStream
* AudioManagerAndroid::MakeLowLatencyInputStream(
226 const AudioParameters
& params
, const std::string
& device_id
) {
227 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
228 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
229 DLOG_IF(ERROR
, device_id
.empty()) << "Invalid device ID!";
231 // Use the device ID to select the correct input device.
232 // Note that the input device is always associated with a certain output
233 // device, i.e., this selection does also switch the output device.
234 // All input and output streams will be affected by the device selection.
235 if (!SetAudioDevice(device_id
)) {
236 LOG(ERROR
) << "Unable to select audio device!";
240 if (params
.effects() != AudioParameters::NO_EFFECTS
) {
241 // Platform effects can only be enabled through the AudioRecord path.
242 // An effect should only have been requested here if recommended by
243 // AudioManagerAndroid.shouldUse<Effect>.
245 // Creating this class requires Jelly Bean, which is already guaranteed by
246 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use
247 // the effect settings as a way to select the input path.
248 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16);
249 DVLOG(1) << "Creating AudioRecordInputStream";
250 return new AudioRecordInputStream(this, params
);
252 DVLOG(1) << "Creating OpenSLESInputStream";
253 return new OpenSLESInputStream(this, params
);
257 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv
* env
) {
258 return RegisterNativesImpl(env
);
261 void AudioManagerAndroid::SetMute(JNIEnv
* env
, jobject obj
, jboolean muted
) {
262 GetTaskRunner()->PostTask(
265 &AudioManagerAndroid::DoSetMuteOnAudioThread
,
266 base::Unretained(this),
270 void AudioManagerAndroid::SetOutputVolumeOverride(double volume
) {
271 GetTaskRunner()->PostTask(
274 &AudioManagerAndroid::DoSetVolumeOnAudioThread
,
275 base::Unretained(this),
279 bool AudioManagerAndroid::HasOutputVolumeOverride(double* out_volume
) const {
280 if (output_volume_override_set_
) {
281 *out_volume
= output_volume_override_
;
283 return output_volume_override_set_
;
286 AudioParameters
AudioManagerAndroid::GetPreferredOutputStreamParameters(
287 const std::string
& output_device_id
,
288 const AudioParameters
& input_params
) {
289 // TODO(tommi): Support |output_device_id|.
290 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
291 DLOG_IF(ERROR
, !output_device_id
.empty()) << "Not implemented!";
292 ChannelLayout channel_layout
= CHANNEL_LAYOUT_STEREO
;
293 int sample_rate
= GetNativeOutputSampleRate();
294 int buffer_size
= GetOptimalOutputFrameSize(sample_rate
, 2);
295 int bits_per_sample
= 16;
296 if (input_params
.IsValid()) {
297 // Use the client's input parameters if they are valid.
298 sample_rate
= input_params
.sample_rate();
299 bits_per_sample
= input_params
.bits_per_sample();
300 channel_layout
= input_params
.channel_layout();
301 buffer_size
= GetOptimalOutputFrameSize(
302 sample_rate
, ChannelLayoutToChannelCount(channel_layout
));
305 int user_buffer_size
= GetUserBufferSize();
306 if (user_buffer_size
)
307 buffer_size
= user_buffer_size
;
309 return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY
, channel_layout
,
310 sample_rate
, bits_per_sample
, buffer_size
);
313 bool AudioManagerAndroid::HasNoAudioInputStreams() {
314 return input_stream_count() == 0;
317 void AudioManagerAndroid::InitializeOnAudioThread() {
318 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
320 // Create the Android audio manager on the audio thread.
321 DVLOG(2) << "Creating Java part of the audio manager";
322 j_audio_manager_
.Reset(
323 Java_AudioManagerAndroid_createAudioManagerAndroid(
324 base::android::AttachCurrentThread(),
325 base::android::GetApplicationContext(),
326 reinterpret_cast<intptr_t>(this)));
328 // Prepare the list of audio devices and register receivers for device
330 Java_AudioManagerAndroid_init(
331 base::android::AttachCurrentThread(),
332 j_audio_manager_
.obj());
335 void AudioManagerAndroid::ShutdownOnAudioThread() {
336 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
337 DVLOG(2) << "Destroying Java part of the audio manager";
338 Java_AudioManagerAndroid_close(
339 base::android::AttachCurrentThread(),
340 j_audio_manager_
.obj());
341 j_audio_manager_
.Reset();
344 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on
) {
345 Java_AudioManagerAndroid_setCommunicationAudioModeOn(
346 base::android::AttachCurrentThread(),
347 j_audio_manager_
.obj(), on
);
350 bool AudioManagerAndroid::SetAudioDevice(const std::string
& device_id
) {
351 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
353 // Send the unique device ID to the Java audio manager and make the
354 // device switch. Provide an empty string to the Java audio manager
355 // if the default device is selected.
356 JNIEnv
* env
= AttachCurrentThread();
357 ScopedJavaLocalRef
<jstring
> j_device_id
= ConvertUTF8ToJavaString(
359 device_id
== AudioManagerBase::kDefaultDeviceId
?
360 std::string() : device_id
);
361 return Java_AudioManagerAndroid_setDevice(
362 env
, j_audio_manager_
.obj(), j_device_id
.obj());
365 int AudioManagerAndroid::GetNativeOutputSampleRate() {
366 return Java_AudioManagerAndroid_getNativeOutputSampleRate(
367 base::android::AttachCurrentThread(),
368 j_audio_manager_
.obj());
371 bool AudioManagerAndroid::IsAudioLowLatencySupported() {
372 return Java_AudioManagerAndroid_isAudioLowLatencySupported(
373 base::android::AttachCurrentThread(),
374 j_audio_manager_
.obj());
377 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
378 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
379 base::android::AttachCurrentThread(),
380 j_audio_manager_
.obj());
383 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate
,
385 if (IsAudioLowLatencySupported())
386 return GetAudioLowLatencyOutputFrameSize();
388 return std::max(kDefaultOutputBufferSize
,
389 Java_AudioManagerAndroid_getMinOutputFrameSize(
390 base::android::AttachCurrentThread(),
391 sample_rate
, channels
));
394 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted
) {
395 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
396 for (OutputStreams::iterator it
= streams_
.begin();
397 it
!= streams_
.end(); ++it
) {
398 (*it
)->SetMute(muted
);
402 void AudioManagerAndroid::DoSetVolumeOnAudioThread(double volume
) {
403 output_volume_override_set_
= true;
404 output_volume_override_
= volume
;
406 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
407 for (OutputStreams::iterator it
= streams_
.begin();
408 it
!= streams_
.end(); ++it
) {
409 (*it
)->SetVolume(volume
);