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