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