Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 if (GetTaskRunner()->BelongsToCurrentThread()) { |
| 78 JNIEnv* env = AttachCurrentThread(); | 81 GetAudioInputDeviceNamesOnAudioThread(NULL, device_names); |
| 79 ScopedJavaLocalRef<jobjectArray> j_device_array = | 82 } else { |
| 80 Java_AudioManagerAndroid_getAudioInputDeviceNames( | 83 base::WaitableEvent event(false, false); |
| 81 env, j_audio_manager_.obj()); | 84 GetTaskRunner()->PostTask( |
|
tommi (sloooow) - chröme
2014/01/30 12:51:11
nit: You could avoid calling GetTaskRunner more th
henrika (OOO until Aug 14)
2014/01/30 14:48:24
Done.
| |
| 82 jsize len = env->GetArrayLength(j_device_array.obj()); | 85 FROM_HERE, |
| 83 AudioDeviceName device; | 86 base::Bind( |
| 84 for (jsize i = 0; i < len; ++i) { | 87 &AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread, |
| 85 ScopedJavaLocalRef<jobject> j_device( | 88 base::Unretained(this), |
| 86 env, env->GetObjectArrayElement(j_device_array.obj(), i)); | 89 &event, |
| 87 ScopedJavaLocalRef<jstring> j_device_name = | 90 device_names)); |
| 88 Java_AudioDeviceName_name(env, j_device.obj()); | 91 event.Wait(); |
| 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); | |
| 94 } | 92 } |
| 95 } | 93 } |
| 96 | 94 |
| 97 void AudioManagerAndroid::GetAudioOutputDeviceNames( | 95 void AudioManagerAndroid::GetAudioOutputDeviceNames( |
| 98 AudioDeviceNames* device_names) { | 96 AudioDeviceNames* device_names) { |
| 99 // TODO(henrika): enumerate using GetAudioInputDeviceNames(). | 97 // TODO(henrika): enumerate using GetAudioInputDeviceNames(). |
| 100 AddDefaultDevice(device_names); | 98 AddDefaultDevice(device_names); |
| 101 } | 99 } |
| 102 | 100 |
| 103 AudioParameters AudioManagerAndroid::GetInputStreamParameters( | 101 AudioParameters AudioManagerAndroid::GetInputStreamParameters( |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use | 223 // shouldUse<Effect>. Only DCHECK on that condition to allow tests to use |
| 226 // the effect settings as a way to select the input path. | 224 // the effect settings as a way to select the input path. |
| 227 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); | 225 DCHECK_GE(base::android::BuildInfo::GetInstance()->sdk_int(), 16); |
| 228 DVLOG(1) << "Creating AudioRecordInputStream"; | 226 DVLOG(1) << "Creating AudioRecordInputStream"; |
| 229 return new AudioRecordInputStream(this, params); | 227 return new AudioRecordInputStream(this, params); |
| 230 } | 228 } |
| 231 DVLOG(1) << "Creating OpenSLESInputStream"; | 229 DVLOG(1) << "Creating OpenSLESInputStream"; |
| 232 return new OpenSLESInputStream(this, params); | 230 return new OpenSLESInputStream(this, params); |
| 233 } | 231 } |
| 234 | 232 |
| 233 void AudioManagerAndroid::WillDestroyCurrentMessageLoop() { | |
| 234 // This call matches previous calls to InitializeOnAudioThread() and it | |
| 235 // ensures that we unregister receivers for events related to changes in | |
| 236 // availability of audio devices. | |
| 237 CloseOnAudioThread(); | |
| 238 } | |
| 239 | |
| 235 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, | 240 int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate, |
| 236 int channels) { | 241 int channels) { |
| 237 if (IsAudioLowLatencySupported()) { | 242 if (IsAudioLowLatencySupported()) { |
| 238 return GetAudioLowLatencyOutputFrameSize(); | 243 return GetAudioLowLatencyOutputFrameSize(); |
| 239 } else { | 244 } else { |
| 240 return std::max(kDefaultOutputBufferSize, | 245 return std::max(kDefaultOutputBufferSize, |
| 241 Java_AudioManagerAndroid_getMinOutputFrameSize( | 246 Java_AudioManagerAndroid_getMinOutputFrameSize( |
| 242 base::android::AttachCurrentThread(), | 247 base::android::AttachCurrentThread(), |
| 243 sample_rate, channels)); | 248 sample_rate, channels)); |
| 244 } | 249 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 | 301 |
| 297 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { | 302 void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) { |
| 298 GetTaskRunner()->PostTask( | 303 GetTaskRunner()->PostTask( |
| 299 FROM_HERE, | 304 FROM_HERE, |
| 300 base::Bind( | 305 base::Bind( |
| 301 &AudioManagerAndroid::DoSetMuteOnAudioThread, | 306 &AudioManagerAndroid::DoSetMuteOnAudioThread, |
| 302 base::Unretained(this), | 307 base::Unretained(this), |
| 303 muted)); | 308 muted)); |
| 304 } | 309 } |
| 305 | 310 |
| 311 void AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread( | |
| 312 base::WaitableEvent* event, AudioDeviceNames* device_names) { | |
| 313 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 314 | |
| 315 // Set up the initial list of available audio devices and register for | |
| 316 // broadcasted notifications about any changes of availability. | |
| 317 // This method is only executed when called for the first time and it can | |
| 318 // also be called from SetAudioDeviceOnAudioThread(). | |
| 319 InitializeOnAudioThread(); | |
| 320 | |
| 321 // Always add default device parameters as first element. | |
| 322 DCHECK(device_names->empty()); | |
| 323 AddDefaultDevice(device_names); | |
| 324 | |
| 325 JNIEnv* env = AttachCurrentThread(); | |
| 326 ScopedJavaLocalRef<jobjectArray> j_device_array = | |
| 327 Java_AudioManagerAndroid_getAudioInputDeviceNames( | |
| 328 env, j_audio_manager_.obj()); | |
| 329 jsize len = env->GetArrayLength(j_device_array.obj()); | |
| 330 AudioDeviceName device; | |
| 331 for (jsize i = 0; i < len; ++i) { | |
| 332 ScopedJavaLocalRef<jobject> j_device( | |
| 333 env, env->GetObjectArrayElement(j_device_array.obj(), i)); | |
| 334 ScopedJavaLocalRef<jstring> j_device_name = | |
| 335 Java_AudioDeviceName_name(env, j_device.obj()); | |
| 336 ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name); | |
| 337 ScopedJavaLocalRef<jstring> j_device_id = | |
| 338 Java_AudioDeviceName_id(env, j_device.obj()); | |
| 339 ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id); | |
| 340 device_names->push_back(device); | |
| 341 } | |
| 342 | |
| 343 if (event) | |
| 344 event->Signal(); | |
| 345 } | |
| 346 | |
| 347 void AudioManagerAndroid::InitializeOnAudioThread() { | |
| 348 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 349 if (!initialized_on_audio_thread_) { | |
| 350 base::MessageLoop::current()->AddDestructionObserver(this); | |
| 351 Java_AudioManagerAndroid_initAudioDeviceList( | |
| 352 base::android::AttachCurrentThread(), | |
| 353 j_audio_manager_.obj()); | |
| 354 initialized_on_audio_thread_ = true; | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 void AudioManagerAndroid::CloseOnAudioThread() { | |
| 359 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 360 if (!initialized_on_audio_thread_) | |
| 361 return; | |
| 362 Java_AudioManagerAndroid_closeAudioDeviceList( | |
| 363 base::android::AttachCurrentThread(), | |
| 364 j_audio_manager_.obj()); | |
| 365 initialized_on_audio_thread_ = false; | |
| 366 } | |
| 367 | |
| 368 bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) { | |
| 369 // Select audio device and use the audio thread to reduce the number of | |
| 370 // calling threads to the Java layer. Also, ensure that the calling thread | |
| 371 // sees this function call as synchronous. | |
| 372 bool result = false; | |
| 373 if (GetTaskRunner()->BelongsToCurrentThread()) { | |
| 374 SetAudioDeviceOnAudioThread(NULL, device_id, &result); | |
| 375 } else { | |
| 376 base::WaitableEvent event(false, false); | |
|
tommi (sloooow) - chröme
2014/01/30 12:51:11
When is SetAudioDevice called outside of the audio
henrika (OOO until Aug 14)
2014/01/30 14:48:24
I will have to fix the unit test to do so. Discuss
| |
| 377 GetTaskRunner()->PostTask( | |
| 378 FROM_HERE, | |
| 379 base::Bind( | |
| 380 &AudioManagerAndroid::SetAudioDeviceOnAudioThread, | |
| 381 base::Unretained(this), | |
| 382 &event, | |
| 383 device_id, | |
| 384 &result)); | |
| 385 event.Wait(); | |
| 386 } | |
| 387 return result; | |
| 388 } | |
| 389 | |
| 390 void AudioManagerAndroid::SetAudioDeviceOnAudioThread( | |
| 391 base::WaitableEvent* event, const std::string& device_id, bool* result) { | |
| 392 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 393 | |
| 394 // Set up the initial list of available audio devices and register for | |
| 395 // broadcasted notifications about any changes of availability. | |
| 396 // This method is only executed when called for the first time and it can | |
| 397 // also be called from GetAudioInputDeviceNamesOnAudioThread(). | |
| 398 InitializeOnAudioThread(); | |
| 399 | |
| 400 // Send the unique device ID to the Java audio manager and make the | |
| 401 // device switch. Provide an empty string to the Java audio manager | |
| 402 // if the default device is selected. | |
| 403 JNIEnv* env = AttachCurrentThread(); | |
| 404 ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString( | |
| 405 env, | |
| 406 device_id == AudioManagerBase::kDefaultDeviceId ? | |
| 407 std::string() : device_id); | |
| 408 *result = Java_AudioManagerAndroid_setDevice( | |
| 409 env, j_audio_manager_.obj(), j_device_id.obj()); | |
| 410 | |
| 411 if (event) | |
| 412 event->Signal(); | |
| 413 } | |
| 414 | |
| 306 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { | 415 void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) { |
| 416 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | |
| 307 base::AutoLock lock(streams_lock_); | 417 base::AutoLock lock(streams_lock_); |
| 308 for (OutputStreams::iterator it = streams_.begin(); | 418 for (OutputStreams::iterator it = streams_.begin(); |
| 309 it != streams_.end(); ++it) { | 419 it != streams_.end(); ++it) { |
| 310 (*it)->SetMute(muted); | 420 (*it)->SetMute(muted); |
| 311 } | 421 } |
| 312 } | 422 } |
| 313 | 423 |
| 314 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { | 424 void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) { |
| 315 Java_AudioManagerAndroid_setCommunicationAudioModeOn( | 425 Java_AudioManagerAndroid_setCommunicationAudioModeOn( |
| 316 base::android::AttachCurrentThread(), | 426 base::android::AttachCurrentThread(), |
| 317 j_audio_manager_.obj(), on); | 427 j_audio_manager_.obj(), on); |
| 318 } | 428 } |
| 319 | 429 |
| 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() { | 430 int AudioManagerAndroid::GetNativeOutputSampleRate() { |
| 335 return Java_AudioManagerAndroid_getNativeOutputSampleRate( | 431 return Java_AudioManagerAndroid_getNativeOutputSampleRate( |
| 336 base::android::AttachCurrentThread(), | 432 base::android::AttachCurrentThread(), |
| 337 j_audio_manager_.obj()); | 433 j_audio_manager_.obj()); |
| 338 } | 434 } |
| 339 | 435 |
| 340 bool AudioManagerAndroid::IsAudioLowLatencySupported() { | 436 bool AudioManagerAndroid::IsAudioLowLatencySupported() { |
| 341 return Java_AudioManagerAndroid_isAudioLowLatencySupported( | 437 return Java_AudioManagerAndroid_isAudioLowLatencySupported( |
| 342 base::android::AttachCurrentThread(), | 438 base::android::AttachCurrentThread(), |
| 343 j_audio_manager_.obj()); | 439 j_audio_manager_.obj()); |
| 344 } | 440 } |
| 345 | 441 |
| 346 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { | 442 int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() { |
| 347 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( | 443 return Java_AudioManagerAndroid_getAudioLowLatencyOutputFrameSize( |
| 348 base::android::AttachCurrentThread(), | 444 base::android::AttachCurrentThread(), |
| 349 j_audio_manager_.obj()); | 445 j_audio_manager_.obj()); |
| 350 } | 446 } |
| 351 | 447 |
| 352 } // namespace media | 448 } // namespace media |
| OLD | NEW |