• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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