Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: media/audio/android/audio_manager_android.cc

Issue 131503006: Initialization of audio manager for Android is now done on the audio thread (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: tommi@ Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/android/audio_manager_android.h" 5 #include "media/audio/android/audio_manager_android.h"
6 6
7 #include "base/android/build_info.h" 7 #include "base/android/build_info.h"
8 #include "base/android/jni_array.h" 8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h" 9 #include "base/android/jni_string.h"
10 #include "base/android/scoped_java_ref.h" 10 #include "base/android/scoped_java_ref.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
13 #include "jni/AudioManagerAndroid_jni.h" 14 #include "jni/AudioManagerAndroid_jni.h"
14 #include "media/audio/android/audio_record_input.h" 15 #include "media/audio/android/audio_record_input.h"
15 #include "media/audio/android/opensles_input.h" 16 #include "media/audio/android/opensles_input.h"
16 #include "media/audio/android/opensles_output.h" 17 #include "media/audio/android/opensles_output.h"
17 #include "media/audio/audio_manager.h" 18 #include "media/audio/audio_manager.h"
18 #include "media/audio/audio_parameters.h" 19 #include "media/audio/audio_parameters.h"
19 #include "media/audio/fake_audio_input_stream.h" 20 #include "media/audio/fake_audio_input_stream.h"
20 #include "media/base/channel_layout.h" 21 #include "media/base/channel_layout.h"
21 22
(...skipping 16 matching lines...) Expand all
38 static const int kMaxOutputStreams = 10; 39 static const int kMaxOutputStreams = 10;
39 40
40 static const int kDefaultInputBufferSize = 1024; 41 static const int kDefaultInputBufferSize = 1024;
41 static const int kDefaultOutputBufferSize = 2048; 42 static const int kDefaultOutputBufferSize = 2048;
42 43
43 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 44 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
44 return new AudioManagerAndroid(audio_log_factory); 45 return new AudioManagerAndroid(audio_log_factory);
45 } 46 }
46 47
47 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory) 48 AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory)
48 : AudioManagerBase(audio_log_factory) { 49 : AudioManagerBase(audio_log_factory),
50 initialized_on_audio_thread_(false) {
49 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 51 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
50
51 j_audio_manager_.Reset( 52 j_audio_manager_.Reset(
52 Java_AudioManagerAndroid_createAudioManagerAndroid( 53 Java_AudioManagerAndroid_createAudioManagerAndroid(
53 base::android::AttachCurrentThread(), 54 base::android::AttachCurrentThread(),
54 base::android::GetApplicationContext(), 55 base::android::GetApplicationContext(),
55 reinterpret_cast<intptr_t>(this))); 56 reinterpret_cast<intptr_t>(this)));
56 Init(); 57 Init();
57 } 58 }
58 59
59 AudioManagerAndroid::~AudioManagerAndroid() { 60 AudioManagerAndroid::~AudioManagerAndroid() {
60 Close(); 61 Close();
61 Shutdown(); 62 Shutdown();
63 // Verify that WillDestroyCurrentMessageLoop() has been called.
64 DCHECK(!initialized_on_audio_thread_);
62 } 65 }
63 66
64 bool AudioManagerAndroid::HasAudioOutputDevices() { 67 bool AudioManagerAndroid::HasAudioOutputDevices() {
65 return true; 68 return true;
66 } 69 }
67 70
68 bool AudioManagerAndroid::HasAudioInputDevices() { 71 bool AudioManagerAndroid::HasAudioInputDevices() {
69 return true; 72 return true;
70 } 73 }
71 74
72 void AudioManagerAndroid::GetAudioInputDeviceNames( 75 void AudioManagerAndroid::GetAudioInputDeviceNames(
73 AudioDeviceNames* device_names) { 76 AudioDeviceNames* device_names) {
74 // Always add default device parameters as first element. 77 // Get list of available audio devices and use the audio thread to reduce
75 DCHECK(device_names->empty()); 78 // the number of calling threads to the Java layer. Also, ensure that the
76 AddDefaultDevice(device_names); 79 // calling thread sees this function call as synchronous.
77 80 scoped_refptr<base::SingleThreadTaskRunner> task_runner(GetTaskRunner());
78 JNIEnv* env = AttachCurrentThread(); 81 if (task_runner->BelongsToCurrentThread()) {
79 ScopedJavaLocalRef<jobjectArray> j_device_array = 82 GetAudioInputDeviceNamesOnAudioThread(NULL, device_names);
80 Java_AudioManagerAndroid_getAudioInputDeviceNames( 83 } else {
81 env, j_audio_manager_.obj()); 84 base::WaitableEvent event(false, false);
82 jsize len = env->GetArrayLength(j_device_array.obj()); 85 task_runner->PostTask(
83 AudioDeviceName device; 86 FROM_HERE,
84 for (jsize i = 0; i < len; ++i) { 87 base::Bind(
85 ScopedJavaLocalRef<jobject> j_device( 88 &AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread,
86 env, env->GetObjectArrayElement(j_device_array.obj(), i)); 89 base::Unretained(this),
87 ScopedJavaLocalRef<jstring> j_device_name = 90 &event,
88 Java_AudioDeviceName_name(env, j_device.obj()); 91 device_names));
89 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); 92 event.Wait();
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);
94 } 93 }
95 } 94 }
96 95
97 void AudioManagerAndroid::GetAudioOutputDeviceNames( 96 void AudioManagerAndroid::GetAudioOutputDeviceNames(
98 AudioDeviceNames* device_names) { 97 AudioDeviceNames* device_names) {
99 // TODO(henrika): enumerate using GetAudioInputDeviceNames(). 98 // TODO(henrika): enumerate using GetAudioInputDeviceNames().
100 AddDefaultDevice(device_names); 99 AddDefaultDevice(device_names);
101 } 100 }
102 101
103 AudioParameters AudioManagerAndroid::GetInputStreamParameters( 102 AudioParameters AudioManagerAndroid::GetInputStreamParameters(
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 { 138 {
140 base::AutoLock lock(streams_lock_); 139 base::AutoLock lock(streams_lock_);
141 streams_.insert(static_cast<OpenSLESOutputStream*>(stream)); 140 streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
142 } 141 }
143 142
144 return stream; 143 return stream;
145 } 144 }
146 145
147 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( 146 AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
148 const AudioParameters& params, const std::string& device_id) { 147 const AudioParameters& params, const std::string& device_id) {
148 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
149 bool had_no_streams = HadNoAudioStreams(); 149 bool had_no_streams = HadNoAudioStreams();
150 AudioInputStream* stream = 150 AudioInputStream* stream =
151 AudioManagerBase::MakeAudioInputStream(params, device_id); 151 AudioManagerBase::MakeAudioInputStream(params, device_id);
152 152
153 // The audio manager for Android creates streams intended for real-time 153 // The audio manager for Android creates streams intended for real-time
154 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION. 154 // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
155 // If a Bluetooth headset is used, the audio stream will use the SCO 155 // If a Bluetooth headset is used, the audio stream will use the SCO
156 // channel and therefore have a limited bandwidth (8kHz). 156 // channel and therefore have a limited bandwidth (8kHz).
157 if (stream && had_no_streams) 157 if (stream && had_no_streams)
158 SetCommunicationAudioModeOn(true); 158 SetCommunicationAudioModeOn(true);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 // TODO(henrika): add support for device selection if/when any client 199 // TODO(henrika): add support for device selection if/when any client
200 // needs it. 200 // needs it.
201 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 201 DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
202 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 202 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
203 return new OpenSLESInputStream(this, params); 203 return new OpenSLESInputStream(this, params);
204 } 204 }
205 205
206 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( 206 AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
207 const AudioParameters& params, const std::string& device_id) { 207 const AudioParameters& params, const std::string& device_id) {
208 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 208 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
209 // DCHECK(GetTaskRunner()->BelongsToCurrentThread());
tommi (sloooow) - chröme 2014/01/30 15:26:04 will you uncomment this before checkin?
henrika (OOO until Aug 14) 2014/01/30 17:20:23 Done.
209 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!"; 210 DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
210 // Use the device ID to select the correct input device. 211 // Use the device ID to select the correct input device.
211 // Note that the input device is always associated with a certain output 212 // Note that the input device is always associated with a certain output
212 // device, i.e., this selection does also switch the output device. 213 // device, i.e., this selection does also switch the output device.
213 // All input and output streams will be affected by the device selection. 214 // All input and output streams will be affected by the device selection.
214 if (!SetAudioDevice(device_id)) { 215 if (!SetAudioDevice(device_id)) {
215 LOG(ERROR) << "Unable to select audio device!"; 216 LOG(ERROR) << "Unable to select audio device!";
216 return NULL; 217 return NULL;
217 } 218 }
218 219
219 if (params.effects() != AudioParameters::NO_EFFECTS) { 220 if (params.effects() != AudioParameters::NO_EFFECTS) {
220 // Platform effects can only be enabled through the AudioRecord path. 221 // Platform effects can only be enabled through the AudioRecord path.
221 // An effect should only have been requested here if recommended by 222 // An effect should only have been requested here if recommended by
222 // AudioManagerAndroid.shouldUse<Effect>. 223 // AudioManagerAndroid.shouldUse<Effect>.
223 // 224 //
224 // Creating this class requires Jelly Bean, which is already guaranteed by 225 // Creating this class requires Jelly Bean, which is already guaranteed by
225 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use 226 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use
226 // the effect settings as a way to select the input path. 227 // the effect settings as a way to select the input path.
227 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); 228 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16);
228 DVLOG(1) << "Creating AudioRecordInputStream"; 229 DVLOG(1) << "Creating AudioRecordInputStream";
229 return new AudioRecordInputStream(this, params); 230 return new AudioRecordInputStream(this, params);
230 } 231 }
231 DVLOG(1) << "Creating OpenSLESInputStream"; 232 DVLOG(1) << "Creating OpenSLESInputStream";
232 return new OpenSLESInputStream(this, params); 233 return new OpenSLESInputStream(this, params);
233 } 234 }
234 235
236 void AudioManagerAndroid::WillDestroyCurrentMessageLoop() {
237 // This call matches previous calls to InitializeOnAudioThread() and it
238 // ensures that we unregister receivers for events related to changes in
239 // availability of audio devices.
240 CloseOnAudioThread();
241 }
242
235 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, 243 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
236 int channels) { 244 int channels) {
237 if (IsAudioLowLatencySupported()) { 245 if (IsAudioLowLatencySupported()) {
238 return GetAudioLowLatencyOutputFrameSize(); 246 return GetAudioLowLatencyOutputFrameSize();
239 } else { 247 } else {
240 return std::max(kDefaultOutputBufferSize, 248 return std::max(kDefaultOutputBufferSize,
241 Java_AudioManagerAndroid_getMinOutputFrameSize( 249 Java_AudioManagerAndroid_getMinOutputFrameSize(
242 base::android::AttachCurrentThread(), 250 base::android::AttachCurrentThread(),
243 sample_rate, channels)); 251 sample_rate, channels));
244 } 252 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 304
297 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { 305 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
298 GetTaskRunner()->PostTask( 306 GetTaskRunner()->PostTask(
299 FROM_HERE, 307 FROM_HERE,
300 base::Bind( 308 base::Bind(
301 &AudioManagerAndroid::DoSetMuteOnAudioThread, 309 &AudioManagerAndroid::DoSetMuteOnAudioThread,
302 base::Unretained(this), 310 base::Unretained(this),
303 muted)); 311 muted));
304 } 312 }
305 313
314 void AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread(
315 base::WaitableEvent* event, AudioDeviceNames* device_names) {
316 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
317
318 // Set up the initial list of available audio devices and register for
319 // broadcasted notifications about any changes of availability.
320 // This method is only executed when called for the first time and it can
321 // also be called from SetAudioDeviceOnAudioThread().
322 InitializeOnAudioThread();
323
324 // Always add default device parameters as first element.
325 DCHECK(device_names->empty());
326 AddDefaultDevice(device_names);
327
328 JNIEnv* env = AttachCurrentThread();
329 ScopedJavaLocalRef<jobjectArray> j_device_array =
330 Java_AudioManagerAndroid_getAudioInputDeviceNames(
331 env, j_audio_manager_.obj());
332 jsize len = env->GetArrayLength(j_device_array.obj());
333 AudioDeviceName device;
334 for (jsize i = 0; i < len; ++i) {
335 ScopedJavaLocalRef<jobject> j_device(
336 env, env->GetObjectArrayElement(j_device_array.obj(), i));
337 ScopedJavaLocalRef<jstring> j_device_name =
338 Java_AudioDeviceName_name(env, j_device.obj());
339 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name);
340 ScopedJavaLocalRef<jstring> j_device_id =
341 Java_AudioDeviceName_id(env, j_device.obj());
342 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id);
343 device_names->push_back(device);
344 }
345
346 if (event)
347 event->Signal();
348 }
349
350 void AudioManagerAndroid::InitializeOnAudioThread() {
351 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
352 if (!initialized_on_audio_thread_) {
353 base::MessageLoop::current()->AddDestructionObserver(this);
354 Java_AudioManagerAndroid_initAudioDeviceList(
355 base::android::AttachCurrentThread(),
356 j_audio_manager_.obj());
357 initialized_on_audio_thread_ = true;
358 }
359 }
360
361 void AudioManagerAndroid::CloseOnAudioThread() {
362 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
363 if (!initialized_on_audio_thread_)
364 return;
365 Java_AudioManagerAndroid_closeAudioDeviceList(
366 base::android::AttachCurrentThread(),
367 j_audio_manager_.obj());
368 initialized_on_audio_thread_ = false;
369 }
370
371 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
372 // Select audio device and use the audio thread to reduce the number of
373 // calling threads to the Java layer. Also, ensure that the calling thread
374 // sees this function call as synchronous.
375 bool result = false;
376 scoped_refptr<base::SingleThreadTaskRunner> task_runner(GetTaskRunner());
377 if (task_runner->BelongsToCurrentThread()) {
378 SetAudioDeviceOnAudioThread(NULL, device_id, &result);
379 } else {
380 base::WaitableEvent event(false, false);
381 task_runner->PostTask(
382 FROM_HERE,
383 base::Bind(
384 &AudioManagerAndroid::SetAudioDeviceOnAudioThread,
385 base::Unretained(this),
386 &event,
387 device_id,
388 &result));
389 event.Wait();
390 }
391 return result;
392 }
393
394 void AudioManagerAndroid::SetAudioDeviceOnAudioThread(
395 base::WaitableEvent* event, const std::string& device_id, bool* result) {
396 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
397
398 // Set up the initial list of available audio devices and register for
399 // broadcasted notifications about any changes of availability.
400 // This method is only executed when called for the first time and it can
401 // also be called from GetAudioInputDeviceNamesOnAudioThread().
402 InitializeOnAudioThread();
403
404 // Send the unique device ID to the Java audio manager and make the
405 // device switch. Provide an empty string to the Java audio manager
406 // if the default device is selected.
407 JNIEnv* env = AttachCurrentThread();
408 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
409 env,
410 device_id == AudioManagerBase::kDefaultDeviceId ?
411 std::string() : device_id);
412 *result = Java_AudioManagerAndroid_setDevice(
413 env, j_audio_manager_.obj(), j_device_id.obj());
414
415 if (event)
416 event->Signal();
417 }
418
306 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { 419 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
420 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
307 base::AutoLock lock(streams_lock_); 421 base::AutoLock lock(streams_lock_);
308 for (OutputStreams::iterator it = streams_.begin(); 422 for (OutputStreams::iterator it = streams_.begin();
309 it != streams_.end(); ++it) { 423 it != streams_.end(); ++it) {
310 (*it)->SetMute(muted); 424 (*it)->SetMute(muted);
311 } 425 }
312 } 426 }
313 427
314 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { 428 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
315 Java_AudioManagerAndroid_setCommunicationAudioModeOn( 429 Java_AudioManagerAndroid_setCommunicationAudioModeOn(
316 base::android::AttachCurrentThread(), 430 base::android::AttachCurrentThread(),
317 j_audio_manager_.obj(), on); 431 j_audio_manager_.obj(), on);
318 } 432 }
319 433
320 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
321 JNIEnv* env = AttachCurrentThread();
322
323 // Send the unique device ID to the Java audio manager and make the
324 // device switch. Provide an empty string to the Java audio manager
325 // if the default device is selected.
326 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
327 env,
328 device_id == AudioManagerBase::kDefaultDeviceId ?
329 std::string() : device_id);
330 return Java_AudioManagerAndroid_setDevice(
331 env, j_audio_manager_.obj(), j_device_id.obj());
332 }
333
334 int AudioManagerAndroid::GetNativeOutputSampleRate() { 434 int AudioManagerAndroid::GetNativeOutputSampleRate() {
335 return Java_AudioManagerAndroid_getNativeOutputSampleRate( 435 return Java_AudioManagerAndroid_getNativeOutputSampleRate(
336 base::android::AttachCurrentThread(), 436 base::android::AttachCurrentThread(),
337 j_audio_manager_.obj()); 437 j_audio_manager_.obj());
338 } 438 }
339 439
340 bool AudioManagerAndroid::IsAudioLowLatencySupported() { 440 bool AudioManagerAndroid::IsAudioLowLatencySupported() {
341 return Java_AudioManagerAndroid_isAudioLowLatencySupported( 441 return Java_AudioManagerAndroid_isAudioLowLatencySupported(
342 base::android::AttachCurrentThread(), 442 base::android::AttachCurrentThread(),
343 j_audio_manager_.obj()); 443 j_audio_manager_.obj());
344 } 444 }
345 445
346 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { 446 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
347 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( 447 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize(
348 base::android::AttachCurrentThread(), 448 base::android::AttachCurrentThread(),
349 j_audio_manager_.obj()); 449 j_audio_manager_.obj());
350 } 450 }
351 451
352 } // namespace media 452 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698