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