| Index: media/audio/android/audio_manager_android.cc
|
| diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc
|
| index 33e9e085688de87c37eebfbdbfdeddfb9949f2db..24ad96882382edfe5f20a08949f5ec945f796b6d 100644
|
| --- a/media/audio/android/audio_manager_android.cc
|
| +++ b/media/audio/android/audio_manager_android.cc
|
| @@ -9,6 +9,7 @@
|
| #include "base/android/jni_string.h"
|
| #include "base/android/scoped_java_ref.h"
|
| #include "base/logging.h"
|
| +#include "base/message_loop/message_loop.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "jni/AudioManagerAndroid_jni.h"
|
| #include "media/audio/android/audio_record_input.h"
|
| @@ -45,9 +46,9 @@ AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
|
| }
|
|
|
| AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory)
|
| - : AudioManagerBase(audio_log_factory) {
|
| + : AudioManagerBase(audio_log_factory),
|
| + initialized_on_audio_thread_(false) {
|
| SetMaxOutputStreamsAllowed(kMaxOutputStreams);
|
| -
|
| j_audio_manager_.Reset(
|
| Java_AudioManagerAndroid_createAudioManagerAndroid(
|
| base::android::AttachCurrentThread(),
|
| @@ -59,6 +60,8 @@ AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory)
|
| AudioManagerAndroid::~AudioManagerAndroid() {
|
| Close();
|
| Shutdown();
|
| + // Verify that WillDestroyCurrentMessageLoop() has been called.
|
| + DCHECK(!initialized_on_audio_thread_);
|
| }
|
|
|
| bool AudioManagerAndroid::HasAudioOutputDevices() {
|
| @@ -71,26 +74,22 @@ bool AudioManagerAndroid::HasAudioInputDevices() {
|
|
|
| void AudioManagerAndroid::GetAudioInputDeviceNames(
|
| AudioDeviceNames* device_names) {
|
| - // Always add default device parameters as first element.
|
| - DCHECK(device_names->empty());
|
| - AddDefaultDevice(device_names);
|
| -
|
| - JNIEnv* env = AttachCurrentThread();
|
| - ScopedJavaLocalRef<jobjectArray> j_device_array =
|
| - Java_AudioManagerAndroid_getAudioInputDeviceNames(
|
| - env, j_audio_manager_.obj());
|
| - jsize len = env->GetArrayLength(j_device_array.obj());
|
| - AudioDeviceName device;
|
| - for (jsize i = 0; i < len; ++i) {
|
| - ScopedJavaLocalRef<jobject> j_device(
|
| - env, env->GetObjectArrayElement(j_device_array.obj(), i));
|
| - ScopedJavaLocalRef<jstring> j_device_name =
|
| - Java_AudioDeviceName_name(env, j_device.obj());
|
| - ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name);
|
| - ScopedJavaLocalRef<jstring> j_device_id =
|
| - Java_AudioDeviceName_id(env, j_device.obj());
|
| - ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id);
|
| - device_names->push_back(device);
|
| + // Get list of available audio devices and use the audio thread to reduce
|
| + // the number of calling threads to the Java layer. Also, ensure that the
|
| + // calling thread sees this function call as synchronous.
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner(GetTaskRunner());
|
| + if (task_runner->BelongsToCurrentThread()) {
|
| + GetAudioInputDeviceNamesOnAudioThread(NULL, device_names);
|
| + } else {
|
| + base::WaitableEvent event(false, false);
|
| + task_runner->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread,
|
| + base::Unretained(this),
|
| + &event,
|
| + device_names));
|
| + event.Wait();
|
| }
|
| }
|
|
|
| @@ -146,6 +145,7 @@ AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
|
|
|
| AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
|
| const AudioParameters& params, const std::string& device_id) {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| bool had_no_streams = HadNoAudioStreams();
|
| AudioInputStream* stream =
|
| AudioManagerBase::MakeAudioInputStream(params, device_id);
|
| @@ -206,6 +206,7 @@ AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
|
| AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
|
| const AudioParameters& params, const std::string& device_id) {
|
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
|
| // Use the device ID to select the correct input device.
|
| // Note that the input device is always associated with a certain output
|
| @@ -232,6 +233,13 @@ AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
|
| return new OpenSLESInputStream(this, params);
|
| }
|
|
|
| +void AudioManagerAndroid::WillDestroyCurrentMessageLoop() {
|
| + // This call matches previous calls to InitializeOnAudioThread() and it
|
| + // ensures that we unregister receivers for events related to changes in
|
| + // availability of audio devices.
|
| + CloseOnAudioThread();
|
| +}
|
| +
|
| int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
|
| int channels) {
|
| if (IsAudioLowLatencySupported()) {
|
| @@ -303,26 +311,75 @@ void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
|
| muted));
|
| }
|
|
|
| -void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
|
| - base::AutoLock lock(streams_lock_);
|
| - for (OutputStreams::iterator it = streams_.begin();
|
| - it != streams_.end(); ++it) {
|
| - (*it)->SetMute(muted);
|
| +void AudioManagerAndroid::GetAudioInputDeviceNamesOnAudioThread(
|
| + base::WaitableEvent* event, AudioDeviceNames* device_names) {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| +
|
| + // Set up the initial list of available audio devices and register for
|
| + // broadcasted notifications about any changes of availability.
|
| + // This method is only executed when called for the first time and it can
|
| + // also be called from SetAudioDeviceOnAudioThread().
|
| + InitializeOnAudioThread();
|
| +
|
| + // Always add default device parameters as first element.
|
| + DCHECK(device_names->empty());
|
| + AddDefaultDevice(device_names);
|
| +
|
| + JNIEnv* env = AttachCurrentThread();
|
| + ScopedJavaLocalRef<jobjectArray> j_device_array =
|
| + Java_AudioManagerAndroid_getAudioInputDeviceNames(
|
| + env, j_audio_manager_.obj());
|
| + jsize len = env->GetArrayLength(j_device_array.obj());
|
| + AudioDeviceName device;
|
| + for (jsize i = 0; i < len; ++i) {
|
| + ScopedJavaLocalRef<jobject> j_device(
|
| + env, env->GetObjectArrayElement(j_device_array.obj(), i));
|
| + ScopedJavaLocalRef<jstring> j_device_name =
|
| + Java_AudioDeviceName_name(env, j_device.obj());
|
| + ConvertJavaStringToUTF8(env, j_device_name.obj(), &device.device_name);
|
| + ScopedJavaLocalRef<jstring> j_device_id =
|
| + Java_AudioDeviceName_id(env, j_device.obj());
|
| + ConvertJavaStringToUTF8(env, j_device_id.obj(), &device.unique_id);
|
| + device_names->push_back(device);
|
| }
|
| +
|
| + if (event)
|
| + event->Signal();
|
| }
|
|
|
| -void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
|
| - Java_AudioManagerAndroid_setCommunicationAudioModeOn(
|
| - base::android::AttachCurrentThread(),
|
| - j_audio_manager_.obj(), on);
|
| +void AudioManagerAndroid::InitializeOnAudioThread() {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| + if (!initialized_on_audio_thread_) {
|
| + base::MessageLoop::current()->AddDestructionObserver(this);
|
| + Java_AudioManagerAndroid_initAudioDeviceList(
|
| + base::android::AttachCurrentThread(),
|
| + j_audio_manager_.obj());
|
| + initialized_on_audio_thread_ = true;
|
| + }
|
| +}
|
| +
|
| +void AudioManagerAndroid::CloseOnAudioThread() {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| + if (!initialized_on_audio_thread_)
|
| + return;
|
| + Java_AudioManagerAndroid_closeAudioDeviceList(
|
| + base::android::AttachCurrentThread(),
|
| + j_audio_manager_.obj());
|
| + initialized_on_audio_thread_ = false;
|
| }
|
|
|
| bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
|
| - JNIEnv* env = AttachCurrentThread();
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| + // Set up the initial list of available audio devices and register for
|
| + // broadcasted notifications about any changes of availability.
|
| + // This method is only executed when called for the first time and it can
|
| + // also be called from GetAudioInputDeviceNamesOnAudioThread().
|
| + InitializeOnAudioThread();
|
|
|
| // Send the unique device ID to the Java audio manager and make the
|
| // device switch. Provide an empty string to the Java audio manager
|
| // if the default device is selected.
|
| + JNIEnv* env = AttachCurrentThread();
|
| ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
|
| env,
|
| device_id == AudioManagerBase::kDefaultDeviceId ?
|
| @@ -331,6 +388,21 @@ bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
|
| env, j_audio_manager_.obj(), j_device_id.obj());
|
| }
|
|
|
| +void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| + base::AutoLock lock(streams_lock_);
|
| + for (OutputStreams::iterator it = streams_.begin();
|
| + it != streams_.end(); ++it) {
|
| + (*it)->SetMute(muted);
|
| + }
|
| +}
|
| +
|
| +void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
|
| + Java_AudioManagerAndroid_setCommunicationAudioModeOn(
|
| + base::android::AttachCurrentThread(),
|
| + j_audio_manager_.obj(), on);
|
| +}
|
| +
|
| int AudioManagerAndroid::GetNativeOutputSampleRate() {
|
| return Java_AudioManagerAndroid_getNativeOutputSampleRate(
|
| base::android::AttachCurrentThread(),
|
|
|