| 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 a8d81c7e829af4ffa2697427db608c73ecfdbbdf..593e8e5249f8a489c37640286a5b6225278ffcd7 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"
|
| @@ -47,18 +48,12 @@ AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
|
| AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory)
|
| : AudioManagerBase(audio_log_factory) {
|
| SetMaxOutputStreamsAllowed(kMaxOutputStreams);
|
| -
|
| - j_audio_manager_.Reset(
|
| - Java_AudioManagerAndroid_createAudioManagerAndroid(
|
| - base::android::AttachCurrentThread(),
|
| - base::android::GetApplicationContext(),
|
| - reinterpret_cast<intptr_t>(this)));
|
| - Init();
|
| }
|
|
|
| AudioManagerAndroid::~AudioManagerAndroid() {
|
| - Close();
|
| Shutdown();
|
| + // Verify that WillDestroyCurrentMessageLoop() has been called.
|
| + DCHECK(j_audio_manager_.is_null());
|
| }
|
|
|
| bool AudioManagerAndroid::HasAudioOutputDevices() {
|
| @@ -71,10 +66,13 @@ bool AudioManagerAndroid::HasAudioInputDevices() {
|
|
|
| void AudioManagerAndroid::GetAudioInputDeviceNames(
|
| AudioDeviceNames* device_names) {
|
| + CreateAndInitOnAudioThread();
|
| +
|
| // Always add default device parameters as first element.
|
| DCHECK(device_names->empty());
|
| AddDefaultDevice(device_names);
|
|
|
| + // Get list of available audio devices.
|
| JNIEnv* env = AttachCurrentThread();
|
| ScopedJavaLocalRef<jobjectArray> j_device_array =
|
| Java_AudioManagerAndroid_getAudioInputDeviceNames(
|
| @@ -102,10 +100,13 @@ void AudioManagerAndroid::GetAudioOutputDeviceNames(
|
|
|
| AudioParameters AudioManagerAndroid::GetInputStreamParameters(
|
| const std::string& device_id) {
|
| - JNIEnv* env = AttachCurrentThread();
|
| + CreateAndInitOnAudioThread();
|
| +
|
| // Use mono as preferred number of input channels on Android to save
|
| // resources. Using mono also avoids a driver issue seen on Samsung
|
| // Galaxy S3 and S4 devices. See http://crbug.com/256851 for details.
|
| + JNIEnv* env = AttachCurrentThread();
|
| + CHECK(env);
|
| ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
|
| int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
|
| env, GetNativeOutputSampleRate(),
|
| @@ -123,28 +124,27 @@ AudioParameters AudioManagerAndroid::GetInputStreamParameters(
|
| AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
|
| const AudioParameters& params,
|
| const std::string& device_id) {
|
| - bool had_no_streams = HadNoAudioStreams();
|
| + CreateAndInitOnAudioThread();
|
| + bool has_no_streams = HasNoAudioStreams();
|
| AudioOutputStream* stream =
|
| AudioManagerBase::MakeAudioOutputStream(params, std::string());
|
|
|
| // The audio manager for Android creates streams intended for real-time
|
| // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
|
| - // If a Bluetooth headset is used, the audio stream will use the SCO
|
| + // If a Bluetooth headset is selected, the audio stream will use the SCO
|
| // channel and therefore have a limited bandwidth (8-16kHz).
|
| - if (stream && had_no_streams)
|
| + if (stream && has_no_streams)
|
| SetCommunicationAudioModeOn(true);
|
|
|
| - {
|
| - base::AutoLock lock(streams_lock_);
|
| - streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
|
| - }
|
| + streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
|
|
|
| return stream;
|
| }
|
|
|
| AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
|
| const AudioParameters& params, const std::string& device_id) {
|
| - bool had_no_streams = HadNoAudioStreams();
|
| + CreateAndInitOnAudioThread();
|
| + bool has_no_streams = HasNoAudioStreams();
|
| AudioInputStream* stream =
|
| AudioManagerBase::MakeAudioInputStream(params, device_id);
|
|
|
| @@ -152,28 +152,31 @@ AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
|
| // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION.
|
| // If a Bluetooth headset is used, the audio stream will use the SCO
|
| // channel and therefore have a limited bandwidth (8kHz).
|
| - if (stream && had_no_streams)
|
| + if (stream && has_no_streams)
|
| SetCommunicationAudioModeOn(true);
|
| return stream;
|
| }
|
|
|
| void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| AudioManagerBase::ReleaseOutputStream(stream);
|
|
|
| // Restore the audio mode which was used before the first communication-
|
| // mode stream was created.
|
| - if (HadNoAudioStreams())
|
| + if (HasNoAudioStreams())
|
| SetCommunicationAudioModeOn(false);
|
| - base::AutoLock lock(streams_lock_);
|
| +
|
| streams_.erase(static_cast<OpenSLESOutputStream*>(stream));
|
| }
|
|
|
| void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| + DCHECK(!j_audio_manager_.is_null());
|
| AudioManagerBase::ReleaseInputStream(stream);
|
|
|
| // Restore the audio mode which was used before the first communication-
|
| // mode stream was created.
|
| - if (HadNoAudioStreams())
|
| + if (HasNoAudioStreams())
|
| SetCommunicationAudioModeOn(false);
|
| }
|
|
|
| @@ -188,6 +191,7 @@ AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
|
| const std::string& device_id) {
|
| DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
|
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
|
| + CreateAndInitOnAudioThread();
|
| return new OpenSLESOutputStream(this, params);
|
| }
|
|
|
| @@ -197,6 +201,7 @@ AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
|
| // needs it.
|
| DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
|
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
|
| + CreateAndInitOnAudioThread();
|
| return new OpenSLESInputStream(this, params);
|
| }
|
|
|
| @@ -204,6 +209,8 @@ AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
|
| const AudioParameters& params, const std::string& device_id) {
|
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
|
| DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
|
| + CreateAndInitOnAudioThread();
|
| +
|
| // Use the device ID to select the correct input device.
|
| // Note that the input device is always associated with a certain output
|
| // device, i.e., this selection does also switch the output device.
|
| @@ -229,21 +236,25 @@ AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
|
| return new OpenSLESInputStream(this, params);
|
| }
|
|
|
| -int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
|
| - int channels) {
|
| - if (IsAudioLowLatencySupported()) {
|
| - return GetAudioLowLatencyOutputFrameSize();
|
| - } else {
|
| - return std::max(kDefaultOutputBufferSize,
|
| - Java_AudioManagerAndroid_getMinOutputFrameSize(
|
| - base::android::AttachCurrentThread(),
|
| - sample_rate, channels));
|
| - }
|
| +// static
|
| +bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
|
| + return RegisterNativesImpl(env);
|
| +}
|
| +
|
| +void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
|
| + GetTaskRunner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &AudioManagerAndroid::DoSetMuteOnAudioThread,
|
| + base::Unretained(this),
|
| + muted));
|
| }
|
|
|
| AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
|
| const std::string& output_device_id,
|
| const AudioParameters& input_params) {
|
| + CreateAndInitOnAudioThread();
|
| +
|
| // TODO(tommi): Support |output_device_id|.
|
| DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
|
| ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
|
| @@ -270,13 +281,48 @@ AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
|
| sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS);
|
| }
|
|
|
| -bool AudioManagerAndroid::HadNoAudioStreams() {
|
| - return output_stream_count() == 0 && input_stream_count() == 0;
|
| +void AudioManagerAndroid::WillDestroyCurrentMessageLoop() {
|
| + CloseOnAudioThread();
|
| }
|
|
|
| -// static
|
| -bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
|
| - return RegisterNativesImpl(env);
|
| +void AudioManagerAndroid::CreateAndInitOnAudioThread() {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| +
|
| + // Ensure that we only create and initialize the Java part once.
|
| + if (!j_audio_manager_.is_null()) {
|
| + return;
|
| + }
|
| +
|
| + JNIEnv* env = base::android::AttachCurrentThread();
|
| + CHECK(env);
|
| +
|
| + // Create the Android audio manager on the audio thread.
|
| + DVLOG(2) << "Creating Java part of the audio manager";
|
| + j_audio_manager_.Reset(
|
| + Java_AudioManagerAndroid_createAudioManagerAndroid(
|
| + env,
|
| + base::android::GetApplicationContext(),
|
| + reinterpret_cast<intptr_t>(this)));
|
| +
|
| + // Prepare the list of audio devices and register receivers for device
|
| + // notifications.
|
| + Init();
|
| +
|
| + // Ensure that we are notified when the audio thread dies.
|
| + base::MessageLoop::current()->AddDestructionObserver(this);
|
| +}
|
| +
|
| +void AudioManagerAndroid::CloseOnAudioThread() {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| + if (j_audio_manager_.is_null())
|
| + return;
|
| + Close();
|
| + DVLOG(2) << "Destroying Java part of the audio manager";
|
| + j_audio_manager_.Reset();
|
| +}
|
| +
|
| +bool AudioManagerAndroid::HasNoAudioStreams() {
|
| + return output_stream_count() == 0 && input_stream_count() == 0;
|
| }
|
|
|
| void AudioManagerAndroid::Init() {
|
| @@ -291,23 +337,6 @@ void AudioManagerAndroid::Close() {
|
| j_audio_manager_.obj());
|
| }
|
|
|
| -void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
|
| - GetTaskRunner()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(
|
| - &AudioManagerAndroid::DoSetMuteOnAudioThread,
|
| - base::Unretained(this),
|
| - 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::SetCommunicationAudioModeOn(bool on) {
|
| Java_AudioManagerAndroid_setCommunicationAudioModeOn(
|
| base::android::AttachCurrentThread(),
|
| @@ -315,11 +344,13 @@ void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
|
| }
|
|
|
| bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
|
| - JNIEnv* env = AttachCurrentThread();
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
|
|
| // 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();
|
| + CHECK(env);
|
| ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
|
| env,
|
| device_id == AudioManagerBase::kDefaultDeviceId ?
|
| @@ -346,4 +377,24 @@ int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
|
| j_audio_manager_.obj());
|
| }
|
|
|
| +int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
|
| + int channels) {
|
| + if (IsAudioLowLatencySupported()) {
|
| + return GetAudioLowLatencyOutputFrameSize();
|
| + } else {
|
| + return std::max(kDefaultOutputBufferSize,
|
| + Java_AudioManagerAndroid_getMinOutputFrameSize(
|
| + base::android::AttachCurrentThread(),
|
| + sample_rate, channels));
|
| + }
|
| +}
|
| +
|
| +void AudioManagerAndroid::DoSetMuteOnAudioThread(bool muted) {
|
| + DCHECK(GetTaskRunner()->BelongsToCurrentThread());
|
| + for (OutputStreams::iterator it = streams_.begin();
|
| + it != streams_.end(); ++it) {
|
| + (*it)->SetMute(muted);
|
| + }
|
| +}
|
| +
|
| } // namespace media
|
|
|