Add localized default audio device names.
[chromium-blink-merge.git] / media / audio / android / audio_manager_android.cc
blob01379b8a97c1eb07575054254db5d2895fccc21c
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;
30 namespace media {
31 namespace {
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;
45 } // namespace
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
63 // audio thread.
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)));
74 Shutdown();
77 bool AudioManagerAndroid::HasAudioOutputDevices() {
78 return true;
81 bool AudioManagerAndroid::HasAudioInputDevices() {
82 return true;
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.
101 return;
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);
148 return params;
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));
158 return 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);
176 return stream;
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
221 // needs it.
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!";
239 return NULL;
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);
258 // static
259 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
260 return RegisterNativesImpl(env);
263 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
264 GetTaskRunner()->PostTask(
265 FROM_HERE,
266 base::Bind(
267 &AudioManagerAndroid::DoSetMuteOnAudioThread,
268 base::Unretained(this),
269 muted));
272 void AudioManagerAndroid::SetOutputVolumeOverride(double volume) {
273 GetTaskRunner()->PostTask(
274 FROM_HERE,
275 base::Bind(
276 &AudioManagerAndroid::DoSetVolumeOnAudioThread,
277 base::Unretained(this),
278 volume));
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
331 // notifications.
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(
360 env,
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,
386 int channels) {
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);
415 } // namespace media