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/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"
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
;
30 static void AddDefaultDevice(AudioDeviceNames
* device_names
) {
31 DCHECK(device_names
->empty());
32 device_names
->push_front(
33 AudioDeviceName(AudioManagerBase::kDefaultDeviceName
,
34 AudioManagerBase::kDefaultDeviceId
));
37 // Maximum number of output streams that can be open simultaneously.
38 static const int kMaxOutputStreams
= 10;
40 static const int kDefaultInputBufferSize
= 1024;
41 static const int kDefaultOutputBufferSize
= 2048;
43 AudioManager
* CreateAudioManager(AudioLogFactory
* audio_log_factory
) {
44 return new AudioManagerAndroid(audio_log_factory
);
47 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory
* audio_log_factory
)
48 : AudioManagerBase(audio_log_factory
) {
49 SetMaxOutputStreamsAllowed(kMaxOutputStreams
);
51 j_audio_manager_
.Reset(
52 Java_AudioManagerAndroid_createAudioManagerAndroid(
53 base::android::AttachCurrentThread(),
54 base::android::GetApplicationContext(),
55 reinterpret_cast<intptr_t>(this)));
59 AudioManagerAndroid::~AudioManagerAndroid() {
64 bool AudioManagerAndroid::HasAudioOutputDevices() {
68 bool AudioManagerAndroid::HasAudioInputDevices() {
72 void AudioManagerAndroid::GetAudioInputDeviceNames(
73 AudioDeviceNames
* device_names
) {
74 // Always add default device parameters as first element.
75 DCHECK(device_names
->empty());
76 AddDefaultDevice(device_names
);
78 JNIEnv
* env
= AttachCurrentThread();
79 ScopedJavaLocalRef
<jobjectArray
> j_device_array
=
80 Java_AudioManagerAndroid_getAudioInputDeviceNames(
81 env
, j_audio_manager_
.obj());
82 jsize len
= env
->GetArrayLength(j_device_array
.obj());
83 AudioDeviceName device
;
84 for (jsize i
= 0; i
< len
; ++i
) {
85 ScopedJavaLocalRef
<jobject
> j_device(
86 env
, env
->GetObjectArrayElement(j_device_array
.obj(), i
));
87 ScopedJavaLocalRef
<jstring
> j_device_name
=
88 Java_AudioDeviceName_name(env
, j_device
.obj());
89 ConvertJavaStringToUTF8(env
, j_device_name
.obj(), &device
.device_name
);
90 ScopedJavaLocalRef
<jstring
> j_device_id
=
91 Java_AudioDeviceName_id(env
, j_device
.obj());
92 ConvertJavaStringToUTF8(env
, j_device_id
.obj(), &device
.unique_id
);
93 device_names
->push_back(device
);
97 void AudioManagerAndroid::GetAudioOutputDeviceNames(
98 AudioDeviceNames
* device_names
) {
99 // TODO(henrika): enumerate using GetAudioInputDeviceNames().
100 AddDefaultDevice(device_names
);
103 AudioParameters
AudioManagerAndroid::GetInputStreamParameters(
104 const std::string
& device_id
) {
105 JNIEnv
* env
= AttachCurrentThread();
106 // Use mono as preferred number of input channels on Android to save
107 // resources. Using mono also avoids a driver issue seen on Samsung
108 // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
109 ChannelLayout channel_layout
= CHANNEL_LAYOUT_MONO
;
110 int buffer_size
= Java_AudioManagerAndroid_getMinInputFrameSize(
111 env
, GetNativeOutputSampleRate(),
112 ChannelLayoutToChannelCount(channel_layout
));
113 int effects
= AudioParameters::NO_EFFECTS
;
114 effects
|= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env
) ?
115 AudioParameters::ECHO_CANCELLER
: AudioParameters::NO_EFFECTS
;
116 AudioParameters
params(
117 AudioParameters::AUDIO_PCM_LOW_LATENCY
, channel_layout
, 0,
118 GetNativeOutputSampleRate(), 16,
119 buffer_size
<= 0 ? kDefaultInputBufferSize
: buffer_size
, effects
);
123 AudioOutputStream
* AudioManagerAndroid::MakeAudioOutputStream(
124 const AudioParameters
& params
,
125 const std::string
& device_id
) {
126 bool had_no_streams
= HadNoAudioStreams();
127 AudioOutputStream
* stream
=
128 AudioManagerBase::MakeAudioOutputStream(params
, std::string());
130 // The audio manager for Android creates streams intended for real-time
131 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
132 // If a Bluetooth headset is used, the audio stream will use the SCO
133 // channel and therefore have a limited bandwidth (8-16kHz).
134 if (stream
&& had_no_streams
)
135 SetCommunicationAudioModeOn(true);
138 base::AutoLock
lock(streams_lock_
);
139 streams_
.insert(static_cast<OpenSLESOutputStream
*>(stream
));
145 AudioInputStream
* AudioManagerAndroid::MakeAudioInputStream(
146 const AudioParameters
& params
, const std::string
& device_id
) {
147 bool had_no_streams
= HadNoAudioStreams();
148 AudioInputStream
* stream
=
149 AudioManagerBase::MakeAudioInputStream(params
, device_id
);
151 // The audio manager for Android creates streams intended for real-time
152 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
153 // If a Bluetooth headset is used, the audio stream will use the SCO
154 // channel and therefore have a limited bandwidth (8kHz).
155 if (stream
&& had_no_streams
)
156 SetCommunicationAudioModeOn(true);
160 void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream
* stream
) {
161 AudioManagerBase::ReleaseOutputStream(stream
);
163 // Restore the audio mode which was used before the first communication-
164 // mode stream was created.
165 if (HadNoAudioStreams())
166 SetCommunicationAudioModeOn(false);
167 base::AutoLock
lock(streams_lock_
);
168 streams_
.erase(static_cast<OpenSLESOutputStream
*>(stream
));
171 void AudioManagerAndroid::ReleaseInputStream(AudioInputStream
* stream
) {
172 AudioManagerBase::ReleaseInputStream(stream
);
174 // Restore the audio mode which was used before the first communication-
175 // mode stream was created.
176 if (HadNoAudioStreams())
177 SetCommunicationAudioModeOn(false);
180 AudioOutputStream
* AudioManagerAndroid::MakeLinearOutputStream(
181 const AudioParameters
& params
) {
182 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
183 return new OpenSLESOutputStream(this, params
);
186 AudioOutputStream
* AudioManagerAndroid::MakeLowLatencyOutputStream(
187 const AudioParameters
& params
,
188 const std::string
& device_id
) {
189 DLOG_IF(ERROR
, !device_id
.empty()) << "Not implemented!";
190 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
191 return new OpenSLESOutputStream(this, params
);
194 AudioInputStream
* AudioManagerAndroid::MakeLinearInputStream(
195 const AudioParameters
& params
, const std::string
& device_id
) {
196 // TODO(henrika): add support for device selection if/when any client
198 DLOG_IF(ERROR
, !device_id
.empty()) << "Not implemented!";
199 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR
, params
.format());
200 return new OpenSLESInputStream(this, params
);
203 AudioInputStream
* AudioManagerAndroid::MakeLowLatencyInputStream(
204 const AudioParameters
& params
, const std::string
& device_id
) {
205 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY
, params
.format());
206 DLOG_IF(ERROR
, device_id
.empty()) << "Invalid device ID!";
207 // Use the device ID to select the correct input device.
208 // Note that the input device is always associated with a certain output
209 // device, i.e., this selection does also switch the output device.
210 // All input and output streams will be affected by the device selection.
211 if (!SetAudioDevice(device_id
)) {
212 LOG(ERROR
) << "Unable to select audio device!";
216 if (params
.effects() != AudioParameters::NO_EFFECTS
) {
217 // Platform effects can only be enabled through the AudioRecord path.
218 // An effect should only have been requested here if recommended by
219 // AudioManagerAndroid.shouldUse<Effect>.
221 // Creating this class requires Jelly Bean, which is already guaranteed by
222 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use
223 // the effect settings as a way to select the input path.
224 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16);
225 DVLOG(1) << "Creating AudioRecordInputStream";
226 return new AudioRecordInputStream(this, params
);
228 DVLOG(1) << "Creating OpenSLESInputStream";
229 return new OpenSLESInputStream(this, params
);
232 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate
,
234 if (IsAudioLowLatencySupported()) {
235 return GetAudioLowLatencyOutputFrameSize();
237 return std::max(kDefaultOutputBufferSize
,
238 Java_AudioManagerAndroid_getMinOutputFrameSize(
239 base::android::AttachCurrentThread(),
240 sample_rate
, channels
));
244 AudioParameters
AudioManagerAndroid::GetPreferredOutputStreamParameters(
245 const std::string
& output_device_id
,
246 const AudioParameters
& input_params
) {
247 // TODO(tommi): Support |output_device_id|.
248 DLOG_IF(ERROR
, !output_device_id
.empty()) << "Not implemented!";
249 ChannelLayout channel_layout
= CHANNEL_LAYOUT_STEREO
;
250 int sample_rate
= GetNativeOutputSampleRate();
251 int buffer_size
= GetOptimalOutputFrameSize(sample_rate
, 2);
252 int bits_per_sample
= 16;
253 int input_channels
= 0;
254 if (input_params
.IsValid()) {
255 // Use the client's input parameters if they are valid.
256 sample_rate
= input_params
.sample_rate();
257 bits_per_sample
= input_params
.bits_per_sample();
258 channel_layout
= input_params
.channel_layout();
259 input_channels
= input_params
.input_channels();
260 buffer_size
= GetOptimalOutputFrameSize(
261 sample_rate
, ChannelLayoutToChannelCount(channel_layout
));
264 int user_buffer_size
= GetUserBufferSize();
265 if (user_buffer_size
)
266 buffer_size
= user_buffer_size
;
268 return AudioParameters(
269 AudioParameters::AUDIO_PCM_LOW_LATENCY
, channel_layout
, input_channels
,
270 sample_rate
, bits_per_sample
, buffer_size
, AudioParameters::NO_EFFECTS
);
273 bool AudioManagerAndroid::HadNoAudioStreams() {
274 return output_stream_count() == 0 && input_stream_count() == 0;
278 bool AudioManagerAndroid::RegisterAudioManager(JNIEnv
* env
) {
279 return RegisterNativesImpl(env
);
282 void AudioManagerAndroid::Init() {
283 Java_AudioManagerAndroid_init(
284 base::android::AttachCurrentThread(),
285 j_audio_manager_
.obj());
288 void AudioManagerAndroid::Close() {
289 Java_AudioManagerAndroid_close(
290 base::android::AttachCurrentThread(),
291 j_audio_manager_
.obj());
294 void AudioManagerAndroid::SetMute(JNIEnv
* env
, jobject obj
, jboolean muted
) {
295 GetTaskRunner()->PostTask(
298 &AudioManagerAndroid::DoSetMuteOnAudioThread
,
299 base::Unretained(this),
303 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted
) {
304 base::AutoLock
lock(streams_lock_
);
305 for (OutputStreams::iterator it
= streams_
.begin();
306 it
!= streams_
.end(); ++it
) {
307 (*it
)->SetMute(muted
);
311 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on
) {
312 Java_AudioManagerAndroid_setCommunicationAudioModeOn(
313 base::android::AttachCurrentThread(),
314 j_audio_manager_
.obj(), on
);
317 bool AudioManagerAndroid::SetAudioDevice(const std::string
& device_id
) {
318 JNIEnv
* env
= AttachCurrentThread();
320 // Send the unique device ID to the Java audio manager and make the
321 // device switch. Provide an empty string to the Java audio manager
322 // if the default device is selected.
323 ScopedJavaLocalRef
<jstring
> j_device_id
= ConvertUTF8ToJavaString(
325 device_id
== AudioManagerBase::kDefaultDeviceId
?
326 std::string() : device_id
);
327 return Java_AudioManagerAndroid_setDevice(
328 env
, j_audio_manager_
.obj(), j_device_id
.obj());
331 int AudioManagerAndroid::GetNativeOutputSampleRate() {
332 return Java_AudioManagerAndroid_getNativeOutputSampleRate(
333 base::android::AttachCurrentThread(),
334 j_audio_manager_
.obj());
337 bool AudioManagerAndroid::IsAudioLowLatencySupported() {
338 return Java_AudioManagerAndroid_isAudioLowLatencySupported(
339 base::android::AttachCurrentThread(),
340 j_audio_manager_
.obj());
343 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
344 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
345 base::android::AttachCurrentThread(),
346 j_audio_manager_
.obj());