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

Unified 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: Removed bad getter in unit test 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 side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698