summaryrefslogtreecommitdiffstats
path: root/chromium/media/audio/android
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/audio/android')
-rw-r--r--chromium/media/audio/android/audio_android_unittest.cc533
-rw-r--r--chromium/media/audio/android/audio_manager_android.cc209
-rw-r--r--chromium/media/audio/android/audio_manager_android.h28
-rw-r--r--chromium/media/audio/android/audio_record_input.cc18
-rw-r--r--chromium/media/audio/android/audio_record_input.h4
-rw-r--r--chromium/media/audio/android/opensles_input.cc24
-rw-r--r--chromium/media/audio/android/opensles_input.h3
-rw-r--r--chromium/media/audio/android/opensles_output.cc11
-rw-r--r--chromium/media/audio/android/opensles_output.h7
9 files changed, 537 insertions, 300 deletions
diff --git a/chromium/media/audio/android/audio_android_unittest.cc b/chromium/media/audio/android/audio_android_unittest.cc
index e7913265269..a356d9c25de 100644
--- a/chromium/media/audio/android/audio_android_unittest.cc
+++ b/chromium/media/audio/android/audio_android_unittest.cc
@@ -8,6 +8,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
+#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
@@ -17,6 +18,7 @@
#include "media/audio/android/audio_manager_android.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager_base.h"
+#include "media/audio/mock_audio_source_callback.h"
#include "media/base/decoder_buffer.h"
#include "media/base/seekable_buffer.h"
#include "media/base/test_data_util.h"
@@ -85,6 +87,47 @@ static double ExpectedTimeBetweenCallbacks(AudioParameters params) {
static_cast<double>(params.sample_rate()))).InMillisecondsF();
}
+// Helper method which verifies that the device list starts with a valid
+// default device name followed by non-default device names.
+static void CheckDeviceNames(const AudioDeviceNames& device_names) {
+ VLOG(2) << "Got " << device_names.size() << " audio devices.";
+ if (device_names.empty()) {
+ // Log a warning so we can see the status on the build bots. No need to
+ // break the test though since this does successfully test the code and
+ // some failure cases.
+ LOG(WARNING) << "No input devices detected";
+ return;
+ }
+
+ AudioDeviceNames::const_iterator it = device_names.begin();
+
+ // The first device in the list should always be the default device.
+ EXPECT_EQ(std::string(AudioManagerBase::kDefaultDeviceName),
+ it->device_name);
+ EXPECT_EQ(std::string(AudioManagerBase::kDefaultDeviceId), it->unique_id);
+ ++it;
+
+ // Other devices should have non-empty name and id and should not contain
+ // default name or id.
+ while (it != device_names.end()) {
+ EXPECT_FALSE(it->device_name.empty());
+ EXPECT_FALSE(it->unique_id.empty());
+ VLOG(2) << "Device ID(" << it->unique_id
+ << "), label: " << it->device_name;
+ EXPECT_NE(std::string(AudioManagerBase::kDefaultDeviceName),
+ it->device_name);
+ EXPECT_NE(std::string(AudioManagerBase::kDefaultDeviceId),
+ it->unique_id);
+ ++it;
+ }
+}
+
+// We clear the data bus to ensure that the test does not cause noise.
+static int RealOnMoreData(AudioBus* dest, AudioBuffersState buffers_state) {
+ dest->Zero();
+ return dest->frames();
+}
+
std::ostream& operator<<(std::ostream& os, const AudioParameters& params) {
using namespace std;
os << endl << "format: " << FormatToString(params.format()) << endl
@@ -105,34 +148,14 @@ std::ostream& operator<<(std::ostream& os, const AudioParameters& params) {
// Gmock implementation of AudioInputStream::AudioInputCallback.
class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
public:
- MOCK_METHOD5(OnData,
+ MOCK_METHOD4(OnData,
void(AudioInputStream* stream,
- const uint8* src,
- uint32 size,
+ const AudioBus* src,
uint32 hardware_delay_bytes,
double volume));
- MOCK_METHOD1(OnClose, void(AudioInputStream* stream));
MOCK_METHOD1(OnError, void(AudioInputStream* stream));
};
-// Gmock implementation of AudioOutputStream::AudioSourceCallback.
-class MockAudioOutputCallback : public AudioOutputStream::AudioSourceCallback {
- public:
- MOCK_METHOD2(OnMoreData,
- int(AudioBus* dest, AudioBuffersState buffers_state));
- MOCK_METHOD3(OnMoreIOData,
- int(AudioBus* source,
- AudioBus* dest,
- AudioBuffersState buffers_state));
- MOCK_METHOD1(OnError, void(AudioOutputStream* stream));
-
- // We clear the data bus to ensure that the test does not cause noise.
- int RealOnMoreData(AudioBus* dest, AudioBuffersState buffers_state) {
- dest->Zero();
- return dest->frames();
- }
-};
-
// Implements AudioOutputStream::AudioSourceCallback and provides audio data
// by reading from a data file.
class FileAudioSource : public AudioOutputStream::AudioSourceCallback {
@@ -183,13 +206,6 @@ class FileAudioSource : public AudioOutputStream::AudioSourceCallback {
return frames;
}
- virtual int OnMoreIOData(AudioBus* source,
- AudioBus* dest,
- AudioBuffersState buffers_state) OVERRIDE {
- NOTREACHED();
- return 0;
- }
-
virtual void OnError(AudioOutputStream* stream) OVERRIDE {}
int file_size() { return file_->data_size(); }
@@ -247,18 +263,22 @@ class FileAudioSink : public AudioInputStream::AudioInputCallback {
// AudioInputStream::AudioInputCallback implementation.
virtual void OnData(AudioInputStream* stream,
- const uint8* src,
- uint32 size,
+ const AudioBus* src,
uint32 hardware_delay_bytes,
double volume) OVERRIDE {
+ const int num_samples = src->frames() * src->channels();
+ scoped_ptr<int16> interleaved(new int16[num_samples]);
+ const int bytes_per_sample = sizeof(*interleaved);
+ src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
+
// Store data data in a temporary buffer to avoid making blocking
// fwrite() calls in the audio callback. The complete buffer will be
// written to file in the destructor.
- if (!buffer_->Append(src, size))
+ const int size = bytes_per_sample * num_samples;
+ if (!buffer_->Append((const uint8*)interleaved.get(), size))
event_->Signal();
}
- virtual void OnClose(AudioInputStream* stream) OVERRIDE {}
virtual void OnError(AudioInputStream* stream) OVERRIDE {}
private:
@@ -291,13 +311,19 @@ class FullDuplexAudioSinkSource
// AudioInputStream::AudioInputCallback implementation
virtual void OnData(AudioInputStream* stream,
- const uint8* src,
- uint32 size,
+ const AudioBus* src,
uint32 hardware_delay_bytes,
double volume) OVERRIDE {
const base::TimeTicks now_time = base::TimeTicks::Now();
const int diff = (now_time - previous_time_).InMilliseconds();
+ EXPECT_EQ(params_.bits_per_sample(), 16);
+ const int num_samples = src->frames() * src->channels();
+ scoped_ptr<int16> interleaved(new int16[num_samples]);
+ const int bytes_per_sample = sizeof(*interleaved);
+ src->ToInterleaved(src->frames(), bytes_per_sample, interleaved.get());
+ const int size = bytes_per_sample * num_samples;
+
base::AutoLock lock(lock_);
if (diff > 1000) {
started_ = true;
@@ -318,13 +344,12 @@ class FullDuplexAudioSinkSource
// Append new data to the FIFO and extend the size if the max capacity
// was exceeded. Flush the FIFO when extended just in case.
- if (!fifo_->Append(src, size)) {
+ if (!fifo_->Append((const uint8*)interleaved.get(), size)) {
fifo_->set_forward_capacity(2 * fifo_->forward_capacity());
fifo_->Clear();
}
}
- virtual void OnClose(AudioInputStream* stream) OVERRIDE {}
virtual void OnError(AudioInputStream* stream) OVERRIDE {}
// AudioOutputStream::AudioSourceCallback implementation
@@ -357,13 +382,6 @@ class FullDuplexAudioSinkSource
return dest->frames();
}
- virtual int OnMoreIOData(AudioBus* source,
- AudioBus* dest,
- AudioBuffersState buffers_state) OVERRIDE {
- NOTREACHED();
- return 0;
- }
-
virtual void OnError(AudioOutputStream* stream) OVERRIDE {}
private:
@@ -389,21 +407,76 @@ class FullDuplexAudioSinkSource
// Test fixture class for tests which only exercise the output path.
class AudioAndroidOutputTest : public testing::Test {
public:
- AudioAndroidOutputTest() {}
-
- protected:
- virtual void SetUp() {
- audio_manager_.reset(AudioManager::CreateForTesting());
- loop_.reset(new base::MessageLoopForUI());
+ AudioAndroidOutputTest()
+ : loop_(new base::MessageLoopForUI()),
+ audio_manager_(AudioManager::CreateForTesting()),
+ audio_output_stream_(NULL) {
}
- virtual void TearDown() {}
+ virtual ~AudioAndroidOutputTest() {
+ }
+ protected:
AudioManager* audio_manager() { return audio_manager_.get(); }
base::MessageLoopForUI* loop() { return loop_.get(); }
+ const AudioParameters& audio_output_parameters() {
+ return audio_output_parameters_;
+ }
- AudioParameters GetDefaultOutputStreamParameters() {
- return audio_manager()->GetDefaultOutputStreamParameters();
+ // Synchronously runs the provided callback/closure on the audio thread.
+ void RunOnAudioThread(const base::Closure& closure) {
+ if (!audio_manager()->GetTaskRunner()->BelongsToCurrentThread()) {
+ base::WaitableEvent event(false, false);
+ audio_manager()->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioAndroidOutputTest::RunOnAudioThreadImpl,
+ base::Unretained(this),
+ closure,
+ &event));
+ event.Wait();
+ } else {
+ closure.Run();
+ }
+ }
+
+ void RunOnAudioThreadImpl(const base::Closure& closure,
+ base::WaitableEvent* event) {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ closure.Run();
+ event->Signal();
+ }
+
+ void GetDefaultOutputStreamParametersOnAudioThread() {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidOutputTest::GetDefaultOutputStreamParameters,
+ base::Unretained(this)));
+ }
+
+ void MakeAudioOutputStreamOnAudioThread(const AudioParameters& params) {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidOutputTest::MakeOutputStream,
+ base::Unretained(this),
+ params));
+ }
+
+ void OpenAndCloseAudioOutputStreamOnAudioThread() {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidOutputTest::OpenAndClose,
+ base::Unretained(this)));
+ }
+
+ void OpenAndStartAudioOutputStreamOnAudioThread(
+ AudioOutputStream::AudioSourceCallback* source) {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidOutputTest::OpenAndStart,
+ base::Unretained(this),
+ source));
+ }
+
+ void StopAndCloseAudioOutputStreamOnAudioThread() {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidOutputTest::StopAndClose,
+ base::Unretained(this)));
}
double AverageTimeBetweenCallbacks(int num_callbacks) const {
@@ -416,28 +489,25 @@ class AudioAndroidOutputTest : public testing::Test {
ExpectedTimeBetweenCallbacks(params);
const int num_callbacks =
(kCallbackTestTimeMs / expected_time_between_callbacks_ms);
- AudioOutputStream* stream = audio_manager()->MakeAudioOutputStream(
- params, std::string(), std::string());
- EXPECT_TRUE(stream);
+ MakeAudioOutputStreamOnAudioThread(params);
int count = 0;
- MockAudioOutputCallback source;
+ MockAudioSourceCallback source;
EXPECT_CALL(source, OnMoreData(NotNull(), _))
.Times(AtLeast(num_callbacks))
.WillRepeatedly(
DoAll(CheckCountAndPostQuitTask(&count, num_callbacks, loop()),
- Invoke(&source, &MockAudioOutputCallback::RealOnMoreData)));
- EXPECT_CALL(source, OnError(stream)).Times(0);
- EXPECT_CALL(source, OnMoreIOData(_, _, _)).Times(0);
+ Invoke(RealOnMoreData)));
+ EXPECT_CALL(source, OnError(audio_output_stream_)).Times(0);
+
+ OpenAndStartAudioOutputStreamOnAudioThread(&source);
- EXPECT_TRUE(stream->Open());
- stream->Start(&source);
start_time_ = base::TimeTicks::Now();
loop()->Run();
end_time_ = base::TimeTicks::Now();
- stream->Stop();
- stream->Close();
+
+ StopAndCloseAudioOutputStreamOnAudioThread();
double average_time_between_callbacks_ms =
AverageTimeBetweenCallbacks(num_callbacks);
@@ -448,11 +518,47 @@ class AudioAndroidOutputTest : public testing::Test {
EXPECT_GE(average_time_between_callbacks_ms,
0.70 * expected_time_between_callbacks_ms);
EXPECT_LE(average_time_between_callbacks_ms,
- 1.30 * expected_time_between_callbacks_ms);
+ 1.35 * expected_time_between_callbacks_ms);
+ }
+
+ void GetDefaultOutputStreamParameters() {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ audio_output_parameters_ =
+ audio_manager()->GetDefaultOutputStreamParameters();
+ EXPECT_TRUE(audio_output_parameters_.IsValid());
+ }
+
+ void MakeOutputStream(const AudioParameters& params) {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ audio_output_stream_ = audio_manager()->MakeAudioOutputStream(
+ params, std::string());
+ EXPECT_TRUE(audio_output_stream_);
+ }
+
+ void OpenAndClose() {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ EXPECT_TRUE(audio_output_stream_->Open());
+ audio_output_stream_->Close();
+ audio_output_stream_ = NULL;
+ }
+
+ void OpenAndStart(AudioOutputStream::AudioSourceCallback* source) {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ EXPECT_TRUE(audio_output_stream_->Open());
+ audio_output_stream_->Start(source);
+ }
+
+ void StopAndClose() {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ audio_output_stream_->Stop();
+ audio_output_stream_->Close();
+ audio_output_stream_ = NULL;
}
scoped_ptr<base::MessageLoopForUI> loop_;
scoped_ptr<AudioManager> audio_manager_;
+ AudioParameters audio_output_parameters_;
+ AudioOutputStream* audio_output_stream_;
base::TimeTicks start_time_;
base::TimeTicks end_time_;
@@ -476,53 +582,87 @@ std::vector<bool> RunAudioRecordInputPathTests() {
class AudioAndroidInputTest : public AudioAndroidOutputTest,
public testing::WithParamInterface<bool> {
public:
- AudioAndroidInputTest() {}
+ AudioAndroidInputTest() : audio_input_stream_(NULL) {}
protected:
+ const AudioParameters& audio_input_parameters() {
+ return audio_input_parameters_;
+ }
+
AudioParameters GetInputStreamParameters() {
- AudioParameters input_params = audio_manager()->GetInputStreamParameters(
- AudioManagerBase::kDefaultDeviceId);
+ GetDefaultInputStreamParametersOnAudioThread();
+
// Override the platform effects setting to use the AudioRecord or OpenSLES
// path as requested.
int effects = GetParam() ? AudioParameters::ECHO_CANCELLER :
AudioParameters::NO_EFFECTS;
- AudioParameters params(input_params.format(),
- input_params.channel_layout(),
- input_params.input_channels(),
- input_params.sample_rate(),
- input_params.bits_per_sample(),
- input_params.frames_per_buffer(),
+ AudioParameters params(audio_input_parameters().format(),
+ audio_input_parameters().channel_layout(),
+ audio_input_parameters().input_channels(),
+ audio_input_parameters().sample_rate(),
+ audio_input_parameters().bits_per_sample(),
+ audio_input_parameters().frames_per_buffer(),
effects);
return params;
}
+ void GetDefaultInputStreamParametersOnAudioThread() {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidInputTest::GetDefaultInputStreamParameters,
+ base::Unretained(this)));
+ }
+
+ void MakeAudioInputStreamOnAudioThread(const AudioParameters& params) {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidInputTest::MakeInputStream,
+ base::Unretained(this),
+ params));
+ }
+
+ void OpenAndCloseAudioInputStreamOnAudioThread() {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidInputTest::OpenAndClose,
+ base::Unretained(this)));
+ }
+
+ void OpenAndStartAudioInputStreamOnAudioThread(
+ AudioInputStream::AudioInputCallback* sink) {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidInputTest::OpenAndStart,
+ base::Unretained(this),
+ sink));
+ }
+
+ void StopAndCloseAudioInputStreamOnAudioThread() {
+ RunOnAudioThread(
+ base::Bind(&AudioAndroidInputTest::StopAndClose,
+ base::Unretained(this)));
+ }
+
void StartInputStreamCallbacks(const AudioParameters& params) {
double expected_time_between_callbacks_ms =
ExpectedTimeBetweenCallbacks(params);
const int num_callbacks =
(kCallbackTestTimeMs / expected_time_between_callbacks_ms);
- AudioInputStream* stream = audio_manager()->MakeAudioInputStream(
- params, AudioManagerBase::kDefaultDeviceId);
- EXPECT_TRUE(stream);
+
+ MakeAudioInputStreamOnAudioThread(params);
int count = 0;
MockAudioInputCallback sink;
- EXPECT_CALL(sink,
- OnData(stream, NotNull(), params.GetBytesPerBuffer(), _, _))
+ EXPECT_CALL(sink, OnData(audio_input_stream_, NotNull(), _, _))
.Times(AtLeast(num_callbacks))
.WillRepeatedly(
- CheckCountAndPostQuitTask(&count, num_callbacks, loop()));
- EXPECT_CALL(sink, OnError(stream)).Times(0);
- EXPECT_CALL(sink, OnClose(stream)).Times(1);
+ CheckCountAndPostQuitTask(&count, num_callbacks, loop()));
+ EXPECT_CALL(sink, OnError(audio_input_stream_)).Times(0);
+
+ OpenAndStartAudioInputStreamOnAudioThread(&sink);
- EXPECT_TRUE(stream->Open());
- stream->Start(&sink);
start_time_ = base::TimeTicks::Now();
loop()->Run();
end_time_ = base::TimeTicks::Now();
- stream->Stop();
- stream->Close();
+
+ StopAndCloseAudioInputStreamOnAudioThread();
double average_time_between_callbacks_ms =
AverageTimeBetweenCallbacks(num_callbacks);
@@ -536,6 +676,41 @@ class AudioAndroidInputTest : public AudioAndroidOutputTest,
1.30 * expected_time_between_callbacks_ms);
}
+ void GetDefaultInputStreamParameters() {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ audio_input_parameters_ = audio_manager()->GetInputStreamParameters(
+ AudioManagerBase::kDefaultDeviceId);
+ }
+
+ void MakeInputStream(const AudioParameters& params) {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ audio_input_stream_ = audio_manager()->MakeAudioInputStream(
+ params, AudioManagerBase::kDefaultDeviceId);
+ EXPECT_TRUE(audio_input_stream_);
+ }
+
+ void OpenAndClose() {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ EXPECT_TRUE(audio_input_stream_->Open());
+ audio_input_stream_->Close();
+ audio_input_stream_ = NULL;
+ }
+
+ void OpenAndStart(AudioInputStream::AudioInputCallback* sink) {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ EXPECT_TRUE(audio_input_stream_->Open());
+ audio_input_stream_->Start(sink);
+ }
+
+ void StopAndClose() {
+ DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
+ audio_input_stream_->Stop();
+ audio_input_stream_->Close();
+ audio_input_stream_ = NULL;
+ }
+
+ AudioInputStream* audio_input_stream_;
+ AudioParameters audio_input_parameters_;
private:
DISALLOW_COPY_AND_ASSIGN(AudioAndroidInputTest);
@@ -545,35 +720,48 @@ class AudioAndroidInputTest : public AudioAndroidOutputTest,
TEST_P(AudioAndroidInputTest, GetDefaultInputStreamParameters) {
// We don't go through AudioAndroidInputTest::GetInputStreamParameters() here
// so that we can log the real (non-overridden) values of the effects.
- AudioParameters params = audio_manager()->GetInputStreamParameters(
- AudioManagerBase::kDefaultDeviceId);
- EXPECT_TRUE(params.IsValid());
- VLOG(1) << params;
+ GetDefaultInputStreamParametersOnAudioThread();
+ EXPECT_TRUE(audio_input_parameters().IsValid());
+ VLOG(1) << audio_input_parameters();
}
// Get the default audio output parameters and log the result.
TEST_F(AudioAndroidOutputTest, GetDefaultOutputStreamParameters) {
- AudioParameters params = GetDefaultOutputStreamParameters();
- EXPECT_TRUE(params.IsValid());
- VLOG(1) << params;
+ GetDefaultOutputStreamParametersOnAudioThread();
+ VLOG(1) << audio_output_parameters();
+}
+
+// Verify input device enumeration.
+TEST_F(AudioAndroidInputTest, GetAudioInputDeviceNames) {
+ if (!audio_manager()->HasAudioInputDevices())
+ return;
+ AudioDeviceNames devices;
+ RunOnAudioThread(
+ base::Bind(&AudioManager::GetAudioInputDeviceNames,
+ base::Unretained(audio_manager()),
+ &devices));
+ CheckDeviceNames(devices);
}
-// Check if low-latency output is supported and log the result as output.
-TEST_F(AudioAndroidOutputTest, IsAudioLowLatencySupported) {
- AudioManagerAndroid* manager =
- static_cast<AudioManagerAndroid*>(audio_manager());
- bool low_latency = manager->IsAudioLowLatencySupported();
- low_latency ? VLOG(0) << "Low latency output is supported"
- : VLOG(0) << "Low latency output is *not* supported";
+// Verify output device enumeration.
+TEST_F(AudioAndroidOutputTest, GetAudioOutputDeviceNames) {
+ if (!audio_manager()->HasAudioOutputDevices())
+ return;
+ AudioDeviceNames devices;
+ RunOnAudioThread(
+ base::Bind(&AudioManager::GetAudioOutputDeviceNames,
+ base::Unretained(audio_manager()),
+ &devices));
+ CheckDeviceNames(devices);
}
// Ensure that a default input stream can be created and closed.
TEST_P(AudioAndroidInputTest, CreateAndCloseInputStream) {
AudioParameters params = GetInputStreamParameters();
- AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
- params, AudioManagerBase::kDefaultDeviceId);
- EXPECT_TRUE(ais);
- ais->Close();
+ MakeAudioInputStreamOnAudioThread(params);
+ RunOnAudioThread(
+ base::Bind(&AudioInputStream::Close,
+ base::Unretained(audio_input_stream_)));
}
// Ensure that a default output stream can be created and closed.
@@ -581,45 +769,39 @@ TEST_P(AudioAndroidInputTest, CreateAndCloseInputStream) {
// to communication mode, and calls RegisterHeadsetReceiver, the first time
// it is called?
TEST_F(AudioAndroidOutputTest, CreateAndCloseOutputStream) {
- AudioParameters params = GetDefaultOutputStreamParameters();
- AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
- params, std::string(), std::string());
- EXPECT_TRUE(aos);
- aos->Close();
+ GetDefaultOutputStreamParametersOnAudioThread();
+ MakeAudioOutputStreamOnAudioThread(audio_output_parameters());
+ RunOnAudioThread(
+ base::Bind(&AudioOutputStream::Close,
+ base::Unretained(audio_output_stream_)));
}
// Ensure that a default input stream can be opened and closed.
TEST_P(AudioAndroidInputTest, OpenAndCloseInputStream) {
AudioParameters params = GetInputStreamParameters();
- AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
- params, AudioManagerBase::kDefaultDeviceId);
- EXPECT_TRUE(ais);
- EXPECT_TRUE(ais->Open());
- ais->Close();
+ MakeAudioInputStreamOnAudioThread(params);
+ OpenAndCloseAudioInputStreamOnAudioThread();
}
// Ensure that a default output stream can be opened and closed.
TEST_F(AudioAndroidOutputTest, OpenAndCloseOutputStream) {
- AudioParameters params = GetDefaultOutputStreamParameters();
- AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
- params, std::string(), std::string());
- EXPECT_TRUE(aos);
- EXPECT_TRUE(aos->Open());
- aos->Close();
+ GetDefaultOutputStreamParametersOnAudioThread();
+ MakeAudioOutputStreamOnAudioThread(audio_output_parameters());
+ OpenAndCloseAudioOutputStreamOnAudioThread();
}
// Start input streaming using default input parameters and ensure that the
// callback sequence is sane.
-TEST_P(AudioAndroidInputTest, StartInputStreamCallbacks) {
- AudioParameters params = GetInputStreamParameters();
- StartInputStreamCallbacks(params);
+TEST_P(AudioAndroidInputTest, DISABLED_StartInputStreamCallbacks) {
+ AudioParameters native_params = GetInputStreamParameters();
+ StartInputStreamCallbacks(native_params);
}
// Start input streaming using non default input parameters and ensure that the
// callback sequence is sane. The only change we make in this test is to select
// a 10ms buffer size instead of the default size.
-// TODO(henrika): possibly add support for more variations.
-TEST_P(AudioAndroidInputTest, StartInputStreamCallbacksNonDefaultParameters) {
+TEST_P(AudioAndroidInputTest,
+ DISABLED_StartInputStreamCallbacksNonDefaultParameters) {
AudioParameters native_params = GetInputStreamParameters();
AudioParameters params(native_params.format(),
native_params.channel_layout(),
@@ -634,8 +816,8 @@ TEST_P(AudioAndroidInputTest, StartInputStreamCallbacksNonDefaultParameters) {
// Start output streaming using default output parameters and ensure that the
// callback sequence is sane.
TEST_F(AudioAndroidOutputTest, StartOutputStreamCallbacks) {
- AudioParameters params = GetDefaultOutputStreamParameters();
- StartOutputStreamCallbacks(params);
+ GetDefaultOutputStreamParametersOnAudioThread();
+ StartOutputStreamCallbacks(audio_output_parameters());
}
// Start output streaming using non default output parameters and ensure that
@@ -643,13 +825,13 @@ TEST_F(AudioAndroidOutputTest, StartOutputStreamCallbacks) {
// select a 10ms buffer size instead of the default size and to open up the
// device in mono.
// TODO(henrika): possibly add support for more variations.
-TEST_F(AudioAndroidOutputTest, StartOutputStreamCallbacksNonDefaultParameters) {
- AudioParameters native_params = GetDefaultOutputStreamParameters();
- AudioParameters params(native_params.format(),
+TEST_F(AudioAndroidOutputTest, DISABLED_StartOutputStreamCallbacksNonDefaultParameters) {
+ GetDefaultOutputStreamParametersOnAudioThread();
+ AudioParameters params(audio_output_parameters().format(),
CHANNEL_LAYOUT_MONO,
- native_params.sample_rate(),
- native_params.bits_per_sample(),
- native_params.sample_rate() / 100);
+ audio_output_parameters().sample_rate(),
+ audio_output_parameters().bits_per_sample(),
+ audio_output_parameters().sample_rate() / 100);
StartOutputStreamCallbacks(params);
}
@@ -658,13 +840,12 @@ TEST_F(AudioAndroidOutputTest, StartOutputStreamCallbacksNonDefaultParameters) {
// NOTE: this test requires user interaction and is not designed to run as an
// automatized test on bots.
TEST_F(AudioAndroidOutputTest, DISABLED_RunOutputStreamWithFileAsSource) {
- AudioParameters params = GetDefaultOutputStreamParameters();
- VLOG(1) << params;
- AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
- params, std::string(), std::string());
- EXPECT_TRUE(aos);
+ GetDefaultOutputStreamParametersOnAudioThread();
+ VLOG(1) << audio_output_parameters();
+ MakeAudioOutputStreamOnAudioThread(audio_output_parameters());
std::string file_name;
+ const AudioParameters params = audio_output_parameters();
if (params.sample_rate() == 48000 && params.channels() == 2) {
file_name = kSpeechFile_16b_s_48k;
} else if (params.sample_rate() == 48000 && params.channels() == 1) {
@@ -681,13 +862,10 @@ TEST_F(AudioAndroidOutputTest, DISABLED_RunOutputStreamWithFileAsSource) {
base::WaitableEvent event(false, false);
FileAudioSource source(&event, file_name);
- EXPECT_TRUE(aos->Open());
- aos->SetVolume(1.0);
- aos->Start(&source);
+ OpenAndStartAudioOutputStreamOnAudioThread(&source);
VLOG(0) << ">> Verify that the file is played out correctly...";
EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
- aos->Stop();
- aos->Close();
+ StopAndCloseAudioOutputStreamOnAudioThread();
}
// Start input streaming and run it for ten seconds while recording to a
@@ -697,9 +875,7 @@ TEST_F(AudioAndroidOutputTest, DISABLED_RunOutputStreamWithFileAsSource) {
TEST_P(AudioAndroidInputTest, DISABLED_RunSimplexInputStreamWithFileAsSink) {
AudioParameters params = GetInputStreamParameters();
VLOG(1) << params;
- AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
- params, AudioManagerBase::kDefaultDeviceId);
- EXPECT_TRUE(ais);
+ MakeAudioInputStreamOnAudioThread(params);
std::string file_name = base::StringPrintf("out_simplex_%d_%d_%d.pcm",
params.sample_rate(),
@@ -709,12 +885,10 @@ TEST_P(AudioAndroidInputTest, DISABLED_RunSimplexInputStreamWithFileAsSink) {
base::WaitableEvent event(false, false);
FileAudioSink sink(&event, params, file_name);
- EXPECT_TRUE(ais->Open());
- ais->Start(&sink);
+ OpenAndStartAudioInputStreamOnAudioThread(&sink);
VLOG(0) << ">> Speak into the microphone to record audio...";
EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
- ais->Stop();
- ais->Close();
+ StopAndCloseAudioInputStreamOnAudioThread();
}
// Same test as RunSimplexInputStreamWithFileAsSink but this time output
@@ -723,15 +897,12 @@ TEST_P(AudioAndroidInputTest, DISABLED_RunSimplexInputStreamWithFileAsSink) {
// automatized test on bots.
TEST_P(AudioAndroidInputTest, DISABLED_RunDuplexInputStreamWithFileAsSink) {
AudioParameters in_params = GetInputStreamParameters();
- AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
- in_params, AudioManagerBase::kDefaultDeviceId);
- EXPECT_TRUE(ais);
+ VLOG(1) << in_params;
+ MakeAudioInputStreamOnAudioThread(in_params);
- AudioParameters out_params =
- audio_manager()->GetDefaultOutputStreamParameters();
- AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
- out_params, std::string(), std::string());
- EXPECT_TRUE(aos);
+ GetDefaultOutputStreamParametersOnAudioThread();
+ VLOG(1) << audio_output_parameters();
+ MakeAudioOutputStreamOnAudioThread(audio_output_parameters());
std::string file_name = base::StringPrintf("out_duplex_%d_%d_%d.pcm",
in_params.sample_rate(),
@@ -740,23 +911,18 @@ TEST_P(AudioAndroidInputTest, DISABLED_RunDuplexInputStreamWithFileAsSink) {
base::WaitableEvent event(false, false);
FileAudioSink sink(&event, in_params, file_name);
- MockAudioOutputCallback source;
+ MockAudioSourceCallback source;
- EXPECT_CALL(source, OnMoreData(NotNull(), _)).WillRepeatedly(
- Invoke(&source, &MockAudioOutputCallback::RealOnMoreData));
- EXPECT_CALL(source, OnError(aos)).Times(0);
- EXPECT_CALL(source, OnMoreIOData(_, _, _)).Times(0);
+ EXPECT_CALL(source, OnMoreData(NotNull(), _))
+ .WillRepeatedly(Invoke(RealOnMoreData));
+ EXPECT_CALL(source, OnError(audio_output_stream_)).Times(0);
- EXPECT_TRUE(ais->Open());
- EXPECT_TRUE(aos->Open());
- ais->Start(&sink);
- aos->Start(&source);
+ OpenAndStartAudioInputStreamOnAudioThread(&sink);
+ OpenAndStartAudioOutputStreamOnAudioThread(&source);
VLOG(0) << ">> Speak into the microphone to record audio";
EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
- aos->Stop();
- ais->Stop();
- aos->Close();
- ais->Close();
+ StopAndCloseAudioOutputStreamOnAudioThread();
+ StopAndCloseAudioInputStreamOnAudioThread();
}
// Start audio in both directions while feeding captured data into a FIFO so
@@ -776,18 +942,17 @@ TEST_P(AudioAndroidInputTest,
// audio on Android.
AudioParameters io_params(default_input_params.format(),
default_input_params.channel_layout(),
+ ChannelLayoutToChannelCount(
+ default_input_params.channel_layout()),
default_input_params.sample_rate(),
default_input_params.bits_per_sample(),
- default_input_params.sample_rate() / 100);
+ default_input_params.sample_rate() / 100,
+ default_input_params.effects());
VLOG(1) << io_params;
// Create input and output streams using the common audio parameters.
- AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
- io_params, AudioManagerBase::kDefaultDeviceId);
- EXPECT_TRUE(ais);
- AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
- io_params, std::string(), std::string());
- EXPECT_TRUE(aos);
+ MakeAudioInputStreamOnAudioThread(io_params);
+ MakeAudioOutputStreamOnAudioThread(io_params);
FullDuplexAudioSinkSource full_duplex(io_params);
@@ -795,20 +960,16 @@ TEST_P(AudioAndroidInputTest,
// delay we should expect from the FIFO. If real-time delay measurements are
// performed, the result should be reduced by this extra delay since it is
// something that has been added by the test.
- EXPECT_TRUE(ais->Open());
- EXPECT_TRUE(aos->Open());
- ais->Start(&full_duplex);
- aos->Start(&full_duplex);
+ OpenAndStartAudioInputStreamOnAudioThread(&full_duplex);
+ OpenAndStartAudioOutputStreamOnAudioThread(&full_duplex);
VLOG(1) << "HINT: an estimate of the extra FIFO delay will be updated "
<< "once per second during this test.";
VLOG(0) << ">> Speak into the mic and listen to the audio in loopback...";
fflush(stdout);
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
printf("\n");
- aos->Stop();
- ais->Stop();
- aos->Close();
- ais->Close();
+ StopAndCloseAudioOutputStreamOnAudioThread();
+ StopAndCloseAudioInputStreamOnAudioThread();
}
INSTANTIATE_TEST_CASE_P(AudioAndroidInputTest, AudioAndroidInputTest,
diff --git a/chromium/media/audio/android/audio_manager_android.cc b/chromium/media/audio/android/audio_manager_android.cc
index 3464d89a30f..48f203ab74e 100644
--- a/chromium/media/audio/android/audio_manager_android.cc
+++ b/chromium/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"
@@ -37,9 +38,6 @@ static void AddDefaultDevice(AudioDeviceNames* device_names) {
// Maximum number of output streams that can be open simultaneously.
static const int kMaxOutputStreams = 10;
-static const int kAudioModeNormal = 0x00000000;
-static const int kAudioModeInCommunication = 0x00000003;
-
static const int kDefaultInputBufferSize = 1024;
static const int kDefaultOutputBufferSize = 2048;
@@ -48,19 +46,26 @@ AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) {
}
AudioManagerAndroid::AudioManagerAndroid(AudioLogFactory* audio_log_factory)
- : AudioManagerBase(audio_log_factory) {
+ : AudioManagerBase(audio_log_factory),
+ communication_mode_is_on_(false) {
SetMaxOutputStreamsAllowed(kMaxOutputStreams);
- j_audio_manager_.Reset(
- Java_AudioManagerAndroid_createAudioManagerAndroid(
- base::android::AttachCurrentThread(),
- base::android::GetApplicationContext(),
- reinterpret_cast<intptr_t>(this)));
- Init();
+ // WARNING: This is executed on the UI loop, do not add any code here which
+ // loads libraries or attempts to call out into the OS. Instead add such code
+ // to the InitializeOnAudioThread() method below.
+
+ // Task must be posted last to avoid races from handing out "this" to the
+ // audio thread.
+ GetTaskRunner()->PostTask(FROM_HERE, base::Bind(
+ &AudioManagerAndroid::InitializeOnAudioThread,
+ base::Unretained(this)));
}
AudioManagerAndroid::~AudioManagerAndroid() {
- Close();
+ // It's safe to post a task here since Shutdown() will wait for all tasks to
+ // complete before returning.
+ GetTaskRunner()->PostTask(FROM_HERE, base::Bind(
+ &AudioManagerAndroid::ShutdownOnAudioThread, base::Unretained(this)));
Shutdown();
}
@@ -74,13 +79,22 @@ bool AudioManagerAndroid::HasAudioInputDevices() {
void AudioManagerAndroid::GetAudioInputDeviceNames(
AudioDeviceNames* device_names) {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+
// 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(
env, j_audio_manager_.obj());
+ if (j_device_array.is_null()) {
+ // Most probable reason for a NULL result here is that the process lacks
+ // MODIFY_AUDIO_SETTINGS or RECORD_AUDIO permissions.
+ return;
+ }
jsize len = env->GetArrayLength(j_device_array.obj());
AudioDeviceName device;
for (jsize i = 0; i < len; ++i) {
@@ -104,76 +118,96 @@ void AudioManagerAndroid::GetAudioOutputDeviceNames(
AudioParameters AudioManagerAndroid::GetInputStreamParameters(
const std::string& device_id) {
- JNIEnv* env = AttachCurrentThread();
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+
// 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();
ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO;
int buffer_size = Java_AudioManagerAndroid_getMinInputFrameSize(
env, GetNativeOutputSampleRate(),
ChannelLayoutToChannelCount(channel_layout));
+ buffer_size = buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size;
int effects = AudioParameters::NO_EFFECTS;
effects |= Java_AudioManagerAndroid_shouldUseAcousticEchoCanceler(env) ?
AudioParameters::ECHO_CANCELLER : AudioParameters::NO_EFFECTS;
+
+ int user_buffer_size = GetUserBufferSize();
+ if (user_buffer_size)
+ buffer_size = user_buffer_size;
+
AudioParameters params(
AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0,
- GetNativeOutputSampleRate(), 16,
- buffer_size <= 0 ? kDefaultInputBufferSize : buffer_size, effects);
+ GetNativeOutputSampleRate(), 16, buffer_size, effects);
return params;
}
AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
const AudioParameters& params,
- const std::string& device_id,
- const std::string& input_device_id) {
+ const std::string& device_id) {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
AudioOutputStream* stream =
- AudioManagerBase::MakeAudioOutputStream(params, std::string(),
- std::string());
- if (stream && output_stream_count() == 1) {
- SetAudioMode(kAudioModeInCommunication);
- }
-
- {
- base::AutoLock lock(streams_lock_);
- streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
- }
-
+ AudioManagerBase::MakeAudioOutputStream(params, std::string());
+ streams_.insert(static_cast<OpenSLESOutputStream*>(stream));
return stream;
}
AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
const AudioParameters& params, const std::string& device_id) {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ bool has_no_input_streams = HasNoAudioInputStreams();
AudioInputStream* stream =
AudioManagerBase::MakeAudioInputStream(params, device_id);
+
+ // 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
+ // channel and therefore have a limited bandwidth (8kHz).
+ if (stream && has_no_input_streams) {
+ communication_mode_is_on_ = true;
+ SetCommunicationAudioModeOn(true);
+ }
return stream;
}
void AudioManagerAndroid::ReleaseOutputStream(AudioOutputStream* stream) {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
AudioManagerBase::ReleaseOutputStream(stream);
- if (!output_stream_count()) {
- SetAudioMode(kAudioModeNormal);
- }
- 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 (HasNoAudioInputStreams()) {
+ communication_mode_is_on_ = false;
+ SetCommunicationAudioModeOn(false);
+ }
}
AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
const AudioParameters& params) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
- return new OpenSLESOutputStream(this, params);
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ return new OpenSLESOutputStream(this, params, SL_ANDROID_STREAM_MEDIA);
}
AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
const AudioParameters& params,
- const std::string& device_id,
- const std::string& input_device_id) {
+ const std::string& device_id) {
DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
- return new OpenSLESOutputStream(this, params);
+
+ // Set stream type which matches the current system-wide audio mode used by
+ // the Android audio manager.
+ const SLint32 stream_type = communication_mode_is_on_ ?
+ SL_ANDROID_STREAM_VOICE : SL_ANDROID_STREAM_MEDIA;
+ return new OpenSLESOutputStream(this, params, stream_type);
}
AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
@@ -187,13 +221,18 @@ AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
DLOG_IF(ERROR, device_id.empty()) << "Invalid device ID!";
- // Utilize the device ID to select the correct input device.
+
+ // 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.
// All input and output streams will be affected by the device selection.
- SetAudioDevice(device_id);
+ if (!SetAudioDevice(device_id)) {
+ LOG(ERROR) << "Unable to select audio device!";
+ return NULL;
+ }
if (params.effects() != AudioParameters::NO_EFFECTS) {
// Platform effects can only be enabled through the AudioRecord path.
@@ -211,22 +250,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) {
// TODO(tommi): Support |output_device_id|.
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = GetNativeOutputSampleRate();
@@ -252,57 +294,55 @@ AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS);
}
-// static
-bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
- return RegisterNativesImpl(env);
+bool AudioManagerAndroid::HasNoAudioInputStreams() {
+ return input_stream_count() == 0;
}
-void AudioManagerAndroid::Init() {
+void AudioManagerAndroid::InitializeOnAudioThread() {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+
+ // 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(
+ base::android::AttachCurrentThread(),
+ base::android::GetApplicationContext(),
+ reinterpret_cast<intptr_t>(this)));
+
+ // Prepare the list of audio devices and register receivers for device
+ // notifications.
Java_AudioManagerAndroid_init(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
}
-void AudioManagerAndroid::Close() {
+void AudioManagerAndroid::ShutdownOnAudioThread() {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ DVLOG(2) << "Destroying Java part of the audio manager";
Java_AudioManagerAndroid_close(
base::android::AttachCurrentThread(),
j_audio_manager_.obj());
+ j_audio_manager_.Reset();
}
-void AudioManagerAndroid::SetMute(JNIEnv* env, jobject obj, jboolean muted) {
- GetMessageLoop()->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::SetAudioMode(int mode) {
- Java_AudioManagerAndroid_setMode(
+void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
+ Java_AudioManagerAndroid_setCommunicationAudioModeOn(
base::android::AttachCurrentThread(),
- j_audio_manager_.obj(), mode);
+ j_audio_manager_.obj(), on);
}
-void AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
- JNIEnv* env = AttachCurrentThread();
+bool AudioManagerAndroid::SetAudioDevice(const std::string& device_id) {
+ 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();
ScopedJavaLocalRef<jstring> j_device_id = ConvertUTF8ToJavaString(
env,
device_id == AudioManagerBase::kDefaultDeviceId ?
std::string() : device_id);
- Java_AudioManagerAndroid_setDevice(
+ return Java_AudioManagerAndroid_setDevice(
env, j_audio_manager_.obj(), j_device_id.obj());
}
@@ -324,4 +364,23 @@ int AudioManagerAndroid::GetAudioLowLatencyOutputFrameSize() {
j_audio_manager_.obj());
}
+int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
+ int channels) {
+ if (IsAudioLowLatencySupported())
+ return GetAudioLowLatencyOutputFrameSize();
+
+ 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
diff --git a/chromium/media/audio/android/audio_manager_android.h b/chromium/media/audio/android/audio_manager_android.h
index 2900c0f8e29..ee5ad28e36e 100644
--- a/chromium/media/audio/android/audio_manager_android.h
+++ b/chromium/media/audio/android/audio_manager_android.h
@@ -10,6 +10,7 @@
#include "base/android/jni_android.h"
#include "base/gtest_prod_util.h"
#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
#include "media/audio/audio_manager_base.h"
namespace media {
@@ -33,8 +34,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
virtual AudioOutputStream* MakeAudioOutputStream(
const AudioParameters& params,
- const std::string& device_id,
- const std::string& input_device_id) OVERRIDE;
+ const std::string& device_id) OVERRIDE;
virtual AudioInputStream* MakeAudioInputStream(
const AudioParameters& params,
const std::string& device_id) OVERRIDE;
@@ -46,8 +46,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
- const std::string& device_id,
- const std::string& input_device_id) OVERRIDE;
+ const std::string& device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params,
const std::string& device_id) OVERRIDE;
@@ -67,10 +66,12 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
const AudioParameters& input_params) OVERRIDE;
private:
- void Init();
- void Close();
- void SetAudioMode(int mode);
- void SetAudioDevice(const std::string& device_id);
+ void InitializeOnAudioThread();
+ void ShutdownOnAudioThread();
+
+ bool HasNoAudioInputStreams();
+ void SetCommunicationAudioModeOn(bool on);
+ bool SetAudioDevice(const std::string& device_id);
int GetNativeOutputSampleRate();
bool IsAudioLowLatencySupported();
int GetAudioLowLatencyOutputFrameSize();
@@ -78,18 +79,15 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
void DoSetMuteOnAudioThread(bool muted);
- // Allow the AudioAndroidTest to access private methods.
- FRIEND_TEST_ALL_PREFIXES(AudioAndroidOutputTest, IsAudioLowLatencySupported);
-
// Java AudioManager instance.
base::android::ScopedJavaGlobalRef<jobject> j_audio_manager_;
typedef std::set<OpenSLESOutputStream*> OutputStreams;
OutputStreams streams_;
- // TODO(wjia): remove this lock once unit test modules are fixed to call
- // AudioManager::MakeAudioOutputStream on the audio thread. For now, this
- // lock is used to guard access to |streams_|.
- base::Lock streams_lock_;
+
+ // Enabled when first input stream is created and set to false when last
+ // input stream is destroyed. Also affects the stream type of output streams.
+ bool communication_mode_is_on_;
DISALLOW_COPY_AND_ASSIGN(AudioManagerAndroid);
};
diff --git a/chromium/media/audio/android/audio_record_input.cc b/chromium/media/audio/android/audio_record_input.cc
index 15a0c3d3b7b..3f19588b4a6 100644
--- a/chromium/media/audio/android/audio_record_input.cc
+++ b/chromium/media/audio/android/audio_record_input.cc
@@ -7,14 +7,18 @@
#include "base/logging.h"
#include "jni/AudioRecordInput_jni.h"
#include "media/audio/android/audio_manager_android.h"
+#include "media/base/audio_bus.h"
namespace media {
AudioRecordInputStream::AudioRecordInputStream(
- AudioManagerAndroid* audio_manager, const AudioParameters& params)
+ AudioManagerAndroid* audio_manager,
+ const AudioParameters& params)
: audio_manager_(audio_manager),
callback_(NULL),
- direct_buffer_address_(NULL) {
+ direct_buffer_address_(NULL),
+ audio_bus_(media::AudioBus::Create(params)),
+ bytes_per_sample_(params.bits_per_sample() / 8) {
DVLOG(2) << __PRETTY_FUNCTION__;
DCHECK(params.IsValid());
j_audio_record_.Reset(
@@ -48,10 +52,13 @@ bool AudioRecordInputStream::RegisterAudioRecordInput(JNIEnv* env) {
void AudioRecordInputStream::OnData(JNIEnv* env, jobject obj, jint size,
jint hardware_delay_bytes) {
DCHECK(direct_buffer_address_);
+ DCHECK_EQ(size,
+ audio_bus_->frames() * audio_bus_->channels() * bytes_per_sample_);
// Passing zero as the volume parameter indicates there is no access to a
// hardware volume slider.
- callback_->OnData(this, direct_buffer_address_, size, hardware_delay_bytes,
- 0.0);
+ audio_bus_->FromInterleaved(
+ direct_buffer_address_, audio_bus_->frames(), bytes_per_sample_);
+ callback_->OnData(this, audio_bus_.get(), hardware_delay_bytes, 0.0);
}
bool AudioRecordInputStream::Open() {
@@ -90,8 +97,7 @@ void AudioRecordInputStream::Stop() {
base::android::AttachCurrentThread(), j_audio_record_.obj());
// The Java thread must have been stopped at this point, so we are free to
- // set |callback_|.
- callback_->OnClose(this);
+ // clear |callback_|.
callback_ = NULL;
}
diff --git a/chromium/media/audio/android/audio_record_input.h b/chromium/media/audio/android/audio_record_input.h
index 0a2578b1079..c240038360b 100644
--- a/chromium/media/audio/android/audio_record_input.h
+++ b/chromium/media/audio/android/audio_record_input.h
@@ -12,6 +12,7 @@
namespace media {
+class AudioBus;
class AudioManagerAndroid;
// Implements PCM audio input support for Android using the Java AudioRecord
@@ -64,6 +65,9 @@ class MEDIA_EXPORT AudioRecordInputStream : public AudioInputStream {
// Owned by j_audio_record_.
uint8* direct_buffer_address_;
+ scoped_ptr<media::AudioBus> audio_bus_;
+ int bytes_per_sample_;
+
DISALLOW_COPY_AND_ASSIGN(AudioRecordInputStream);
};
diff --git a/chromium/media/audio/android/opensles_input.cc b/chromium/media/audio/android/opensles_input.cc
index e51ba4f3a97..1ef3aaca5ef 100644
--- a/chromium/media/audio/android/opensles_input.cc
+++ b/chromium/media/audio/android/opensles_input.cc
@@ -7,6 +7,7 @@
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "media/audio/android/audio_manager_android.h"
+#include "media/base/audio_bus.h"
#define LOG_ON_FAILURE_AND_RETURN(op, ...) \
do { \
@@ -27,7 +28,8 @@ OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager,
simple_buffer_queue_(NULL),
active_buffer_index_(0),
buffer_size_bytes_(0),
- started_(false) {
+ started_(false),
+ audio_bus_(media::AudioBus::Create(params)) {
DVLOG(2) << __PRETTY_FUNCTION__;
format_.formatType = SL_DATAFORMAT_PCM;
format_.numChannels = static_cast<SLuint32>(params.channels());
@@ -132,6 +134,7 @@ void OpenSLESInputStream::Stop() {
(*simple_buffer_queue_)->Clear(simple_buffer_queue_));
started_ = false;
+ callback_ = NULL;
}
void OpenSLESInputStream::Close() {
@@ -141,15 +144,9 @@ void OpenSLESInputStream::Close() {
// Stop the stream if it is still recording.
Stop();
{
+ // TODO(henrika): Do we need to hold the lock here?
base::AutoLock lock(lock_);
- // TODO(henrika): we use |callback_| in Close() but |callback_| is set
- // in Start(). Hence, it should be cleared in Stop() and not used here.
- if (callback_) {
- callback_->OnClose(this);
- callback_ = NULL;
- }
-
// Destroy the buffer queue recorder object and invalidate all associated
// interfaces.
recorder_object_.Reset();
@@ -300,13 +297,14 @@ void OpenSLESInputStream::ReadBufferQueue() {
TRACE_EVENT0("audio", "OpenSLESOutputStream::ReadBufferQueue");
+ // Convert from interleaved format to deinterleaved audio bus format.
+ audio_bus_->FromInterleaved(audio_data_[active_buffer_index_],
+ audio_bus_->frames(),
+ format_.bitsPerSample / 8);
+
// TODO(henrika): Investigate if it is possible to get an accurate
// delay estimation.
- callback_->OnData(this,
- audio_data_[active_buffer_index_],
- buffer_size_bytes_,
- buffer_size_bytes_,
- 0.0);
+ callback_->OnData(this, audio_bus_.get(), buffer_size_bytes_, 0.0);
// Done with this buffer. Send it to device for recording.
SLresult err =
diff --git a/chromium/media/audio/android/opensles_input.h b/chromium/media/audio/android/opensles_input.h
index cb07d51f78b..288ab43425e 100644
--- a/chromium/media/audio/android/opensles_input.h
+++ b/chromium/media/audio/android/opensles_input.h
@@ -17,6 +17,7 @@
namespace media {
+class AudioBus;
class AudioManagerAndroid;
// Implements PCM audio input support for Android using the OpenSLES API.
@@ -94,6 +95,8 @@ class OpenSLESInputStream : public AudioInputStream {
bool started_;
+ scoped_ptr<media::AudioBus> audio_bus_;
+
DISALLOW_COPY_AND_ASSIGN(OpenSLESInputStream);
};
diff --git a/chromium/media/audio/android/opensles_output.cc b/chromium/media/audio/android/opensles_output.cc
index b71680f0a7e..41c03c7867a 100644
--- a/chromium/media/audio/android/opensles_output.cc
+++ b/chromium/media/audio/android/opensles_output.cc
@@ -20,8 +20,10 @@
namespace media {
OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
- const AudioParameters& params)
+ const AudioParameters& params,
+ SLint32 stream_type)
: audio_manager_(manager),
+ stream_type_(stream_type),
callback_(NULL),
player_(NULL),
simple_buffer_queue_(NULL),
@@ -30,7 +32,8 @@ OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
started_(false),
muted_(false),
volume_(1.0) {
- DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream()";
+ DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream("
+ << "stream_type=" << stream_type << ")";
format_.formatType = SL_DATAFORMAT_PCM;
format_.numChannels = static_cast<SLuint32>(params.channels());
// Provides sampling rate in milliHertz to OpenSLES.
@@ -248,11 +251,11 @@ bool OpenSLESOutputStream::CreatePlayer() {
player_object_.Get(), SL_IID_ANDROIDCONFIGURATION, &player_config),
false);
- SLint32 stream_type = SL_ANDROID_STREAM_VOICE;
+ // Set configuration using the stream type provided at construction.
LOG_ON_FAILURE_AND_RETURN(
(*player_config)->SetConfiguration(player_config,
SL_ANDROID_KEY_STREAM_TYPE,
- &stream_type,
+ &stream_type_,
sizeof(SLint32)),
false);
diff --git a/chromium/media/audio/android/opensles_output.h b/chromium/media/audio/android/opensles_output.h
index 623b0193894..b0b678cea6e 100644
--- a/chromium/media/audio/android/opensles_output.h
+++ b/chromium/media/audio/android/opensles_output.h
@@ -28,7 +28,8 @@ class OpenSLESOutputStream : public AudioOutputStream {
static const int kMaxNumOfBuffersInQueue = 2;
OpenSLESOutputStream(AudioManagerAndroid* manager,
- const AudioParameters& params);
+ const AudioParameters& params,
+ SLint32 stream_type);
virtual ~OpenSLESOutputStream();
@@ -77,6 +78,10 @@ class OpenSLESOutputStream : public AudioOutputStream {
AudioManagerAndroid* audio_manager_;
+ // Audio playback stream type.
+ // See SLES/OpenSLES_Android.h for details.
+ SLint32 stream_type_;
+
AudioSourceCallback* callback_;
// Shared engine interfaces for the app.