summaryrefslogtreecommitdiff
path: root/chromium/media/audio
diff options
context:
space:
mode:
authorAndras Becsi <andras.becsi@digia.com>2013-12-11 21:33:03 +0100
committerAndras Becsi <andras.becsi@digia.com>2013-12-13 12:34:07 +0100
commitf2a33ff9cbc6d19943f1c7fbddd1f23d23975577 (patch)
tree0586a32aa390ade8557dfd6b4897f43a07449578 /chromium/media/audio
parent5362912cdb5eea702b68ebe23702468d17c3017a (diff)
downloadqtwebengine-chromium-f2a33ff9cbc6d19943f1c7fbddd1f23d23975577.tar.gz
Update Chromium to branch 1650 (31.0.1650.63)
Change-Id: I57d8c832eaec1eb2364e0a8e7352a6dd354db99f Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Diffstat (limited to 'chromium/media/audio')
-rw-r--r--chromium/media/audio/android/audio_android_unittest.cc769
-rw-r--r--chromium/media/audio/android/audio_manager_android.cc37
-rw-r--r--chromium/media/audio/android/audio_manager_android.h22
-rw-r--r--chromium/media/audio/android/opensles_input.cc197
-rw-r--r--chromium/media/audio/android/opensles_input.h24
-rw-r--r--chromium/media/audio/android/opensles_output.cc240
-rw-r--r--chromium/media/audio/android/opensles_output.h31
-rw-r--r--chromium/media/audio/android/opensles_wrapper.cc109
-rw-r--r--chromium/media/audio/async_socket_io_handler.h113
-rw-r--r--chromium/media/audio/async_socket_io_handler_posix.cc98
-rw-r--r--chromium/media/audio/async_socket_io_handler_unittest.cc168
-rw-r--r--chromium/media/audio/async_socket_io_handler_win.cc77
-rw-r--r--chromium/media/audio/audio_input_controller.cc70
-rw-r--r--chromium/media/audio/audio_input_controller.h40
-rw-r--r--chromium/media/audio/audio_input_controller_unittest.cc50
-rw-r--r--chromium/media/audio/audio_input_device.cc9
-rw-r--r--chromium/media/audio/audio_low_latency_input_output_unittest.cc3
-rw-r--r--chromium/media/audio/audio_manager.h39
-rw-r--r--chromium/media/audio/audio_manager_base.cc77
-rw-r--r--chromium/media/audio/audio_manager_base.h37
-rw-r--r--chromium/media/audio/audio_manager_unittest.cc (renamed from chromium/media/audio/audio_input_device_unittest.cc)176
-rw-r--r--chromium/media/audio/audio_output_controller.cc43
-rw-r--r--chromium/media/audio/audio_output_controller.h30
-rw-r--r--chromium/media/audio/audio_output_controller_unittest.cc6
-rw-r--r--chromium/media/audio/audio_output_dispatcher.cc2
-rw-r--r--chromium/media/audio/audio_output_dispatcher.h2
-rw-r--r--chromium/media/audio/audio_output_dispatcher_impl.cc6
-rw-r--r--chromium/media/audio/audio_output_dispatcher_impl.h1
-rw-r--r--chromium/media/audio/audio_output_proxy_unittest.cc57
-rw-r--r--chromium/media/audio/audio_output_resampler.cc8
-rw-r--r--chromium/media/audio/audio_output_resampler.h4
-rw-r--r--chromium/media/audio/audio_parameters.h1
-rw-r--r--chromium/media/audio/clockless_audio_sink.cc107
-rw-r--r--chromium/media/audio/clockless_audio_sink.h55
-rw-r--r--chromium/media/audio/cras/audio_manager_cras.cc38
-rw-r--r--chromium/media/audio/cras/audio_manager_cras.h15
-rw-r--r--chromium/media/audio/cras/cras_input.cc6
-rw-r--r--chromium/media/audio/cras/cras_unified.cc1
-rw-r--r--chromium/media/audio/cross_process_notification.cc30
-rw-r--r--chromium/media/audio/cross_process_notification.h172
-rw-r--r--chromium/media/audio/cross_process_notification_posix.cc114
-rw-r--r--chromium/media/audio/cross_process_notification_unittest.cc462
-rw-r--r--chromium/media/audio/cross_process_notification_win.cc270
-rw-r--r--chromium/media/audio/ios/audio_manager_ios.h56
-rw-r--r--chromium/media/audio/ios/audio_manager_ios.mm140
-rw-r--r--chromium/media/audio/ios/audio_manager_ios_unittest.cc34
-rw-r--r--chromium/media/audio/ios/audio_session_util_ios.h17
-rw-r--r--chromium/media/audio/ios/audio_session_util_ios.mm40
-rw-r--r--chromium/media/audio/linux/alsa_output_unittest.cc6
-rw-r--r--chromium/media/audio/linux/audio_manager_linux.cc91
-rw-r--r--chromium/media/audio/linux/audio_manager_linux.h26
-rw-r--r--chromium/media/audio/mac/audio_auhal_mac_unittest.cc2
-rw-r--r--chromium/media/audio/mac/audio_input_mac.cc5
-rw-r--r--chromium/media/audio/mac/audio_low_latency_input_mac.cc32
-rw-r--r--chromium/media/audio/mac/audio_low_latency_input_mac.h3
-rw-r--r--chromium/media/audio/mac/audio_manager_mac.cc171
-rw-r--r--chromium/media/audio/mac/audio_manager_mac.h11
-rw-r--r--chromium/media/audio/mock_audio_manager.cc22
-rw-r--r--chromium/media/audio/mock_audio_manager.h9
-rw-r--r--chromium/media/audio/openbsd/audio_manager_openbsd.cc5
-rw-r--r--chromium/media/audio/openbsd/audio_manager_openbsd.h2
-rw-r--r--chromium/media/audio/pulse/audio_manager_pulse.cc52
-rw-r--r--chromium/media/audio/pulse/audio_manager_pulse.h10
-rw-r--r--chromium/media/audio/shared_memory_util.cc2
-rw-r--r--chromium/media/audio/test_audio_input_controller_factory.cc12
-rw-r--r--chromium/media/audio/test_audio_input_controller_factory.h7
-rw-r--r--chromium/media/audio/win/audio_low_latency_input_win.cc136
-rw-r--r--chromium/media/audio/win/audio_low_latency_input_win.h8
-rw-r--r--chromium/media/audio/win/audio_low_latency_input_win_unittest.cc169
-rw-r--r--chromium/media/audio/win/audio_low_latency_output_win.cc44
-rw-r--r--chromium/media/audio/win/audio_low_latency_output_win.h9
-rw-r--r--chromium/media/audio/win/audio_low_latency_output_win_unittest.cc4
-rw-r--r--chromium/media/audio/win/audio_manager_win.cc134
-rw-r--r--chromium/media/audio/win/audio_manager_win.h15
-rw-r--r--chromium/media/audio/win/audio_output_win_unittest.cc40
-rw-r--r--chromium/media/audio/win/audio_unified_win_unittest.cc15
-rw-r--r--chromium/media/audio/win/core_audio_util_win.cc128
-rw-r--r--chromium/media/audio/win/core_audio_util_win.h22
-rw-r--r--chromium/media/audio/win/core_audio_util_win_unittest.cc71
-rw-r--r--chromium/media/audio/win/device_enumeration_win.cc55
-rw-r--r--chromium/media/audio/win/device_enumeration_win.h16
-rw-r--r--chromium/media/audio/win/wavein_input_win.h2
82 files changed, 2956 insertions, 2483 deletions
diff --git a/chromium/media/audio/android/audio_android_unittest.cc b/chromium/media/audio/android/audio_android_unittest.cc
new file mode 100644
index 00000000000..a8e448f821f
--- /dev/null
+++ b/chromium/media/audio/android/audio_android_unittest.cc
@@ -0,0 +1,769 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "media/audio/android/audio_manager_android.h"
+#include "media/audio/audio_io.h"
+#include "media/audio/audio_manager_base.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/seekable_buffer.h"
+#include "media/base/test_data_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::NotNull;
+using ::testing::Return;
+
+namespace media {
+
+ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) {
+ if (++*count >= limit) {
+ loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+ }
+}
+
+static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw";
+static const char kSpeechFile_16b_m_48k[] = "speech_16b_mono_48kHz.raw";
+static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw";
+static const char kSpeechFile_16b_m_44k[] = "speech_16b_mono_44kHz.raw";
+
+static const float kCallbackTestTimeMs = 2000.0;
+static const int kBitsPerSample = 16;
+static const int kBytesPerSample = kBitsPerSample / 8;
+
+// Converts AudioParameters::Format enumerator to readable string.
+static std::string FormatToString(AudioParameters::Format format) {
+ switch (format) {
+ case AudioParameters::AUDIO_PCM_LINEAR:
+ return std::string("AUDIO_PCM_LINEAR");
+ case AudioParameters::AUDIO_PCM_LOW_LATENCY:
+ return std::string("AUDIO_PCM_LOW_LATENCY");
+ case AudioParameters::AUDIO_FAKE:
+ return std::string("AUDIO_FAKE");
+ case AudioParameters::AUDIO_LAST_FORMAT:
+ return std::string("AUDIO_LAST_FORMAT");
+ default:
+ return std::string();
+ }
+}
+
+// Converts ChannelLayout enumerator to readable string. Does not include
+// multi-channel cases since these layouts are not supported on Android.
+static std::string LayoutToString(ChannelLayout channel_layout) {
+ switch (channel_layout) {
+ case CHANNEL_LAYOUT_NONE:
+ return std::string("CHANNEL_LAYOUT_NONE");
+ case CHANNEL_LAYOUT_MONO:
+ return std::string("CHANNEL_LAYOUT_MONO");
+ case CHANNEL_LAYOUT_STEREO:
+ return std::string("CHANNEL_LAYOUT_STEREO");
+ case CHANNEL_LAYOUT_UNSUPPORTED:
+ default:
+ return std::string("CHANNEL_LAYOUT_UNSUPPORTED");
+ }
+}
+
+static double ExpectedTimeBetweenCallbacks(AudioParameters params) {
+ return (base::TimeDelta::FromMicroseconds(
+ params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
+ static_cast<double>(params.sample_rate()))).InMillisecondsF();
+}
+
+std::ostream& operator<<(std::ostream& os, const AudioParameters& params) {
+ using namespace std;
+ os << endl << "format: " << FormatToString(params.format()) << endl
+ << "channel layout: " << LayoutToString(params.channel_layout()) << endl
+ << "sample rate: " << params.sample_rate() << endl
+ << "bits per sample: " << params.bits_per_sample() << endl
+ << "frames per buffer: " << params.frames_per_buffer() << endl
+ << "channels: " << params.channels() << endl
+ << "bytes per buffer: " << params.GetBytesPerBuffer() << endl
+ << "bytes per second: " << params.GetBytesPerSecond() << endl
+ << "bytes per frame: " << params.GetBytesPerFrame() << endl
+ << "frame size in ms: " << ExpectedTimeBetweenCallbacks(params);
+ return os;
+}
+
+// Gmock implementation of AudioInputStream::AudioInputCallback.
+class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
+ public:
+ MOCK_METHOD5(OnData,
+ void(AudioInputStream* stream,
+ const uint8* src,
+ uint32 size,
+ 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 {
+ public:
+ explicit FileAudioSource(base::WaitableEvent* event, const std::string& name)
+ : event_(event), pos_(0) {
+ // Reads a test file from media/test/data directory and stores it in
+ // a DecoderBuffer.
+ file_ = ReadTestDataFile(name);
+
+ // Log the name of the file which is used as input for this test.
+ base::FilePath file_path = GetTestDataFilePath(name);
+ LOG(INFO) << "Reading from file: " << file_path.value().c_str();
+ }
+
+ virtual ~FileAudioSource() {}
+
+ // AudioOutputStream::AudioSourceCallback implementation.
+
+ // Use samples read from a data file and fill up the audio buffer
+ // provided to us in the callback.
+ virtual int OnMoreData(AudioBus* audio_bus,
+ AudioBuffersState buffers_state) OVERRIDE {
+ bool stop_playing = false;
+ int max_size =
+ audio_bus->frames() * audio_bus->channels() * kBytesPerSample;
+
+ // Adjust data size and prepare for end signal if file has ended.
+ if (pos_ + max_size > file_size()) {
+ stop_playing = true;
+ max_size = file_size() - pos_;
+ }
+
+ // File data is stored as interleaved 16-bit values. Copy data samples from
+ // the file and deinterleave to match the audio bus format.
+ // FromInterleaved() will zero out any unfilled frames when there is not
+ // sufficient data remaining in the file to fill up the complete frame.
+ int frames = max_size / (audio_bus->channels() * kBytesPerSample);
+ if (max_size) {
+ audio_bus->FromInterleaved(file_->data() + pos_, frames, kBytesPerSample);
+ pos_ += max_size;
+ }
+
+ // Set event to ensure that the test can stop when the file has ended.
+ if (stop_playing)
+ event_->Signal();
+
+ 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(); }
+
+ private:
+ base::WaitableEvent* event_;
+ int pos_;
+ scoped_refptr<DecoderBuffer> file_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileAudioSource);
+};
+
+// Implements AudioInputStream::AudioInputCallback and writes the recorded
+// audio data to a local output file. Note that this implementation should
+// only be used for manually invoked and evaluated tests, hence the created
+// file will not be destroyed after the test is done since the intention is
+// that it shall be available for off-line analysis.
+class FileAudioSink : public AudioInputStream::AudioInputCallback {
+ public:
+ explicit FileAudioSink(base::WaitableEvent* event,
+ const AudioParameters& params,
+ const std::string& file_name)
+ : event_(event), params_(params) {
+ // Allocate space for ~10 seconds of data.
+ const int kMaxBufferSize = 10 * params.GetBytesPerSecond();
+ buffer_.reset(new media::SeekableBuffer(0, kMaxBufferSize));
+
+ // Open up the binary file which will be written to in the destructor.
+ base::FilePath file_path;
+ EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
+ file_path = file_path.AppendASCII(file_name.c_str());
+ binary_file_ = file_util::OpenFile(file_path, "wb");
+ DLOG_IF(ERROR, !binary_file_) << "Failed to open binary PCM data file.";
+ LOG(INFO) << "Writing to file: " << file_path.value().c_str();
+ }
+
+ virtual ~FileAudioSink() {
+ int bytes_written = 0;
+ while (bytes_written < buffer_->forward_capacity()) {
+ const uint8* chunk;
+ int chunk_size;
+
+ // Stop writing if no more data is available.
+ if (!buffer_->GetCurrentChunk(&chunk, &chunk_size))
+ break;
+
+ // Write recorded data chunk to the file and prepare for next chunk.
+ // TODO(henrika): use file_util:: instead.
+ fwrite(chunk, 1, chunk_size, binary_file_);
+ buffer_->Seek(chunk_size);
+ bytes_written += chunk_size;
+ }
+ file_util::CloseFile(binary_file_);
+ }
+
+ // AudioInputStream::AudioInputCallback implementation.
+ virtual void OnData(AudioInputStream* stream,
+ const uint8* src,
+ uint32 size,
+ uint32 hardware_delay_bytes,
+ double volume) OVERRIDE {
+ // 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))
+ event_->Signal();
+ }
+
+ virtual void OnClose(AudioInputStream* stream) OVERRIDE {}
+ virtual void OnError(AudioInputStream* stream) OVERRIDE {}
+
+ private:
+ base::WaitableEvent* event_;
+ AudioParameters params_;
+ scoped_ptr<media::SeekableBuffer> buffer_;
+ FILE* binary_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileAudioSink);
+};
+
+// Implements AudioInputCallback and AudioSourceCallback to support full
+// duplex audio where captured samples are played out in loopback after
+// reading from a temporary FIFO storage.
+class FullDuplexAudioSinkSource
+ : public AudioInputStream::AudioInputCallback,
+ public AudioOutputStream::AudioSourceCallback {
+ public:
+ explicit FullDuplexAudioSinkSource(const AudioParameters& params)
+ : params_(params),
+ previous_time_(base::TimeTicks::Now()),
+ started_(false) {
+ // Start with a reasonably small FIFO size. It will be increased
+ // dynamically during the test if required.
+ fifo_.reset(new media::SeekableBuffer(0, 2 * params.GetBytesPerBuffer()));
+ buffer_.reset(new uint8[params_.GetBytesPerBuffer()]);
+ }
+
+ virtual ~FullDuplexAudioSinkSource() {}
+
+ // AudioInputStream::AudioInputCallback implementation
+ virtual void OnData(AudioInputStream* stream,
+ const uint8* src,
+ uint32 size,
+ uint32 hardware_delay_bytes,
+ double volume) OVERRIDE {
+ const base::TimeTicks now_time = base::TimeTicks::Now();
+ const int diff = (now_time - previous_time_).InMilliseconds();
+
+ base::AutoLock lock(lock_);
+ if (diff > 1000) {
+ started_ = true;
+ previous_time_ = now_time;
+
+ // Log out the extra delay added by the FIFO. This is a best effort
+ // estimate. We might be +- 10ms off here.
+ int extra_fifo_delay =
+ static_cast<int>(BytesToMilliseconds(fifo_->forward_bytes() + size));
+ DVLOG(1) << extra_fifo_delay;
+ }
+
+ // We add an initial delay of ~1 second before loopback starts to ensure
+ // a stable callback sequence and to avoid initial bursts which might add
+ // to the extra FIFO delay.
+ if (!started_)
+ return;
+
+ // 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)) {
+ 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
+ virtual int OnMoreData(AudioBus* dest,
+ AudioBuffersState buffers_state) OVERRIDE {
+ const int size_in_bytes =
+ (params_.bits_per_sample() / 8) * dest->frames() * dest->channels();
+ EXPECT_EQ(size_in_bytes, params_.GetBytesPerBuffer());
+
+ base::AutoLock lock(lock_);
+
+ // We add an initial delay of ~1 second before loopback starts to ensure
+ // a stable callback sequences and to avoid initial bursts which might add
+ // to the extra FIFO delay.
+ if (!started_) {
+ dest->Zero();
+ return dest->frames();
+ }
+
+ // Fill up destination with zeros if the FIFO does not contain enough
+ // data to fulfill the request.
+ if (fifo_->forward_bytes() < size_in_bytes) {
+ dest->Zero();
+ } else {
+ fifo_->Read(buffer_.get(), size_in_bytes);
+ dest->FromInterleaved(
+ buffer_.get(), dest->frames(), params_.bits_per_sample() / 8);
+ }
+
+ return dest->frames();
+ }
+
+ virtual int OnMoreIOData(AudioBus* source,
+ AudioBus* dest,
+ AudioBuffersState buffers_state) OVERRIDE {
+ NOTREACHED();
+ return 0;
+ }
+
+ virtual void OnError(AudioOutputStream* stream) OVERRIDE {}
+
+ private:
+ // Converts from bytes to milliseconds given number of bytes and existing
+ // audio parameters.
+ double BytesToMilliseconds(int bytes) const {
+ const int frames = bytes / params_.GetBytesPerFrame();
+ return (base::TimeDelta::FromMicroseconds(
+ frames * base::Time::kMicrosecondsPerSecond /
+ static_cast<double>(params_.sample_rate()))).InMillisecondsF();
+ }
+
+ AudioParameters params_;
+ base::TimeTicks previous_time_;
+ base::Lock lock_;
+ scoped_ptr<media::SeekableBuffer> fifo_;
+ scoped_ptr<uint8[]> buffer_;
+ bool started_;
+
+ DISALLOW_COPY_AND_ASSIGN(FullDuplexAudioSinkSource);
+};
+
+// Test fixture class.
+class AudioAndroidTest : public testing::Test {
+ public:
+ AudioAndroidTest() {}
+
+ protected:
+ virtual void SetUp() {
+ audio_manager_.reset(AudioManager::Create());
+ loop_.reset(new base::MessageLoopForUI());
+ }
+
+ virtual void TearDown() {}
+
+ AudioManager* audio_manager() { return audio_manager_.get(); }
+ base::MessageLoopForUI* loop() { return loop_.get(); }
+
+ AudioParameters GetDefaultInputStreamParameters() {
+ return audio_manager()->GetInputStreamParameters(
+ AudioManagerBase::kDefaultDeviceId);
+ }
+
+ AudioParameters GetDefaultOutputStreamParameters() {
+ return audio_manager()->GetDefaultOutputStreamParameters();
+ }
+
+ double AverageTimeBetweenCallbacks(int num_callbacks) const {
+ return ((end_time_ - start_time_) / static_cast<double>(num_callbacks - 1))
+ .InMillisecondsF();
+ }
+
+ 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);
+
+ int count = 0;
+ MockAudioInputCallback sink;
+
+ EXPECT_CALL(sink,
+ OnData(stream, NotNull(), params.GetBytesPerBuffer(), _, _))
+ .Times(AtLeast(num_callbacks))
+ .WillRepeatedly(
+ CheckCountAndPostQuitTask(&count, num_callbacks, loop()));
+ EXPECT_CALL(sink, OnError(stream)).Times(0);
+ EXPECT_CALL(sink, OnClose(stream)).Times(1);
+
+ EXPECT_TRUE(stream->Open());
+ stream->Start(&sink);
+ start_time_ = base::TimeTicks::Now();
+ loop()->Run();
+ end_time_ = base::TimeTicks::Now();
+ stream->Stop();
+ stream->Close();
+
+ double average_time_between_callbacks_ms =
+ AverageTimeBetweenCallbacks(num_callbacks);
+ LOG(INFO) << "expected time between callbacks: "
+ << expected_time_between_callbacks_ms << " ms";
+ LOG(INFO) << "average time between callbacks: "
+ << average_time_between_callbacks_ms << " ms";
+ 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);
+ }
+
+ void StartOutputStreamCallbacks(const AudioParameters& params) {
+ double expected_time_between_callbacks_ms =
+ 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);
+
+ int count = 0;
+ MockAudioOutputCallback 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);
+
+ EXPECT_TRUE(stream->Open());
+ stream->Start(&source);
+ start_time_ = base::TimeTicks::Now();
+ loop()->Run();
+ end_time_ = base::TimeTicks::Now();
+ stream->Stop();
+ stream->Close();
+
+ double average_time_between_callbacks_ms =
+ AverageTimeBetweenCallbacks(num_callbacks);
+ LOG(INFO) << "expected time between callbacks: "
+ << expected_time_between_callbacks_ms << " ms";
+ LOG(INFO) << "average time between callbacks: "
+ << average_time_between_callbacks_ms << " ms";
+ 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);
+ }
+
+ scoped_ptr<base::MessageLoopForUI> loop_;
+ scoped_ptr<AudioManager> audio_manager_;
+ base::TimeTicks start_time_;
+ base::TimeTicks end_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioAndroidTest);
+};
+
+// Get the default audio input parameters and log the result.
+TEST_F(AudioAndroidTest, GetInputStreamParameters) {
+ AudioParameters params = GetDefaultInputStreamParameters();
+ EXPECT_TRUE(params.IsValid());
+ VLOG(1) << params;
+}
+
+// Get the default audio output parameters and log the result.
+TEST_F(AudioAndroidTest, GetDefaultOutputStreamParameters) {
+ AudioParameters params = GetDefaultOutputStreamParameters();
+ EXPECT_TRUE(params.IsValid());
+ VLOG(1) << params;
+}
+
+// Check if low-latency output is supported and log the result as output.
+TEST_F(AudioAndroidTest, IsAudioLowLatencySupported) {
+ AudioManagerAndroid* manager =
+ static_cast<AudioManagerAndroid*>(audio_manager());
+ bool low_latency = manager->IsAudioLowLatencySupported();
+ low_latency ? LOG(INFO) << "Low latency output is supported"
+ : LOG(INFO) << "Low latency output is *not* supported";
+}
+
+// Ensure that a default input stream can be created and closed.
+TEST_F(AudioAndroidTest, CreateAndCloseInputStream) {
+ AudioParameters params = GetDefaultInputStreamParameters();
+ AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
+ params, AudioManagerBase::kDefaultDeviceId);
+ EXPECT_TRUE(ais);
+ ais->Close();
+}
+
+// Ensure that a default output stream can be created and closed.
+// TODO(henrika): should we also verify that this API changes the audio mode
+// to communication mode, and calls RegisterHeadsetReceiver, the first time
+// it is called?
+TEST_F(AudioAndroidTest, CreateAndCloseOutputStream) {
+ AudioParameters params = GetDefaultOutputStreamParameters();
+ AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
+ params, std::string(), std::string());
+ EXPECT_TRUE(aos);
+ aos->Close();
+}
+
+// Ensure that a default input stream can be opened and closed.
+TEST_F(AudioAndroidTest, OpenAndCloseInputStream) {
+ AudioParameters params = GetDefaultInputStreamParameters();
+ AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
+ params, AudioManagerBase::kDefaultDeviceId);
+ EXPECT_TRUE(ais);
+ EXPECT_TRUE(ais->Open());
+ ais->Close();
+}
+
+// Ensure that a default output stream can be opened and closed.
+TEST_F(AudioAndroidTest, OpenAndCloseOutputStream) {
+ AudioParameters params = GetDefaultOutputStreamParameters();
+ AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
+ params, std::string(), std::string());
+ EXPECT_TRUE(aos);
+ EXPECT_TRUE(aos->Open());
+ aos->Close();
+}
+
+// Start input streaming using default input parameters and ensure that the
+// callback sequence is sane.
+TEST_F(AudioAndroidTest, StartInputStreamCallbacks) {
+ AudioParameters params = GetDefaultInputStreamParameters();
+ StartInputStreamCallbacks(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_F(AudioAndroidTest, StartInputStreamCallbacksNonDefaultParameters) {
+ AudioParameters native_params = GetDefaultInputStreamParameters();
+ AudioParameters params(native_params.format(),
+ native_params.channel_layout(),
+ native_params.sample_rate(),
+ native_params.bits_per_sample(),
+ native_params.sample_rate() / 100);
+ StartInputStreamCallbacks(params);
+}
+
+// Start output streaming using default output parameters and ensure that the
+// callback sequence is sane.
+TEST_F(AudioAndroidTest, StartOutputStreamCallbacks) {
+ AudioParameters params = GetDefaultOutputStreamParameters();
+ StartOutputStreamCallbacks(params);
+}
+
+// Start output streaming using non default output 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 and to open up the
+// device in mono.
+// TODO(henrika): possibly add support for more variations.
+TEST_F(AudioAndroidTest, StartOutputStreamCallbacksNonDefaultParameters) {
+ AudioParameters native_params = GetDefaultOutputStreamParameters();
+ AudioParameters params(native_params.format(),
+ CHANNEL_LAYOUT_MONO,
+ native_params.sample_rate(),
+ native_params.bits_per_sample(),
+ native_params.sample_rate() / 100);
+ StartOutputStreamCallbacks(params);
+}
+
+// Play out a PCM file segment in real time and allow the user to verify that
+// the rendered audio sounds OK.
+// NOTE: this test requires user interaction and is not designed to run as an
+// automatized test on bots.
+TEST_F(AudioAndroidTest, DISABLED_RunOutputStreamWithFileAsSource) {
+ AudioParameters params = GetDefaultOutputStreamParameters();
+ VLOG(1) << params;
+ AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
+ params, std::string(), std::string());
+ EXPECT_TRUE(aos);
+
+ std::string file_name;
+ if (params.sample_rate() == 48000 && params.channels() == 2) {
+ file_name = kSpeechFile_16b_s_48k;
+ } else if (params.sample_rate() == 48000 && params.channels() == 1) {
+ file_name = kSpeechFile_16b_m_48k;
+ } else if (params.sample_rate() == 44100 && params.channels() == 2) {
+ file_name = kSpeechFile_16b_s_44k;
+ } else if (params.sample_rate() == 44100 && params.channels() == 1) {
+ file_name = kSpeechFile_16b_m_44k;
+ } else {
+ FAIL() << "This test supports 44.1kHz and 48kHz mono/stereo only.";
+ return;
+ }
+
+ base::WaitableEvent event(false, false);
+ FileAudioSource source(&event, file_name);
+
+ EXPECT_TRUE(aos->Open());
+ aos->SetVolume(1.0);
+ aos->Start(&source);
+ LOG(INFO) << ">> Verify that the file is played out correctly...";
+ EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
+ aos->Stop();
+ aos->Close();
+}
+
+// Start input streaming and run it for ten seconds while recording to a
+// local audio file.
+// NOTE: this test requires user interaction and is not designed to run as an
+// automatized test on bots.
+TEST_F(AudioAndroidTest, DISABLED_RunSimplexInputStreamWithFileAsSink) {
+ AudioParameters params = GetDefaultInputStreamParameters();
+ VLOG(1) << params;
+ AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
+ params, AudioManagerBase::kDefaultDeviceId);
+ EXPECT_TRUE(ais);
+
+ std::string file_name = base::StringPrintf("out_simplex_%d_%d_%d.pcm",
+ params.sample_rate(),
+ params.frames_per_buffer(),
+ params.channels());
+
+ base::WaitableEvent event(false, false);
+ FileAudioSink sink(&event, params, file_name);
+
+ EXPECT_TRUE(ais->Open());
+ ais->Start(&sink);
+ LOG(INFO) << ">> Speak into the microphone to record audio...";
+ EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
+ ais->Stop();
+ ais->Close();
+}
+
+// Same test as RunSimplexInputStreamWithFileAsSink but this time output
+// streaming is active as well (reads zeros only).
+// NOTE: this test requires user interaction and is not designed to run as an
+// automatized test on bots.
+TEST_F(AudioAndroidTest, DISABLED_RunDuplexInputStreamWithFileAsSink) {
+ AudioParameters in_params = GetDefaultInputStreamParameters();
+ AudioInputStream* ais = audio_manager()->MakeAudioInputStream(
+ in_params, AudioManagerBase::kDefaultDeviceId);
+ EXPECT_TRUE(ais);
+
+ AudioParameters out_params =
+ audio_manager()->GetDefaultOutputStreamParameters();
+ AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream(
+ out_params, std::string(), std::string());
+ EXPECT_TRUE(aos);
+
+ std::string file_name = base::StringPrintf("out_duplex_%d_%d_%d.pcm",
+ in_params.sample_rate(),
+ in_params.frames_per_buffer(),
+ in_params.channels());
+
+ base::WaitableEvent event(false, false);
+ FileAudioSink sink(&event, in_params, file_name);
+ MockAudioOutputCallback 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_TRUE(ais->Open());
+ EXPECT_TRUE(aos->Open());
+ ais->Start(&sink);
+ aos->Start(&source);
+ LOG(INFO) << ">> Speak into the microphone to record audio";
+ EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
+ aos->Stop();
+ ais->Stop();
+ aos->Close();
+ ais->Close();
+}
+
+// Start audio in both directions while feeding captured data into a FIFO so
+// it can be read directly (in loopback) by the render side. A small extra
+// delay will be added by the FIFO and an estimate of this delay will be
+// printed out during the test.
+// NOTE: this test requires user interaction and is not designed to run as an
+// automatized test on bots.
+TEST_F(AudioAndroidTest,
+ DISABLED_RunSymmetricInputAndOutputStreamsInFullDuplex) {
+ // Get native audio parameters for the input side.
+ AudioParameters default_input_params = GetDefaultInputStreamParameters();
+
+ // Modify the parameters so that both input and output can use the same
+ // parameters by selecting 10ms as buffer size. This will also ensure that
+ // the output stream will be a mono stream since mono is default for input
+ // audio on Android.
+ AudioParameters io_params(default_input_params.format(),
+ default_input_params.channel_layout(),
+ default_input_params.sample_rate(),
+ default_input_params.bits_per_sample(),
+ default_input_params.sample_rate() / 100);
+ 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);
+
+ FullDuplexAudioSinkSource full_duplex(io_params);
+
+ // Start a full duplex audio session and print out estimates of the extra
+ // 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);
+ VLOG(1) << "HINT: an estimate of the extra FIFO delay will be updated "
+ << "once per second during this test.";
+ LOG(INFO) << ">> 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();
+}
+
+} // namespace media
diff --git a/chromium/media/audio/android/audio_manager_android.cc b/chromium/media/audio/android/audio_manager_android.cc
index 164344aba0b..04b226fa64f 100644
--- a/chromium/media/audio/android/audio_manager_android.cc
+++ b/chromium/media/audio/android/audio_manager_android.cc
@@ -16,6 +16,13 @@
namespace media {
+static void AddDefaultDevice(AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
+ device_names->push_front(
+ AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
+ AudioManagerBase::kDefaultDeviceId));
+}
+
// Maximum number of output streams that can be open simultaneously.
static const int kMaxOutputStreams = 10;
@@ -51,10 +58,13 @@ bool AudioManagerAndroid::HasAudioInputDevices() {
}
void AudioManagerAndroid::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
- DCHECK(device_names->empty());
- device_names->push_front(
- media::AudioDeviceName(kDefaultDeviceName, kDefaultDeviceId));
+ AudioDeviceNames* device_names) {
+ AddDefaultDevice(device_names);
+}
+
+void AudioManagerAndroid::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
+ AddDefaultDevice(device_names);
}
AudioParameters AudioManagerAndroid::GetInputStreamParameters(
@@ -74,9 +84,12 @@ AudioParameters AudioManagerAndroid::GetInputStreamParameters(
}
AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
AudioOutputStream* stream =
- AudioManagerBase::MakeAudioOutputStream(params, std::string());
+ AudioManagerBase::MakeAudioOutputStream(params, std::string(),
+ std::string());
if (stream && output_stream_count() == 1) {
SetAudioMode(kAudioModeInCommunication);
RegisterHeadsetReceiver();
@@ -87,7 +100,7 @@ AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
AudioInputStream* AudioManagerAndroid::MakeAudioInputStream(
const AudioParameters& params, const std::string& device_id) {
AudioInputStream* stream =
- AudioManagerBase::MakeAudioInputStream(params, device_id);
+ AudioManagerBase::MakeAudioInputStream(params, device_id);
return stream;
}
@@ -104,13 +117,16 @@ void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
}
AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
- const AudioParameters& params) {
+ const AudioParameters& params) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
return new OpenSLESOutputStream(this, params);
}
AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return new OpenSLESOutputStream(this, params);
}
@@ -140,7 +156,10 @@ int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
}
AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = GetNativeOutputSampleRate();
int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2);
diff --git a/chromium/media/audio/android/audio_manager_android.h b/chromium/media/audio/android/audio_manager_android.h
index fa1c3736a35..ed2b2c3ce91 100644
--- a/chromium/media/audio/android/audio_manager_android.h
+++ b/chromium/media/audio/android/audio_manager_android.h
@@ -6,6 +6,7 @@
#define MEDIA_AUDIO_ANDROID_AUDIO_MANAGER_ANDROID_H_
#include "base/android/jni_android.h"
+#include "base/gtest_prod_util.h"
#include "media/audio/audio_manager_base.h"
namespace media {
@@ -18,16 +19,20 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
// Implementation of AudioManager.
virtual bool HasAudioOutputDevices() OVERRIDE;
virtual bool HasAudioInputDevices() OVERRIDE;
- virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
- OVERRIDE;
+ virtual void GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
virtual AudioOutputStream* MakeAudioOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeAudioInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ const AudioParameters& params,
+ const std::string& device_id) OVERRIDE;
virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE;
virtual void ReleaseInputStream(AudioInputStream* stream) OVERRIDE;
@@ -36,11 +41,14 @@ 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;
virtual AudioInputStream* MakeLinearInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ const AudioParameters& params,
+ const std::string& device_id) OVERRIDE;
virtual AudioInputStream* MakeLowLatencyInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ const AudioParameters& params,
+ const std::string& device_id) OVERRIDE;
static bool RegisterAudioManager(JNIEnv* env);
@@ -48,6 +56,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
virtual ~AudioManagerAndroid();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
@@ -59,6 +68,9 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
int GetAudioLowLatencyOutputFrameSize();
int GetOptimalOutputFrameSize(int sample_rate, int channels);
+ // Allow the AudioAndroidTest to access private methods.
+ FRIEND_TEST_ALL_PREFIXES(AudioAndroidTest, IsAudioLowLatencySupported);
+
// Java AudioManager instance.
base::android::ScopedJavaGlobalRef<jobject> j_audio_manager_;
diff --git a/chromium/media/audio/android/opensles_input.cc b/chromium/media/audio/android/opensles_input.cc
index 15c3eac3726..a0e4ce3b987 100644
--- a/chromium/media/audio/android/opensles_input.cc
+++ b/chromium/media/audio/android/opensles_input.cc
@@ -4,16 +4,17 @@
#include "media/audio/android/opensles_input.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "media/audio/android/audio_manager_android.h"
-#define LOG_ON_FAILURE_AND_RETURN(op, ...) \
- do { \
- SLresult err = (op); \
- if (err != SL_RESULT_SUCCESS) { \
+#define LOG_ON_FAILURE_AND_RETURN(op, ...) \
+ do { \
+ SLresult err = (op); \
+ if (err != SL_RESULT_SUCCESS) { \
DLOG(ERROR) << #op << " failed: " << err; \
- return __VA_ARGS__; \
- } \
+ return __VA_ARGS__; \
+ } \
} while (0)
namespace media {
@@ -24,9 +25,10 @@ OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager,
callback_(NULL),
recorder_(NULL),
simple_buffer_queue_(NULL),
- active_queue_(0),
+ active_buffer_index_(0),
buffer_size_bytes_(0),
started_(false) {
+ DVLOG(2) << "OpenSLESInputStream::OpenSLESInputStream()";
format_.formatType = SL_DATAFORMAT_PCM;
format_.numChannels = static_cast<SLuint32>(params.channels());
// Provides sampling rate in milliHertz to OpenSLES.
@@ -47,6 +49,8 @@ OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager,
}
OpenSLESInputStream::~OpenSLESInputStream() {
+ DVLOG(2) << "OpenSLESInputStream::~OpenSLESInputStream()";
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!recorder_object_.Get());
DCHECK(!engine_object_.Get());
DCHECK(!recorder_);
@@ -55,6 +59,8 @@ OpenSLESInputStream::~OpenSLESInputStream() {
}
bool OpenSLESInputStream::Open() {
+ DVLOG(2) << "OpenSLESInputStream::Open()";
+ DCHECK(thread_checker_.CalledOnValidThread());
if (engine_object_.Get())
return false;
@@ -67,44 +73,59 @@ bool OpenSLESInputStream::Open() {
}
void OpenSLESInputStream::Start(AudioInputCallback* callback) {
+ DVLOG(2) << "OpenSLESInputStream::Start()";
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(callback);
DCHECK(recorder_);
DCHECK(simple_buffer_queue_);
if (started_)
return;
- // Enable the flags before streaming.
+ base::AutoLock lock(lock_);
+ DCHECK(callback_ == NULL || callback_ == callback);
callback_ = callback;
- active_queue_ = 0;
- started_ = true;
+ active_buffer_index_ = 0;
+ // Enqueues kMaxNumOfBuffersInQueue zero buffers to get the ball rolling.
+ // TODO(henrika): add support for Start/Stop/Start sequences when we are
+ // able to clear the buffer queue. There is currently a bug in the OpenSLES
+ // implementation which forces us to always call Stop() and Close() before
+ // calling Start() again.
SLresult err = SL_RESULT_UNKNOWN_ERROR;
- // Enqueues |kNumOfQueuesInBuffer| zero buffers to get the ball rolling.
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
err = (*simple_buffer_queue_)->Enqueue(
- simple_buffer_queue_,
- audio_data_[i],
- buffer_size_bytes_);
+ simple_buffer_queue_, audio_data_[i], buffer_size_bytes_);
if (SL_RESULT_SUCCESS != err) {
HandleError(err);
+ started_ = false;
return;
}
}
- // Start the recording by setting the state to |SL_RECORDSTATE_RECORDING|.
+ // Start the recording by setting the state to SL_RECORDSTATE_RECORDING.
+ // When the object is in the SL_RECORDSTATE_RECORDING state, adding buffers
+ // will implicitly start the filling process.
err = (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_RECORDING);
- if (SL_RESULT_SUCCESS != err)
+ if (SL_RESULT_SUCCESS != err) {
HandleError(err);
+ started_ = false;
+ return;
+ }
+
+ started_ = true;
}
void OpenSLESInputStream::Stop() {
+ DVLOG(2) << "OpenSLESInputStream::Stop()";
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!started_)
return;
- // Stop recording by setting the record state to |SL_RECORDSTATE_STOPPED|.
+ base::AutoLock lock(lock_);
+
+ // Stop recording by setting the record state to SL_RECORDSTATE_STOPPED.
LOG_ON_FAILURE_AND_RETURN(
- (*recorder_)->SetRecordState(recorder_,
- SL_RECORDSTATE_STOPPED));
+ (*recorder_)->SetRecordState(recorder_, SL_RECORDSTATE_STOPPED));
// Clear the buffer queue to get rid of old data when resuming recording.
LOG_ON_FAILURE_AND_RETURN(
@@ -114,17 +135,32 @@ void OpenSLESInputStream::Stop() {
}
void OpenSLESInputStream::Close() {
+ DVLOG(2) << "OpenSLESInputStream::Close()";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
// Stop the stream if it is still recording.
Stop();
+ {
+ 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;
+ }
- // Explicitly free the player objects and invalidate their associated
- // interfaces. They have to be done in the correct order.
- recorder_object_.Reset();
- engine_object_.Reset();
- simple_buffer_queue_ = NULL;
- recorder_ = NULL;
+ // Destroy the buffer queue recorder object and invalidate all associated
+ // interfaces.
+ recorder_object_.Reset();
+ simple_buffer_queue_ = NULL;
+ recorder_ = NULL;
- ReleaseAudioBuffer();
+ // Destroy the engine object. We don't store any associated interface for
+ // this object.
+ engine_object_.Reset();
+ ReleaseAudioBuffer();
+ }
audio_manager_->ReleaseInputStream(this);
}
@@ -134,9 +170,7 @@ double OpenSLESInputStream::GetMaxVolume() {
return 0.0;
}
-void OpenSLESInputStream::SetVolume(double volume) {
- NOTIMPLEMENTED();
-}
+void OpenSLESInputStream::SetVolume(double volume) { NOTIMPLEMENTED(); }
double OpenSLESInputStream::GetVolume() {
NOTIMPLEMENTED();
@@ -153,54 +187,47 @@ bool OpenSLESInputStream::GetAutomaticGainControl() {
}
bool OpenSLESInputStream::CreateRecorder() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!engine_object_.Get());
+ DCHECK(!recorder_object_.Get());
+ DCHECK(!recorder_);
+ DCHECK(!simple_buffer_queue_);
+
// Initializes the engine object with specific option. After working with the
// object, we need to free the object and its resources.
SLEngineOption option[] = {
- { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) }
- };
- LOG_ON_FAILURE_AND_RETURN(slCreateEngine(engine_object_.Receive(),
- 1,
- option,
- 0,
- NULL,
- NULL),
- false);
+ {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
+ LOG_ON_FAILURE_AND_RETURN(
+ slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
+ false);
// Realize the SL engine object in synchronous mode.
- LOG_ON_FAILURE_AND_RETURN(engine_object_->Realize(engine_object_.Get(),
- SL_BOOLEAN_FALSE),
- false);
+ LOG_ON_FAILURE_AND_RETURN(
+ engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
// Get the SL engine interface which is implicit.
SLEngineItf engine;
- LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(engine_object_.Get(),
- SL_IID_ENGINE,
- &engine),
+ LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
+ engine_object_.Get(), SL_IID_ENGINE, &engine),
false);
// Audio source configuration.
SLDataLocator_IODevice mic_locator = {
- SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
- SL_DEFAULTDEVICEID_AUDIOINPUT, NULL
- };
- SLDataSource audio_source = { &mic_locator, NULL };
+ SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
+ SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
+ SLDataSource audio_source = {&mic_locator, NULL};
// Audio sink configuration.
SLDataLocator_AndroidSimpleBufferQueue buffer_queue = {
- SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // Locator type.
- static_cast<SLuint32>(kNumOfQueuesInBuffer) // Number of buffers.
- };
- SLDataSink audio_sink = { &buffer_queue, &format_ };
+ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
+ static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
+ SLDataSink audio_sink = {&buffer_queue, &format_};
// Create an audio recorder.
- const SLInterfaceID interface_id[] = {
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
- SL_IID_ANDROIDCONFIGURATION
- };
- const SLboolean interface_required[] = {
- SL_BOOLEAN_TRUE,
- SL_BOOLEAN_TRUE
- };
+ const SLInterfaceID interface_id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+ SL_IID_ANDROIDCONFIGURATION};
+ const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+
// Create AudioRecorder and specify SL_IID_ANDROIDCONFIGURATION.
LOG_ON_FAILURE_AND_RETURN(
(*engine)->CreateAudioRecorder(engine,
@@ -219,24 +246,24 @@ bool OpenSLESInputStream::CreateRecorder() {
&recorder_config),
false);
+ // Uses the main microphone tuned for audio communications.
SLint32 stream_type = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
LOG_ON_FAILURE_AND_RETURN(
(*recorder_config)->SetConfiguration(recorder_config,
SL_ANDROID_KEY_RECORDING_PRESET,
- &stream_type, sizeof(SLint32)),
+ &stream_type,
+ sizeof(SLint32)),
false);
// Realize the recorder object in synchronous mode.
LOG_ON_FAILURE_AND_RETURN(
- recorder_object_->Realize(recorder_object_.Get(),
- SL_BOOLEAN_FALSE),
+ recorder_object_->Realize(recorder_object_.Get(), SL_BOOLEAN_FALSE),
false);
// Get an implicit recorder interface.
LOG_ON_FAILURE_AND_RETURN(
- recorder_object_->GetInterface(recorder_object_.Get(),
- SL_IID_RECORD,
- &recorder_),
+ recorder_object_->GetInterface(
+ recorder_object_.Get(), SL_IID_RECORD, &recorder_),
false);
// Get the simple buffer queue interface.
@@ -249,61 +276,67 @@ bool OpenSLESInputStream::CreateRecorder() {
// Register the input callback for the simple buffer queue.
// This callback will be called when receiving new data from the device.
LOG_ON_FAILURE_AND_RETURN(
- (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_,
- SimpleBufferQueueCallback,
- this),
+ (*simple_buffer_queue_)->RegisterCallback(
+ simple_buffer_queue_, SimpleBufferQueueCallback, this),
false);
return true;
}
void OpenSLESInputStream::SimpleBufferQueueCallback(
- SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) {
+ SLAndroidSimpleBufferQueueItf buffer_queue,
+ void* instance) {
OpenSLESInputStream* stream =
reinterpret_cast<OpenSLESInputStream*>(instance);
stream->ReadBufferQueue();
}
void OpenSLESInputStream::ReadBufferQueue() {
+ base::AutoLock lock(lock_);
if (!started_)
return;
- // TODO(xians): Get an accurate delay estimation.
+ TRACE_EVENT0("audio", "OpenSLESOutputStream::ReadBufferQueue");
+
+ // TODO(henrika): Investigate if it is possible to get an accurate
+ // delay estimation.
callback_->OnData(this,
- audio_data_[active_queue_],
+ audio_data_[active_buffer_index_],
buffer_size_bytes_,
buffer_size_bytes_,
0.0);
// Done with this buffer. Send it to device for recording.
- SLresult err = (*simple_buffer_queue_)->Enqueue(
- simple_buffer_queue_,
- audio_data_[active_queue_],
- buffer_size_bytes_);
+ SLresult err =
+ (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
+ audio_data_[active_buffer_index_],
+ buffer_size_bytes_);
if (SL_RESULT_SUCCESS != err)
HandleError(err);
- active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer;
+ active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
}
void OpenSLESInputStream::SetupAudioBuffer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!audio_data_[0]);
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
audio_data_[i] = new uint8[buffer_size_bytes_];
}
}
void OpenSLESInputStream::ReleaseAudioBuffer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (audio_data_[0]) {
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
- delete [] audio_data_[i];
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
+ delete[] audio_data_[i];
audio_data_[i] = NULL;
}
}
}
void OpenSLESInputStream::HandleError(SLresult error) {
- DLOG(FATAL) << "OpenSLES Input error " << error;
+ DLOG(ERROR) << "OpenSLES Input error " << error;
if (callback_)
callback_->OnError(this);
}
diff --git a/chromium/media/audio/android/opensles_input.h b/chromium/media/audio/android/opensles_input.h
index 9743992fc65..e05831c6712 100644
--- a/chromium/media/audio/android/opensles_input.h
+++ b/chromium/media/audio/android/opensles_input.h
@@ -9,18 +9,23 @@
#include <SLES/OpenSLES_Android.h>
#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "media/audio/android/opensles_util.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
-#include "media/audio/android/opensles_util.h"
namespace media {
class AudioManagerAndroid;
// Implements PCM audio input support for Android using the OpenSLES API.
+// This class is created and lives on the Audio Manager thread but recorded
+// audio buffers are given to us from an internal OpenSLES audio thread.
+// All public methods should be called on the Audio Manager thread.
class OpenSLESInputStream : public AudioInputStream {
public:
- static const int kNumOfQueuesInBuffer = 2;
+ static const int kMaxNumOfBuffersInQueue = 2;
OpenSLESInputStream(AudioManagerAndroid* manager,
const AudioParameters& params);
@@ -41,9 +46,12 @@ class OpenSLESInputStream : public AudioInputStream {
private:
bool CreateRecorder();
+ // Called from OpenSLES specific audio worker thread.
static void SimpleBufferQueueCallback(
- SLAndroidSimpleBufferQueueItf buffer_queue, void* instance);
+ SLAndroidSimpleBufferQueueItf buffer_queue,
+ void* instance);
+ // Called from OpenSLES specific audio worker thread.
void ReadBufferQueue();
// Called in Open();
@@ -56,6 +64,12 @@ class OpenSLESInputStream : public AudioInputStream {
// the attached AudioInputCallback::OnError().
void HandleError(SLresult error);
+ base::ThreadChecker thread_checker_;
+
+ // Protects |callback_|, |active_buffer_index_|, |audio_data_|,
+ // |buffer_size_bytes_| and |simple_buffer_queue_|.
+ base::Lock lock_;
+
AudioManagerAndroid* audio_manager_;
AudioInputCallback* callback_;
@@ -73,9 +87,9 @@ class OpenSLESInputStream : public AudioInputStream {
// Audio buffers that are allocated in the constructor based on
// info from audio parameters.
- uint8* audio_data_[kNumOfQueuesInBuffer];
+ uint8* audio_data_[kMaxNumOfBuffersInQueue];
- int active_queue_;
+ int active_buffer_index_;
int buffer_size_bytes_;
bool started_;
diff --git a/chromium/media/audio/android/opensles_output.cc b/chromium/media/audio/android/opensles_output.cc
index c6d455715d9..5643f833c3d 100644
--- a/chromium/media/audio/android/opensles_output.cc
+++ b/chromium/media/audio/android/opensles_output.cc
@@ -8,13 +8,13 @@
#include "base/logging.h"
#include "media/audio/android/audio_manager_android.h"
-#define LOG_ON_FAILURE_AND_RETURN(op, ...) \
- do { \
- SLresult err = (op); \
- if (err != SL_RESULT_SUCCESS) { \
+#define LOG_ON_FAILURE_AND_RETURN(op, ...) \
+ do { \
+ SLresult err = (op); \
+ if (err != SL_RESULT_SUCCESS) { \
DLOG(ERROR) << #op << " failed: " << err; \
- return __VA_ARGS__; \
- } \
+ return __VA_ARGS__; \
+ } \
} while (0)
namespace media {
@@ -25,10 +25,11 @@ OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
callback_(NULL),
player_(NULL),
simple_buffer_queue_(NULL),
- active_queue_(0),
+ active_buffer_index_(0),
buffer_size_bytes_(0),
started_(false),
volume_(1.0) {
+ DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream()";
format_.formatType = SL_DATAFORMAT_PCM;
format_.numChannels = static_cast<SLuint32>(params.channels());
// Provides sampling rate in milliHertz to OpenSLES.
@@ -50,6 +51,8 @@ OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
}
OpenSLESOutputStream::~OpenSLESOutputStream() {
+ DVLOG(2) << "OpenSLESOutputStream::~OpenSLESOutputStream()";
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!engine_object_.Get());
DCHECK(!player_object_.Get());
DCHECK(!output_mixer_.Get());
@@ -59,6 +62,8 @@ OpenSLESOutputStream::~OpenSLESOutputStream() {
}
bool OpenSLESOutputStream::Open() {
+ DVLOG(2) << "OpenSLESOutputStream::Open()";
+ DCHECK(thread_checker_.CalledOnValidThread());
if (engine_object_.Get())
return false;
@@ -66,37 +71,46 @@ bool OpenSLESOutputStream::Open() {
return false;
SetupAudioBuffer();
+ active_buffer_index_ = 0;
return true;
}
void OpenSLESOutputStream::Start(AudioSourceCallback* callback) {
+ DVLOG(2) << "OpenSLESOutputStream::Start()";
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(callback);
DCHECK(player_);
DCHECK(simple_buffer_queue_);
if (started_)
return;
- // Enable the flags before streaming.
+ base::AutoLock lock(lock_);
+ DCHECK(callback_ == NULL || callback_ == callback);
callback_ = callback;
- active_queue_ = 0;
- started_ = true;
// Avoid start-up glitches by filling up one buffer queue before starting
// the stream.
- FillBufferQueue();
+ FillBufferQueueNoLock();
- // Start streaming data by setting the play state to |SL_PLAYSTATE_PLAYING|.
+ // Start streaming data by setting the play state to SL_PLAYSTATE_PLAYING.
+ // For a player object, when the object is in the SL_PLAYSTATE_PLAYING
+ // state, adding buffers will implicitly start playback.
LOG_ON_FAILURE_AND_RETURN(
(*player_)->SetPlayState(player_, SL_PLAYSTATE_PLAYING));
+
+ started_ = true;
}
void OpenSLESOutputStream::Stop() {
+ DVLOG(2) << "OpenSLESOutputStream::Stop()";
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!started_)
return;
- started_ = false;
- // Stop playing by setting the play state to |SL_PLAYSTATE_STOPPED|.
+ base::AutoLock lock(lock_);
+
+ // Stop playing by setting the play state to SL_PLAYSTATE_STOPPED.
LOG_ON_FAILURE_AND_RETURN(
(*player_)->SetPlayState(player_, SL_PLAYSTATE_STOPPED));
@@ -104,26 +118,48 @@ void OpenSLESOutputStream::Stop() {
// resuming playing.
LOG_ON_FAILURE_AND_RETURN(
(*simple_buffer_queue_)->Clear(simple_buffer_queue_));
+
+#ifndef NDEBUG
+ // Verify that the buffer queue is in fact cleared as it should.
+ SLAndroidSimpleBufferQueueState buffer_queue_state;
+ LOG_ON_FAILURE_AND_RETURN((*simple_buffer_queue_)->GetState(
+ simple_buffer_queue_, &buffer_queue_state));
+ DCHECK_EQ(0u, buffer_queue_state.count);
+ DCHECK_EQ(0u, buffer_queue_state.index);
+#endif
+
+ started_ = false;
}
void OpenSLESOutputStream::Close() {
+ DVLOG(2) << "OpenSLESOutputStream::Close()";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
// Stop the stream if it is still playing.
Stop();
-
- // Explicitly free the player objects and invalidate their associated
- // interfaces. They have to be done in the correct order.
- player_object_.Reset();
- output_mixer_.Reset();
- engine_object_.Reset();
- simple_buffer_queue_ = NULL;
- player_ = NULL;
-
- ReleaseAudioBuffer();
+ {
+ // Destroy the buffer queue player object and invalidate all associated
+ // interfaces.
+ player_object_.Reset();
+ simple_buffer_queue_ = NULL;
+ player_ = NULL;
+
+ // Destroy the mixer object. We don't store any associated interface for
+ // this object.
+ output_mixer_.Reset();
+
+ // Destroy the engine object. We don't store any associated interface for
+ // this object.
+ engine_object_.Reset();
+ ReleaseAudioBuffer();
+ }
audio_manager_->ReleaseOutputStream(this);
}
void OpenSLESOutputStream::SetVolume(double volume) {
+ DVLOG(2) << "OpenSLESOutputStream::SetVolume(" << volume << ")";
+ DCHECK(thread_checker_.CalledOnValidThread());
float volume_float = static_cast<float>(volume);
if (volume_float < 0.0f || volume_float > 1.0f) {
return;
@@ -132,70 +168,61 @@ void OpenSLESOutputStream::SetVolume(double volume) {
}
void OpenSLESOutputStream::GetVolume(double* volume) {
+ DCHECK(thread_checker_.CalledOnValidThread());
*volume = static_cast<double>(volume_);
}
bool OpenSLESOutputStream::CreatePlayer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!engine_object_.Get());
+ DCHECK(!player_object_.Get());
+ DCHECK(!output_mixer_.Get());
+ DCHECK(!player_);
+ DCHECK(!simple_buffer_queue_);
+
// Initializes the engine object with specific option. After working with the
// object, we need to free the object and its resources.
SLEngineOption option[] = {
- { SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE) }
- };
+ {SL_ENGINEOPTION_THREADSAFE, static_cast<SLuint32>(SL_BOOLEAN_TRUE)}};
LOG_ON_FAILURE_AND_RETURN(
slCreateEngine(engine_object_.Receive(), 1, option, 0, NULL, NULL),
false);
// Realize the SL engine object in synchronous mode.
LOG_ON_FAILURE_AND_RETURN(
- engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE),
- false);
+ engine_object_->Realize(engine_object_.Get(), SL_BOOLEAN_FALSE), false);
// Get the SL engine interface which is implicit.
SLEngineItf engine;
- LOG_ON_FAILURE_AND_RETURN(
- engine_object_->GetInterface(engine_object_.Get(),
- SL_IID_ENGINE,
- &engine),
- false);
+ LOG_ON_FAILURE_AND_RETURN(engine_object_->GetInterface(
+ engine_object_.Get(), SL_IID_ENGINE, &engine),
+ false);
// Create ouput mixer object to be used by the player.
- LOG_ON_FAILURE_AND_RETURN(
- (*engine)->CreateOutputMix(engine,
- output_mixer_.Receive(),
- 0,
- NULL,
- NULL),
- false);
+ LOG_ON_FAILURE_AND_RETURN((*engine)->CreateOutputMix(
+ engine, output_mixer_.Receive(), 0, NULL, NULL),
+ false);
// Realizing the output mix object in synchronous mode.
LOG_ON_FAILURE_AND_RETURN(
- output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE),
- false);
+ output_mixer_->Realize(output_mixer_.Get(), SL_BOOLEAN_FALSE), false);
// Audio source configuration.
SLDataLocator_AndroidSimpleBufferQueue simple_buffer_queue = {
- SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
- static_cast<SLuint32>(kNumOfQueuesInBuffer)
- };
- SLDataSource audio_source = { &simple_buffer_queue, &format_ };
+ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
+ static_cast<SLuint32>(kMaxNumOfBuffersInQueue)};
+ SLDataSource audio_source = {&simple_buffer_queue, &format_};
// Audio sink configuration.
- SLDataLocator_OutputMix locator_output_mix = {
- SL_DATALOCATOR_OUTPUTMIX, output_mixer_.Get()
- };
- SLDataSink audio_sink = { &locator_output_mix, NULL };
+ SLDataLocator_OutputMix locator_output_mix = {SL_DATALOCATOR_OUTPUTMIX,
+ output_mixer_.Get()};
+ SLDataSink audio_sink = {&locator_output_mix, NULL};
// Create an audio player.
- const SLInterfaceID interface_id[] = {
- SL_IID_BUFFERQUEUE,
- SL_IID_VOLUME,
- SL_IID_ANDROIDCONFIGURATION
- };
- const SLboolean interface_required[] = {
- SL_BOOLEAN_TRUE,
- SL_BOOLEAN_TRUE,
- SL_BOOLEAN_TRUE
- };
+ const SLInterfaceID interface_id[] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME,
+ SL_IID_ANDROIDCONFIGURATION};
+ const SLboolean interface_required[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
+ SL_BOOLEAN_TRUE};
LOG_ON_FAILURE_AND_RETURN(
(*engine)->CreateAudioPlayer(engine,
player_object_.Receive(),
@@ -209,22 +236,21 @@ bool OpenSLESOutputStream::CreatePlayer() {
// Create AudioPlayer and specify SL_IID_ANDROIDCONFIGURATION.
SLAndroidConfigurationItf player_config;
LOG_ON_FAILURE_AND_RETURN(
- player_object_->GetInterface(player_object_.Get(),
- SL_IID_ANDROIDCONFIGURATION,
- &player_config),
+ player_object_->GetInterface(
+ player_object_.Get(), SL_IID_ANDROIDCONFIGURATION, &player_config),
false);
SLint32 stream_type = SL_ANDROID_STREAM_VOICE;
LOG_ON_FAILURE_AND_RETURN(
(*player_config)->SetConfiguration(player_config,
SL_ANDROID_KEY_STREAM_TYPE,
- &stream_type, sizeof(SLint32)),
+ &stream_type,
+ sizeof(SLint32)),
false);
// Realize the player object in synchronous mode.
LOG_ON_FAILURE_AND_RETURN(
- player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE),
- false);
+ player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), false);
// Get an implicit player interface.
LOG_ON_FAILURE_AND_RETURN(
@@ -233,72 +259,104 @@ bool OpenSLESOutputStream::CreatePlayer() {
// Get the simple buffer queue interface.
LOG_ON_FAILURE_AND_RETURN(
- player_object_->GetInterface(player_object_.Get(),
- SL_IID_BUFFERQUEUE,
- &simple_buffer_queue_),
+ player_object_->GetInterface(
+ player_object_.Get(), SL_IID_BUFFERQUEUE, &simple_buffer_queue_),
false);
// Register the input callback for the simple buffer queue.
// This callback will be called when the soundcard needs data.
LOG_ON_FAILURE_AND_RETURN(
- (*simple_buffer_queue_)->RegisterCallback(simple_buffer_queue_,
- SimpleBufferQueueCallback,
- this),
+ (*simple_buffer_queue_)->RegisterCallback(
+ simple_buffer_queue_, SimpleBufferQueueCallback, this),
false);
return true;
}
void OpenSLESOutputStream::SimpleBufferQueueCallback(
- SLAndroidSimpleBufferQueueItf buffer_queue, void* instance) {
+ SLAndroidSimpleBufferQueueItf buffer_queue,
+ void* instance) {
OpenSLESOutputStream* stream =
reinterpret_cast<OpenSLESOutputStream*>(instance);
stream->FillBufferQueue();
}
void OpenSLESOutputStream::FillBufferQueue() {
+ base::AutoLock lock(lock_);
if (!started_)
return;
TRACE_EVENT0("audio", "OpenSLESOutputStream::FillBufferQueue");
+
+ // Verify that we are in a playing state.
+ SLuint32 state;
+ SLresult err = (*player_)->GetPlayState(player_, &state);
+ if (SL_RESULT_SUCCESS != err) {
+ HandleError(err);
+ return;
+ }
+ if (state != SL_PLAYSTATE_PLAYING) {
+ DLOG(WARNING) << "Received callback in non-playing state";
+ return;
+ }
+
+ // Fill up one buffer in the queue by asking the registered source for
+ // data using the OnMoreData() callback.
+ FillBufferQueueNoLock();
+}
+
+void OpenSLESOutputStream::FillBufferQueueNoLock() {
+ // Ensure that the calling thread has acquired the lock since it is not
+ // done in this method.
+ lock_.AssertAcquired();
+
// Read data from the registered client source.
- // TODO(xians): Get an accurate delay estimation.
- uint32 hardware_delay = buffer_size_bytes_;
+ // TODO(henrika): Investigate if it is possible to get a more accurate
+ // delay estimation.
+ const uint32 hardware_delay = buffer_size_bytes_;
int frames_filled = callback_->OnMoreData(
audio_bus_.get(), AudioBuffersState(0, hardware_delay));
- if (frames_filled <= 0)
- return; // Audio source is shutting down, or halted on error.
- int num_filled_bytes =
+ if (frames_filled <= 0) {
+ // Audio source is shutting down, or halted on error.
+ return;
+ }
+
+ // Note: If the internal representation ever changes from 16-bit PCM to
+ // raw float, the data must be clipped and sanitized since it may come
+ // from an untrusted source such as NaCl.
+ audio_bus_->Scale(volume_);
+ audio_bus_->ToInterleaved(frames_filled,
+ format_.bitsPerSample / 8,
+ audio_data_[active_buffer_index_]);
+
+ const int num_filled_bytes =
frames_filled * audio_bus_->channels() * format_.bitsPerSample / 8;
DCHECK_LE(static_cast<size_t>(num_filled_bytes), buffer_size_bytes_);
- // Note: If this ever changes to output raw float the data must be clipped and
- // sanitized since it may come from an untrusted source such as NaCl.
- audio_bus_->Scale(volume_);
- audio_bus_->ToInterleaved(
- frames_filled, format_.bitsPerSample / 8, audio_data_[active_queue_]);
// Enqueue the buffer for playback.
- SLresult err = (*simple_buffer_queue_)->Enqueue(
- simple_buffer_queue_,
- audio_data_[active_queue_],
- num_filled_bytes);
+ SLresult err =
+ (*simple_buffer_queue_)->Enqueue(simple_buffer_queue_,
+ audio_data_[active_buffer_index_],
+ num_filled_bytes);
if (SL_RESULT_SUCCESS != err)
HandleError(err);
- active_queue_ = (active_queue_ + 1) % kNumOfQueuesInBuffer;
+ active_buffer_index_ = (active_buffer_index_ + 1) % kMaxNumOfBuffersInQueue;
}
void OpenSLESOutputStream::SetupAudioBuffer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!audio_data_[0]);
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
audio_data_[i] = new uint8[buffer_size_bytes_];
}
}
void OpenSLESOutputStream::ReleaseAudioBuffer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (audio_data_[0]) {
- for (int i = 0; i < kNumOfQueuesInBuffer; ++i) {
- delete [] audio_data_[i];
+ for (int i = 0; i < kMaxNumOfBuffersInQueue; ++i) {
+ delete[] audio_data_[i];
audio_data_[i] = NULL;
}
}
diff --git a/chromium/media/audio/android/opensles_output.h b/chromium/media/audio/android/opensles_output.h
index f505b5165cd..7232d5da5f7 100644
--- a/chromium/media/audio/android/opensles_output.h
+++ b/chromium/media/audio/android/opensles_output.h
@@ -9,6 +9,8 @@
#include <SLES/OpenSLES_Android.h>
#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
#include "media/audio/android/opensles_util.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
@@ -18,9 +20,12 @@ namespace media {
class AudioManagerAndroid;
// Implements PCM audio output support for Android using the OpenSLES API.
+// This class is created and lives on the Audio Manager thread but recorded
+// audio buffers are given to us from an internal OpenSLES audio thread.
+// All public methods should be called on the Audio Manager thread.
class OpenSLESOutputStream : public AudioOutputStream {
public:
- static const int kNumOfQueuesInBuffer = 2;
+ static const int kMaxNumOfBuffersInQueue = 2;
OpenSLESOutputStream(AudioManagerAndroid* manager,
const AudioParameters& params);
@@ -38,11 +43,18 @@ class OpenSLESOutputStream : public AudioOutputStream {
private:
bool CreatePlayer();
+ // Called from OpenSLES specific audio worker thread.
static void SimpleBufferQueueCallback(
- SLAndroidSimpleBufferQueueItf buffer_queue, void* instance);
+ SLAndroidSimpleBufferQueueItf buffer_queue,
+ void* instance);
+ // Fills up one buffer by asking the registered source for data.
+ // Called from OpenSLES specific audio worker thread.
void FillBufferQueue();
+ // Called from the audio manager thread.
+ void FillBufferQueueNoLock();
+
// Called in Open();
void SetupAudioBuffer();
@@ -53,6 +65,12 @@ class OpenSLESOutputStream : public AudioOutputStream {
// the attached AudioOutputCallback::OnError().
void HandleError(SLresult error);
+ base::ThreadChecker thread_checker_;
+
+ // Protects |callback_|, |active_buffer_index_|, |audio_data_|,
+ // |buffer_size_bytes_| and |simple_buffer_queue_|.
+ base::Lock lock_;
+
AudioManagerAndroid* audio_manager_;
AudioSourceCallback* callback_;
@@ -69,10 +87,11 @@ class OpenSLESOutputStream : public AudioOutputStream {
SLDataFormat_PCM format_;
- // Audio buffer arrays that are allocated in the constructor.
- uint8* audio_data_[kNumOfQueuesInBuffer];
+ // Audio buffers that are allocated in the constructor based on
+ // info from audio parameters.
+ uint8* audio_data_[kMaxNumOfBuffersInQueue];
- int active_queue_;
+ int active_buffer_index_;
size_t buffer_size_bytes_;
bool started_;
@@ -88,4 +107,4 @@ class OpenSLESOutputStream : public AudioOutputStream {
} // namespace media
-#endif // MEDIA_AUDIO_ANDROID_OPENSLES_INPUT_H_
+#endif // MEDIA_AUDIO_ANDROID_OPENSLES_OUTPUT_H_
diff --git a/chromium/media/audio/android/opensles_wrapper.cc b/chromium/media/audio/android/opensles_wrapper.cc
new file mode 100644
index 00000000000..b8f9ea45e4d
--- /dev/null
+++ b/chromium/media/audio/android/opensles_wrapper.cc
@@ -0,0 +1,109 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The file defines the symbols from OpenSLES that android is using. It then
+// loads the library dynamically on first use.
+
+// The openSLES API is using constant as part of the API. This file will define
+// proxies for those constants and redefine those when the library is first
+// loaded. For this, it need to be able to change their content and so import
+// the headers without const. This is correct because OpenSLES.h is a C API.
+#define const
+#include <SLES/OpenSLES.h>
+#include <SLES/OpenSLES_Android.h>
+#undef const
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/native_library.h"
+
+// The constants used in chromium. SLInterfaceID is actually a pointer to
+// SLInterfaceID_. Those symbols are defined as extern symbols in the OpenSLES
+// headers. They will be initialized to their correct values when the library is
+// loaded.
+SLInterfaceID SL_IID_ENGINE = NULL;
+SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE = NULL;
+SLInterfaceID SL_IID_ANDROIDCONFIGURATION = NULL;
+SLInterfaceID SL_IID_RECORD = NULL;
+SLInterfaceID SL_IID_BUFFERQUEUE = NULL;
+SLInterfaceID SL_IID_VOLUME = NULL;
+SLInterfaceID SL_IID_PLAY = NULL;
+
+namespace {
+
+// The name of the library to load.
+const char kOpenSLLibraryName[] = "libOpenSLES.so";
+
+// Loads the OpenSLES library, and initializes all the proxies.
+base::NativeLibrary IntializeLibraryHandle() {
+ base::NativeLibrary handle =
+ base::LoadNativeLibrary(base::FilePath(kOpenSLLibraryName), NULL);
+ DCHECK(handle) << "Unable to load " << kOpenSLLibraryName;
+
+ // Setup the proxy for each symbol.
+ // Attach the symbol name to the proxy address.
+ struct SymbolDefinition {
+ const char* name;
+ SLInterfaceID* sl_iid;
+ };
+
+ // The list of defined symbols.
+ const SymbolDefinition kSymbols[] = {
+ {"SL_IID_ENGINE", &SL_IID_ENGINE},
+ {"SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &SL_IID_ANDROIDSIMPLEBUFFERQUEUE},
+ {"SL_IID_ANDROIDCONFIGURATION", &SL_IID_ANDROIDCONFIGURATION},
+ {"SL_IID_RECORD", &SL_IID_RECORD},
+ {"SL_IID_BUFFERQUEUE", &SL_IID_BUFFERQUEUE},
+ {"SL_IID_VOLUME", &SL_IID_VOLUME},
+ {"SL_IID_PLAY", &SL_IID_PLAY}
+ };
+
+ for (size_t i = 0; i < sizeof(kSymbols) / sizeof(kSymbols[0]); ++i) {
+ memcpy(kSymbols[i].sl_iid,
+ base::GetFunctionPointerFromNativeLibrary(handle, kSymbols[i].name),
+ sizeof(SLInterfaceID));
+ DCHECK(*kSymbols[i].sl_iid) << "Unable to find symbol for "
+ << kSymbols[i].name;
+ }
+ return handle;
+}
+
+// Returns the handler to the shared library. The library itself will be lazily
+// loaded during the first call to this function.
+base::NativeLibrary LibraryHandle() {
+ // The handle is lazily initialized on the first call.
+ static base::NativeLibrary g_opensles_LibraryHandle =
+ IntializeLibraryHandle();
+ return g_opensles_LibraryHandle;
+}
+
+} // namespace
+
+// Redefine slCreateEngine symbol.
+SLresult slCreateEngine(SLObjectItf* engine,
+ SLuint32 num_options,
+ SLEngineOption* engine_options,
+ SLuint32 num_interfaces,
+ SLInterfaceID* interface_ids,
+ SLboolean* interfaces_required) {
+ typedef SLresult (*SlCreateEngineSignature)(SLObjectItf*,
+ SLuint32,
+ SLEngineOption*,
+ SLuint32,
+ SLInterfaceID*,
+ SLboolean*);
+ static SlCreateEngineSignature g_sl_create_engine_handle =
+ reinterpret_cast<SlCreateEngineSignature>(
+ base::GetFunctionPointerFromNativeLibrary(LibraryHandle(),
+ "slCreateEngine"));
+ DCHECK(g_sl_create_engine_handle)
+ << "Unable to find symbol for slCreateEngine";
+ return g_sl_create_engine_handle(engine,
+ num_options,
+ engine_options,
+ num_interfaces,
+ interface_ids,
+ interfaces_required);
+}
diff --git a/chromium/media/audio/async_socket_io_handler.h b/chromium/media/audio/async_socket_io_handler.h
deleted file mode 100644
index cc7185eb243..00000000000
--- a/chromium/media/audio/async_socket_io_handler.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_AUDIO_ASYNC_SOCKET_IO_HANDLER_H_
-#define MEDIA_AUDIO_ASYNC_SOCKET_IO_HANDLER_H_
-
-#include "base/message_loop/message_loop.h"
-#include "base/sync_socket.h"
-#include "base/threading/non_thread_safe.h"
-#include "media/base/media_export.h"
-
-namespace media {
-
-// The message loop callback interface is different based on platforms.
-#if defined(OS_WIN)
-typedef base::MessageLoopForIO::IOHandler MessageLoopIOHandler;
-#elif defined(OS_POSIX)
-typedef base::MessageLoopForIO::Watcher MessageLoopIOHandler;
-#endif
-
-// Extends the CancelableSyncSocket class to allow reading from a socket
-// asynchronously on a TYPE_IO message loop thread. This makes it easy to share
-// a thread that uses a message loop (e.g. for IPC and other things) and not
-// require a separate thread to read from the socket.
-//
-// Example usage (also see the unit tests):
-//
-// class SocketReader {
-// public:
-// SocketReader(base::CancelableSyncSocket* socket)
-// : socket_(socket), buffer_() {
-// io_handler.Initialize(socket_->handle(),
-// base::Bind(&SocketReader::OnDataAvailable,
-// base::Unretained(this));
-// }
-//
-// void AsyncRead() {
-// CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
-// }
-//
-// private:
-// void OnDataAvailable(int bytes_read) {
-// if (ProcessData(&buffer_[0], bytes_read)) {
-// // Issue another read.
-// CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
-// }
-// }
-//
-// media::AsyncSocketIoHandler io_handler;
-// base::CancelableSyncSocket* socket_;
-// char buffer_[kBufferSize];
-// };
-//
-class MEDIA_EXPORT AsyncSocketIoHandler
- : public NON_EXPORTED_BASE(base::NonThreadSafe),
- public NON_EXPORTED_BASE(MessageLoopIOHandler) {
- public:
- AsyncSocketIoHandler();
- virtual ~AsyncSocketIoHandler();
-
- // Type definition for the callback. The parameter tells how many
- // bytes were read and is 0 if an error occurred.
- typedef base::Callback<void(int)> ReadCompleteCallback;
-
- // Initializes the AsyncSocketIoHandler by hooking it up to the current
- // thread's message loop (must be TYPE_IO), to do async reads from the socket
- // on the current thread. The |callback| will be invoked whenever a Read()
- // has completed.
- bool Initialize(base::SyncSocket::Handle socket,
- const ReadCompleteCallback& callback);
-
- // Attempts to read from the socket. The return value will be |false|
- // if an error occurred and |true| if data was read or a pending read
- // was issued. Regardless of async or sync operation, the
- // ReadCompleteCallback (see above) will be called when data is available.
- bool Read(char* buffer, int buffer_len);
-
- private:
-#if defined(OS_WIN)
- // Implementation of IOHandler on Windows.
- virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
- DWORD bytes_transfered,
- DWORD error) OVERRIDE;
-#elif defined(OS_POSIX)
- // Implementation of base::MessageLoopForIO::Watcher.
- virtual void OnFileCanWriteWithoutBlocking(int socket) OVERRIDE {}
- virtual void OnFileCanReadWithoutBlocking(int socket) OVERRIDE;
-
- void EnsureWatchingSocket();
-#endif
-
- base::SyncSocket::Handle socket_;
-#if defined(OS_WIN)
- base::MessageLoopForIO::IOContext* context_;
- bool is_pending_;
-#elif defined(OS_POSIX)
- base::MessageLoopForIO::FileDescriptorWatcher socket_watcher_;
- // |pending_buffer_| and |pending_buffer_len_| are valid only between
- // Read() and OnFileCanReadWithoutBlocking().
- char* pending_buffer_;
- int pending_buffer_len_;
- // |true| iff the message loop is watching the socket for IO events.
- bool is_watching_;
-#endif
- ReadCompleteCallback read_complete_;
-
- DISALLOW_COPY_AND_ASSIGN(AsyncSocketIoHandler);
-};
-
-} // namespace media.
-
-#endif // MEDIA_AUDIO_ASYNC_SOCKET_IO_HANDLER_H_
diff --git a/chromium/media/audio/async_socket_io_handler_posix.cc b/chromium/media/audio/async_socket_io_handler_posix.cc
deleted file mode 100644
index be8f3708cb7..00000000000
--- a/chromium/media/audio/async_socket_io_handler_posix.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/async_socket_io_handler.h"
-
-#include <fcntl.h>
-
-#include "base/posix/eintr_wrapper.h"
-
-namespace media {
-
-AsyncSocketIoHandler::AsyncSocketIoHandler()
- : socket_(base::SyncSocket::kInvalidHandle),
- pending_buffer_(NULL),
- pending_buffer_len_(0),
- is_watching_(false) {
-}
-
-AsyncSocketIoHandler::~AsyncSocketIoHandler() {
- DCHECK(CalledOnValidThread());
-}
-
-void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
- DCHECK(CalledOnValidThread());
- DCHECK_EQ(socket, socket_);
- DCHECK(!read_complete_.is_null());
-
- if (pending_buffer_) {
- int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
- pending_buffer_len_));
- DCHECK_GE(bytes_read, 0);
- pending_buffer_ = NULL;
- pending_buffer_len_ = 0;
- read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
- } else {
- // We're getting notifications that we can read from the socket while
- // we're not waiting for data. In order to not starve the message loop,
- // let's stop watching the fd and restart the watch when Read() is called.
- is_watching_ = false;
- socket_watcher_.StopWatchingFileDescriptor();
- }
-}
-
-bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
- DCHECK(CalledOnValidThread());
- DCHECK(!read_complete_.is_null());
- DCHECK(!pending_buffer_);
-
- EnsureWatchingSocket();
-
- int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
- if (bytes_read < 0) {
- if (errno == EAGAIN) {
- pending_buffer_ = buffer;
- pending_buffer_len_ = buffer_len;
- } else {
- NOTREACHED() << "read(): " << errno;
- return false;
- }
- } else {
- read_complete_.Run(bytes_read);
- }
- return true;
-}
-
-bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
- const ReadCompleteCallback& callback) {
- DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
-
- DetachFromThread();
-
- socket_ = socket;
- read_complete_ = callback;
-
- // SyncSocket is blocking by default, so let's convert it to non-blocking.
- int value = fcntl(socket, F_GETFL);
- if (!(value & O_NONBLOCK)) {
- // Set the socket to be non-blocking so we can do async reads.
- if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
- NOTREACHED();
- return false;
- }
- }
-
- return true;
-}
-
-void AsyncSocketIoHandler::EnsureWatchingSocket() {
- DCHECK(CalledOnValidThread());
- if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
- is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
- socket_, true, base::MessageLoopForIO::WATCH_READ,
- &socket_watcher_, this);
- }
-}
-
-} // namespace media.
diff --git a/chromium/media/audio/async_socket_io_handler_unittest.cc b/chromium/media/audio/async_socket_io_handler_unittest.cc
deleted file mode 100644
index ae971464dbc..00000000000
--- a/chromium/media/audio/async_socket_io_handler_unittest.cc
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/async_socket_io_handler.h"
-
-#include "base/bind.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-const char kAsyncSocketIoTestString[] = "Hello, AsyncSocketIoHandler";
-const size_t kAsyncSocketIoTestStringLength =
- arraysize(kAsyncSocketIoTestString);
-
-class TestSocketReader {
- public:
- // Set |number_of_reads_before_quit| to >0 when you expect a specific number
- // of Read operations to complete. Once that number is reached, the current
- // message loop will be Quit(). Set |number_of_reads_before_quit| to -1 if
- // callbacks should not be counted.
- TestSocketReader(base::CancelableSyncSocket* socket,
- int number_of_reads_before_quit,
- bool issue_reads_from_callback,
- bool expect_eof)
- : socket_(socket), buffer_(),
- number_of_reads_before_quit_(number_of_reads_before_quit),
- callbacks_received_(0),
- issue_reads_from_callback_(issue_reads_from_callback),
- expect_eof_(expect_eof) {
- io_handler.Initialize(socket_->handle(),
- base::Bind(&TestSocketReader::OnRead,
- base::Unretained(this)));
- }
- ~TestSocketReader() {}
-
- bool IssueRead() {
- return io_handler.Read(&buffer_[0], sizeof(buffer_));
- }
-
- const char* buffer() const { return &buffer_[0]; }
-
- int callbacks_received() const { return callbacks_received_; }
-
- private:
- void OnRead(int bytes_read) {
- if (!expect_eof_) {
- EXPECT_GT(bytes_read, 0);
- } else {
- EXPECT_GE(bytes_read, 0);
- }
- ++callbacks_received_;
- if (number_of_reads_before_quit_ == callbacks_received_) {
- base::MessageLoop::current()->Quit();
- } else if (issue_reads_from_callback_) {
- IssueRead();
- }
- }
-
- media::AsyncSocketIoHandler io_handler;
- base::CancelableSyncSocket* socket_; // Ownership lies outside the class.
- char buffer_[kAsyncSocketIoTestStringLength];
- int number_of_reads_before_quit_;
- int callbacks_received_;
- bool issue_reads_from_callback_;
- bool expect_eof_;
-};
-
-// Workaround to be able to use a base::Closure for sending data.
-// Send() returns int but a closure must return void.
-void SendData(base::CancelableSyncSocket* socket,
- const void* buffer,
- size_t length) {
- socket->Send(buffer, length);
-}
-
-} // end namespace.
-
-// Tests doing a pending read from a socket and use an IO handler to get
-// notified of data.
-TEST(AsyncSocketIoHandlerTest, AsynchronousReadWithMessageLoop) {
- base::MessageLoopForIO loop;
-
- base::CancelableSyncSocket pair[2];
- ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
- TestSocketReader reader(&pair[0], 1, false, false);
- EXPECT_TRUE(reader.IssueRead());
-
- pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
- base::MessageLoop::current()->Run();
- EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
- EXPECT_EQ(1, reader.callbacks_received());
-}
-
-// Tests doing a read from a socket when we know that there is data in the
-// socket. Here we want to make sure that any async 'can read' notifications
-// won't trip us off and that the synchronous case works as well.
-TEST(AsyncSocketIoHandlerTest, SynchronousReadWithMessageLoop) {
- base::MessageLoopForIO loop;
-
- base::CancelableSyncSocket pair[2];
- ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
- TestSocketReader reader(&pair[0], -1, false, false);
-
- pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitClosure(),
- base::TimeDelta::FromMilliseconds(100));
- base::MessageLoop::current()->Run();
-
- EXPECT_TRUE(reader.IssueRead());
- EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
- // We've now verified that the read happened synchronously, but it's not
- // guaranteed that the callback has been issued since the callback will be
- // called asynchronously even though the read may have been done.
- // So we call RunUntilIdle() to allow any event notifications or APC's on
- // Windows, to execute before checking the count of how many callbacks we've
- // received.
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(1, reader.callbacks_received());
-}
-
-// Calls Read() from within a callback to test that simple read "loops" work.
-TEST(AsyncSocketIoHandlerTest, ReadFromCallback) {
- base::MessageLoopForIO loop;
-
- base::CancelableSyncSocket pair[2];
- ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
- const int kReadOperationCount = 10;
- TestSocketReader reader(&pair[0], kReadOperationCount, true, false);
- EXPECT_TRUE(reader.IssueRead());
-
- // Issue sends on an interval to satisfy the Read() requirements.
- int64 milliseconds = 0;
- for (int i = 0; i < kReadOperationCount; ++i) {
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
- kAsyncSocketIoTestStringLength),
- base::TimeDelta::FromMilliseconds(milliseconds));
- milliseconds += 10;
- }
-
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::MessageLoop::QuitClosure(),
- base::TimeDelta::FromMilliseconds(100 + milliseconds));
-
- base::MessageLoop::current()->Run();
- EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
-}
-
-// Calls Read() then close other end, check that a correct callback is received.
-TEST(AsyncSocketIoHandlerTest, ReadThenClose) {
- base::MessageLoopForIO loop;
-
- base::CancelableSyncSocket pair[2];
- ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
- const int kReadOperationCount = 1;
- TestSocketReader reader(&pair[0], kReadOperationCount, false, true);
- EXPECT_TRUE(reader.IssueRead());
-
- pair[1].Close();
-
- base::MessageLoop::current()->Run();
- EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
-}
diff --git a/chromium/media/audio/async_socket_io_handler_win.cc b/chromium/media/audio/async_socket_io_handler_win.cc
deleted file mode 100644
index ea6bd4ad0d5..00000000000
--- a/chromium/media/audio/async_socket_io_handler_win.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/async_socket_io_handler.h"
-
-namespace media {
-
-AsyncSocketIoHandler::AsyncSocketIoHandler()
- : socket_(base::SyncSocket::kInvalidHandle),
- context_(NULL),
- is_pending_(false) {}
-
-AsyncSocketIoHandler::~AsyncSocketIoHandler() {
- // We need to be deleted on the correct thread to avoid racing with the
- // message loop thread.
- DCHECK(CalledOnValidThread());
-
- if (context_) {
- if (is_pending_) {
- // Make the context be deleted by the message pump when done.
- context_->handler = NULL;
- } else {
- delete context_;
- }
- }
-}
-
-// Implementation of IOHandler on Windows.
-void AsyncSocketIoHandler::OnIOCompleted(
- base::MessageLoopForIO::IOContext* context,
- DWORD bytes_transfered,
- DWORD error) {
- DCHECK(CalledOnValidThread());
- DCHECK_EQ(context_, context);
- DCHECK(!read_complete_.is_null());
- is_pending_ = false;
- read_complete_.Run(error == ERROR_SUCCESS ? bytes_transfered : 0);
-}
-
-bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
- DCHECK(CalledOnValidThread());
- DCHECK(!read_complete_.is_null());
- DCHECK(!is_pending_);
- DCHECK_NE(socket_, base::SyncSocket::kInvalidHandle);
-
- DWORD bytes_read = 0;
- BOOL ok = ::ReadFile(socket_, buffer, buffer_len, &bytes_read,
- &context_->overlapped);
- // The completion port will be signaled regardless of completing the read
- // straight away or asynchronously (ERROR_IO_PENDING). OnIOCompleted() will
- // be called regardless and we don't need to explicitly run the callback
- // in the case where ok is FALSE and GLE==ERROR_IO_PENDING.
- is_pending_ = !ok && (GetLastError() == ERROR_IO_PENDING);
- return ok || is_pending_;
-}
-
-bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
- const ReadCompleteCallback& callback) {
- DCHECK(!context_);
- DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
-
- DetachFromThread();
-
- socket_ = socket;
- read_complete_ = callback;
-
- base::MessageLoopForIO::current()->RegisterIOHandler(socket, this);
-
- context_ = new base::MessageLoopForIO::IOContext();
- context_->handler = this;
- memset(&context_->overlapped, 0, sizeof(context_->overlapped));
-
- return true;
-}
-
-} // namespace media.
diff --git a/chromium/media/audio/audio_input_controller.cc b/chromium/media/audio/audio_input_controller.cc
index 31e137e2b17..ef94d1274d6 100644
--- a/chromium/media/audio/audio_input_controller.cc
+++ b/chromium/media/audio/audio_input_controller.cc
@@ -8,6 +8,7 @@
#include "base/threading/thread_restrictions.h"
#include "media/base/limits.h"
#include "media/base/scoped_histogram_timer.h"
+#include "media/base/user_input_monitor.h"
namespace {
const int kMaxInputChannels = 2;
@@ -18,16 +19,10 @@ const int kMaxInputChannels = 2;
// breakage (very hard to repro bugs!) on other platforms: See
// http://crbug.com/226327 and http://crbug.com/230972.
const int kTimerResetIntervalSeconds = 1;
-#if defined(OS_IOS)
-// The first callback on iOS is received after the current background
-// audio has faded away.
-const int kTimerInitialIntervalSeconds = 4;
-#else
// We have received reports that the timer can be too trigger happy on some
// Mac devices and the initial timer interval has therefore been increased
// from 1 second to 5 seconds.
const int kTimerInitialIntervalSeconds = 5;
-#endif // defined(OS_IOS)
}
namespace media {
@@ -36,14 +31,17 @@ namespace media {
AudioInputController::Factory* AudioInputController::factory_ = NULL;
AudioInputController::AudioInputController(EventHandler* handler,
- SyncWriter* sync_writer)
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor)
: creator_loop_(base::MessageLoopProxy::current()),
handler_(handler),
stream_(NULL),
data_is_active_(false),
state_(kEmpty),
sync_writer_(sync_writer),
- max_volume_(0.0) {
+ max_volume_(0.0),
+ user_input_monitor_(user_input_monitor),
+ prev_key_down_count_(0) {
DCHECK(creator_loop_.get());
}
@@ -56,17 +54,19 @@ scoped_refptr<AudioInputController> AudioInputController::Create(
AudioManager* audio_manager,
EventHandler* event_handler,
const AudioParameters& params,
- const std::string& device_id) {
+ const std::string& device_id,
+ UserInputMonitor* user_input_monitor) {
DCHECK(audio_manager);
if (!params.IsValid() || (params.channels() > kMaxInputChannels))
return NULL;
- if (factory_)
- return factory_->Create(audio_manager, event_handler, params);
-
- scoped_refptr<AudioInputController> controller(new AudioInputController(
- event_handler, NULL));
+ if (factory_) {
+ return factory_->Create(
+ audio_manager, event_handler, params, user_input_monitor);
+ }
+ scoped_refptr<AudioInputController> controller(
+ new AudioInputController(event_handler, NULL, user_input_monitor));
controller->message_loop_ = audio_manager->GetMessageLoop();
@@ -87,7 +87,8 @@ scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
EventHandler* event_handler,
const AudioParameters& params,
const std::string& device_id,
- SyncWriter* sync_writer) {
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor) {
DCHECK(audio_manager);
DCHECK(sync_writer);
@@ -96,8 +97,8 @@ scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
// Create the AudioInputController object and ensure that it runs on
// the audio-manager thread.
- scoped_refptr<AudioInputController> controller(new AudioInputController(
- event_handler, sync_writer));
+ scoped_refptr<AudioInputController> controller(
+ new AudioInputController(event_handler, sync_writer, user_input_monitor));
controller->message_loop_ = audio_manager->GetMessageLoop();
// Create and open a new audio input stream from the existing
@@ -116,14 +117,15 @@ scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
EventHandler* event_handler,
AudioInputStream* stream,
- SyncWriter* sync_writer) {
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor) {
DCHECK(sync_writer);
DCHECK(stream);
// Create the AudioInputController object and ensure that it runs on
// the audio-manager thread.
- scoped_refptr<AudioInputController> controller(new AudioInputController(
- event_handler, sync_writer));
+ scoped_refptr<AudioInputController> controller(
+ new AudioInputController(event_handler, sync_writer, user_input_monitor));
controller->message_loop_ = message_loop;
// TODO(miu): See TODO at top of file. Until that's resolved, we need to
@@ -171,7 +173,7 @@ void AudioInputController::DoCreate(AudioManager* audio_manager,
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
// TODO(miu): See TODO at top of file. Until that's resolved, assume all
// platform audio input requires the |no_data_timer_| be used to auto-detect
- // errors. In reality, probably only Windows and IOS need to be treated as
+ // errors. In reality, probably only Windows needs to be treated as
// unreliable here.
DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
true);
@@ -211,6 +213,11 @@ void AudioInputController::DoCreateForStream(
state_ = kCreated;
handler_->OnCreated(this);
+
+ if (user_input_monitor_) {
+ user_input_monitor_->EnableKeyPressMonitoring();
+ prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
+ }
}
void AudioInputController::DoRecord() {
@@ -251,6 +258,9 @@ void AudioInputController::DoClose() {
}
state_ = kClosed;
+
+ if (user_input_monitor_)
+ user_input_monitor_->DisableKeyPressMonitoring();
}
}
@@ -317,8 +327,10 @@ void AudioInputController::DoCheckForNoData() {
base::Unretained(this)));
}
-void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
- uint32 size, uint32 hardware_delay_bytes,
+void AudioInputController::OnData(AudioInputStream* stream,
+ const uint8* data,
+ uint32 size,
+ uint32 hardware_delay_bytes,
double volume) {
{
base::AutoLock auto_lock(lock_);
@@ -326,13 +338,21 @@ void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
return;
}
+ bool key_pressed = false;
+ if (user_input_monitor_) {
+ size_t current_count = user_input_monitor_->GetKeyPressCount();
+ key_pressed = current_count != prev_key_down_count_;
+ prev_key_down_count_ = current_count;
+ DVLOG_IF(6, key_pressed) << "Detected keypress.";
+ }
+
// Mark data as active to ensure that the periodic calls to
// DoCheckForNoData() does not report an error to the event handler.
SetDataIsActive(true);
// Use SyncSocket if we are in a low-latency mode.
if (LowLatencyMode()) {
- sync_writer_->Write(data, size, volume);
+ sync_writer_->Write(data, size, volume, key_pressed);
sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
return;
}
@@ -354,7 +374,7 @@ void AudioInputController::OnError(AudioInputStream* stream) {
}
void AudioInputController::DoStopCloseAndClearStream(
- base::WaitableEvent *done) {
+ base::WaitableEvent* done) {
DCHECK(message_loop_->BelongsToCurrentThread());
// Allow calling unconditionally and bail if we don't have a stream to close.
diff --git a/chromium/media/audio/audio_input_controller.h b/chromium/media/audio/audio_input_controller.h
index 586d47703a1..6b40459ded6 100644
--- a/chromium/media/audio/audio_input_controller.h
+++ b/chromium/media/audio/audio_input_controller.h
@@ -72,6 +72,8 @@
//
namespace media {
+class UserInputMonitor;
+
class MEDIA_EXPORT AudioInputController
: public base::RefCountedThreadSafe<AudioInputController>,
public AudioInputStream::AudioInputCallback {
@@ -102,7 +104,10 @@ class MEDIA_EXPORT AudioInputController
// Write certain amount of data from |data|. This method returns
// number of written bytes.
- virtual uint32 Write(const void* data, uint32 size, double volume) = 0;
+ virtual uint32 Write(const void* data,
+ uint32 size,
+ double volume,
+ bool key_pressed) = 0;
// Close this synchronous writer.
virtual void Close() = 0;
@@ -110,11 +115,15 @@ class MEDIA_EXPORT AudioInputController
// AudioInputController::Create() can use the currently registered Factory
// to create the AudioInputController. Factory is intended for testing only.
+ // |user_input_monitor| is used for typing detection and can be NULL.
class Factory {
public:
- virtual AudioInputController* Create(AudioManager* audio_manager,
- EventHandler* event_handler,
- AudioParameters params) = 0;
+ virtual AudioInputController* Create(
+ AudioManager* audio_manager,
+ EventHandler* event_handler,
+ AudioParameters params,
+ UserInputMonitor* user_input_monitor) = 0;
+
protected:
virtual ~Factory() {}
};
@@ -123,11 +132,13 @@ class MEDIA_EXPORT AudioInputController
// The audio device will be created on the audio thread, and when that is
// done, the event handler will receive an OnCreated() call from that same
// thread. |device_id| is the unique ID of the audio device to be opened.
+ // |user_input_monitor| is used for typing detection and can be NULL.
static scoped_refptr<AudioInputController> Create(
AudioManager* audio_manager,
EventHandler* event_handler,
const AudioParameters& params,
- const std::string& device_id);
+ const std::string& device_id,
+ UserInputMonitor* user_input_monitor);
// Sets the factory used by the static method Create(). AudioInputController
// does not take ownership of |factory|. A value of NULL results in an
@@ -138,25 +149,28 @@ class MEDIA_EXPORT AudioInputController
// Factory method for creating an AudioInputController for low-latency mode.
// The audio device will be created on the audio thread, and when that is
// done, the event handler will receive an OnCreated() call from that same
- // thread.
+ // thread. |user_input_monitor| is used for typing detection and can be NULL.
static scoped_refptr<AudioInputController> CreateLowLatency(
AudioManager* audio_manager,
EventHandler* event_handler,
const AudioParameters& params,
const std::string& device_id,
// External synchronous writer for audio controller.
- SyncWriter* sync_writer);
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor);
// Factory method for creating an AudioInputController for low-latency mode,
// taking ownership of |stream|. The stream will be opened on the audio
// thread, and when that is done, the event handler will receive an
- // OnCreated() call from that same thread.
+ // OnCreated() call from that same thread. |user_input_monitor| is used for
+ // typing detection and can be NULL.
static scoped_refptr<AudioInputController> CreateForStream(
const scoped_refptr<base::MessageLoopProxy>& message_loop,
EventHandler* event_handler,
AudioInputStream* stream,
// External synchronous writer for audio controller.
- SyncWriter* sync_writer);
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor);
// Starts recording using the created audio input stream.
// This method is called on the creator thread.
@@ -201,7 +215,9 @@ class MEDIA_EXPORT AudioInputController
kError
};
- AudioInputController(EventHandler* handler, SyncWriter* sync_writer);
+ AudioInputController(EventHandler* handler,
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor);
virtual ~AudioInputController();
// Methods called on the audio thread (owned by the AudioManager).
@@ -266,6 +282,10 @@ class MEDIA_EXPORT AudioInputController
double max_volume_;
+ UserInputMonitor* user_input_monitor_;
+
+ size_t prev_key_down_count_;
+
DISALLOW_COPY_AND_ASSIGN(AudioInputController);
};
diff --git a/chromium/media/audio/audio_input_controller_unittest.cc b/chromium/media/audio/audio_input_controller_unittest.cc
index b96ef3ad016..6388cbf975b 100644
--- a/chromium/media/audio/audio_input_controller_unittest.cc
+++ b/chromium/media/audio/audio_input_controller_unittest.cc
@@ -83,9 +83,13 @@ TEST_F(AudioInputControllerTest, CreateAndClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
kSampleRate, kBitsPerSample, kSamplesPerPacket);
+
scoped_refptr<AudioInputController> controller =
- AudioInputController::Create(audio_manager.get(), &event_handler, params,
- AudioManagerBase::kDefaultDeviceId);
+ AudioInputController::Create(audio_manager.get(),
+ &event_handler,
+ params,
+ AudioManagerBase::kDefaultDeviceId,
+ NULL);
ASSERT_TRUE(controller.get());
// Wait for OnCreated() to fire.
@@ -120,8 +124,11 @@ TEST_F(AudioInputControllerTest, RecordAndClose) {
// Creating the AudioInputController should render an OnCreated() call.
scoped_refptr<AudioInputController> controller =
- AudioInputController::Create(audio_manager.get(), &event_handler, params,
- AudioManagerBase::kDefaultDeviceId);
+ AudioInputController::Create(audio_manager.get(),
+ &event_handler,
+ params,
+ AudioManagerBase::kDefaultDeviceId,
+ NULL);
ASSERT_TRUE(controller.get());
// Start recording and trigger one OnRecording() call.
@@ -167,8 +174,11 @@ TEST_F(AudioInputControllerTest, RecordAndError) {
// Creating the AudioInputController should render an OnCreated() call.
scoped_refptr<AudioInputController> controller =
- AudioInputController::Create(audio_manager.get(), &event_handler, params,
- AudioManagerBase::kDefaultDeviceId);
+ AudioInputController::Create(audio_manager.get(),
+ &event_handler,
+ params,
+ AudioManagerBase::kDefaultDeviceId,
+ NULL);
ASSERT_TRUE(controller.get());
// Start recording and trigger one OnRecording() call.
@@ -196,11 +206,17 @@ TEST_F(AudioInputControllerTest, SamplesPerPacketTooLarge) {
.Times(Exactly(0));
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
- AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
- kSampleRate, kBitsPerSample, kSamplesPerPacket * 1000);
+ AudioParameters params(AudioParameters::AUDIO_FAKE,
+ kChannelLayout,
+ kSampleRate,
+ kBitsPerSample,
+ kSamplesPerPacket * 1000);
scoped_refptr<AudioInputController> controller =
- AudioInputController::Create(audio_manager.get(), &event_handler, params,
- AudioManagerBase::kDefaultDeviceId);
+ AudioInputController::Create(audio_manager.get(),
+ &event_handler,
+ params,
+ AudioManagerBase::kDefaultDeviceId,
+ NULL);
ASSERT_FALSE(controller.get());
}
@@ -216,11 +232,17 @@ TEST_F(AudioInputControllerTest, CloseTwice) {
.Times(Exactly(1));
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
- AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
- kSampleRate, kBitsPerSample, kSamplesPerPacket);
+ AudioParameters params(AudioParameters::AUDIO_FAKE,
+ kChannelLayout,
+ kSampleRate,
+ kBitsPerSample,
+ kSamplesPerPacket);
scoped_refptr<AudioInputController> controller =
- AudioInputController::Create(audio_manager.get(), &event_handler, params,
- AudioManagerBase::kDefaultDeviceId);
+ AudioInputController::Create(audio_manager.get(),
+ &event_handler,
+ params,
+ AudioManagerBase::kDefaultDeviceId,
+ NULL);
ASSERT_TRUE(controller.get());
controller->Record();
diff --git a/chromium/media/audio/audio_input_device.cc b/chromium/media/audio/audio_input_device.cc
index 87fd57143cd..d7685840ecf 100644
--- a/chromium/media/audio/audio_input_device.cc
+++ b/chromium/media/audio/audio_input_device.cc
@@ -291,9 +291,12 @@ void AudioInputDevice::AudioThreadCallback::Process(int pending_data) {
uint8* ptr = static_cast<uint8*>(shared_memory_.memory());
ptr += current_segment_id_ * segment_length_;
AudioInputBuffer* buffer = reinterpret_cast<AudioInputBuffer*>(ptr);
- DCHECK_EQ(buffer->params.size,
+ // Usually this will be equal but in the case of low sample rate (e.g. 8kHz,
+ // the buffer may be bigger (on mac at least)).
+ DCHECK_GE(buffer->params.size,
segment_length_ - sizeof(AudioInputBufferParameters));
double volume = buffer->params.volume;
+ bool key_pressed = buffer->params.key_pressed;
int audio_delay_milliseconds = pending_data / bytes_per_ms_;
int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]);
@@ -308,8 +311,8 @@ void AudioInputDevice::AudioThreadCallback::Process(int pending_data) {
// Deliver captured data to the client in floating point format
// and update the audio-delay measurement.
- capture_callback_->Capture(audio_bus_.get(),
- audio_delay_milliseconds, volume);
+ capture_callback_->Capture(
+ audio_bus_.get(), audio_delay_milliseconds, volume, key_pressed);
}
} // namespace media
diff --git a/chromium/media/audio/audio_low_latency_input_output_unittest.cc b/chromium/media/audio/audio_low_latency_input_output_unittest.cc
index 33729c45a04..a616761294d 100644
--- a/chromium/media/audio/audio_low_latency_input_output_unittest.cc
+++ b/chromium/media/audio/audio_low_latency_input_output_unittest.cc
@@ -308,7 +308,8 @@ class AudioOutputStreamTraits {
static StreamType* CreateStream(AudioManager* audio_manager,
const AudioParameters& params) {
- return audio_manager->MakeAudioOutputStream(params, std::string());
+ return audio_manager->MakeAudioOutputStream(params, std::string(),
+ std::string());
}
};
diff --git a/chromium/media/audio/audio_manager.h b/chromium/media/audio/audio_manager.h
index cc5b95c8197..891d2a26589 100644
--- a/chromium/media/audio/audio_manager.h
+++ b/chromium/media/audio/audio_manager.h
@@ -58,11 +58,16 @@ class MEDIA_EXPORT AudioManager {
// threads to avoid blocking the rest of the application.
virtual void ShowAudioInputSettings() = 0;
- // Appends a list of available input devices. It is not guaranteed that
- // all the devices in the list support all formats and sample rates for
+ // Appends a list of available input devices to |device_names|,
+ // which must initially be empty. It is not guaranteed that all the
+ // devices in the list support all formats and sample rates for
// recording.
virtual void GetAudioInputDeviceNames(AudioDeviceNames* device_names) = 0;
+ // Appends a list of available output devices to |device_names|,
+ // which must initially be empty.
+ virtual void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) = 0;
+
// Factory for all the supported stream formats. |params| defines parameters
// of the audio stream to be created.
//
@@ -71,6 +76,14 @@ class MEDIA_EXPORT AudioManager {
// or three buffers are created, one will be locked for playback and one will
// be ready to be filled in the call to AudioSourceCallback::OnMoreData().
//
+ // To create a stream for the default output device, pass an empty string
+ // for |device_id|, otherwise the specified audio device will be opened.
+ //
+ // The |input_device_id| is used for low-latency unified streams
+ // (input+output) only and then only if the audio parameters specify a >0
+ // input channel count. In other cases this id is ignored and should be
+ // empty.
+ //
// Returns NULL if the combination of the parameters is not supported, or if
// we have reached some other platform specific limit.
//
@@ -82,14 +95,18 @@ class MEDIA_EXPORT AudioManager {
//
// Do not free the returned AudioOutputStream. It is owned by AudioManager.
virtual AudioOutputStream* MakeAudioOutputStream(
- const AudioParameters& params, const std::string& input_device_id) = 0;
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) = 0;
// Creates new audio output proxy. A proxy implements
// AudioOutputStream interface, but unlike regular output stream
// created with MakeAudioOutputStream() it opens device only when a
// sound is actually playing.
virtual AudioOutputStream* MakeAudioOutputStreamProxy(
- const AudioParameters& params, const std::string& input_device_id) = 0;
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) = 0;
// Factory to create audio recording streams.
// |channels| can be 1 or 2.
@@ -130,14 +147,28 @@ class MEDIA_EXPORT AudioManager {
// streams. It is a convenience interface to
// AudioManagerBase::GetPreferredOutputStreamParameters and each AudioManager
// does not need their own implementation to this interface.
+ // TODO(tommi): Remove this method and use GetOutputStreamParameteres instead.
virtual AudioParameters GetDefaultOutputStreamParameters() = 0;
+ // Returns the output hardware audio parameters for a specific output device.
+ virtual AudioParameters GetOutputStreamParameters(
+ const std::string& device_id) = 0;
+
// Returns the input hardware audio parameters of the specific device
// for opening input streams. Each AudioManager needs to implement their own
// version of this interface.
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) = 0;
+ // Returns the device id of an output device that belongs to the same hardware
+ // as the specified input device.
+ // If the hardware has only an input device (e.g. a webcam), the return value
+ // will be empty (which the caller can then interpret to be the default output
+ // device). Implementations that don't yet support this feature, must return
+ // an empty string.
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) = 0;
+
protected:
AudioManager();
diff --git a/chromium/media/audio/audio_manager_base.cc b/chromium/media/audio/audio_manager_base.cc
index db77f004e38..5b1f4b3690a 100644
--- a/chromium/media/audio/audio_manager_base.cc
+++ b/chromium/media/audio/audio_manager_base.cc
@@ -34,19 +34,23 @@ static const int kMaxInputChannels = 2;
const char AudioManagerBase::kDefaultDeviceName[] = "Default";
const char AudioManagerBase::kDefaultDeviceId[] = "default";
+const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback";
struct AudioManagerBase::DispatcherParams {
DispatcherParams(const AudioParameters& input,
const AudioParameters& output,
- const std::string& device_id)
+ const std::string& output_device_id,
+ const std::string& input_device_id)
: input_params(input),
output_params(output),
- input_device_id(device_id) {}
+ input_device_id(input_device_id),
+ output_device_id(output_device_id) {}
~DispatcherParams() {}
const AudioParameters input_params;
const AudioParameters output_params;
const std::string input_device_id;
+ const std::string output_device_id;
scoped_refptr<AudioOutputDispatcher> dispatcher;
private:
@@ -65,6 +69,7 @@ class AudioManagerBase::CompareByParams {
// of the existing dispatcher are the same as the request dispatcher.
return (dispatcher_->input_params == dispatcher_in->input_params &&
dispatcher_->output_params == dispatcher_in->output_params &&
+ dispatcher_->output_device_id == dispatcher_in->output_device_id &&
(!dispatcher_->input_params.input_channels() ||
dispatcher_->input_device_id == dispatcher_in->input_device_id));
}
@@ -134,6 +139,7 @@ scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetWorkerLoop() {
AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
// TODO(miu): Fix ~50 call points across several unit test modules to call
// this method on the audio thread, then uncomment the following:
@@ -159,10 +165,12 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
AudioOutputStream* stream;
switch (params.format()) {
case AudioParameters::AUDIO_PCM_LINEAR:
+ DCHECK(device_id.empty())
+ << "AUDIO_PCM_LINEAR supports only the default device.";
stream = MakeLinearOutputStream(params);
break;
case AudioParameters::AUDIO_PCM_LOW_LATENCY:
- stream = MakeLowLatencyOutputStream(params, input_device_id);
+ stream = MakeLowLatencyOutputStream(params, device_id, input_device_id);
break;
case AudioParameters::AUDIO_FAKE:
stream = FakeAudioOutputStream::MakeFakeStream(this, params);
@@ -180,7 +188,8 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
}
AudioInputStream* AudioManagerBase::MakeAudioInputStream(
- const AudioParameters& params, const std::string& device_id) {
+ const AudioParameters& params,
+ const std::string& device_id) {
// TODO(miu): Fix ~20 call points across several unit test modules to call
// this method on the audio thread, then uncomment the following:
// DCHECK(message_loop_->BelongsToCurrentThread());
@@ -222,19 +231,26 @@ AudioInputStream* AudioManagerBase::MakeAudioInputStream(
}
AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
- const AudioParameters& params, const std::string& input_device_id) {
-#if defined(OS_IOS)
- // IOS implements audio input only.
- NOTIMPLEMENTED();
- return NULL;
-#else
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
DCHECK(message_loop_->BelongsToCurrentThread());
+ // If the caller supplied an empty device id to select the default device,
+ // we fetch the actual device id of the default device so that the lookup
+ // will find the correct device regardless of whether it was opened as
+ // "default" or via the specific id.
+ // NOTE: Implementations that don't yet support opening non-default output
+ // devices may return an empty string from GetDefaultOutputDeviceID().
+ std::string output_device_id = device_id.empty() ?
+ GetDefaultOutputDeviceID() : device_id;
+
// If we're not using AudioOutputResampler our output parameters are the same
// as our input parameters.
AudioParameters output_params = params;
if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
- output_params = GetPreferredOutputStreamParameters(params);
+ output_params =
+ GetPreferredOutputStreamParameters(output_device_id, params);
// Ensure we only pass on valid output parameters.
if (!output_params.IsValid()) {
@@ -257,7 +273,8 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
}
DispatcherParams* dispatcher_params =
- new DispatcherParams(params, output_params, input_device_id);
+ new DispatcherParams(params, output_params, output_device_id,
+ input_device_id);
AudioOutputDispatchers::iterator it =
std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(),
@@ -272,23 +289,28 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
scoped_refptr<AudioOutputDispatcher> dispatcher;
if (output_params.format() != AudioParameters::AUDIO_FAKE) {
dispatcher = new AudioOutputResampler(this, params, output_params,
- input_device_id, kCloseDelay);
+ output_device_id, input_device_id,
+ kCloseDelay);
} else {
dispatcher = new AudioOutputDispatcherImpl(this, output_params,
+ output_device_id,
input_device_id, kCloseDelay);
}
dispatcher_params->dispatcher = dispatcher;
output_dispatchers_.push_back(dispatcher_params);
return new AudioOutputProxy(dispatcher.get());
-#endif // defined(OS_IOS)
}
void AudioManagerBase::ShowAudioInputSettings() {
}
void AudioManagerBase::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+ AudioDeviceNames* device_names) {
+}
+
+void AudioManagerBase::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
}
void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
@@ -333,10 +355,6 @@ void AudioManagerBase::Shutdown() {
}
void AudioManagerBase::ShutdownOnAudioThread() {
-// IOS implements audio input only.
-#if defined(OS_IOS)
- return;
-#else
// This should always be running on the audio thread, but since we've cleared
// the audio_thread_ member pointer when we get here, we can't verify exactly
// what thread we're running on. The method is not public though and only
@@ -357,7 +375,6 @@ void AudioManagerBase::ShutdownOnAudioThread() {
}
output_dispatchers_.clear();
-#endif // defined(OS_IOS)
}
void AudioManagerBase::AddOutputDeviceChangeListener(
@@ -379,7 +396,14 @@ void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
}
AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
- return GetPreferredOutputStreamParameters(AudioParameters());
+ return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
+ AudioParameters());
+}
+
+AudioParameters AudioManagerBase::GetOutputStreamParameters(
+ const std::string& device_id) {
+ return GetPreferredOutputStreamParameters(device_id,
+ AudioParameters());
}
AudioParameters AudioManagerBase::GetInputStreamParameters(
@@ -388,4 +412,15 @@ AudioParameters AudioManagerBase::GetInputStreamParameters(
return AudioParameters();
}
+std::string AudioManagerBase::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ NOTIMPLEMENTED();
+ return "";
+}
+
+std::string AudioManagerBase::GetDefaultOutputDeviceID() {
+ NOTIMPLEMENTED();
+ return "";
+}
+
} // namespace media
diff --git a/chromium/media/audio/audio_manager_base.h b/chromium/media/audio/audio_manager_base.h
index 8b34d9fcf94..cdf7d3a76ae 100644
--- a/chromium/media/audio/audio_manager_base.h
+++ b/chromium/media/audio/audio_manager_base.h
@@ -32,11 +32,24 @@ class AudioOutputDispatcher;
// AudioManagerBase provides AudioManager functions common for all platforms.
class MEDIA_EXPORT AudioManagerBase : public AudioManager {
public:
+ // TODO(sergeyu): The constants below belong to AudioManager interface, not
+ // to the base implementation.
+
// Name of the generic "default" device.
static const char kDefaultDeviceName[];
// Unique Id of the generic "default" device.
static const char kDefaultDeviceId[];
+ // Input device ID used to capture the default system playback stream. When
+ // this device ID is passed to MakeAudioInputStream() the returned
+ // AudioInputStream will be capturing audio currently being played on the
+ // default playback device. At the moment this feature is supported only on
+ // some platforms. AudioInputStream::Intialize() will return an error on
+ // platforms that don't support it. GetInputStreamParameters() must be used
+ // to get the parameters of the loopback device before creating a loopback
+ // stream, otherwise stream initialization may fail.
+ static const char kLoopbackInputDeviceId[];
+
virtual ~AudioManagerBase();
virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE;
@@ -47,10 +60,14 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
virtual void ShowAudioInputSettings() OVERRIDE;
virtual void GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) OVERRIDE;
+ AudioDeviceNames* device_names) OVERRIDE;
+
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioOutputStream* MakeAudioOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeAudioInputStream(
@@ -58,6 +75,7 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
virtual AudioOutputStream* MakeAudioOutputStreamProxy(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
// Called internally by the audio stream when it has been closed.
@@ -72,7 +90,9 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
// Creates the output stream for the |AUDIO_PCM_LOW_LATENCY| format.
// |input_device_id| is used by unified IO to open the correct input device.
virtual AudioOutputStream* MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) = 0;
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) = 0;
// Creates the input stream for the |AUDIO_PCM_LINEAR| format. The legacy
// name is also from |AUDIO_PCM_LINEAR|.
@@ -90,9 +110,15 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
AudioDeviceListener* listener) OVERRIDE;
virtual AudioParameters GetDefaultOutputStreamParameters() OVERRIDE;
+ virtual AudioParameters GetOutputStreamParameters(
+ const std::string& device_id) OVERRIDE;
+
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
+
protected:
AudioManagerBase();
@@ -115,9 +141,16 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
// will decide if they should return the values from |input_params| or the
// default hardware values. If the |input_params| is invalid, it will return
// the default hardware audio parameters.
+ // If |output_device_id| is empty, the implementation must treat that as
+ // a request for the default output device.
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) = 0;
+ // Returns the ID of the default audio output device.
+ // Implementations that don't yet support this should return an empty string.
+ virtual std::string GetDefaultOutputDeviceID();
+
// Get number of input or output streams.
int input_stream_count() { return num_input_streams_; }
int output_stream_count() { return num_output_streams_; }
diff --git a/chromium/media/audio/audio_input_device_unittest.cc b/chromium/media/audio/audio_manager_unittest.cc
index dc211a48a93..4747c2e2996 100644
--- a/chromium/media/audio/audio_input_device_unittest.cc
+++ b/chromium/media/audio/audio_manager_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,20 +9,28 @@
#include "media/audio/audio_manager_base.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_LINUX)
+#include "media/audio/linux/audio_manager_linux.h"
+#endif // defined(OS_LINUX)
+
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
#include "media/audio/win/audio_manager_win.h"
#include "media/audio/win/wavein_input_win.h"
#endif
+#if defined(USE_PULSEAUDIO)
+#include "media/audio/pulse/audio_manager_pulse.h"
+#endif // defined(USE_PULSEAUDIO)
+
namespace media {
// Test fixture which allows us to override the default enumeration API on
// Windows.
-class AudioInputDeviceTest
+class AudioManagerTest
: public ::testing::Test {
protected:
- AudioInputDeviceTest()
+ AudioManagerTest()
: audio_manager_(AudioManager::Create())
#if defined(OS_WIN)
, com_init_(base::win::ScopedCOMInitializer::kMTA)
@@ -64,6 +72,7 @@ class AudioInputDeviceTest
// Helper method which verifies that the device list starts with a valid
// default record 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()) {
AudioDeviceNames::const_iterator it = device_names.begin();
@@ -78,6 +87,8 @@ class AudioInputDeviceTest
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),
@@ -92,10 +103,14 @@ class AudioInputDeviceTest
}
}
- bool CanRunAudioTest() {
+ bool CanRunInputTest() {
return audio_manager_->HasAudioInputDevices();
}
+ bool CanRunOutputTest() {
+ return audio_manager_->HasAudioOutputDevices();
+ }
+
scoped_ptr<AudioManager> audio_manager_;
#if defined(OS_WIN)
@@ -105,8 +120,8 @@ class AudioInputDeviceTest
};
// Test that devices can be enumerated.
-TEST_F(AudioInputDeviceTest, EnumerateDevices) {
- if (!CanRunAudioTest())
+TEST_F(AudioManagerTest, EnumerateInputDevices) {
+ if (!CanRunInputTest())
return;
AudioDeviceNames device_names;
@@ -114,6 +129,16 @@ TEST_F(AudioInputDeviceTest, EnumerateDevices) {
CheckDeviceNames(device_names);
}
+// Test that devices can be enumerated.
+TEST_F(AudioManagerTest, EnumerateOutputDevices) {
+ if (!CanRunOutputTest())
+ return;
+
+ AudioDeviceNames device_names;
+ audio_manager_->GetAudioOutputDeviceNames(&device_names);
+ CheckDeviceNames(device_names);
+}
+
// Run additional tests for Windows since enumeration can be done using
// two different APIs. MMDevice is default for Vista and higher and Wave
// is default for XP and lower.
@@ -121,8 +146,8 @@ TEST_F(AudioInputDeviceTest, EnumerateDevices) {
// Override default enumeration API and force usage of Windows MMDevice.
// This test will only run on Windows Vista and higher.
-TEST_F(AudioInputDeviceTest, EnumerateDevicesWinMMDevice) {
- if (!CanRunAudioTest())
+TEST_F(AudioManagerTest, EnumerateInputDevicesWinMMDevice) {
+ if (!CanRunInputTest())
return;
AudioDeviceNames device_names;
@@ -135,10 +160,24 @@ TEST_F(AudioInputDeviceTest, EnumerateDevicesWinMMDevice) {
CheckDeviceNames(device_names);
}
+TEST_F(AudioManagerTest, EnumerateOutputDevicesWinMMDevice) {
+ if (!CanRunOutputTest())
+ return;
+
+ AudioDeviceNames device_names;
+ if (!SetMMDeviceEnumeration()) {
+ // Usage of MMDevice will fail on XP and lower.
+ LOG(WARNING) << "MM device enumeration is not supported.";
+ return;
+ }
+ audio_manager_->GetAudioOutputDeviceNames(&device_names);
+ CheckDeviceNames(device_names);
+}
+
// Override default enumeration API and force usage of Windows Wave.
// This test will run on Windows XP, Windows Vista and Windows 7.
-TEST_F(AudioInputDeviceTest, EnumerateDevicesWinWave) {
- if (!CanRunAudioTest())
+TEST_F(AudioManagerTest, EnumerateInputDevicesWinWave) {
+ if (!CanRunInputTest())
return;
AudioDeviceNames device_names;
@@ -147,8 +186,18 @@ TEST_F(AudioInputDeviceTest, EnumerateDevicesWinWave) {
CheckDeviceNames(device_names);
}
-TEST_F(AudioInputDeviceTest, WinXPDeviceIdUnchanged) {
- if (!CanRunAudioTest())
+TEST_F(AudioManagerTest, EnumerateOutputDevicesWinWave) {
+ if (!CanRunOutputTest())
+ return;
+
+ AudioDeviceNames device_names;
+ SetWaveEnumeration();
+ audio_manager_->GetAudioOutputDeviceNames(&device_names);
+ CheckDeviceNames(device_names);
+}
+
+TEST_F(AudioManagerTest, WinXPDeviceIdUnchanged) {
+ if (!CanRunInputTest())
return;
AudioDeviceNames xp_device_names;
@@ -164,8 +213,8 @@ TEST_F(AudioInputDeviceTest, WinXPDeviceIdUnchanged) {
}
}
-TEST_F(AudioInputDeviceTest, ConvertToWinXPDeviceId) {
- if (!CanRunAudioTest())
+TEST_F(AudioManagerTest, ConvertToWinXPInputDeviceId) {
+ if (!CanRunInputTest())
return;
if (!SetMMDeviceEnumeration()) {
@@ -194,6 +243,103 @@ TEST_F(AudioInputDeviceTest, ConvertToWinXPDeviceId) {
}
}
-#endif
+#endif // defined(OS_WIN)
+
+#if defined(USE_PULSEAUDIO)
+// On Linux, there are two implementations available and both can
+// sometimes be tested on a single system. These tests specifically
+// test Pulseaudio.
+
+TEST_F(AudioManagerTest, EnumerateInputDevicesPulseaudio) {
+ if (!CanRunInputTest())
+ return;
+
+ audio_manager_.reset(AudioManagerPulse::Create());
+ if (audio_manager_.get()) {
+ AudioDeviceNames device_names;
+ audio_manager_->GetAudioInputDeviceNames(&device_names);
+ CheckDeviceNames(device_names);
+ } else {
+ LOG(WARNING) << "No pulseaudio on this system.";
+ }
+}
+
+TEST_F(AudioManagerTest, EnumerateOutputDevicesPulseaudio) {
+ if (!CanRunOutputTest())
+ return;
+
+ audio_manager_.reset(AudioManagerPulse::Create());
+ if (audio_manager_.get()) {
+ AudioDeviceNames device_names;
+ audio_manager_->GetAudioOutputDeviceNames(&device_names);
+ CheckDeviceNames(device_names);
+ } else {
+ LOG(WARNING) << "No pulseaudio on this system.";
+ }
+}
+#endif // defined(USE_PULSEAUDIO)
+
+#if defined(USE_ALSA)
+// On Linux, there are two implementations available and both can
+// sometimes be tested on a single system. These tests specifically
+// test Alsa.
+
+TEST_F(AudioManagerTest, EnumerateInputDevicesAlsa) {
+ if (!CanRunInputTest())
+ return;
+
+ VLOG(2) << "Testing AudioManagerLinux.";
+ audio_manager_.reset(new AudioManagerLinux());
+ AudioDeviceNames device_names;
+ audio_manager_->GetAudioInputDeviceNames(&device_names);
+ CheckDeviceNames(device_names);
+}
+
+TEST_F(AudioManagerTest, EnumerateOutputDevicesAlsa) {
+ if (!CanRunOutputTest())
+ return;
+
+ VLOG(2) << "Testing AudioManagerLinux.";
+ audio_manager_.reset(new AudioManagerLinux());
+ AudioDeviceNames device_names;
+ audio_manager_->GetAudioOutputDeviceNames(&device_names);
+ CheckDeviceNames(device_names);
+}
+#endif // defined(USE_ALSA)
+
+TEST_F(AudioManagerTest, GetDefaultOutputStreamParameters) {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ if (!CanRunInputTest())
+ return;
+
+ AudioParameters params = audio_manager_->GetDefaultOutputStreamParameters();
+ EXPECT_TRUE(params.IsValid());
+#endif // defined(OS_WIN) || defined(OS_MACOSX)
+}
+
+TEST_F(AudioManagerTest, GetAssociatedOutputDeviceID) {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ if (!CanRunInputTest() || !CanRunOutputTest())
+ return;
+
+ AudioDeviceNames device_names;
+ audio_manager_->GetAudioInputDeviceNames(&device_names);
+ bool found_an_associated_device = false;
+ for (AudioDeviceNames::iterator it = device_names.begin();
+ it != device_names.end();
+ ++it) {
+ EXPECT_FALSE(it->unique_id.empty());
+ EXPECT_FALSE(it->device_name.empty());
+ std::string output_device_id(
+ audio_manager_->GetAssociatedOutputDeviceID(it->unique_id));
+ if (!output_device_id.empty()) {
+ VLOG(2) << it->unique_id << " matches with " << output_device_id;
+ found_an_associated_device = true;
+ }
+ }
+
+ EXPECT_TRUE(found_an_associated_device);
+#endif // defined(OS_WIN) || defined(OS_MACOSX)
+}
} // namespace media
diff --git a/chromium/media/audio/audio_output_controller.cc b/chromium/media/audio/audio_output_controller.cc
index f7f4cf8240b..649612cd4f6 100644
--- a/chromium/media/audio/audio_output_controller.cc
+++ b/chromium/media/audio/audio_output_controller.cc
@@ -20,26 +20,31 @@ using base::TimeDelta;
namespace media {
+#if defined(AUDIO_POWER_MONITORING)
// Time constant for AudioPowerMonitor. See AudioPowerMonitor ctor comments for
// semantics. This value was arbitrarily chosen, but seems to work well.
static const int kPowerMeasurementTimeConstantMillis = 10;
// Desired frequency of calls to EventHandler::OnPowerMeasured() for reporting
// power levels in the audio signal.
-static const int kPowerMeasurementsPerSecond = 30;
+static const int kPowerMeasurementsPerSecond = 4;
+#endif
// Polling-related constants.
const int AudioOutputController::kPollNumAttempts = 3;
const int AudioOutputController::kPollPauseInMilliseconds = 3;
-AudioOutputController::AudioOutputController(AudioManager* audio_manager,
- EventHandler* handler,
- const AudioParameters& params,
- const std::string& input_device_id,
- SyncReader* sync_reader)
+AudioOutputController::AudioOutputController(
+ AudioManager* audio_manager,
+ EventHandler* handler,
+ const AudioParameters& params,
+ const std::string& output_device_id,
+ const std::string& input_device_id,
+ SyncReader* sync_reader)
: audio_manager_(audio_manager),
params_(params),
handler_(handler),
+ output_device_id_(output_device_id),
input_device_id_(input_device_id),
stream_(NULL),
diverting_to_stream_(NULL),
@@ -48,10 +53,12 @@ AudioOutputController::AudioOutputController(AudioManager* audio_manager,
num_allowed_io_(0),
sync_reader_(sync_reader),
message_loop_(audio_manager->GetMessageLoop()),
- number_polling_attempts_left_(0),
+#if defined(AUDIO_POWER_MONITORING)
power_monitor_(
params.sample_rate(),
- TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)) {
+ TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
+#endif
+ number_polling_attempts_left_(0) {
DCHECK(audio_manager);
DCHECK(handler_);
DCHECK(sync_reader_);
@@ -67,6 +74,7 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create(
AudioManager* audio_manager,
EventHandler* event_handler,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
SyncReader* sync_reader) {
DCHECK(audio_manager);
@@ -76,7 +84,8 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create(
return NULL;
scoped_refptr<AudioOutputController> controller(new AudioOutputController(
- audio_manager, event_handler, params, input_device_id, sync_reader));
+ audio_manager, event_handler, params, output_device_id, input_device_id,
+ sync_reader));
controller->message_loop_->PostTask(FROM_HERE, base::Bind(
&AudioOutputController::DoCreate, controller, false));
return controller;
@@ -114,8 +123,10 @@ void AudioOutputController::DoCreate(bool is_for_device_change) {
DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener().
DCHECK_EQ(kEmpty, state_);
- stream_ = diverting_to_stream_ ? diverting_to_stream_ :
- audio_manager_->MakeAudioOutputStreamProxy(params_, input_device_id_);
+ stream_ = diverting_to_stream_ ?
+ diverting_to_stream_ :
+ audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
+ input_device_id_);
if (!stream_) {
state_ = kError;
handler_->OnError();
@@ -158,6 +169,7 @@ void AudioOutputController::DoPlay() {
state_ = kPlaying;
+#if defined(AUDIO_POWER_MONITORING)
power_monitor_.Reset();
power_poll_callback_.Reset(
base::Bind(&AudioOutputController::ReportPowerMeasurementPeriodically,
@@ -165,6 +177,7 @@ void AudioOutputController::DoPlay() {
// Run the callback to send an initial notification that we're starting in
// silence, and to schedule periodic callbacks.
power_poll_callback_.callback().Run();
+#endif
// We start the AudioOutputStream lazily.
AllowEntryToOnMoreIOData();
@@ -173,6 +186,7 @@ void AudioOutputController::DoPlay() {
handler_->OnPlaying();
}
+#if defined(AUDIO_POWER_MONITORING)
void AudioOutputController::ReportPowerMeasurementPeriodically() {
DCHECK(message_loop_->BelongsToCurrentThread());
const std::pair<float, bool>& reading =
@@ -182,6 +196,7 @@ void AudioOutputController::ReportPowerMeasurementPeriodically() {
FROM_HERE, power_poll_callback_.callback(),
TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond);
}
+#endif
void AudioOutputController::StopStream() {
DCHECK(message_loop_->BelongsToCurrentThread());
@@ -190,7 +205,9 @@ void AudioOutputController::StopStream() {
stream_->Stop();
DisallowEntryToOnMoreIOData();
+#if defined(AUDIO_POWER_MONITORING)
power_poll_callback_.Cancel();
+#endif
state_ = kPaused;
}
@@ -208,8 +225,10 @@ void AudioOutputController::DoPause() {
// Send a special pause mark to the low-latency audio thread.
sync_reader_->UpdatePendingBytes(kPauseMark);
+#if defined(AUDIO_POWER_MONITORING)
// Paused means silence follows.
handler_->OnPowerMeasured(AudioPowerMonitor::zero_power(), false);
+#endif
handler_->OnPaused();
}
@@ -283,7 +302,9 @@ int AudioOutputController::OnMoreIOData(AudioBus* source,
sync_reader_->UpdatePendingBytes(
buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
+#if defined(AUDIO_POWER_MONITORING)
power_monitor_.Scan(*dest, frames);
+#endif
AllowEntryToOnMoreIOData();
return frames;
diff --git a/chromium/media/audio/audio_output_controller.h b/chromium/media/audio/audio_output_controller.h
index 38a2c03f590..615c6a5e6c6 100644
--- a/chromium/media/audio/audio_output_controller.h
+++ b/chromium/media/audio/audio_output_controller.h
@@ -52,6 +52,11 @@
namespace media {
+// Only do power monitoring for non-mobile platforms that need it for the UI.
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#define AUDIO_POWER_MONITORING
+#endif
+
class MEDIA_EXPORT AudioOutputController
: public base::RefCountedThreadSafe<AudioOutputController>,
public AudioOutputStream::AudioSourceCallback,
@@ -101,10 +106,14 @@ class MEDIA_EXPORT AudioOutputController
// thread, and if this is successful, the |event_handler| will receive an
// OnCreated() call from the same audio manager thread. |audio_manager| must
// outlive AudioOutputController.
+ // The |output_device_id| can be either empty (default device) or specify a
+ // specific hardware device for audio output. The |input_device_id| is
+ // used only for unified audio when opening up input and output at the same
+ // time (controlled by |params.input_channel_count()|).
static scoped_refptr<AudioOutputController> Create(
AudioManager* audio_manager, EventHandler* event_handler,
- const AudioParameters& params, const std::string& input_device_id,
- SyncReader* sync_reader);
+ const AudioParameters& params, const std::string& output_device_id,
+ const std::string& input_device_id, SyncReader* sync_reader);
// Methods to control playback of the stream.
@@ -166,6 +175,7 @@ class MEDIA_EXPORT AudioOutputController
AudioOutputController(AudioManager* audio_manager, EventHandler* handler,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
SyncReader* sync_reader);
@@ -198,8 +208,12 @@ class MEDIA_EXPORT AudioOutputController
const AudioParameters params_;
EventHandler* const handler_;
+ // Specifies the device id of the output device to open or empty for the
+ // default output device.
+ const std::string output_device_id_;
+
// Used by the unified IO to open the correct input device.
- std::string input_device_id_;
+ const std::string input_device_id_;
AudioOutputStream* stream_;
@@ -227,15 +241,17 @@ class MEDIA_EXPORT AudioOutputController
// The message loop of audio manager thread that this object runs on.
const scoped_refptr<base::MessageLoopProxy> message_loop_;
- // When starting stream we wait for data to become available.
- // Number of times left.
- int number_polling_attempts_left_;
-
+#if defined(AUDIO_POWER_MONITORING)
// Scans audio samples from OnMoreIOData() as input to compute power levels.
AudioPowerMonitor power_monitor_;
// Periodic callback to report power levels during playback.
base::CancelableClosure power_poll_callback_;
+#endif
+
+ // When starting stream we wait for data to become available.
+ // Number of times left.
+ int number_polling_attempts_left_;
DISALLOW_COPY_AND_ASSIGN(AudioOutputController);
};
diff --git a/chromium/media/audio/audio_output_controller_unittest.cc b/chromium/media/audio/audio_output_controller_unittest.cc
index 128cc07716f..a7118e17a30 100644
--- a/chromium/media/audio/audio_output_controller_unittest.cc
+++ b/chromium/media/audio/audio_output_controller_unittest.cc
@@ -29,8 +29,6 @@ static const int kSampleRate = AudioParameters::kAudioCDSampleRate;
static const int kBitsPerSample = 16;
static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
static const int kSamplesPerPacket = kSampleRate / 100;
-static const int kHardwareBufferSize = kSamplesPerPacket *
- ChannelLayoutToChannelCount(kChannelLayout) * kBitsPerSample / 8;
static const double kTestVolume = 0.25;
class MockAudioOutputControllerEventHandler
@@ -122,7 +120,7 @@ class AudioOutputControllerTest : public testing::Test {
controller_ = AudioOutputController::Create(
audio_manager_.get(), &mock_event_handler_, params_, std::string(),
- &mock_sync_reader_);
+ std::string(), &mock_sync_reader_);
if (controller_.get())
controller_->SetVolume(kTestVolume);
@@ -134,8 +132,10 @@ class AudioOutputControllerTest : public testing::Test {
// OnPowerMeasured() calls.
EXPECT_CALL(mock_event_handler_, OnPlaying())
.WillOnce(SignalEvent(&play_event_));
+#if defined(AUDIO_POWER_MONITORING)
EXPECT_CALL(mock_event_handler_, OnPowerMeasured(_, false))
.Times(AtLeast(1));
+#endif
// During playback, the mock pretends to provide audio data rendered and
// sent from the render process.
diff --git a/chromium/media/audio/audio_output_dispatcher.cc b/chromium/media/audio/audio_output_dispatcher.cc
index 06206d7be7f..a151c449f02 100644
--- a/chromium/media/audio/audio_output_dispatcher.cc
+++ b/chromium/media/audio/audio_output_dispatcher.cc
@@ -11,10 +11,12 @@ namespace media {
AudioOutputDispatcher::AudioOutputDispatcher(
AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id)
: audio_manager_(audio_manager),
message_loop_(base::MessageLoop::current()),
params_(params),
+ output_device_id_(output_device_id),
input_device_id_(input_device_id) {
// We expect to be instantiated on the audio thread. Otherwise the
// message_loop_ member will point to the wrong message loop!
diff --git a/chromium/media/audio/audio_output_dispatcher.h b/chromium/media/audio/audio_output_dispatcher.h
index a79fd94477f..30266ed6a9a 100644
--- a/chromium/media/audio/audio_output_dispatcher.h
+++ b/chromium/media/audio/audio_output_dispatcher.h
@@ -38,6 +38,7 @@ class MEDIA_EXPORT AudioOutputDispatcher
public:
AudioOutputDispatcher(AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id);
// Called by AudioOutputProxy to open the stream.
@@ -79,6 +80,7 @@ class MEDIA_EXPORT AudioOutputDispatcher
AudioManager* audio_manager_;
base::MessageLoop* message_loop_;
AudioParameters params_;
+ const std::string output_device_id_;
const std::string input_device_id_;
private:
diff --git a/chromium/media/audio/audio_output_dispatcher_impl.cc b/chromium/media/audio/audio_output_dispatcher_impl.cc
index 1df8e7ddd5b..bcdcd65146e 100644
--- a/chromium/media/audio/audio_output_dispatcher_impl.cc
+++ b/chromium/media/audio/audio_output_dispatcher_impl.cc
@@ -19,9 +19,11 @@ namespace media {
AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay)
- : AudioOutputDispatcher(audio_manager, params, input_device_id),
+ : AudioOutputDispatcher(audio_manager, params, output_device_id,
+ input_device_id),
pause_delay_(base::TimeDelta::FromMicroseconds(
2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
static_cast<float>(params.sample_rate()))),
@@ -168,7 +170,7 @@ void AudioOutputDispatcherImpl::Shutdown() {
bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
- params_, input_device_id_);
+ params_, output_device_id_, input_device_id_);
if (!stream)
return false;
diff --git a/chromium/media/audio/audio_output_dispatcher_impl.h b/chromium/media/audio/audio_output_dispatcher_impl.h
index 06fe3ebeaf1..b59f835f9b0 100644
--- a/chromium/media/audio/audio_output_dispatcher_impl.h
+++ b/chromium/media/audio/audio_output_dispatcher_impl.h
@@ -35,6 +35,7 @@ class MEDIA_EXPORT AudioOutputDispatcherImpl : public AudioOutputDispatcher {
// the audio device is closed.
AudioOutputDispatcherImpl(AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay);
diff --git a/chromium/media/audio/audio_output_proxy_unittest.cc b/chromium/media/audio/audio_output_proxy_unittest.cc
index de95b0661ec..1806ce66131 100644
--- a/chromium/media/audio/audio_output_proxy_unittest.cc
+++ b/chromium/media/audio/audio_output_proxy_unittest.cc
@@ -95,10 +95,14 @@ class MockAudioManager : public AudioManagerBase {
MOCK_METHOD0(HasAudioOutputDevices, bool());
MOCK_METHOD0(HasAudioInputDevices, bool());
MOCK_METHOD0(GetAudioInputDeviceModel, string16());
- MOCK_METHOD2(MakeAudioOutputStream, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
- MOCK_METHOD2(MakeAudioOutputStreamProxy, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
+ MOCK_METHOD3(MakeAudioOutputStream, AudioOutputStream*(
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id));
+ MOCK_METHOD3(MakeAudioOutputStreamProxy, AudioOutputStream*(
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id));
MOCK_METHOD2(MakeAudioInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
MOCK_METHOD0(ShowAudioInputSettings, void());
@@ -108,14 +112,15 @@ class MockAudioManager : public AudioManagerBase {
MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*(
const AudioParameters& params));
- MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
+ MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*(
+ const AudioParameters& params, const std::string& device_id,
+ const std::string& input_device_id));
MOCK_METHOD2(MakeLinearInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
- MOCK_METHOD1(GetPreferredOutputStreamParameters, AudioParameters(
- const AudioParameters& params));
+ MOCK_METHOD2(GetPreferredOutputStreamParameters, AudioParameters(
+ const std::string& device_id, const AudioParameters& params));
};
class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
@@ -161,6 +166,7 @@ class AudioOutputProxyTest : public testing::Test {
dispatcher_impl_ = new AudioOutputDispatcherImpl(&manager(),
params_,
std::string(),
+ std::string(),
close_delay);
// Necessary to know how long the dispatcher will wait before posting
@@ -186,7 +192,7 @@ class AudioOutputProxyTest : public testing::Test {
void OpenAndClose(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -203,7 +209,7 @@ class AudioOutputProxyTest : public testing::Test {
void StartAndStop(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -229,7 +235,7 @@ class AudioOutputProxyTest : public testing::Test {
void CloseAfterStop(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -261,7 +267,7 @@ class AudioOutputProxyTest : public testing::Test {
void TwoStreams(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -283,7 +289,7 @@ class AudioOutputProxyTest : public testing::Test {
void OpenFailed(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(false));
@@ -301,7 +307,7 @@ class AudioOutputProxyTest : public testing::Test {
void CreateAndWait(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -328,7 +334,7 @@ class AudioOutputProxyTest : public testing::Test {
MockAudioOutputStream stream1(&manager_, params_);
MockAudioOutputStream stream2(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream1))
.WillOnce(Return(&stream2));
@@ -366,7 +372,7 @@ class AudioOutputProxyTest : public testing::Test {
MockAudioOutputStream stream1(&manager_, params_);
MockAudioOutputStream stream2(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream1))
.WillOnce(Return(&stream2));
@@ -406,7 +412,7 @@ class AudioOutputProxyTest : public testing::Test {
void StartFailed(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -425,7 +431,7 @@ class AudioOutputProxyTest : public testing::Test {
Mock::VerifyAndClear(&stream);
// |stream| is closed at this point. Start() should reopen it again.
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(2)
.WillRepeatedly(Return(reinterpret_cast<AudioOutputStream*>(NULL)));
@@ -467,7 +473,8 @@ class AudioOutputResamplerTest : public AudioOutputProxyTest {
AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
16000, 16, 1024);
resampler_ = new AudioOutputResampler(
- &manager(), params_, resampler_params_, std::string(), close_delay);
+ &manager(), params_, resampler_params_, std::string(), std::string(),
+ close_delay);
}
virtual void OnStart() OVERRIDE {
@@ -568,7 +575,7 @@ TEST_F(AudioOutputResamplerTest, StartFailed) { StartFailed(resampler_.get()); }
// ensure AudioOutputResampler falls back to the high latency path.
TEST_F(AudioOutputResamplerTest, LowLatencyCreateFailedFallback) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(2)
.WillOnce(Return(static_cast<AudioOutputStream*>(NULL)))
.WillRepeatedly(Return(&stream));
@@ -588,7 +595,7 @@ TEST_F(AudioOutputResamplerTest, LowLatencyCreateFailedFallback) {
TEST_F(AudioOutputResamplerTest, LowLatencyOpenFailedFallback) {
MockAudioOutputStream failed_stream(&manager_, params_);
MockAudioOutputStream okay_stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(2)
.WillOnce(Return(&failed_stream))
.WillRepeatedly(Return(&okay_stream));
@@ -619,7 +626,7 @@ TEST_F(AudioOutputResamplerTest, HighLatencyFallbackFailed) {
#else
static const int kFallbackCount = 1;
#endif
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(kFallbackCount)
.WillRepeatedly(Return(static_cast<AudioOutputStream*>(NULL)));
@@ -630,7 +637,7 @@ TEST_F(AudioOutputResamplerTest, HighLatencyFallbackFailed) {
testing::Property(&AudioParameters::sample_rate, params_.sample_rate()),
testing::Property(
&AudioParameters::frames_per_buffer, params_.frames_per_buffer())),
- _))
+ _, _))
.Times(1)
.WillOnce(Return(&okay_stream));
EXPECT_CALL(okay_stream, Open())
@@ -655,7 +662,7 @@ TEST_F(AudioOutputResamplerTest, AllFallbackFailed) {
#else
static const int kFallbackCount = 2;
#endif
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(kFallbackCount)
.WillRepeatedly(Return(static_cast<AudioOutputStream*>(NULL)));
@@ -673,7 +680,7 @@ TEST_F(AudioOutputResamplerTest, LowLatencyOpenEventuallyFails) {
MockAudioOutputStream stream3(&manager_, params_);
// Setup the mock such that all three streams are successfully created.
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream1))
.WillOnce(Return(&stream2))
.WillOnce(Return(&stream3))
diff --git a/chromium/media/audio/audio_output_resampler.cc b/chromium/media/audio/audio_output_resampler.cc
index 6db0e2fb2fe..da424ec1246 100644
--- a/chromium/media/audio/audio_output_resampler.cc
+++ b/chromium/media/audio/audio_output_resampler.cc
@@ -147,12 +147,13 @@ static AudioParameters SetupFallbackParams(
AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
const AudioParameters& input_params,
const AudioParameters& output_params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay)
- : AudioOutputDispatcher(audio_manager, input_params, input_device_id),
+ : AudioOutputDispatcher(audio_manager, input_params, output_device_id,
+ input_device_id),
close_delay_(close_delay),
output_params_(output_params),
- input_device_id_(input_device_id),
streams_opened_(false) {
DCHECK(input_params.IsValid());
DCHECK(output_params.IsValid());
@@ -172,7 +173,8 @@ void AudioOutputResampler::Initialize() {
DCHECK(!streams_opened_);
DCHECK(callbacks_.empty());
dispatcher_ = new AudioOutputDispatcherImpl(
- audio_manager_, output_params_, input_device_id_, close_delay_);
+ audio_manager_, output_params_, output_device_id_, input_device_id_,
+ close_delay_);
}
bool AudioOutputResampler::OpenStream() {
diff --git a/chromium/media/audio/audio_output_resampler.h b/chromium/media/audio/audio_output_resampler.h
index df9e4320b55..f9a75ac38f5 100644
--- a/chromium/media/audio/audio_output_resampler.h
+++ b/chromium/media/audio/audio_output_resampler.h
@@ -40,6 +40,7 @@ class MEDIA_EXPORT AudioOutputResampler : public AudioOutputDispatcher {
AudioOutputResampler(AudioManager* audio_manager,
const AudioParameters& input_params,
const AudioParameters& output_params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay);
@@ -74,9 +75,6 @@ class MEDIA_EXPORT AudioOutputResampler : public AudioOutputDispatcher {
// AudioParameters used to setup the output stream.
AudioParameters output_params_;
- // Device ID to be used by the unified IO to open the correct input device.
- const std::string input_device_id_;
-
// Whether any streams have been opened through |dispatcher_|, if so we can't
// fallback on future OpenStream() failures.
bool streams_opened_;
diff --git a/chromium/media/audio/audio_parameters.h b/chromium/media/audio/audio_parameters.h
index 2817cd2c5a6..bc629a7db00 100644
--- a/chromium/media/audio/audio_parameters.h
+++ b/chromium/media/audio/audio_parameters.h
@@ -14,6 +14,7 @@ namespace media {
struct MEDIA_EXPORT AudioInputBufferParameters {
double volume;
uint32 size;
+ bool key_pressed;
};
// Use a struct-in-struct approach to ensure that we can calculate the required
diff --git a/chromium/media/audio/clockless_audio_sink.cc b/chromium/media/audio/clockless_audio_sink.cc
new file mode 100644
index 00000000000..ff809d0541d
--- /dev/null
+++ b/chromium/media/audio/clockless_audio_sink.cc
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/audio/clockless_audio_sink.h"
+
+#include "base/threading/simple_thread.h"
+#include "base/time/time.h"
+#include "media/base/audio_renderer_sink.h"
+
+namespace media {
+
+// Internal to ClocklessAudioSink. Class is used to call Render() on a seperate
+// thread, running as fast as it can read the data.
+class ClocklessAudioSinkThread : public base::DelegateSimpleThread::Delegate {
+ public:
+ explicit ClocklessAudioSinkThread(const AudioParameters& params,
+ AudioRendererSink::RenderCallback* callback)
+ : callback_(callback),
+ audio_bus_(AudioBus::Create(params)),
+ stop_event_(new base::WaitableEvent(false, false)) {}
+
+ void Start() {
+ stop_event_->Reset();
+ thread_.reset(new base::DelegateSimpleThread(this, "ClocklessAudioSink"));
+ thread_->Start();
+ }
+
+ // Generate a signal to stop calling Render().
+ base::TimeDelta Stop() {
+ stop_event_->Signal();
+ thread_->Join();
+ return playback_time_;
+ }
+
+ private:
+ // Call Render() repeatedly, keeping track of the rendering time.
+ virtual void Run() OVERRIDE {
+ base::TimeTicks start;
+ while (!stop_event_->IsSignaled()) {
+ int frames_received = callback_->Render(audio_bus_.get(), 0);
+ if (frames_received <= 0) {
+ // No data received, so let other threads run to provide data.
+ base::PlatformThread::YieldCurrentThread();
+ } else if (start.is_null()) {
+ // First time we processed some audio, so record the starting time.
+ start = base::TimeTicks::HighResNow();
+ } else {
+ // Keep track of the last time data was rendered.
+ playback_time_ = base::TimeTicks::HighResNow() - start;
+ }
+ }
+ }
+
+ AudioRendererSink::RenderCallback* callback_;
+ scoped_ptr<AudioBus> audio_bus_;
+ scoped_ptr<base::WaitableEvent> stop_event_;
+ scoped_ptr<base::DelegateSimpleThread> thread_;
+ base::TimeDelta playback_time_;
+};
+
+ClocklessAudioSink::ClocklessAudioSink()
+ : initialized_(false),
+ playing_(false) {}
+
+ClocklessAudioSink::~ClocklessAudioSink() {}
+
+void ClocklessAudioSink::Initialize(const AudioParameters& params,
+ RenderCallback* callback) {
+ DCHECK(!initialized_);
+ thread_.reset(new ClocklessAudioSinkThread(params, callback));
+ initialized_ = true;
+}
+
+void ClocklessAudioSink::Start() {
+ DCHECK(!playing_);
+}
+
+void ClocklessAudioSink::Stop() {
+ DCHECK(initialized_);
+
+ if (!playing_)
+ return;
+
+ playback_time_ = thread_->Stop();
+}
+
+void ClocklessAudioSink::Play() {
+ DCHECK(initialized_);
+
+ if (playing_)
+ return;
+
+ playing_ = true;
+ thread_->Start();
+}
+
+void ClocklessAudioSink::Pause() {
+ Stop();
+}
+
+bool ClocklessAudioSink::SetVolume(double volume) {
+ // Audio is always muted.
+ return volume == 0.0;
+}
+
+} // namespace media
diff --git a/chromium/media/audio/clockless_audio_sink.h b/chromium/media/audio/clockless_audio_sink.h
new file mode 100644
index 00000000000..9e73b1a8817
--- /dev/null
+++ b/chromium/media/audio/clockless_audio_sink.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_AUDIO_CLOCKLESS_AUDIO_SINK_H_
+#define MEDIA_AUDIO_CLOCKLESS_AUDIO_SINK_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "media/base/audio_renderer_sink.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace media {
+class AudioBus;
+class ClocklessAudioSinkThread;
+
+// Implementation of an AudioRendererSink that consumes the audio as fast as
+// possible. This class does not support multiple Play()/Pause() events.
+class MEDIA_EXPORT ClocklessAudioSink
+ : NON_EXPORTED_BASE(public AudioRendererSink) {
+ public:
+ ClocklessAudioSink();
+
+ // AudioRendererSink implementation.
+ virtual void Initialize(const AudioParameters& params,
+ RenderCallback* callback) OVERRIDE;
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+ virtual void Pause() OVERRIDE;
+ virtual void Play() OVERRIDE;
+ virtual bool SetVolume(double volume) OVERRIDE;
+
+ // Returns the time taken to consume all the audio.
+ base::TimeDelta render_time() { return playback_time_; }
+
+ protected:
+ virtual ~ClocklessAudioSink();
+
+ private:
+ scoped_ptr<ClocklessAudioSinkThread> thread_;
+ bool initialized_;
+ bool playing_;
+
+ // Time taken in last set of Render() calls.
+ base::TimeDelta playback_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClocklessAudioSink);
+};
+
+} // namespace media
+
+#endif // MEDIA_AUDIO_CLOCKLESS_AUDIO_SINK_H_
diff --git a/chromium/media/audio/cras/audio_manager_cras.cc b/chromium/media/audio/cras/audio_manager_cras.cc
index 165d642922c..14a0c4e86ac 100644
--- a/chromium/media/audio/cras/audio_manager_cras.cc
+++ b/chromium/media/audio/cras/audio_manager_cras.cc
@@ -16,14 +16,21 @@
namespace media {
+static void AddDefaultDevice(AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
+
+ // Cras will route audio from a proper physical device automatically.
+ device_names->push_back(
+ AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
+ AudioManagerBase::kDefaultDeviceId));
+}
+
// Maximum number of output streams that can be open simultaneously.
static const int kMaxOutputStreams = 50;
// Default sample rate for input and output streams.
static const int kDefaultSampleRate = 48000;
-const char AudioManagerCras::kLoopbackDeviceId[] = "loopback";
-
bool AudioManagerCras::HasAudioOutputDevices() {
return true;
}
@@ -45,10 +52,13 @@ void AudioManagerCras::ShowAudioInputSettings() {
}
void AudioManagerCras::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
- DCHECK(device_names->empty());
- GetCrasAudioInputDevices(device_names);
- return;
+ AudioDeviceNames* device_names) {
+ AddDefaultDevice(device_names);
+}
+
+void AudioManagerCras::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
+ AddDefaultDevice(device_names);
}
AudioParameters AudioManagerCras::GetInputStreamParameters(
@@ -61,14 +71,6 @@ AudioParameters AudioManagerCras::GetInputStreamParameters(
kDefaultSampleRate, 16, kDefaultInputBufferSize);
}
-void AudioManagerCras::GetCrasAudioInputDevices(
- media::AudioDeviceNames* device_names) {
- // Cras will route audio from a proper physical device automatically.
- device_names->push_back(
- AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
- AudioManagerBase::kDefaultDeviceId));
-}
-
AudioOutputStream* AudioManagerCras::MakeLinearOutputStream(
const AudioParameters& params) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
@@ -76,7 +78,10 @@ AudioOutputStream* AudioManagerCras::MakeLinearOutputStream(
}
AudioOutputStream* AudioManagerCras::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
// TODO(dgreid): Open the correct input device for unified IO.
return MakeOutputStream(params);
@@ -95,7 +100,10 @@ AudioInputStream* AudioManagerCras::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 512;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
diff --git a/chromium/media/audio/cras/audio_manager_cras.h b/chromium/media/audio/cras/audio_manager_cras.h
index fdc5b02688a..3b0ef530e07 100644
--- a/chromium/media/audio/cras/audio_manager_cras.h
+++ b/chromium/media/audio/cras/audio_manager_cras.h
@@ -15,18 +15,16 @@ namespace media {
class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
public:
- // Unique ID of the "loopback" input device. This device captures post-mix,
- // pre-DSP system audio.
- static const char kLoopbackDeviceId[];
-
AudioManagerCras();
// AudioManager implementation.
virtual bool HasAudioOutputDevices() OVERRIDE;
virtual bool HasAudioInputDevices() OVERRIDE;
virtual void ShowAudioInputSettings() OVERRIDE;
- virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
- OVERRIDE;
+ virtual void GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
@@ -35,6 +33,7 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -45,12 +44,10 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
virtual ~AudioManagerCras();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
- // Gets a list of available cras input devices.
- void GetCrasAudioInputDevices(media::AudioDeviceNames* device_names);
-
// Called by MakeLinearOutputStream and MakeLowLatencyOutputStream.
AudioOutputStream* MakeOutputStream(const AudioParameters& params);
diff --git a/chromium/media/audio/cras/cras_input.cc b/chromium/media/audio/cras/cras_input.cc
index a82fe283f7a..fd574dc86e5 100644
--- a/chromium/media/audio/cras/cras_input.cc
+++ b/chromium/media/audio/cras/cras_input.cc
@@ -26,9 +26,8 @@ CrasInputStream::CrasInputStream(const AudioParameters& params,
params_(params),
started_(false),
stream_id_(0),
- stream_direction_(device_id == AudioManagerCras::kLoopbackDeviceId
- ? CRAS_STREAM_POST_MIX_PRE_DSP
- : CRAS_STREAM_INPUT) {
+ stream_direction_(device_id == AudioManagerBase::kLoopbackInputDeviceId ?
+ CRAS_STREAM_POST_MIX_PRE_DSP : CRAS_STREAM_INPUT) {
DCHECK(audio_manager_);
}
@@ -114,7 +113,6 @@ void CrasInputStream::Start(AudioInputCallback* callback) {
StartAgc();
callback_ = callback;
- LOG(ERROR) << "Input Start";
// Prepare |audio_format| and |stream_params| for the stream we
// will create.
diff --git a/chromium/media/audio/cras/cras_unified.cc b/chromium/media/audio/cras/cras_unified.cc
index c1c3ee9228f..a7741864b31 100644
--- a/chromium/media/audio/cras/cras_unified.cc
+++ b/chromium/media/audio/cras/cras_unified.cc
@@ -168,7 +168,6 @@ void CrasUnifiedStream::Start(AudioSourceCallback* callback) {
if (is_playing_)
return;
- LOG(ERROR) << "Unified Start";
// Prepare |audio_format| and |stream_params| for the stream we
// will create.
cras_audio_format* audio_format = cras_audio_format_create(
diff --git a/chromium/media/audio/cross_process_notification.cc b/chromium/media/audio/cross_process_notification.cc
deleted file mode 100644
index 1806f777da3..00000000000
--- a/chromium/media/audio/cross_process_notification.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/cross_process_notification.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-
-CrossProcessNotification::CrossProcessNotification() {}
-
-CrossProcessNotification::WaitForMultiple::WaitForMultiple(
- const Notifications* notifications) {
- Reset(notifications);
-}
-
-int CrossProcessNotification::WaitForMultiple::Wait() {
- DCHECK(CalledOnValidThread());
- int ret = WaitMultiple(*notifications_, wait_offset_);
- wait_offset_ = (ret + 1) % notifications_->size();
- return ret;
-}
-
-void CrossProcessNotification::WaitForMultiple::Reset(
- const Notifications* notifications) {
- DCHECK(CalledOnValidThread());
- wait_offset_ = 0;
- notifications_ = notifications;
- DCHECK(!notifications_->empty());
-}
diff --git a/chromium/media/audio/cross_process_notification.h b/chromium/media/audio/cross_process_notification.h
deleted file mode 100644
index 16f2fc07fcf..00000000000
--- a/chromium/media/audio/cross_process_notification.h
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_
-#define MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/process/process.h"
-#include "base/threading/non_thread_safe.h"
-#include "media/base/media_export.h"
-
-#if defined(OS_WIN)
-#include "base/win/scoped_handle.h"
-#else
-#include "base/file_descriptor_posix.h"
-#include "base/sync_socket.h"
-#endif
-
-// A mechanism to synchronize access to a shared resource between two parties
-// when the usage pattern resembles that of two players playing a game of chess.
-// Each end has an instance of CrossProcessNotification and calls Signal() when
-// it has finished using the shared resource.
-// Before accessing the resource, it must call Wait() in order to know when the
-// other end has called Signal().
-//
-// Here's some pseudo code for how this class can be used:
-//
-// This method is used by both processes as it's a general way to use the
-// shared resource and then grant the privilege to the other process:
-//
-// void WriteToSharedMemory(CrossProcessNotification* notification,
-// SharedMemory* mem,
-// const char my_char) {
-// notification->Wait(); // Wait for the other process to yield access.
-// reinterpret_cast<char*>(mem->memory())[0] = my_char;
-// notification->Signal(); // Grant the other process access.
-// }
-//
-// Process A:
-//
-// class A {
-// public:
-// void Initialize(base::ProcessHandle process_b) {
-// mem_.CreateNamed("foo", false, 1024);
-//
-// CrossProcessNotification other;
-// CHECK(CrossProcessNotification::InitializePair(&notification_, &other));
-// CrossProcessNotification::IPCHandle handle_1, handle_2;
-// CHECK(other.ShareToProcess(process_b, &handle_1, &handle_2));
-// // This could be implemented by using some IPC mechanism
-// // such as MessageLoop.
-// SendToProcessB(mem_, handle_1, handle_2);
-// // Allow process B the first chance to write to the memory:
-// notification_.Signal();
-// // Once B is done, we'll write 'A' to the shared memory.
-// WriteToSharedMemory(&notification_, &mem_, 'A');
-// }
-//
-// CrossProcessNotification notification_;
-// SharedMemory mem_;
-// };
-//
-// Process B:
-//
-// class B {
-// public:
-// // Called when we receive the IPC message from A.
-// void Initialize(SharedMemoryHandle mem,
-// CrossProcessNotification::IPCHandle handle_1,
-// CrossProcessNotification::IPCHandle handle_2) {
-// mem_.reset(new SharedMemory(mem, false));
-// notification_.reset(new CrossProcessNotification(handle_1, handle_2));
-// WriteToSharedMemory(&notification_, &mem_, 'B');
-// }
-//
-// CrossProcessNotification notification_;
-// scoped_ptr<SharedMemory> mem_;
-// };
-//
-class MEDIA_EXPORT CrossProcessNotification {
- public:
-#if defined(OS_WIN)
- typedef HANDLE IPCHandle;
-#else
- typedef base::FileDescriptor IPCHandle;
-#endif
-
- typedef std::vector<CrossProcessNotification*> Notifications;
-
- // Default ctor. Initializes a NULL notification. User must call
- // InitializePair() to initialize the instance along with a connected one.
- CrossProcessNotification();
-
- // Ctor for the user that does not call InitializePair but instead receives
- // handles from the one that did. These handles come from a call to
- // ShareToProcess.
- CrossProcessNotification(IPCHandle handle_1, IPCHandle handle_2);
- ~CrossProcessNotification();
-
- // Raises a signal that the shared resource now can be accessed by the other
- // party.
- // NOTE: Calling Signal() more than once without calling Wait() in between
- // is not a supported scenario and will result in undefined behavior (and
- // different depending on platform).
- void Signal();
-
- // Waits for the other party to finish using the shared resource.
- // NOTE: As with Signal(), you must not call Wait() more than once without
- // calling Signal() in between.
- void Wait();
-
- bool IsValid() const;
-
- // Copies the internal handles to the output parameters, |handle_1| and
- // |handle_2|. The operation can fail, so the caller must be prepared to
- // handle that case.
- bool ShareToProcess(base::ProcessHandle process, IPCHandle* handle_1,
- IPCHandle* handle_2);
-
- // Initializes a pair of CrossProcessNotification instances. Note that this
- // can fail (e.g. due to EMFILE on Linux).
- static bool InitializePair(CrossProcessNotification* a,
- CrossProcessNotification* b);
-
- // Use an instance of this class when you have to repeatedly wait for multiple
- // notifications on the same thread. The class will store information about
- // which notification was last signaled and try to distribute the signals so
- // that all notifications get a chance to be processed in times of high load
- // and a busy one won't starve the others.
- // TODO(tommi): Support a way to abort the wait.
- class MEDIA_EXPORT WaitForMultiple :
- public NON_EXPORTED_BASE(base::NonThreadSafe) {
- public:
- // Caller must make sure that the lifetime of the array is greater than
- // that of the WaitForMultiple instance.
- explicit WaitForMultiple(const Notifications* notifications);
-
- // Waits for any of the notifications to be signaled. Returns the 0 based
- // index of a signaled notification.
- int Wait();
-
- // Call when the array changes. This should be called on the same thread
- // as Wait() is called on and the array must never change while a Wait()
- // is in progress.
- void Reset(const Notifications* notifications);
-
- private:
- const Notifications* notifications_;
- size_t wait_offset_;
- };
-
- private:
- // Only called by the WaitForMultiple class. See documentation
- // for WaitForMultiple and comments inside WaitMultiple for details.
- static int WaitMultiple(const Notifications& notifications,
- size_t wait_offset);
-
-#if defined(OS_WIN)
- base::win::ScopedHandle mine_;
- base::win::ScopedHandle other_;
-#else
- typedef base::CancelableSyncSocket SocketClass;
- SocketClass socket_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(CrossProcessNotification);
-};
-
-#endif // MEDIA_AUDIO_CROSS_PROCESS_NOTIFICATION_H_
diff --git a/chromium/media/audio/cross_process_notification_posix.cc b/chromium/media/audio/cross_process_notification_posix.cc
deleted file mode 100644
index d5683495ef9..00000000000
--- a/chromium/media/audio/cross_process_notification_posix.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/cross_process_notification.h"
-
-#include <errno.h>
-#include <sys/poll.h>
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/file_descriptor_posix.h"
-
-CrossProcessNotification::~CrossProcessNotification() {}
-
-CrossProcessNotification::CrossProcessNotification(IPCHandle handle_1,
- IPCHandle handle_2)
- : socket_(handle_1.fd) {
- DCHECK_NE(handle_1.fd, -1);
- DCHECK_EQ(handle_2.fd, -1);
- DCHECK(IsValid());
-}
-
-void CrossProcessNotification::Signal() {
- DCHECK(IsValid());
- char signal = 1;
- size_t bytes = socket_.Send(&signal, sizeof(signal));
- DCHECK_EQ(bytes, 1U) << "errno: " << errno;
-}
-
-void CrossProcessNotification::Wait() {
- DCHECK(IsValid());
- char signal = 0;
- size_t bytes = socket_.Receive(&signal, sizeof(signal));
- DCHECK_EQ(bytes, 1U) << "errno: " << errno;
- DCHECK_EQ(signal, 1);
-}
-
-bool CrossProcessNotification::IsValid() const {
- return socket_.handle() != SocketClass::kInvalidHandle;
-}
-
-bool CrossProcessNotification::ShareToProcess(base::ProcessHandle process,
- IPCHandle* handle_1,
- IPCHandle* handle_2) {
- DCHECK(IsValid());
- handle_1->fd = socket_.handle();
- handle_1->auto_close = false;
- handle_2->fd = -1;
- return true;
-}
-
-// static
-bool CrossProcessNotification::InitializePair(CrossProcessNotification* a,
- CrossProcessNotification* b) {
- DCHECK(!a->IsValid());
- DCHECK(!b->IsValid());
-
- bool ok = SocketClass::CreatePair(&a->socket_, &b->socket_);
-
- DLOG_IF(WARNING, !ok) << "failed to create socket: " << errno;
- DCHECK(!ok || a->IsValid());
- DCHECK(!ok || b->IsValid());
- return ok;
-}
-
-// static
-int CrossProcessNotification::WaitMultiple(const Notifications& notifications,
- size_t wait_offset) {
- DCHECK_LT(wait_offset, notifications.size());
-
- for (size_t i = 0; i < notifications.size(); ++i) {
- DCHECK(notifications[i]->IsValid());
- }
-
- // Below, we always check the |revents| of the first socket in the array
- // and return the index of that socket if set. This can cause sockets
- // that come later in the array to starve when the first sockets are
- // very busy. So to avoid the starving problem, we use the |wait_offset|
- // variable to split up the array so that the last socket to be signaled
- // becomes the last socket in the array and all the other sockets will have
- // priority the next time WaitMultiple is called.
- scoped_ptr<struct pollfd[]> sockets(new struct pollfd[notifications.size()]);
- memset(&sockets[0], 0, notifications.size() * sizeof(sockets[0]));
- size_t index = 0;
- for (size_t i = wait_offset; i < notifications.size(); ++i) {
- struct pollfd& fd = sockets[index++];
- fd.events = POLLIN;
- fd.fd = notifications[i]->socket_.handle();
- }
-
- for (size_t i = 0; i < wait_offset; ++i) {
- struct pollfd& fd = sockets[index++];
- fd.events = POLLIN;
- fd.fd = notifications[i]->socket_.handle();
- }
- DCHECK_EQ(index, notifications.size());
-
- int err = poll(&sockets[0], notifications.size(), -1);
- if (err != -1) {
- for (size_t i = 0; i < notifications.size(); ++i) {
- if (sockets[i].revents) {
- size_t ret = (i + wait_offset) % notifications.size();
- DCHECK_EQ(sockets[i].fd, notifications[ret]->socket_.handle());
- notifications[ret]->Wait();
- return ret;
- }
- }
- }
- // Either poll() failed or we failed to find a single socket that was
- // signaled. Either way continuing will result in undefined behavior.
- LOG(FATAL) << "poll() failed: " << errno;
- return -1;
-}
diff --git a/chromium/media/audio/cross_process_notification_unittest.cc b/chromium/media/audio/cross_process_notification_unittest.cc
deleted file mode 100644
index a27219496cb..00000000000
--- a/chromium/media/audio/cross_process_notification_unittest.cc
+++ /dev/null
@@ -1,462 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/kill.h"
-#include "base/stl_util.h"
-#include "base/test/multiprocess_test.h"
-#include "base/threading/platform_thread.h"
-#include "media/audio/cross_process_notification.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/multiprocess_func_list.h"
-
-#include <utility> // NOLINT
-
-namespace {
-
-// Initializes (ctor) and deletes (dtor) two vectors of pairs of
-// CrossProcessNotification instances.
-class NotificationsOwner {
- public:
- // Attempts to create up to |number_of_pairs| number of pairs. Call size()
- // after construction to find out how many pairs were actually created.
- explicit NotificationsOwner(size_t number_of_pairs) {
- CreateMultiplePairs(number_of_pairs);
- }
- ~NotificationsOwner() {
- STLDeleteElements(&a_);
- STLDeleteElements(&b_);
- }
-
- size_t size() const {
- DCHECK_EQ(a_.size(), b_.size());
- return a_.size();
- }
-
- const CrossProcessNotification::Notifications& a() { return a_; }
- const CrossProcessNotification::Notifications& b() { return b_; }
-
- private:
- void CreateMultiplePairs(size_t count) {
- a_.resize(count);
- b_.resize(count);
- size_t i = 0;
- for (; i < count; ++i) {
- a_[i] = new CrossProcessNotification();
- b_[i] = new CrossProcessNotification();
- if (!CrossProcessNotification::InitializePair(a_[i], b_[i])) {
- LOG(WARNING) << "InitializePair failed at " << i;
- delete a_[i];
- delete b_[i];
- break;
- }
- }
- a_.resize(i);
- b_.resize(i);
- }
-
- CrossProcessNotification::Notifications a_;
- CrossProcessNotification::Notifications b_;
-};
-
-// A simple thread that we'll run two instances of. Both threads get a pointer
-// to the same |shared_data| and use a CrossProcessNotification to control when
-// each thread can read/write.
-class SingleNotifierWorker : public base::PlatformThread::Delegate {
- public:
- SingleNotifierWorker(size_t* shared_data, size_t repeats,
- CrossProcessNotification* notifier)
- : shared_data_(shared_data), repeats_(repeats),
- notifier_(notifier) {
- }
- virtual ~SingleNotifierWorker() {}
-
- // base::PlatformThread::Delegate:
- virtual void ThreadMain() OVERRIDE {
- for (size_t i = 0; i < repeats_; ++i) {
- notifier_->Wait();
- ++(*shared_data_);
- notifier_->Signal();
- }
- }
-
- private:
- size_t* shared_data_;
- size_t repeats_;
- CrossProcessNotification* notifier_;
- DISALLOW_COPY_AND_ASSIGN(SingleNotifierWorker);
-};
-
-// Similar to SingleNotifierWorker, except each instance of this class will
-// have >1 instances of CrossProcessNotification to Wait/Signal and an equal
-// amount of |shared_data| that the notifiers control access to.
-class MultiNotifierWorker : public base::PlatformThread::Delegate {
- public:
- MultiNotifierWorker(size_t* shared_data, size_t repeats,
- const CrossProcessNotification::Notifications* notifiers)
- : shared_data_(shared_data), repeats_(repeats),
- notifiers_(notifiers) {
- }
- virtual ~MultiNotifierWorker() {}
-
- // base::PlatformThread::Delegate:
- virtual void ThreadMain() OVERRIDE {
- CrossProcessNotification::WaitForMultiple waiter(notifiers_);
- for (size_t i = 0; i < repeats_; ++i) {
- int signaled = waiter.Wait();
- ++shared_data_[signaled];
- (*notifiers_)[signaled]->Signal();
- }
- }
-
- private:
- size_t* shared_data_;
- size_t repeats_;
- const CrossProcessNotification::Notifications* notifiers_;
- DISALLOW_COPY_AND_ASSIGN(MultiNotifierWorker);
-};
-
-// A fixed array of bool flags. Each flag uses 1 bit. Use sizeof(FlagArray)
-// to determine how much memory you need. The number of flags will therefore
-// be sizeof(FlagArray) * 8.
-// We use 'struct' to signify that this structures represents compiler
-// independent structured data. I.e. you must be able to map this class
-// to a piece of shared memory of size sizeof(FlagArray) and be able to
-// use the class. No vtables etc.
-// TODO(tommi): Move this to its own header when we start using it for signaling
-// audio devices. As is, it's just here for perf comparison against the
-// "multiple notifiers" approach.
-struct FlagArray {
- public:
- FlagArray() : flags_() {}
-
- bool is_set(size_t index) const {
- return (flags_[index >> 5] & (1 << (index & 31)));
- }
-
- void set(size_t index) {
- flags_[index >> 5] |= (1U << (static_cast<uint32>(index) & 31));
- }
-
- void clear(size_t index) {
- flags_[index >> 5] &= ~(1U << (static_cast<uint32>(index) & 31));
- }
-
- // Returns the number of flags that can be set/checked.
- size_t size() const { return sizeof(flags_) * 8; }
-
- private:
- // 256 * 32 = 8192 flags in 1KB.
- uint32 flags_[256];
- DISALLOW_COPY_AND_ASSIGN(FlagArray);
-};
-
-class MultiNotifierWorkerFlagArray : public base::PlatformThread::Delegate {
- public:
- MultiNotifierWorkerFlagArray(size_t count, FlagArray* signals,
- size_t* shared_data, size_t repeats,
- CrossProcessNotification* notifier)
- : count_(count), signals_(signals), shared_data_(shared_data),
- repeats_(repeats), notifier_(notifier) {
- }
- virtual ~MultiNotifierWorkerFlagArray() {}
-
- // base::PlatformThread::Delegate:
- virtual void ThreadMain() OVERRIDE {
- for (size_t i = 0; i < repeats_; ++i) {
- notifier_->Wait();
- for (size_t s = 0; s < count_; ++s) {
- if (signals_->is_set(s)) {
- ++shared_data_[s];
- // We don't clear the flag here but simply leave it signaled because
- // we want the other thread to also increment this variable.
- }
- }
- notifier_->Signal();
- }
- }
-
- private:
- size_t count_;
- FlagArray* signals_;
- size_t* shared_data_;
- size_t repeats_;
- CrossProcessNotification* notifier_;
- DISALLOW_COPY_AND_ASSIGN(MultiNotifierWorkerFlagArray);
-};
-
-} // end namespace
-
-TEST(CrossProcessNotification, FlagArray) {
- FlagArray flags;
- EXPECT_GT(flags.size(), 1000U);
- for (size_t i = 0; i < flags.size(); ++i) {
- EXPECT_FALSE(flags.is_set(i));
- flags.set(i);
- EXPECT_TRUE(flags.is_set(i));
- flags.clear(i);
- EXPECT_FALSE(flags.is_set(i));
- }
-}
-
-// Initializes two notifiers, signals the each one and make sure the others
-// wait is satisfied.
-TEST(CrossProcessNotification, Basic) {
- CrossProcessNotification a, b;
- ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b));
- EXPECT_TRUE(a.IsValid());
- EXPECT_TRUE(b.IsValid());
-
- a.Signal();
- b.Wait();
-
- b.Signal();
- a.Wait();
-}
-
-// Spins two worker threads, each with their own CrossProcessNotification
-// that they use to read and write from a shared memory buffer.
-// Disabled as it trips of the TSAN bot (false positive since TSAN doesn't
-// recognize sockets as being a synchronization primitive).
-TEST(CrossProcessNotification, DISABLED_TwoThreads) {
- CrossProcessNotification a, b;
- ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b));
-
- size_t data = 0;
- const size_t kRepeats = 10000;
- SingleNotifierWorker worker1(&data, kRepeats, &a);
- SingleNotifierWorker worker2(&data, kRepeats, &b);
- base::PlatformThreadHandle thread1, thread2;
- base::PlatformThread::Create(0, &worker1, &thread1);
- base::PlatformThread::Create(0, &worker2, &thread2);
-
- // Start the first thread. They should ping pong a few times and take turns
- // incrementing the shared variable and never step on each other's toes.
- a.Signal();
-
- base::PlatformThread::Join(thread1);
- base::PlatformThread::Join(thread2);
-
- EXPECT_EQ(kRepeats * 2, data);
-}
-
-// Uses a pair of threads to access up to 1000 pieces of synchronized shared
-// data. On regular dev machines, the number of notifiers should be 1000, but on
-// mac and linux bots, the number will be smaller due to the RLIMIT_NOFILE
-// limit. Specifically, linux will have this limit at 1024 which means for this
-// test that the max number of notifiers will be in the range 500-512. On Mac
-// the limit is 256, so |count| will be ~120. Oh, and raising the limit via
-// setrlimit() won't work.
-// DISABLED since the distribution won't be accurate when run on valgrind.
-TEST(CrossProcessNotification, DISABLED_ThousandNotifiersTwoThreads) {
- const size_t kCount = 1000;
- NotificationsOwner pairs(kCount);
- size_t data[kCount] = {0};
- // We use a multiple of the count so that the division in the check below
- // will be nice and round.
- size_t repeats = pairs.size() * 1;
-
- MultiNotifierWorker worker_1(&data[0], repeats, &pairs.a());
- MultiNotifierWorker worker_2(&data[0], repeats, &pairs.b());
- base::PlatformThreadHandle thread_1, thread_2;
- base::PlatformThread::Create(0, &worker_1, &thread_1);
- base::PlatformThread::Create(0, &worker_2, &thread_2);
-
- for (size_t i = 0; i < pairs.size(); ++i)
- pairs.a()[i]->Signal();
-
- base::PlatformThread::Join(thread_1);
- base::PlatformThread::Join(thread_2);
-
- size_t expected_total = pairs.size() * 2;
- size_t total = 0;
- for (size_t i = 0; i < pairs.size(); ++i) {
- // The CrossProcessNotification::WaitForMultiple class should have ensured
- // that all notifiers had the same quality of service.
- EXPECT_EQ(expected_total / pairs.size(), data[i]);
- total += data[i];
- }
- EXPECT_EQ(expected_total, total);
-}
-
-// Functionally equivalent (as far as the shared data goes) to the
-// ThousandNotifiersTwoThreads test but uses a single pair of notifiers +
-// FlagArray for the 1000 signals. This approach is significantly faster.
-// Disabled as it trips of the TSAN bot - "Possible data race during write of
-// size 4" (the flag array).
-TEST(CrossProcessNotification, DISABLED_TwoNotifiersTwoThreads1000Signals) {
- CrossProcessNotification a, b;
- ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b));
-
- const size_t kCount = 1000;
- FlagArray signals;
- ASSERT_GE(signals.size(), kCount);
- size_t data[kCount] = {0};
-
- // Since this algorithm checks all events each time the notifier is
- // signaled, |repeat| doesn't mean the same thing here as it does in
- // ThousandNotifiersTwoThreads. 1 repeat here is the same as kCount
- // repeats in ThousandNotifiersTwoThreads.
- size_t repeats = 1;
- MultiNotifierWorkerFlagArray worker1(kCount, &signals, &data[0], repeats, &a);
- MultiNotifierWorkerFlagArray worker2(kCount, &signals, &data[0], repeats, &b);
- base::PlatformThreadHandle thread1, thread2;
- base::PlatformThread::Create(0, &worker1, &thread1);
- base::PlatformThread::Create(0, &worker2, &thread2);
-
- for (size_t i = 0; i < kCount; ++i)
- signals.set(i);
- a.Signal();
-
- base::PlatformThread::Join(thread1);
- base::PlatformThread::Join(thread2);
-
- size_t expected_total = kCount * 2;
- size_t total = 0;
- for (size_t i = 0; i < kCount; ++i) {
- // Since for each signal, we process all signaled events, the shared data
- // variables should all be equal.
- EXPECT_EQ(expected_total / kCount, data[i]);
- total += data[i];
- }
- EXPECT_EQ(expected_total, total);
-}
-
-// Test the maximum number of notifiers without spinning further wait
-// threads on Windows. This test assumes we can always create 64 pairs and
-// bails if we can't.
-TEST(CrossProcessNotification, MultipleWaits64) {
- const size_t kCount = 64;
- NotificationsOwner pairs(kCount);
- ASSERT_TRUE(pairs.size() == kCount);
-
- CrossProcessNotification::WaitForMultiple waiter(&pairs.b());
- for (size_t i = 0; i < kCount; ++i) {
- pairs.a()[i]->Signal();
- int index = waiter.Wait();
- EXPECT_EQ(i, static_cast<size_t>(index));
- }
-}
-
-// Tests waiting for more notifiers than the OS supports on one thread.
-// The test will create at most 1000 pairs, but on mac/linux bots the actual
-// number will be lower. See comment about the RLIMIT_NOFILE limit above for
-// more details.
-// DISABLED since the distribution won't be accurate when run on valgrind.
-TEST(CrossProcessNotification, DISABLED_MultipleWaits1000) {
- // A 1000 notifiers requires 16 threads on Windows, including the current
- // one, to perform the wait operation.
- const size_t kCount = 1000;
- NotificationsOwner pairs(kCount);
-
- for (size_t i = 0; i < pairs.size(); ++i) {
- pairs.a()[i]->Signal();
- // To disable the load distribution algorithm and force the extra worker
- // thread(s) to catch the signaled event, we define the |waiter| inside
- // the loop.
- CrossProcessNotification::WaitForMultiple waiter(&pairs.b());
- int index = waiter.Wait();
- EXPECT_EQ(i, static_cast<size_t>(index));
- }
-}
-
-class CrossProcessNotificationMultiProcessTest : public base::MultiProcessTest {
-};
-
-namespace {
-
-// A very crude IPC mechanism that we use to set up the spawned child process
-// and the parent process.
-struct CrudeIpc {
- uint8 ready;
- CrossProcessNotification::IPCHandle handle_1;
- CrossProcessNotification::IPCHandle handle_2;
-};
-
-#if defined(OS_POSIX)
-const int kPosixChildSharedMem = 30;
-#else
-const char kSharedMemName[] = "CrossProcessNotificationMultiProcessTest";
-#endif
-
-const size_t kSharedMemSize = 1024;
-
-} // namespace
-
-// The main routine of the child process. Waits for the parent process
-// to copy handles over to the child and then uses a CrossProcessNotification to
-// wait and signal to the parent process.
-MULTIPROCESS_TEST_MAIN(CrossProcessNotificationChildMain) {
-#if defined(OS_POSIX)
- base::SharedMemory mem(
- base::SharedMemoryHandle(kPosixChildSharedMem, true /* auto close */),
- false);
-#else
- base::SharedMemory mem;
- CHECK(mem.CreateNamed(kSharedMemName, true, kSharedMemSize));
-#endif
-
- CHECK(mem.Map(kSharedMemSize));
- CrudeIpc* ipc = reinterpret_cast<CrudeIpc*>(mem.memory());
-
- while (!ipc->ready)
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
-
- CrossProcessNotification notifier(ipc->handle_1, ipc->handle_2);
- notifier.Wait();
- notifier.Signal();
-
- return 0;
-}
-
-// Spawns a new process and hands a CrossProcessNotification instance to the
-// new process. Once that's done, it waits for the child process to signal
-// it's end and quits.
-TEST_F(CrossProcessNotificationMultiProcessTest, Basic) {
- CrossProcessNotification a, b;
- ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b));
- EXPECT_TRUE(a.IsValid());
- EXPECT_TRUE(b.IsValid());
-
- base::SharedMemory mem;
-
-#if defined(OS_POSIX)
- ASSERT_TRUE(mem.CreateAndMapAnonymous(kSharedMemSize));
-#else
- mem.Delete(kSharedMemName); // In case a previous run was unsuccessful.
- ASSERT_TRUE(mem.CreateNamed(kSharedMemName, false, kSharedMemSize));
- ASSERT_TRUE(mem.Map(kSharedMemSize));
-#endif
-
- CrudeIpc* ipc = reinterpret_cast<CrudeIpc*>(mem.memory());
- ipc->ready = false;
-
-#if defined(OS_POSIX)
- const int kPosixChildSocket = 20;
- EXPECT_TRUE(b.ShareToProcess(
- base::kNullProcessHandle, &ipc->handle_1, &ipc->handle_2));
- base::FileHandleMappingVector fd_mapping_vec;
- fd_mapping_vec.push_back(std::make_pair(ipc->handle_1.fd, kPosixChildSocket));
- fd_mapping_vec.push_back(
- std::make_pair(mem.handle().fd, kPosixChildSharedMem));
- ipc->handle_1.fd = kPosixChildSocket;
- base::ProcessHandle process = SpawnChild("CrossProcessNotificationChildMain",
- fd_mapping_vec, false);
-#else
- base::ProcessHandle process = SpawnChild("CrossProcessNotificationChildMain",
- false);
- EXPECT_TRUE(b.ShareToProcess(process, &ipc->handle_1, &ipc->handle_2));
-#endif
-
- ipc->ready = true;
-
- a.Signal();
- a.Wait();
-
- int exit_code = -1;
- base::WaitForExitCode(process, &exit_code);
- EXPECT_EQ(0, exit_code);
-}
diff --git a/chromium/media/audio/cross_process_notification_win.cc b/chromium/media/audio/cross_process_notification_win.cc
deleted file mode 100644
index 53bf0f4525e..00000000000
--- a/chromium/media/audio/cross_process_notification_win.cc
+++ /dev/null
@@ -1,270 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/cross_process_notification.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/platform_thread.h"
-#include "base/win/scoped_handle.h"
-
-CrossProcessNotification::~CrossProcessNotification() {}
-
-CrossProcessNotification::CrossProcessNotification(IPCHandle handle_1,
- IPCHandle handle_2)
- : mine_(handle_1), other_(handle_2) {
- DCHECK(IsValid());
-}
-
-void CrossProcessNotification::Signal() {
- DCHECK(IsValid());
- DCHECK_EQ(::WaitForSingleObject(mine_, 0), static_cast<DWORD>(WAIT_TIMEOUT))
- << "Are you calling Signal() without calling Wait() first?";
- BOOL ok = ::SetEvent(mine_);
- CHECK(ok);
-}
-
-void CrossProcessNotification::Wait() {
- DCHECK(IsValid());
- DWORD wait = ::WaitForSingleObject(other_, INFINITE);
- DCHECK_EQ(wait, WAIT_OBJECT_0);
- BOOL ok = ::ResetEvent(other_);
- CHECK(ok);
-}
-
-bool CrossProcessNotification::IsValid() const {
- return mine_.IsValid() && other_.IsValid();
-}
-
-bool CrossProcessNotification::ShareToProcess(base::ProcessHandle process,
- IPCHandle* handle_1,
- IPCHandle* handle_2) {
- DCHECK(IsValid());
- HANDLE our_process = ::GetCurrentProcess();
- if (!::DuplicateHandle(our_process, mine_, process, handle_1, 0, FALSE,
- DUPLICATE_SAME_ACCESS)) {
- return false;
- }
-
- if (!::DuplicateHandle(our_process, other_, process, handle_2, 0, FALSE,
- DUPLICATE_SAME_ACCESS)) {
- // In case we're sharing to ourselves, we can close the handle, but
- // if the target process is a different process, we do nothing.
- if (process == our_process)
- ::CloseHandle(*handle_1);
- *handle_1 = NULL;
- return false;
- }
-
- return true;
-}
-
-// static
-bool CrossProcessNotification::InitializePair(CrossProcessNotification* a,
- CrossProcessNotification* b) {
- DCHECK(!a->IsValid());
- DCHECK(!b->IsValid());
-
- bool success = false;
-
- // Create two manually resettable events and give each party a handle
- // to both events.
- HANDLE event_a = ::CreateEvent(NULL, TRUE, FALSE, NULL);
- HANDLE event_b = ::CreateEvent(NULL, TRUE, FALSE, NULL);
- if (event_a && event_b) {
- a->mine_.Set(event_a);
- a->other_.Set(event_b);
- success = a->ShareToProcess(GetCurrentProcess(), &event_a, &event_b);
- if (success) {
- b->mine_.Set(event_b);
- b->other_.Set(event_a);
- } else {
- a->mine_.Close();
- a->other_.Close();
- }
- } else {
- if (event_a)
- ::CloseHandle(event_a);
- if (event_b)
- ::CloseHandle(event_b);
- }
-
- DCHECK(!success || a->IsValid());
- DCHECK(!success || b->IsValid());
-
- return success;
-}
-
-namespace {
-class ExtraWaitThread : public base::PlatformThread::Delegate {
- public:
- ExtraWaitThread(HANDLE stop, HANDLE* events, size_t count,
- int* signaled_event)
- : stop_(stop), events_(events), count_(count),
- signaled_event_(signaled_event) {
- *signaled_event_ = -1;
- }
- virtual ~ExtraWaitThread() {}
-
- virtual void ThreadMain() OVERRIDE {
- // Store the |stop_| event as the first event.
- HANDLE events[MAXIMUM_WAIT_OBJECTS] = { stop_ };
- HANDLE next_thread = NULL;
- DWORD event_count = MAXIMUM_WAIT_OBJECTS;
- int thread_signaled_event = -1;
- scoped_ptr<ExtraWaitThread> extra_wait_thread;
- if (count_ > (MAXIMUM_WAIT_OBJECTS - 1)) {
- std::copy(&events_[0], &events_[MAXIMUM_WAIT_OBJECTS - 2], &events[1]);
-
- extra_wait_thread.reset(new ExtraWaitThread(stop_,
- &events_[MAXIMUM_WAIT_OBJECTS - 2],
- count_ - (MAXIMUM_WAIT_OBJECTS - 2),
- &thread_signaled_event));
- base::PlatformThreadHandle handle;
- base::PlatformThread::Create(0, extra_wait_thread.get(), &handle);
- next_thread = handle.platform_handle();
-
- event_count = MAXIMUM_WAIT_OBJECTS;
- events[MAXIMUM_WAIT_OBJECTS - 1] = next_thread;
- } else {
- std::copy(&events_[0], &events_[count_], &events[1]);
- event_count = count_ + 1;
- }
-
- DWORD wait = ::WaitForMultipleObjects(event_count, &events[0], FALSE,
- INFINITE);
- if (wait >= WAIT_OBJECT_0 && wait < (WAIT_OBJECT_0 + event_count)) {
- wait -= WAIT_OBJECT_0;
- if (wait == 0) {
- // The stop event was signaled. Check if it was signaled by a
- // sub thread. In case our sub thread had to spin another thread (and
- // so on), we must wait for ours to exit before we can check the
- // propagated event offset.
- if (next_thread) {
- base::PlatformThread::Join(base::PlatformThreadHandle(next_thread));
- next_thread = NULL;
- }
- if (thread_signaled_event != -1)
- *signaled_event_ = thread_signaled_event + (MAXIMUM_WAIT_OBJECTS - 2);
- } else if (events[wait] == next_thread) {
- NOTREACHED();
- } else {
- *signaled_event_ = static_cast<int>(wait);
- SetEvent(stop_);
- }
- } else {
- NOTREACHED();
- }
-
- if (next_thread)
- base::PlatformThread::Join(base::PlatformThreadHandle(next_thread));
- }
-
- private:
- HANDLE stop_;
- HANDLE* events_;
- size_t count_;
- int* signaled_event_;
- DISALLOW_COPY_AND_ASSIGN(ExtraWaitThread);
-};
-} // end namespace
-
-// static
-int CrossProcessNotification::WaitMultiple(const Notifications& notifications,
- size_t wait_offset) {
- DCHECK_LT(wait_offset, notifications.size());
-
- for (size_t i = 0; i < notifications.size(); ++i) {
- DCHECK(notifications[i]->IsValid());
- }
-
- // TODO(tommi): Should we wait in an alertable state so that we can be
- // canceled via an APC?
- scoped_ptr<HANDLE[]> handles(new HANDLE[notifications.size()]);
-
- // Because of the way WaitForMultipleObjects works, we do a little trick here.
- // When multiple events are signaled, WaitForMultipleObjects will return the
- // index of the first signaled item (lowest). This means that if we always
- // pass the array the same way to WaitForMultipleObjects, the objects that
- // come first, have higher priority. In times of heavy load, this will cause
- // elements at the back to become DOS-ed.
- // So, we store the location of the item that was last signaled. Then we split
- // up the array and move everything higher than the last signaled index to the
- // front and the rest to the back (meaning that the last signaled item will
- // become the last element in the list).
- // Assuming equally busy events, this approach distributes the priority
- // evenly.
-
- size_t index = 0;
- for (size_t i = wait_offset; i < notifications.size(); ++i)
- handles[index++] = notifications[i]->other_;
-
- for (size_t i = 0; i < wait_offset; ++i)
- handles[index++] = notifications[i]->other_;
- DCHECK_EQ(index, notifications.size());
-
- DWORD wait = WAIT_FAILED;
- bool wait_failed = false;
- if (notifications.size() <= MAXIMUM_WAIT_OBJECTS) {
- wait = ::WaitForMultipleObjects(notifications.size(), &handles[0], FALSE,
- INFINITE);
- wait_failed = wait < WAIT_OBJECT_0 ||
- wait >= (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS);
- } else {
- // Used to stop the other wait threads when an event has been signaled.
- base::win::ScopedHandle stop(::CreateEvent(NULL, TRUE, FALSE, NULL));
-
- // Create the first thread and pass a pointer to all handles >63
- // to the thread + 'stop'. Then implement the thread so that it checks
- // if the number of handles is > 63. If so, spawns a new thread and
- // passes >62 handles to that thread and waits for the 62 handles + stop +
- // next thread. etc etc.
-
- // Create a list of threads so that each thread waits on at most 62 events
- // including one event for when a child thread signals completion and one
- // event for when all of the threads must be stopped (due to some event
- // being signaled).
-
- int thread_signaled_event = -1;
- ExtraWaitThread wait_thread(stop, &handles[MAXIMUM_WAIT_OBJECTS - 1],
- notifications.size() - (MAXIMUM_WAIT_OBJECTS - 1),
- &thread_signaled_event);
- base::PlatformThreadHandle thread;
- base::PlatformThread::Create(0, &wait_thread, &thread);
- HANDLE events[MAXIMUM_WAIT_OBJECTS];
- std::copy(&handles[0], &handles[MAXIMUM_WAIT_OBJECTS - 1], &events[0]);
- events[MAXIMUM_WAIT_OBJECTS - 1] = thread.platform_handle();
- wait = ::WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, &events[0], FALSE,
- INFINITE);
- wait_failed = wait < WAIT_OBJECT_0 ||
- wait >= (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS);
- if (wait == WAIT_OBJECT_0 + (MAXIMUM_WAIT_OBJECTS - 1)) {
- if (thread_signaled_event < 0) {
- wait_failed = true;
- NOTREACHED();
- } else {
- wait = WAIT_OBJECT_0 + (MAXIMUM_WAIT_OBJECTS - 2) +
- thread_signaled_event;
- }
- } else {
- ::SetEvent(stop);
- }
- base::PlatformThread::Join(thread);
- }
-
- int ret = -1;
- if (!wait_failed) {
- // Subtract to be politically correct (WAIT_OBJECT_0 is actually 0).
- wait -= WAIT_OBJECT_0;
- BOOL ok = ::ResetEvent(handles[wait]);
- CHECK(ok);
- ret = (wait + wait_offset) % notifications.size();
- DCHECK_EQ(handles[wait], notifications[ret]->other_.Get());
- } else {
- NOTREACHED();
- }
-
- CHECK_NE(ret, -1);
- return ret;
-}
diff --git a/chromium/media/audio/ios/audio_manager_ios.h b/chromium/media/audio/ios/audio_manager_ios.h
deleted file mode 100644
index 19751502fd2..00000000000
--- a/chromium/media/audio/ios/audio_manager_ios.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_AUDIO_IOS_AUDIO_MANAGER_IOS_H_
-#define MEDIA_AUDIO_IOS_AUDIO_MANAGER_IOS_H_
-
-#include "base/basictypes.h"
-#include "media/audio/audio_manager_base.h"
-
-namespace media {
-
-class PCMQueueInAudioInputStream;
-
-// iOS implementation of the AudioManager singleton. Supports only audio input.
-class MEDIA_EXPORT AudioManagerIOS : public AudioManagerBase {
- public:
- AudioManagerIOS();
-
- // Implementation of AudioManager.
- virtual bool HasAudioOutputDevices() OVERRIDE;
- virtual bool HasAudioInputDevices() OVERRIDE;
- virtual AudioOutputStream* MakeAudioOutputStream(
- const AudioParameters& params,
- const std::string& input_device_id) OVERRIDE;
- virtual AudioInputStream* MakeAudioInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
- virtual AudioParameters GetInputStreamParameters(
- const std::string& device_id) OVERRIDE;
-
- // Implementation of AudioManagerBase.
- virtual AudioOutputStream* MakeLinearOutputStream(
- const AudioParameters& params) OVERRIDE;
- virtual AudioOutputStream* MakeLowLatencyOutputStream(
- const AudioParameters& params,
- const std::string& input_device_id) OVERRIDE;
- virtual AudioInputStream* MakeLinearInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
- virtual AudioInputStream* MakeLowLatencyInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
- virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE;
- virtual void ReleaseInputStream(AudioInputStream* stream) OVERRIDE;
-
- protected:
- virtual ~AudioManagerIOS();
-
- virtual AudioParameters GetPreferredOutputStreamParameters(
- const AudioParameters& input_params) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AudioManagerIOS);
-};
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_IOS_AUDIO_MANAGER_IOS_H_
diff --git a/chromium/media/audio/ios/audio_manager_ios.mm b/chromium/media/audio/ios/audio_manager_ios.mm
deleted file mode 100644
index 49479302efc..00000000000
--- a/chromium/media/audio/ios/audio_manager_ios.mm
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/ios/audio_manager_ios.h"
-
-#import <AudioToolbox/AudioToolbox.h>
-#import <AVFoundation/AVFoundation.h>
-
-#include "base/sys_info.h"
-#include "media/audio/audio_parameters.h"
-#include "media/audio/fake_audio_input_stream.h"
-#include "media/audio/ios/audio_session_util_ios.h"
-#include "media/audio/mac/audio_input_mac.h"
-#include "media/base/channel_layout.h"
-#include "media/base/limits.h"
-
-namespace media {
-
-enum { kMaxInputChannels = 2 };
-
-AudioManagerIOS::AudioManagerIOS() {
-}
-
-AudioManagerIOS::~AudioManagerIOS() {
- Shutdown();
-}
-
-bool AudioManagerIOS::HasAudioOutputDevices() {
- return false;
-}
-
-bool AudioManagerIOS::HasAudioInputDevices() {
- if (!InitAudioSessionIOS())
- return false;
- // Note that the |kAudioSessionProperty_AudioInputAvailable| property is a
- // 32-bit integer, not a boolean.
- UInt32 property_size;
- OSStatus error =
- AudioSessionGetPropertySize(kAudioSessionProperty_AudioInputAvailable,
- &property_size);
- if (error != kAudioSessionNoError)
- return false;
- UInt32 audio_input_is_available = false;
- DCHECK(property_size == sizeof(audio_input_is_available));
- error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable,
- &property_size,
- &audio_input_is_available);
- return error == kAudioSessionNoError ? audio_input_is_available : false;
-}
-
-AudioParameters AudioManagerIOS::GetInputStreamParameters(
- const std::string& device_id) {
- // TODO(xians): figure out the right input sample rate and buffer size to
- // achieve the best audio performance for iOS devices.
- // TODO(xians): query the native channel layout for the specific device.
- static const int kDefaultSampleRate = 48000;
- static const int kDefaultBufferSize = 2048;
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
- kDefaultSampleRate, 16, kDefaultBufferSize);
-}
-
-AudioOutputStream* AudioManagerIOS::MakeAudioOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
- return NULL;
-}
-
-AudioInputStream* AudioManagerIOS::MakeAudioInputStream(
- const AudioParameters& params, const std::string& device_id) {
- // Current line of iOS devices has only one audio input.
- // Ignore the device_id (unittest uses a test value in it).
- if (!params.IsValid() || (params.channels() > kMaxInputChannels))
- return NULL;
-
- if (params.format() == AudioParameters::AUDIO_FAKE)
- return FakeAudioInputStream::MakeFakeStream(this, params);
- else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR)
- return new PCMQueueInAudioInputStream(this, params);
- return NULL;
-}
-
-AudioOutputStream* AudioManagerIOS::MakeLinearOutputStream(
- const AudioParameters& params) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
- return NULL;
-}
-
-AudioOutputStream* AudioManagerIOS::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
- return NULL;
-}
-
-AudioInputStream* AudioManagerIOS::MakeLinearInputStream(
- const AudioParameters& params, const std::string& device_id) {
- return MakeAudioInputStream(params, device_id);
-}
-
-AudioInputStream* AudioManagerIOS::MakeLowLatencyInputStream(
- const AudioParameters& params, const std::string& device_id) {
- NOTIMPLEMENTED(); // Only linear audio input is supported on iOS.
- return MakeAudioInputStream(params, device_id);
-}
-
-
-AudioParameters AudioManagerIOS::GetPreferredOutputStreamParameters(
- const AudioParameters& input_params) {
- // TODO(xians): handle the case when input_params is valid.
- // TODO(xians): figure out the right output sample rate and sample rate to
- // achieve the best audio performance for iOS devices.
- // TODO(xians): add support to --audio-buffer-size flag.
- static const int kDefaultSampleRate = 48000;
- static const int kDefaultBufferSize = 2048;
- if (input_params.IsValid()) {
- NOTREACHED();
- }
-
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
- kDefaultSampleRate, 16, kDefaultBufferSize);
-}
-
-// Called by the stream when it has been released by calling Close().
-void AudioManagerIOS::ReleaseOutputStream(AudioOutputStream* stream) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
-}
-
-// Called by the stream when it has been released by calling Close().
-void AudioManagerIOS::ReleaseInputStream(AudioInputStream* stream) {
- delete stream;
-}
-
-// static
-AudioManager* CreateAudioManager() {
- return new AudioManagerIOS();
-}
-
-} // namespace media
diff --git a/chromium/media/audio/ios/audio_manager_ios_unittest.cc b/chromium/media/audio/ios/audio_manager_ios_unittest.cc
deleted file mode 100644
index 30ebc04f204..00000000000
--- a/chromium/media/audio/ios/audio_manager_ios_unittest.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/audio/audio_io.h"
-#include "media/audio/audio_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace media;
-
-// Test that input is supported and output is not.
-TEST(IOSAudioTest, AudioSupport) {
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
- ASSERT_TRUE(NULL != audio_manager.get());
- ASSERT_FALSE(audio_manager->HasAudioOutputDevices());
- ASSERT_TRUE(audio_manager->HasAudioInputDevices());
-}
-
-// Test that input stream can be opened and closed.
-TEST(IOSAudioTest, InputStreamOpenAndClose) {
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
- ASSERT_TRUE(NULL != audio_manager.get());
- if (!audio_manager->HasAudioInputDevices())
- return;
- AudioInputStream* ias = audio_manager->MakeAudioInputStream(
- AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
- 8000, 16, 1024),
- std::string("test_device"));
- ASSERT_TRUE(NULL != ias);
- EXPECT_TRUE(ias->Open());
- ias->Close();
-}
diff --git a/chromium/media/audio/ios/audio_session_util_ios.h b/chromium/media/audio/ios/audio_session_util_ios.h
deleted file mode 100644
index 175db91fae0..00000000000
--- a/chromium/media/audio/ios/audio_session_util_ios.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_AUDIO_IOS_AUDIO_SESSION_UTIL_IOS_H_
-#define MEDIA_AUDIO_IOS_AUDIO_SESSION_UTIL_IOS_H_
-
-namespace media {
-
-// Initializes and configures the audio session, returning a bool indicating
-// whether initialization was successful. Can be called multiple times.
-// Safe to call from any thread.
-bool InitAudioSessionIOS();
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_IOS_AUDIO_SESSION_UTIL_IOS_H_
diff --git a/chromium/media/audio/ios/audio_session_util_ios.mm b/chromium/media/audio/ios/audio_session_util_ios.mm
deleted file mode 100644
index a4071a04cc1..00000000000
--- a/chromium/media/audio/ios/audio_session_util_ios.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/ios/audio_session_util_ios.h"
-
-#include <AVFoundation/AVFoundation.h>
-
-#include "base/logging.h"
-
-namespace media {
-
-bool InitAudioSessionIOS() {
- static bool kSessionInitialized = false;
- static dispatch_once_t once = 0;
- dispatch_once(&once, ^{
- OSStatus error = AudioSessionInitialize(NULL, NULL, NULL, NULL);
- if (error != kAudioSessionNoError)
- DLOG(ERROR) << "AudioSessionInitialize OSStatus error: " << error;
- BOOL result = [[AVAudioSession sharedInstance]
- setCategory:AVAudioSessionCategoryPlayAndRecord
- error:nil];
- if (!result)
- DLOG(ERROR) << "AVAudioSession setCategory failed";
- UInt32 allowMixing = true;
- AudioSessionSetProperty(
- kAudioSessionProperty_OverrideCategoryMixWithOthers,
- sizeof(allowMixing), &allowMixing);
- UInt32 defaultToSpeaker = true;
- AudioSessionSetProperty(
- kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
- sizeof(defaultToSpeaker),
- &defaultToSpeaker);
- // Speech input cannot be used if either of these two conditions fail.
- kSessionInitialized = (error == kAudioSessionNoError) && result;
- });
- return kSessionInitialized;
-}
-
-} // namespace media
diff --git a/chromium/media/audio/linux/alsa_output_unittest.cc b/chromium/media/audio/linux/alsa_output_unittest.cc
index 32456360f47..82fbab94c19 100644
--- a/chromium/media/audio/linux/alsa_output_unittest.cc
+++ b/chromium/media/audio/linux/alsa_output_unittest.cc
@@ -83,8 +83,10 @@ class MockAudioManagerLinux : public AudioManagerLinux {
MOCK_METHOD0(HasAudioInputDevices, bool());
MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*(
const AudioParameters& params));
- MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
+ MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*(
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id));
MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
diff --git a/chromium/media/audio/linux/audio_manager_linux.cc b/chromium/media/audio/linux/audio_manager_linux.cc
index 38253e2e651..708e4f26840 100644
--- a/chromium/media/audio/linux/audio_manager_linux.cc
+++ b/chromium/media/audio/linux/audio_manager_linux.cc
@@ -42,9 +42,9 @@ static const int kDefaultSampleRate = 48000;
// hence surround devices are not stored in the list.
static const char* kInvalidAudioInputDevices[] = {
"default",
+ "dmix",
"null",
"pulse",
- "dmix",
"surround",
};
@@ -103,9 +103,15 @@ void AudioManagerLinux::ShowAudioInputSettings() {
}
void AudioManagerLinux::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+ AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
+ GetAlsaAudioDevices(kStreamCapture, device_names);
+}
+
+void AudioManagerLinux::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
- GetAlsaAudioInputDevices(device_names);
+ GetAlsaAudioDevices(kStreamPlayback, device_names);
}
AudioParameters AudioManagerLinux::GetInputStreamParameters(
@@ -117,7 +123,8 @@ AudioParameters AudioManagerLinux::GetInputStreamParameters(
kDefaultSampleRate, 16, kDefaultInputBufferSize);
}
-void AudioManagerLinux::GetAlsaAudioInputDevices(
+void AudioManagerLinux::GetAlsaAudioDevices(
+ StreamType type,
media::AudioDeviceNames* device_names) {
// Constants specified by the ALSA API for device hints.
static const char kPcmInterfaceName[] = "pcm";
@@ -128,37 +135,40 @@ void AudioManagerLinux::GetAlsaAudioInputDevices(
void** hints = NULL;
int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
if (!error) {
- GetAlsaDevicesInfo(hints, device_names);
+ GetAlsaDevicesInfo(type, hints, device_names);
// Destroy the hints now that we're done with it.
wrapper_->DeviceNameFreeHint(hints);
} else {
- DLOG(WARNING) << "GetAudioInputDevices: unable to get device hints: "
+ DLOG(WARNING) << "GetAlsaAudioDevices: unable to get device hints: "
<< wrapper_->StrError(error);
}
}
}
void AudioManagerLinux::GetAlsaDevicesInfo(
- void** hints, media::AudioDeviceNames* device_names) {
+ AudioManagerLinux::StreamType type,
+ void** hints,
+ media::AudioDeviceNames* device_names) {
static const char kIoHintName[] = "IOID";
static const char kNameHintName[] = "NAME";
static const char kDescriptionHintName[] = "DESC";
- static const char kOutputDevice[] = "Output";
+
+ const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type);
for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
- // Only examine devices that are input capable. Valid values are
+ // Only examine devices of the right type. Valid values are
// "Input", "Output", and NULL which means both input and output.
scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
kIoHintName));
- if (io != NULL && strcmp(kOutputDevice, io.get()) == 0)
+ if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0)
continue;
- // Found an input device, prepend the default device since we always want
- // it to be on the top of the list for all platforms. And there is no
- // duplicate counting here since it is only done if the list is still empty.
- // Note, pulse has exclusively opened the default device, so we must open
- // the device via the "default" moniker.
+ // Found a device, prepend the default device since we always want
+ // it to be on the top of the list for all platforms. And there is
+ // no duplicate counting here since it is only done if the list is
+ // still empty. Note, pulse has exclusively opened the default
+ // device, so we must open the device via the "default" moniker.
if (device_names->empty()) {
device_names->push_front(media::AudioDeviceName(
AudioManagerBase::kDefaultDeviceName,
@@ -170,7 +180,7 @@ void AudioManagerLinux::GetAlsaDevicesInfo(
wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
// Find out if the device is available.
- if (IsAlsaDeviceAvailable(unique_device_name.get())) {
+ if (IsAlsaDeviceAvailable(type, unique_device_name.get())) {
// Get the description for the device.
scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint(
*hint_iter, kDescriptionHintName));
@@ -196,25 +206,46 @@ void AudioManagerLinux::GetAlsaDevicesInfo(
}
}
-bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) {
+// static
+bool AudioManagerLinux::IsAlsaDeviceAvailable(
+ AudioManagerLinux::StreamType type,
+ const char* device_name) {
if (!device_name)
return false;
- // Check if the device is in the list of invalid devices.
- for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
- if (strncmp(kInvalidAudioInputDevices[i], device_name,
- strlen(kInvalidAudioInputDevices[i])) == 0)
- return false;
+ // We do prefix matches on the device name to see whether to include
+ // it or not.
+ if (type == kStreamCapture) {
+ // Check if the device is in the list of invalid devices.
+ for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
+ if (strncmp(kInvalidAudioInputDevices[i], device_name,
+ strlen(kInvalidAudioInputDevices[i])) == 0)
+ return false;
+ }
+ return true;
+ } else {
+ DCHECK_EQ(kStreamPlayback, type);
+ // We prefer the device type that maps straight to hardware but
+ // goes through software conversion if needed (e.g. incompatible
+ // sample rate).
+ // TODO(joi): Should we prefer "hw" instead?
+ static const char kDeviceTypeDesired[] = "plughw";
+ return strncmp(kDeviceTypeDesired,
+ device_name,
+ arraysize(kDeviceTypeDesired) - 1) == 0;
}
+}
- return true;
+// static
+const char* AudioManagerLinux::UnwantedDeviceTypeWhenEnumerating(
+ AudioManagerLinux::StreamType wanted_type) {
+ return wanted_type == kStreamPlayback ? "Input" : "Output";
}
-bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
+bool AudioManagerLinux::HasAnyAlsaAudioDevice(
+ AudioManagerLinux::StreamType stream) {
static const char kPcmInterfaceName[] = "pcm";
static const char kIoHintName[] = "IOID";
- const char* kNotWantedDevice =
- (stream == kStreamPlayback ? "Input" : "Output");
void** hints = NULL;
bool has_device = false;
int card = -1;
@@ -230,7 +261,8 @@ bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
// "Input", "Output", and NULL which means both input and output.
scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
kIoHintName));
- if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0)
+ const char* unwanted_type = UnwantedDeviceTypeWhenEnumerating(stream);
+ if (io != NULL && strcmp(unwanted_type, io.get()) == 0)
continue; // Wrong type, skip the device.
// Found an input device.
@@ -258,7 +290,9 @@ AudioOutputStream* AudioManagerLinux::MakeLinearOutputStream(
AudioOutputStream* AudioManagerLinux::MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
// TODO(xians): Use input_device_id for unified IO.
return MakeOutputStream(params);
@@ -277,7 +311,10 @@ AudioInputStream* AudioManagerLinux::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerLinux::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 2048;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = kDefaultSampleRate;
diff --git a/chromium/media/audio/linux/audio_manager_linux.h b/chromium/media/audio/linux/audio_manager_linux.h
index 28abaa116e7..ab284dfdce9 100644
--- a/chromium/media/audio/linux/audio_manager_linux.h
+++ b/chromium/media/audio/linux/audio_manager_linux.h
@@ -25,8 +25,10 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
virtual bool HasAudioOutputDevices() OVERRIDE;
virtual bool HasAudioInputDevices() OVERRIDE;
virtual void ShowAudioInputSettings() OVERRIDE;
- virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
- OVERRIDE;
+ virtual void GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
@@ -35,6 +37,7 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -45,6 +48,7 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
virtual ~AudioManagerLinux();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
@@ -53,14 +57,22 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
kStreamCapture,
};
- // Gets a list of available ALSA input devices.
- void GetAlsaAudioInputDevices(media::AudioDeviceNames* device_names);
+ // Gets a list of available ALSA devices.
+ void GetAlsaAudioDevices(StreamType type,
+ media::AudioDeviceNames* device_names);
- // Gets the ALSA devices' names and ids.
- void GetAlsaDevicesInfo(void** hint, media::AudioDeviceNames* device_names);
+ // Gets the ALSA devices' names and ids that support streams of the
+ // given type.
+ void GetAlsaDevicesInfo(StreamType type,
+ void** hint,
+ media::AudioDeviceNames* device_names);
// Checks if the specific ALSA device is available.
- bool IsAlsaDeviceAvailable(const char* device_name);
+ static bool IsAlsaDeviceAvailable(StreamType type,
+ const char* device_name);
+
+ static const char* UnwantedDeviceTypeWhenEnumerating(
+ StreamType wanted_type);
// Returns true if a device is present for the given stream type.
bool HasAnyAlsaAudioDevice(StreamType stream);
diff --git a/chromium/media/audio/mac/audio_auhal_mac_unittest.cc b/chromium/media/audio/mac/audio_auhal_mac_unittest.cc
index b4cf8c64cc6..9b699ff10f8 100644
--- a/chromium/media/audio/mac/audio_auhal_mac_unittest.cc
+++ b/chromium/media/audio/mac/audio_auhal_mac_unittest.cc
@@ -101,7 +101,7 @@ class AudioOutputStreamWrapper {
samples_per_packet_);
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params,
- std::string());
+ std::string(), std::string());
EXPECT_TRUE(aos);
return aos;
}
diff --git a/chromium/media/audio/mac/audio_input_mac.cc b/chromium/media/audio/mac/audio_input_mac.cc
index 06af6d11c12..7930567fd9c 100644
--- a/chromium/media/audio/mac/audio_input_mac.cc
+++ b/chromium/media/audio/mac/audio_input_mac.cc
@@ -4,15 +4,14 @@
#include "media/audio/mac/audio_input_mac.h"
+#include <CoreServices/CoreServices.h>
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "media/audio/audio_manager_base.h"
#include "media/audio/audio_util.h"
-#if !defined(OS_IOS)
-#include <CoreServices/CoreServices.h>
-#endif
namespace media {
diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac.cc b/chromium/media/audio/mac/audio_low_latency_input_mac.cc
index 17a87b0a7dc..d97f453ca99 100644
--- a/chromium/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/chromium/media/audio/mac/audio_low_latency_input_mac.cc
@@ -35,7 +35,9 @@ static std::ostream& operator<<(std::ostream& os,
// for more details and background regarding this implementation.
AUAudioInputStream::AUAudioInputStream(
- AudioManagerMac* manager, const AudioParameters& params,
+ AudioManagerMac* manager,
+ const AudioParameters& input_params,
+ const AudioParameters& output_params,
AudioDeviceID audio_device_id)
: manager_(manager),
sink_(NULL),
@@ -48,15 +50,15 @@ AUAudioInputStream::AUAudioInputStream(
DCHECK(manager_);
// Set up the desired (output) format specified by the client.
- format_.mSampleRate = params.sample_rate();
+ format_.mSampleRate = input_params.sample_rate();
format_.mFormatID = kAudioFormatLinearPCM;
format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
kLinearPCMFormatFlagIsSignedInteger;
- format_.mBitsPerChannel = params.bits_per_sample();
- format_.mChannelsPerFrame = params.channels();
+ format_.mBitsPerChannel = input_params.bits_per_sample();
+ format_.mChannelsPerFrame = input_params.channels();
format_.mFramesPerPacket = 1; // uncompressed audio
format_.mBytesPerPacket = (format_.mBitsPerChannel *
- params.channels()) / 8;
+ input_params.channels()) / 8;
format_.mBytesPerFrame = format_.mBytesPerPacket;
format_.mReserved = 0;
@@ -68,10 +70,7 @@ AUAudioInputStream::AUAudioInputStream(
// Note that we use the same native buffer size as for the output side here
// since the AUHAL implementation requires that both capture and render side
// use the same buffer size. See http://crbug.com/154352 for more details.
- // TODO(xians): Get the audio parameters from the right device.
- const AudioParameters parameters =
- manager_->GetInputStreamParameters(AudioManagerBase::kDefaultDeviceId);
- number_of_frames_ = parameters.frames_per_buffer();
+ number_of_frames_ = output_params.frames_per_buffer();
DVLOG(1) << "Size of data buffer in frames : " << number_of_frames_;
// Derive size (in bytes) of the buffers that we will render to.
@@ -85,7 +84,7 @@ AUAudioInputStream::AUAudioInputStream(
audio_buffer_list_.mNumberBuffers = 1;
AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
- audio_buffer->mNumberChannels = params.channels();
+ audio_buffer->mNumberChannels = input_params.channels();
audio_buffer->mDataByteSize = data_byte_size;
audio_buffer->mData = audio_data_buffer_.get();
@@ -93,9 +92,16 @@ AUAudioInputStream::AUAudioInputStream(
// until a requested size is ready to be sent to the client.
// It is not possible to ask for less than |kAudioFramesPerCallback| number of
// audio frames.
- const size_t requested_size_frames =
- params.GetBytesPerBuffer() / format_.mBytesPerPacket;
- DCHECK_GE(requested_size_frames, number_of_frames_);
+ size_t requested_size_frames =
+ input_params.GetBytesPerBuffer() / format_.mBytesPerPacket;
+ if (requested_size_frames < number_of_frames_) {
+ // For devices that only support a low sample rate like 8kHz, we adjust the
+ // buffer size to match number_of_frames_. The value of number_of_frames_
+ // in this case has not been calculated based on hardware settings but
+ // rather our hardcoded defaults (see ChooseBufferSize).
+ requested_size_frames = number_of_frames_;
+ }
+
requested_size_bytes_ = requested_size_frames * format_.mBytesPerFrame;
DVLOG(1) << "Requested buffer size in bytes : " << requested_size_bytes_;
DLOG_IF(INFO, requested_size_frames > number_of_frames_) << "FIFO is used";
diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac.h b/chromium/media/audio/mac/audio_low_latency_input_mac.h
index 736bf082f5b..04592d2cecf 100644
--- a/chromium/media/audio/mac/audio_low_latency_input_mac.h
+++ b/chromium/media/audio/mac/audio_low_latency_input_mac.h
@@ -57,7 +57,8 @@ class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
// The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object.
AUAudioInputStream(AudioManagerMac* manager,
- const AudioParameters& params,
+ const AudioParameters& input_params,
+ const AudioParameters& output_params,
AudioDeviceID audio_device_id);
// The dtor is typically called by the AudioManager only and it is usually
// triggered by calling AudioInputStream::Close().
diff --git a/chromium/media/audio/mac/audio_manager_mac.cc b/chromium/media/audio/mac/audio_manager_mac.cc
index c0c18ee2cce..8e4b969854e 100644
--- a/chromium/media/audio/mac/audio_manager_mac.cc
+++ b/chromium/media/audio/mac/audio_manager_mac.cc
@@ -81,11 +81,10 @@ bool AudioManagerMac::HasUnifiedDefaultIO() {
return input_id == output_id;
}
+// Retrieves information on audio devices, and prepends the default
+// device to the list if the list is non-empty.
static void GetAudioDeviceInfo(bool is_input,
media::AudioDeviceNames* device_names) {
- DCHECK(device_names);
- device_names->clear();
-
// Query the number of total devices.
AudioObjectPropertyAddress property_address = {
kAudioHardwarePropertyDevices,
@@ -176,6 +175,16 @@ static void GetAudioDeviceInfo(bool is_input,
if (name)
CFRelease(name);
}
+
+ if (!device_names->empty()) {
+ // Prepend the default device to the list since we always want it to be
+ // on the top of the list for all platforms. There is no duplicate
+ // counting here since the default device has been abstracted out before.
+ media::AudioDeviceName name;
+ name.device_name = AudioManagerBase::kDefaultDeviceName;
+ name.unique_id = AudioManagerBase::kDefaultDeviceId;
+ device_names->push_front(name);
+ }
}
static AudioDeviceID GetAudioDeviceIdByUId(bool is_input,
@@ -189,7 +198,7 @@ static AudioDeviceID GetAudioDeviceIdByUId(bool is_input,
UInt32 device_size = sizeof(audio_device_id);
OSStatus result = -1;
- if (device_id == AudioManagerBase::kDefaultDeviceId) {
+ if (device_id == AudioManagerBase::kDefaultDeviceId || device_id.empty()) {
// Default Device.
property_address.mSelector = is_input ?
kAudioHardwarePropertyDefaultInputDevice :
@@ -263,7 +272,7 @@ bool AudioManagerMac::HasAudioInputDevices() {
return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
}
-// TODO(crogers): There are several places on the OSX specific code which
+// TODO(xians): There are several places on the OSX specific code which
// could benefit from these helper functions.
bool AudioManagerMac::GetDefaultInputDevice(
AudioDeviceID* device) {
@@ -397,16 +406,14 @@ int AudioManagerMac::HardwareSampleRate() {
void AudioManagerMac::GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
GetAudioDeviceInfo(true, device_names);
- if (!device_names->empty()) {
- // Prepend the default device to the list since we always want it to be
- // on the top of the list for all platforms. There is no duplicate
- // counting here since the default device has been abstracted out before.
- media::AudioDeviceName name;
- name.device_name = AudioManagerBase::kDefaultDeviceName;
- name.unique_id = AudioManagerBase::kDefaultDeviceId;
- device_names->push_front(name);
- }
+}
+
+void AudioManagerMac::GetAudioOutputDeviceNames(
+ media::AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
+ GetAudioDeviceInfo(false, device_names);
}
AudioParameters AudioManagerMac::GetInputStreamParameters(
@@ -443,21 +450,86 @@ AudioParameters AudioManagerMac::GetInputStreamParameters(
sample_rate, 16, buffer_size);
}
+std::string AudioManagerMac::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id);
+ if (device == kAudioObjectUnknown)
+ return std::string();
+
+ UInt32 size = 0;
+ AudioObjectPropertyAddress pa = {
+ kAudioDevicePropertyRelatedDevices,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+ OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size);
+ if (result || !size)
+ return std::string();
+
+ int device_count = size / sizeof(AudioDeviceID);
+ scoped_ptr_malloc<AudioDeviceID>
+ devices(reinterpret_cast<AudioDeviceID*>(malloc(size)));
+ result = AudioObjectGetPropertyData(
+ device, &pa, 0, NULL, &size, devices.get());
+ if (result)
+ return std::string();
+
+ for (int i = 0; i < device_count; ++i) {
+ // Get the number of output channels of the device.
+ pa.mSelector = kAudioDevicePropertyStreams;
+ size = 0;
+ result = AudioObjectGetPropertyDataSize(devices.get()[i],
+ &pa,
+ 0,
+ NULL,
+ &size);
+ if (result || !size)
+ continue; // Skip if there aren't any output channels.
+
+ // Get device UID.
+ CFStringRef uid = NULL;
+ size = sizeof(uid);
+ pa.mSelector = kAudioDevicePropertyDeviceUID;
+ result = AudioObjectGetPropertyData(devices.get()[i],
+ &pa,
+ 0,
+ NULL,
+ &size,
+ &uid);
+ if (result || !uid)
+ continue;
+
+ std::string ret(base::SysCFStringRefToUTF8(uid));
+ CFRelease(uid);
+ return ret;
+ }
+
+ // No matching device found.
+ return std::string();
+}
+
AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
const AudioParameters& params) {
- return MakeLowLatencyOutputStream(params, std::string());
+ return MakeLowLatencyOutputStream(params, std::string(), std::string());
}
AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
// Handle basic output with no input channels.
if (params.input_channels() == 0) {
- AudioDeviceID device = kAudioObjectUnknown;
- GetDefaultOutputDevice(&device);
+ AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id);
+ if (device == kAudioObjectUnknown) {
+ DLOG(ERROR) << "Failed to open output device: " << device_id;
+ return NULL;
+ }
return new AUHALStream(this, params, device);
}
- // TODO(crogers): support more than stereo input.
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
+
+ // TODO(xians): support more than stereo input.
if (params.input_channels() != 2) {
// WebAudio is currently hard-coded to 2 channels so we should not
// see this case.
@@ -494,7 +566,7 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
// different and arbitrary combinations of input and output devices
// even running at different sample-rates.
// kAudioDeviceUnknown translates to "use default" here.
- // TODO(crogers): consider tracking UMA stats on AUHALStream
+ // TODO(xians): consider tracking UMA stats on AUHALStream
// versus AudioSynchronizedStream.
AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, input_device_id);
if (audio_device_id == kAudioObjectUnknown)
@@ -506,6 +578,33 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
kAudioDeviceUnknown);
}
+std::string AudioManagerMac::GetDefaultOutputDeviceID() {
+ AudioDeviceID device_id = kAudioObjectUnknown;
+ if (!GetDefaultOutputDevice(&device_id))
+ return std::string();
+
+ const AudioObjectPropertyAddress property_address = {
+ kAudioDevicePropertyDeviceUID,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+ CFStringRef device_uid = NULL;
+ UInt32 size = sizeof(device_uid);
+ OSStatus status = AudioObjectGetPropertyData(device_id,
+ &property_address,
+ 0,
+ NULL,
+ &size,
+ &device_uid);
+ if (status != kAudioHardwareNoError || !device_uid)
+ return std::string();
+
+ std::string ret(base::SysCFStringRefToUTF8(device_uid));
+ CFRelease(device_uid);
+
+ return ret;
+}
+
AudioInputStream* AudioManagerMac::MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
@@ -515,27 +614,47 @@ AudioInputStream* AudioManagerMac::MakeLinearInputStream(
AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
- // Gets the AudioDeviceID that refers to the AudioOutputDevice with the device
+ // Gets the AudioDeviceID that refers to the AudioInputDevice with the device
// unique id. This AudioDeviceID is used to set the device for Audio Unit.
AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id);
AudioInputStream* stream = NULL;
- if (audio_device_id != kAudioObjectUnknown)
- stream = new AUAudioInputStream(this, params, audio_device_id);
+ if (audio_device_id != kAudioObjectUnknown) {
+ // AUAudioInputStream needs to be fed the preferred audio output parameters
+ // of the matching device so that the buffer size of both input and output
+ // can be matched. See constructor of AUAudioInputStream for more.
+ const std::string associated_output_device(
+ GetAssociatedOutputDeviceID(device_id));
+ const AudioParameters output_params =
+ GetPreferredOutputStreamParameters(
+ associated_output_device.empty() ?
+ AudioManagerBase::kDefaultDeviceId : associated_output_device,
+ params);
+ stream = new AUAudioInputStream(this, params, output_params,
+ audio_device_id);
+ }
return stream;
}
AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id);
+ if (device == kAudioObjectUnknown) {
+ DLOG(ERROR) << "Invalid output device " << output_device_id;
+ return AudioParameters();
+ }
+
int hardware_channels = 2;
- if (!GetDefaultOutputChannels(&hardware_channels)) {
+ if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput,
+ &hardware_channels)) {
// Fallback to stereo.
hardware_channels = 2;
}
ChannelLayout channel_layout = GuessChannelLayout(hardware_channels);
- const int hardware_sample_rate = AUAudioOutputStream::HardwareSampleRate();
+ const int hardware_sample_rate = HardwareSampleRateForDevice(device);
const int buffer_size = ChooseBufferSize(hardware_sample_rate);
int input_channels = 0;
@@ -543,7 +662,7 @@ AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
input_channels = input_params.input_channels();
if (input_channels > 0) {
- // TODO(crogers): given the limitations of the AudioOutputStream
+ // TODO(xians): given the limitations of the AudioOutputStream
// back-ends used with synchronized I/O, we hard-code to stereo.
// Specifically, this is a limitation of AudioSynchronizedStream which
// can be removed as part of the work to consolidate these back-ends.
diff --git a/chromium/media/audio/mac/audio_manager_mac.h b/chromium/media/audio/mac/audio_manager_mac.h
index cd3cc2e94b5..d162554b405 100644
--- a/chromium/media/audio/mac/audio_manager_mac.h
+++ b/chromium/media/audio/mac/audio_manager_mac.h
@@ -27,21 +27,27 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase {
// Implementation of AudioManager.
virtual bool HasAudioOutputDevices() OVERRIDE;
virtual bool HasAudioInputDevices() OVERRIDE;
- virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
- OVERRIDE;
+ virtual void GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
// Implementation of AudioManagerBase.
virtual AudioOutputStream* MakeLinearOutputStream(
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
virtual AudioInputStream* MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ virtual std::string GetDefaultOutputDeviceID() OVERRIDE;
static bool GetDefaultInputDevice(AudioDeviceID* device);
static bool GetDefaultOutputDevice(AudioDeviceID* device);
@@ -64,6 +70,7 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase {
virtual ~AudioManagerMac();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
diff --git a/chromium/media/audio/mock_audio_manager.cc b/chromium/media/audio/mock_audio_manager.cc
index 60898bd61b8..a164332a64a 100644
--- a/chromium/media/audio/mock_audio_manager.cc
+++ b/chromium/media/audio/mock_audio_manager.cc
@@ -33,18 +33,24 @@ void MockAudioManager::ShowAudioInputSettings() {
}
void MockAudioManager::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+ AudioDeviceNames* device_names) {
+}
+
+void MockAudioManager::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
}
media::AudioOutputStream* MockAudioManager::MakeAudioOutputStream(
- const media::AudioParameters& params,
- const std::string& input_device_id) {
+ const media::AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
NOTREACHED();
return NULL;
}
media::AudioOutputStream* MockAudioManager::MakeAudioOutputStreamProxy(
const media::AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
NOTREACHED();
return NULL;
@@ -77,9 +83,19 @@ AudioParameters MockAudioManager::GetDefaultOutputStreamParameters() {
return AudioParameters();
}
+AudioParameters MockAudioManager::GetOutputStreamParameters(
+ const std::string& device_id) {
+ return AudioParameters();
+}
+
AudioParameters MockAudioManager::GetInputStreamParameters(
const std::string& device_id) {
return AudioParameters();
}
+std::string MockAudioManager::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ return std::string();
+}
+
} // namespace media.
diff --git a/chromium/media/audio/mock_audio_manager.h b/chromium/media/audio/mock_audio_manager.h
index eee84b1643f..7bc30f578e7 100644
--- a/chromium/media/audio/mock_audio_manager.h
+++ b/chromium/media/audio/mock_audio_manager.h
@@ -34,12 +34,17 @@ class MockAudioManager : public media::AudioManager {
virtual void GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ media::AudioDeviceNames* device_names) OVERRIDE;
+
virtual media::AudioOutputStream* MakeAudioOutputStream(
const media::AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual media::AudioOutputStream* MakeAudioOutputStreamProxy(
const media::AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual media::AudioInputStream* MakeAudioInputStream(
@@ -55,8 +60,12 @@ class MockAudioManager : public media::AudioManager {
AudioDeviceListener* listener) OVERRIDE;
virtual AudioParameters GetDefaultOutputStreamParameters() OVERRIDE;
+ virtual AudioParameters GetOutputStreamParameters(
+ const std::string& device_id) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
private:
virtual ~MockAudioManager();
diff --git a/chromium/media/audio/openbsd/audio_manager_openbsd.cc b/chromium/media/audio/openbsd/audio_manager_openbsd.cc
index 4005aeb98f0..a97ea8f625e 100644
--- a/chromium/media/audio/openbsd/audio_manager_openbsd.cc
+++ b/chromium/media/audio/openbsd/audio_manager_openbsd.cc
@@ -92,7 +92,9 @@ AudioOutputStream* AudioManagerOpenBSD::MakeLinearOutputStream(
AudioOutputStream* AudioManagerOpenBSD::MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format);
return MakeOutputStream(params);
}
@@ -112,7 +114,10 @@ AudioInputStream* AudioManagerOpenBSD::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerOpenBSD::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 512;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
diff --git a/chromium/media/audio/openbsd/audio_manager_openbsd.h b/chromium/media/audio/openbsd/audio_manager_openbsd.h
index a1adcb6c86c..e4bb3948d28 100644
--- a/chromium/media/audio/openbsd/audio_manager_openbsd.h
+++ b/chromium/media/audio/openbsd/audio_manager_openbsd.h
@@ -27,6 +27,7 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -37,6 +38,7 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase {
virtual ~AudioManagerOpenBSD();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
diff --git a/chromium/media/audio/pulse/audio_manager_pulse.cc b/chromium/media/audio/pulse/audio_manager_pulse.cc
index dcdd3282228..5c09f149057 100644
--- a/chromium/media/audio/pulse/audio_manager_pulse.cc
+++ b/chromium/media/audio/pulse/audio_manager_pulse.cc
@@ -66,19 +66,13 @@ AudioManagerPulse::~AudioManagerPulse() {
// Implementation of AudioManager.
bool AudioManagerPulse::HasAudioOutputDevices() {
- DCHECK(input_mainloop_);
- DCHECK(input_context_);
- media::AudioDeviceNames devices;
- AutoPulseLock auto_lock(input_mainloop_);
- devices_ = &devices;
- pa_operation* operation = pa_context_get_sink_info_list(
- input_context_, OutputDevicesInfoCallback, this);
- WaitForOperationCompletion(input_mainloop_, operation);
+ AudioDeviceNames devices;
+ GetAudioOutputDeviceNames(&devices);
return !devices.empty();
}
bool AudioManagerPulse::HasAudioInputDevices() {
- media::AudioDeviceNames devices;
+ AudioDeviceNames devices;
GetAudioInputDeviceNames(&devices);
return !devices.empty();
}
@@ -87,18 +81,24 @@ void AudioManagerPulse::ShowAudioInputSettings() {
AudioManagerLinux::ShowLinuxAudioInputSettings();
}
-void AudioManagerPulse::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+void AudioManagerPulse::GetAudioDeviceNames(
+ bool input, media::AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
DCHECK(input_mainloop_);
DCHECK(input_context_);
AutoPulseLock auto_lock(input_mainloop_);
devices_ = device_names;
- pa_operation* operation = pa_context_get_source_info_list(
+ pa_operation* operation = NULL;
+ if (input) {
+ operation = pa_context_get_source_info_list(
input_context_, InputDevicesInfoCallback, this);
+ } else {
+ operation = pa_context_get_sink_info_list(
+ input_context_, OutputDevicesInfoCallback, this);
+ }
WaitForOperationCompletion(input_mainloop_, operation);
- // Append the default device on the top of the list if the list is not empty.
+ // Prepend the default device if the list is not empty.
if (!device_names->empty()) {
device_names->push_front(
AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
@@ -106,6 +106,16 @@ void AudioManagerPulse::GetAudioInputDeviceNames(
}
}
+void AudioManagerPulse::GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) {
+ GetAudioDeviceNames(true, device_names);
+}
+
+void AudioManagerPulse::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
+ GetAudioDeviceNames(false, device_names);
+}
+
AudioParameters AudioManagerPulse::GetInputStreamParameters(
const std::string& device_id) {
static const int kDefaultInputBufferSize = 1024;
@@ -123,7 +133,10 @@ AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream(
}
AudioOutputStream* AudioManagerPulse::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return MakeOutputStream(params, input_device_id);
}
@@ -141,7 +154,10 @@ AudioInputStream* AudioManagerPulse::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 512;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
@@ -286,8 +302,8 @@ void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
// Exclude the output devices.
if (info->monitor_of_sink == PA_INVALID_INDEX) {
- manager->devices_->push_back(media::AudioDeviceName(info->description,
- info->name));
+ manager->devices_->push_back(AudioDeviceName(info->description,
+ info->name));
}
}
@@ -302,8 +318,8 @@ void AudioManagerPulse::OutputDevicesInfoCallback(pa_context* context,
return;
}
- manager->devices_->push_back(media::AudioDeviceName(info->description,
- info->name));
+ manager->devices_->push_back(AudioDeviceName(info->description,
+ info->name));
}
void AudioManagerPulse::SampleRateInfoCallback(pa_context* context,
diff --git a/chromium/media/audio/pulse/audio_manager_pulse.h b/chromium/media/audio/pulse/audio_manager_pulse.h
index 6dfebaeff39..36396639929 100644
--- a/chromium/media/audio/pulse/audio_manager_pulse.h
+++ b/chromium/media/audio/pulse/audio_manager_pulse.h
@@ -25,8 +25,10 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
virtual bool HasAudioOutputDevices() OVERRIDE;
virtual bool HasAudioInputDevices() OVERRIDE;
virtual void ShowAudioInputSettings() OVERRIDE;
- virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
- OVERRIDE;
+ virtual void GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
@@ -35,6 +37,7 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -43,12 +46,15 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
protected:
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
bool Init();
void DestroyPulse();
+ void GetAudioDeviceNames(bool input, media::AudioDeviceNames* device_names);
+
// Callback to get the devices' info like names, used by GetInputDevices().
static void InputDevicesInfoCallback(pa_context* context,
const pa_source_info* info,
diff --git a/chromium/media/audio/shared_memory_util.cc b/chromium/media/audio/shared_memory_util.cc
index b65df03e2e1..523cdb9646c 100644
--- a/chromium/media/audio/shared_memory_util.cc
+++ b/chromium/media/audio/shared_memory_util.cc
@@ -4,6 +4,8 @@
#include "media/audio/shared_memory_util.h"
+#include <algorithm>
+
#include "base/atomicops.h"
#include "base/logging.h"
diff --git a/chromium/media/audio/test_audio_input_controller_factory.cc b/chromium/media/audio/test_audio_input_controller_factory.cc
index 64bfb9f060d..d146231a25d 100644
--- a/chromium/media/audio/test_audio_input_controller_factory.cc
+++ b/chromium/media/audio/test_audio_input_controller_factory.cc
@@ -12,8 +12,9 @@ TestAudioInputController::TestAudioInputController(
AudioManager* audio_manager,
const AudioParameters& audio_parameters,
EventHandler* event_handler,
- SyncWriter* sync_writer)
- : AudioInputController(event_handler, sync_writer),
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor)
+ : AudioInputController(event_handler, sync_writer, user_input_monitor),
audio_parameters_(audio_parameters),
factory_(factory),
event_handler_(event_handler) {
@@ -48,10 +49,11 @@ TestAudioInputControllerFactory::~TestAudioInputControllerFactory() {
AudioInputController* TestAudioInputControllerFactory::Create(
AudioManager* audio_manager,
AudioInputController::EventHandler* event_handler,
- AudioParameters params) {
+ AudioParameters params,
+ UserInputMonitor* user_input_monitor) {
DCHECK(!controller_); // Only one test instance managed at a time.
- controller_ = new TestAudioInputController(this, audio_manager, params,
- event_handler, NULL);
+ controller_ = new TestAudioInputController(
+ this, audio_manager, params, event_handler, NULL, user_input_monitor);
return controller_;
}
diff --git a/chromium/media/audio/test_audio_input_controller_factory.h b/chromium/media/audio/test_audio_input_controller_factory.h
index 0a179473c1c..4968c013d97 100644
--- a/chromium/media/audio/test_audio_input_controller_factory.h
+++ b/chromium/media/audio/test_audio_input_controller_factory.h
@@ -10,6 +10,7 @@
namespace media {
+class UserInputMonitor;
class TestAudioInputControllerFactory;
// TestAudioInputController and TestAudioInputControllerFactory are used for
@@ -56,7 +57,8 @@ class TestAudioInputController : public AudioInputController {
AudioManager* audio_manager,
const AudioParameters& audio_parameters,
EventHandler* event_handler,
- SyncWriter* sync_writer);
+ SyncWriter* sync_writer,
+ UserInputMonitor* user_input_monitor);
// Returns the event handler installed on the AudioInputController.
EventHandler* event_handler() const { return event_handler_; }
@@ -94,7 +96,8 @@ class TestAudioInputControllerFactory : public AudioInputController::Factory {
virtual AudioInputController* Create(
AudioManager* audio_manager,
AudioInputController::EventHandler* event_handler,
- AudioParameters params) OVERRIDE;
+ AudioParameters params,
+ UserInputMonitor* user_input_monitor) OVERRIDE;
void SetDelegateForTests(TestAudioInputControllerDelegate* delegate);
diff --git a/chromium/media/audio/win/audio_low_latency_input_win.cc b/chromium/media/audio/win/audio_low_latency_input_win.cc
index e0819439109..a174ea2ea0d 100644
--- a/chromium/media/audio/win/audio_low_latency_input_win.cc
+++ b/chromium/media/audio/win/audio_low_latency_input_win.cc
@@ -103,9 +103,8 @@ bool WASAPIAudioInputStream::Open() {
// Verify that the selected audio endpoint supports the specified format
// set during construction.
- if (!DesiredFormatIsSupported()) {
+ if (!DesiredFormatIsSupported())
return false;
- }
// Initialize the audio stream between the client and the device using
// shared mode and a lowest possible glitch-free latency.
@@ -141,6 +140,9 @@ void WASAPIAudioInputStream::Start(AudioInputCallback* callback) {
HRESULT hr = audio_client_->Start();
DLOG_IF(ERROR, FAILED(hr)) << "Failed to start input streaming.";
+ if (SUCCEEDED(hr) && audio_render_client_for_loopback_)
+ hr = audio_render_client_for_loopback_->Start();
+
started_ = SUCCEEDED(hr);
}
@@ -276,6 +278,10 @@ HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id,
// Retrieve the default capture audio endpoint.
hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
endpoint_device.Receive());
+ } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) {
+ // Capture the default playback stream.
+ hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
+ endpoint_device.Receive());
} else {
// Retrieve a capture endpoint device that is specified by an endpoint
// device-identification string.
@@ -454,42 +460,44 @@ void WASAPIAudioInputStream::HandleError(HRESULT err) {
HRESULT WASAPIAudioInputStream::SetCaptureDevice() {
ScopedComPtr<IMMDeviceEnumerator> enumerator;
- HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
- NULL,
- CLSCTX_INPROC_SERVER,
- __uuidof(IMMDeviceEnumerator),
- enumerator.ReceiveVoid());
- if (SUCCEEDED(hr)) {
- // Retrieve the IMMDevice by using the specified role or the specified
- // unique endpoint device-identification string.
- // TODO(henrika): possibly add support for the eCommunications as well.
- if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
- // Retrieve the default capture audio endpoint for the specified role.
- // Note that, in Windows Vista, the MMDevice API supports device roles
- // but the system-supplied user interface programs do not.
- hr = enumerator->GetDefaultAudioEndpoint(eCapture,
- eConsole,
- endpoint_device_.Receive());
- } else {
- // Retrieve a capture endpoint device that is specified by an endpoint
- // device-identification string.
- hr = enumerator->GetDevice(UTF8ToUTF16(device_id_).c_str(),
- endpoint_device_.Receive());
- }
+ HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
+ NULL, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr))
+ return hr;
- if (FAILED(hr))
- return hr;
+ // Retrieve the IMMDevice by using the specified role or the specified
+ // unique endpoint device-identification string.
+ // TODO(henrika): possibly add support for the eCommunications as well.
+ if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
+ // Retrieve the default capture audio endpoint for the specified role.
+ // Note that, in Windows Vista, the MMDevice API supports device roles
+ // but the system-supplied user interface programs do not.
+ hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
+ endpoint_device_.Receive());
+ } else if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) {
+ // Capture the default playback stream.
+ hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
+ endpoint_device_.Receive());
+ } else {
+ // Retrieve a capture endpoint device that is specified by an endpoint
+ // device-identification string.
+ hr = enumerator->GetDevice(UTF8ToUTF16(device_id_).c_str(),
+ endpoint_device_.Receive());
+ }
- // Verify that the audio endpoint device is active, i.e., the audio
- // adapter that connects to the endpoint device is present and enabled.
- DWORD state = DEVICE_STATE_DISABLED;
- hr = endpoint_device_->GetState(&state);
- if (SUCCEEDED(hr)) {
- if (!(state & DEVICE_STATE_ACTIVE)) {
- DLOG(ERROR) << "Selected capture device is not active.";
- hr = E_ACCESSDENIED;
- }
- }
+ if (FAILED(hr))
+ return hr;
+
+ // Verify that the audio endpoint device is active, i.e., the audio
+ // adapter that connects to the endpoint device is present and enabled.
+ DWORD state = DEVICE_STATE_DISABLED;
+ hr = endpoint_device_->GetState(&state);
+ if (FAILED(hr))
+ return hr;
+
+ if (!(state & DEVICE_STATE_ACTIVE)) {
+ DLOG(ERROR) << "Selected capture device is not active.";
+ hr = E_ACCESSDENIED;
}
return hr;
@@ -565,16 +573,25 @@ bool WASAPIAudioInputStream::DesiredFormatIsSupported() {
}
HRESULT WASAPIAudioInputStream::InitializeAudioEngine() {
+ DWORD flags;
+ // Use event-driven mode only fo regular input devices. For loopback the
+ // EVENTCALLBACK flag is specified when intializing
+ // |audio_render_client_for_loopback_|.
+ if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) {
+ flags = AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_NOPERSIST;
+ } else {
+ flags =
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST;
+ }
+
// Initialize the audio stream between the client and the device.
- // We connect indirectly through the audio engine by using shared mode
- // and WASAPI is initialized in an event driven mode.
+ // We connect indirectly through the audio engine by using shared mode.
// Note that, |hnsBufferDuration| is set of 0, which ensures that the
// buffer is never smaller than the minimum buffer size needed to ensure
// that glitches do not occur between the periodic processing passes.
// This setting should lead to lowest possible latency.
HRESULT hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
- AUDCLNT_STREAMFLAGS_NOPERSIST,
+ flags,
0, // hnsBufferDuration
0,
&format_,
@@ -590,6 +607,7 @@ HRESULT WASAPIAudioInputStream::InitializeAudioEngine() {
hr = audio_client_->GetBufferSize(&endpoint_buffer_size_frames_);
if (FAILED(hr))
return hr;
+
DVLOG(1) << "endpoint buffer size: " << endpoint_buffer_size_frames_
<< " [frames]";
@@ -618,9 +636,41 @@ HRESULT WASAPIAudioInputStream::InitializeAudioEngine() {
}
#endif
- // Set the event handle that the audio engine will signal each time
- // a buffer becomes ready to be processed by the client.
- hr = audio_client_->SetEventHandle(audio_samples_ready_event_.Get());
+ // Set the event handle that the audio engine will signal each time a buffer
+ // becomes ready to be processed by the client.
+ //
+ // In loopback case the capture device doesn't receive any events, so we
+ // need to create a separate playback client to get notifications. According
+ // to MSDN:
+ //
+ // A pull-mode capture client does not receive any events when a stream is
+ // initialized with event-driven buffering and is loopback-enabled. To
+ // work around this, initialize a render stream in event-driven mode. Each
+ // time the client receives an event for the render stream, it must signal
+ // the capture client to run the capture thread that reads the next set of
+ // samples from the capture endpoint buffer.
+ //
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/dd316551(v=vs.85).aspx
+ if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) {
+ hr = endpoint_device_->Activate(
+ __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
+ audio_render_client_for_loopback_.ReceiveVoid());
+ if (FAILED(hr))
+ return hr;
+
+ hr = audio_render_client_for_loopback_->Initialize(
+ AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
+ 0, 0, &format_, NULL);
+ if (FAILED(hr))
+ return hr;
+
+ hr = audio_render_client_for_loopback_->SetEventHandle(
+ audio_samples_ready_event_.Get());
+ } else {
+ hr = audio_client_->SetEventHandle(audio_samples_ready_event_.Get());
+ }
+
if (FAILED(hr))
return hr;
diff --git a/chromium/media/audio/win/audio_low_latency_input_win.h b/chromium/media/audio/win/audio_low_latency_input_win.h
index 4f9c7fb6c88..99e1604925a 100644
--- a/chromium/media/audio/win/audio_low_latency_input_win.h
+++ b/chromium/media/audio/win/audio_low_latency_input_win.h
@@ -184,6 +184,14 @@ class MEDIA_EXPORT WASAPIAudioInputStream
// an audio stream between an audio application and the audio engine.
base::win::ScopedComPtr<IAudioClient> audio_client_;
+ // Loopback IAudioClient doesn't support event-driven mode, so a separate
+ // IAudioClient is needed to receive notifications when data is available in
+ // the buffer. For loopback input |audio_client_| is used to receive data,
+ // while |audio_render_client_for_loopback_| is used to get notifications
+ // when a new buffer is ready. See comment in InitializeAudioEngine() for
+ // details.
+ base::win::ScopedComPtr<IAudioClient> audio_render_client_for_loopback_;
+
// The IAudioCaptureClient interface enables a client to read input data
// from a capture endpoint buffer.
base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_;
diff --git a/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc b/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc
index 40990ec13d4..11fad25d3fe 100644
--- a/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc
+++ b/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc
@@ -39,12 +39,53 @@ ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop) {
class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
public:
MOCK_METHOD5(OnData, void(AudioInputStream* stream,
- const uint8* src, uint32 size,
- uint32 hardware_delay_bytes, double volume));
+ const uint8* src, uint32 size,
+ uint32 hardware_delay_bytes, double volume));
MOCK_METHOD1(OnClose, void(AudioInputStream* stream));
MOCK_METHOD1(OnError, void(AudioInputStream* stream));
};
+class FakeAudioInputCallback : public AudioInputStream::AudioInputCallback {
+ public:
+ FakeAudioInputCallback()
+ : closed_(false),
+ error_(false),
+ data_event_(false, false) {
+ }
+
+ const std::vector<uint8>& received_data() const { return received_data_; }
+ bool closed() const { return closed_; }
+ bool error() const { return error_; }
+
+ // Waits until OnData() is called on another thread.
+ void WaitForData() {
+ data_event_.Wait();
+ }
+
+ virtual void OnData(AudioInputStream* stream,
+ const uint8* src, uint32 size,
+ uint32 hardware_delay_bytes, double volume) OVERRIDE {
+ received_data_.insert(received_data_.end(), src, src + size);
+ data_event_.Signal();
+ }
+
+ virtual void OnClose(AudioInputStream* stream) OVERRIDE {
+ closed_ = true;
+ }
+
+ virtual void OnError(AudioInputStream* stream) OVERRIDE {
+ error_ = true;
+ }
+
+ private:
+ std::vector<uint8> received_data_;
+ base::WaitableEvent data_event_;
+ bool closed_;
+ bool error_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeAudioInputCallback);
+};
+
// This audio sink implementation should be used for manual tests only since
// the recorded data is stored on a raw binary data file.
class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
@@ -188,6 +229,39 @@ static AudioInputStream* CreateDefaultAudioInputStream(
return ais;
}
+class ScopedAudioInputStream {
+ public:
+ explicit ScopedAudioInputStream(AudioInputStream* stream)
+ : stream_(stream) {}
+
+ ~ScopedAudioInputStream() {
+ if (stream_)
+ stream_->Close();
+ }
+
+ void Close() {
+ if (stream_)
+ stream_->Close();
+ stream_ = NULL;
+ }
+
+ AudioInputStream* operator->() {
+ return stream_;
+ }
+
+ AudioInputStream* get() const { return stream_; }
+
+ void Reset(AudioInputStream* new_stream) {
+ Close();
+ stream_ = new_stream;
+ }
+
+ private:
+ AudioInputStream* stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAudioInputStream);
+};
+
// Verify that we can retrieve the current hardware/mixing sample rate
// for all available input devices.
TEST(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) {
@@ -217,8 +291,9 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!CanRunAudioTests(audio_manager.get()))
return;
- AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
- ais->Close();
+ ScopedAudioInputStream ais(
+ CreateDefaultAudioInputStream(audio_manager.get()));
+ ais.Close();
}
// Test Open(), Close() calling sequence.
@@ -226,9 +301,10 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!CanRunAudioTests(audio_manager.get()))
return;
- AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
+ ScopedAudioInputStream ais(
+ CreateDefaultAudioInputStream(audio_manager.get()));
EXPECT_TRUE(ais->Open());
- ais->Close();
+ ais.Close();
}
// Test Open(), Start(), Close() calling sequence.
@@ -236,13 +312,14 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!CanRunAudioTests(audio_manager.get()))
return;
- AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
+ ScopedAudioInputStream ais(
+ CreateDefaultAudioInputStream(audio_manager.get()));
EXPECT_TRUE(ais->Open());
MockAudioInputCallback sink;
ais->Start(&sink);
- EXPECT_CALL(sink, OnClose(ais))
+ EXPECT_CALL(sink, OnClose(ais.get()))
.Times(1);
- ais->Close();
+ ais.Close();
}
// Test Open(), Start(), Stop(), Close() calling sequence.
@@ -250,14 +327,15 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!CanRunAudioTests(audio_manager.get()))
return;
- AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
+ ScopedAudioInputStream ais(
+ CreateDefaultAudioInputStream(audio_manager.get()));
EXPECT_TRUE(ais->Open());
MockAudioInputCallback sink;
ais->Start(&sink);
ais->Stop();
- EXPECT_CALL(sink, OnClose(ais))
+ EXPECT_CALL(sink, OnClose(ais.get()))
.Times(1);
- ais->Close();
+ ais.Close();
}
// Test some additional calling sequences.
@@ -265,8 +343,10 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) {
scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
if (!CanRunAudioTests(audio_manager.get()))
return;
- AudioInputStream* ais = CreateDefaultAudioInputStream(audio_manager.get());
- WASAPIAudioInputStream* wais = static_cast<WASAPIAudioInputStream*>(ais);
+ ScopedAudioInputStream ais(
+ CreateDefaultAudioInputStream(audio_manager.get()));
+ WASAPIAudioInputStream* wais =
+ static_cast<WASAPIAudioInputStream*>(ais.get());
// Open(), Open() should fail the second time.
EXPECT_TRUE(ais->Open());
@@ -286,9 +366,9 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) {
ais->Stop();
EXPECT_FALSE(wais->started());
- EXPECT_CALL(sink, OnClose(ais))
+ EXPECT_CALL(sink, OnClose(ais.get()))
.Times(1);
- ais->Close();
+ ais.Close();
}
TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
@@ -304,7 +384,7 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
// Create default WASAPI input stream which records in stereo using
// the shared mixing rate. The default buffer size is 10ms.
AudioInputStreamWrapper aisw(audio_manager.get());
- AudioInputStream* ais = aisw.Create();
+ ScopedAudioInputStream ais(aisw.Create());
EXPECT_TRUE(ais->Open());
MockAudioInputCallback sink;
@@ -317,7 +397,7 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
// All should contain valid packets of the same size and a valid delay
// estimate.
EXPECT_CALL(sink, OnData(
- ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
+ ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
.Times(AtLeast(10))
.WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
ais->Start(&sink);
@@ -327,49 +407,78 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
// Store current packet size (to be used in the subsequent tests).
int samples_per_packet_10ms = aisw.samples_per_packet();
- EXPECT_CALL(sink, OnClose(ais))
+ EXPECT_CALL(sink, OnClose(ais.get()))
.Times(1);
- ais->Close();
+ ais.Close();
// 20 ms packet size.
count = 0;
- ais = aisw.Create(2 * samples_per_packet_10ms);
+ ais.Reset(aisw.Create(2 * samples_per_packet_10ms));
EXPECT_TRUE(ais->Open());
bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
(aisw.bits_per_sample() / 8);
EXPECT_CALL(sink, OnData(
- ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
+ ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
.Times(AtLeast(10))
.WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
ais->Start(&sink);
loop.Run();
ais->Stop();
- EXPECT_CALL(sink, OnClose(ais))
+ EXPECT_CALL(sink, OnClose(ais.get()))
.Times(1);
- ais->Close();
+ ais.Close();
// 5 ms packet size.
count = 0;
- ais = aisw.Create(samples_per_packet_10ms / 2);
+ ais.Reset(aisw.Create(samples_per_packet_10ms / 2));
EXPECT_TRUE(ais->Open());
bytes_per_packet = aisw.channels() * aisw.samples_per_packet() *
(aisw.bits_per_sample() / 8);
EXPECT_CALL(sink, OnData(
- ais, NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
+ ais.get(), NotNull(), bytes_per_packet, Gt(bytes_per_packet), _))
.Times(AtLeast(10))
.WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &loop));
ais->Start(&sink);
loop.Run();
ais->Stop();
- EXPECT_CALL(sink, OnClose(ais))
+ EXPECT_CALL(sink, OnClose(ais.get()))
.Times(1);
- ais->Close();
+ ais.Close();
+}
+
+// Test that we can capture loopback stream.
+TEST(WinAudioInputTest, WASAPIAudioInputStreamLoopback) {
+ scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
+ if (!audio_manager->HasAudioOutputDevices() || !CoreAudioUtil::IsSupported())
+ return;
+
+ AudioParameters params = audio_manager->GetInputStreamParameters(
+ AudioManagerBase::kLoopbackInputDeviceId);
+
+ AudioParameters output_params =
+ audio_manager->GetOutputStreamParameters(std::string());
+ EXPECT_EQ(params.sample_rate(), output_params.sample_rate());
+ EXPECT_EQ(params.channel_layout(), output_params.channel_layout());
+
+ ScopedAudioInputStream stream(audio_manager->MakeAudioInputStream(
+ params, AudioManagerBase::kLoopbackInputDeviceId));
+ ASSERT_TRUE(stream->Open());
+ FakeAudioInputCallback sink;
+ stream->Start(&sink);
+ ASSERT_FALSE(sink.error());
+
+ sink.WaitForData();
+ stream.Close();
+
+ EXPECT_FALSE(sink.received_data().empty());
+ EXPECT_TRUE(sink.closed());
+ EXPECT_FALSE(sink.error());
}
// This test is intended for manual tests and should only be enabled
@@ -389,7 +498,7 @@ TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
const char* file_name = "out_stereo_10sec.pcm";
AudioInputStreamWrapper aisw(audio_manager.get());
- AudioInputStream* ais = aisw.Create();
+ ScopedAudioInputStream ais(aisw.Create());
EXPECT_TRUE(ais->Open());
LOG(INFO) << ">> Sample rate: " << aisw.sample_rate() << " [Hz]";
@@ -399,7 +508,7 @@ TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
base::PlatformThread::Sleep(TestTimeouts::action_timeout());
ais->Stop();
LOG(INFO) << ">> Recording has stopped.";
- ais->Close();
+ ais.Close();
}
} // namespace media
diff --git a/chromium/media/audio/win/audio_low_latency_output_win.cc b/chromium/media/audio/win/audio_low_latency_output_win.cc
index b2098b02094..c889c03ef2c 100644
--- a/chromium/media/audio/win/audio_low_latency_output_win.cc
+++ b/chromium/media/audio/win/audio_low_latency_output_win.cc
@@ -111,14 +111,26 @@ ChannelLayout WASAPIAudioOutputStream::HardwareChannelLayout() {
}
// static
-int WASAPIAudioOutputStream::HardwareSampleRate() {
+int WASAPIAudioOutputStream::HardwareSampleRate(const std::string& device_id) {
WAVEFORMATPCMEX format;
- return SUCCEEDED(CoreAudioUtil::GetDefaultSharedModeMixFormat(
- eRender, eConsole, &format)) ?
- static_cast<int>(format.Format.nSamplesPerSec) : 0;
+ ScopedComPtr<IAudioClient> client;
+ if (device_id.empty()) {
+ client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
+ } else {
+ ScopedComPtr<IMMDevice> device(CoreAudioUtil::CreateDevice(device_id));
+ if (!device)
+ return 0;
+ client = CoreAudioUtil::CreateClient(device);
+ }
+
+ if (!client || FAILED(CoreAudioUtil::GetSharedModeMixFormat(client, &format)))
+ return 0;
+
+ return static_cast<int>(format.Format.nSamplesPerSec);
}
WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
+ const std::string& device_id,
const AudioParameters& params,
ERole device_role)
: creating_thread_id_(base::PlatformThread::CurrentId()),
@@ -127,6 +139,7 @@ WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
audio_parameters_are_valid_(false),
volume_(1.0),
endpoint_buffer_size_frames_(0),
+ device_id_(device_id),
device_role_(device_role),
share_mode_(GetShareMode()),
num_written_frames_(0),
@@ -142,12 +155,16 @@ WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
// channel count are excluded) to the preferred (native) audio parameters.
// Open() will fail if this is not the case.
AudioParameters preferred_params;
- HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
- eRender, device_role, &preferred_params);
+ HRESULT hr = device_id_.empty() ?
+ CoreAudioUtil::GetPreferredAudioParameters(eRender, device_role,
+ &preferred_params) :
+ CoreAudioUtil::GetPreferredAudioParameters(device_id_,
+ &preferred_params);
audio_parameters_are_valid_ = SUCCEEDED(hr) &&
CompareAudioParametersNoBitDepthOrChannels(params, preferred_params);
LOG_IF(WARNING, !audio_parameters_are_valid_)
- << "Input and preferred parameters are not identical.";
+ << "Input and preferred parameters are not identical. "
+ << "Device id: " << device_id_;
}
// Load the Avrt DLL if not already loaded. Required to support MMCSS.
@@ -203,7 +220,6 @@ bool WASAPIAudioOutputStream::Open() {
if (opened_)
return true;
-
// Audio parameters must be identical to the preferred set of parameters
// if shared mode (default) is utilized.
if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
@@ -214,8 +230,16 @@ bool WASAPIAudioOutputStream::Open() {
}
// Create an IAudioClient interface for the default rendering IMMDevice.
- ScopedComPtr<IAudioClient> audio_client =
- CoreAudioUtil::CreateDefaultClient(eRender, device_role_);
+ ScopedComPtr<IAudioClient> audio_client;
+ if (device_id_.empty()) {
+ audio_client = CoreAudioUtil::CreateDefaultClient(eRender, device_role_);
+ } else {
+ ScopedComPtr<IMMDevice> device(CoreAudioUtil::CreateDevice(device_id_));
+ DLOG_IF(ERROR, !device) << "Failed to open device: " << device_id_;
+ if (device)
+ audio_client = CoreAudioUtil::CreateClient(device);
+ }
+
if (!audio_client)
return false;
diff --git a/chromium/media/audio/win/audio_low_latency_output_win.h b/chromium/media/audio/win/audio_low_latency_output_win.h
index b0e990bb1a4..7884d8840f7 100644
--- a/chromium/media/audio/win/audio_low_latency_output_win.h
+++ b/chromium/media/audio/win/audio_low_latency_output_win.h
@@ -122,6 +122,7 @@ class MEDIA_EXPORT WASAPIAudioOutputStream :
// The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object.
WASAPIAudioOutputStream(AudioManagerWin* manager,
+ const std::string& device_id,
const AudioParameters& params,
ERole device_role);
@@ -149,8 +150,9 @@ class MEDIA_EXPORT WASAPIAudioOutputStream :
static ChannelLayout HardwareChannelLayout();
// Retrieves the sample rate the audio engine uses for its internal
- // processing/mixing of shared-mode streams for the default endpoint device.
- static int HardwareSampleRate();
+ // processing/mixing of shared-mode streams. To fetch the settings for the
+ // default device, pass an empty string as the |device_id|.
+ static int HardwareSampleRate(const std::string& device_id);
// Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used
// as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default).
@@ -219,6 +221,9 @@ class MEDIA_EXPORT WASAPIAudioOutputStream :
// Length of the audio endpoint buffer.
uint32 endpoint_buffer_size_frames_;
+ // The target device id or an empty string for the default device.
+ const std::string device_id_;
+
// Defines the role that the system has assigned to an audio endpoint device.
ERole device_role_;
diff --git a/chromium/media/audio/win/audio_low_latency_output_win_unittest.cc b/chromium/media/audio/win/audio_low_latency_output_win_unittest.cc
index 8c3e366c0cc..1f78facf91d 100644
--- a/chromium/media/audio/win/audio_low_latency_output_win_unittest.cc
+++ b/chromium/media/audio/win/audio_low_latency_output_win_unittest.cc
@@ -234,7 +234,7 @@ class AudioOutputStreamWrapper {
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(
AudioParameters(format_, channel_layout_, sample_rate_,
bits_per_sample_, samples_per_packet_),
- std::string());
+ std::string(), std::string());
EXPECT_TRUE(aos);
return aos;
}
@@ -268,7 +268,7 @@ TEST(WASAPIAudioOutputStreamTest, HardwareSampleRate) {
// Default device intended for games, system notification sounds,
// and voice commands.
int fs = static_cast<int>(
- WASAPIAudioOutputStream::HardwareSampleRate());
+ WASAPIAudioOutputStream::HardwareSampleRate(std::string()));
EXPECT_GE(fs, 0);
}
diff --git a/chromium/media/audio/win/audio_manager_win.cc b/chromium/media/audio/win/audio_manager_win.cc
index a753e554cb4..0352e6677d2 100644
--- a/chromium/media/audio/win/audio_manager_win.cc
+++ b/chromium/media/audio/win/audio_manager_win.cc
@@ -240,27 +240,44 @@ void AudioManagerWin::ShowAudioInputSettings() {
base::LaunchProcess(command_line, base::LaunchOptions(), NULL);
}
-void AudioManagerWin::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+void AudioManagerWin::GetAudioDeviceNamesImpl(
+ bool input,
+ AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
DCHECK(enumeration_type() != kUninitializedEnumeration);
// Enumerate all active audio-endpoint capture devices.
if (enumeration_type() == kWaveEnumeration) {
// Utilize the Wave API for Windows XP.
- media::GetInputDeviceNamesWinXP(device_names);
+ if (input)
+ GetInputDeviceNamesWinXP(device_names);
+ else
+ GetOutputDeviceNamesWinXP(device_names);
} else {
// Utilize the MMDevice API (part of Core Audio) for Vista and higher.
- media::GetInputDeviceNamesWin(device_names);
+ if (input)
+ GetInputDeviceNamesWin(device_names);
+ else
+ GetOutputDeviceNamesWin(device_names);
}
// Always add default device parameters as first element.
if (!device_names->empty()) {
- media::AudioDeviceName name;
+ AudioDeviceName name;
name.device_name = AudioManagerBase::kDefaultDeviceName;
name.unique_id = AudioManagerBase::kDefaultDeviceId;
device_names->push_front(name);
}
}
+void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) {
+ GetAudioDeviceNamesImpl(true, device_names);
+}
+
+void AudioManagerWin::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
+ GetAudioDeviceNamesImpl(false, device_names);
+}
+
AudioParameters AudioManagerWin::GetInputStreamParameters(
const std::string& device_id) {
int sample_rate = 48000;
@@ -280,6 +297,16 @@ AudioParameters AudioManagerWin::GetInputStreamParameters(
sample_rate, 16, kFallbackBufferSize);
}
+std::string AudioManagerWin::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ if (!CoreAudioUtil::IsSupported()) {
+ NOTIMPLEMENTED()
+ << "GetAssociatedOutputDeviceID is not supported on this OS";
+ return std::string();
+ }
+ return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id);
+}
+
// Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR
// mode.
// - PCMWaveOutAudioOutputStream: Based on the waveOut API.
@@ -291,7 +318,7 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream(
return new PCMWaveOutAudioOutputStream(this,
params,
- media::NumberOfWaveOutBuffers(),
+ NumberOfWaveOutBuffers(),
WAVE_MAPPER);
}
@@ -301,25 +328,31 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream(
// - PCMWaveOutAudioOutputStream: Based on the waveOut API.
// - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API.
AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
if (params.channels() > kWinMaxChannels)
return NULL;
if (!CoreAudioUtil::IsSupported()) {
// Fall back to Windows Wave implementation on Windows XP or lower.
+ DLOG_IF(ERROR, !device_id.empty())
+ << "Opening by device id not supported by PCMWaveOutAudioOutputStream";
DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista.";
return new PCMWaveOutAudioOutputStream(
- this, params, media::NumberOfWaveOutBuffers(), WAVE_MAPPER);
+ this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER);
}
- // TODO(crogers): support more than stereo input.
+ // TODO(rtoy): support more than stereo input.
if (params.input_channels() > 0) {
DVLOG(1) << "WASAPIUnifiedStream is created.";
+ DLOG_IF(ERROR, !device_id.empty())
+ << "Opening by device id not supported by WASAPIUnifiedStream";
return new WASAPIUnifiedStream(this, params, input_device_id);
}
- return new WASAPIAudioOutputStream(this, params, eConsole);
+ return new WASAPIAudioOutputStream(this, device_id, params, eConsole);
}
// Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR
@@ -347,55 +380,68 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream(
return stream;
}
+std::string AudioManagerWin::GetDefaultOutputDeviceID() {
+ if (!CoreAudioUtil::IsSupported())
+ return std::string();
+ return CoreAudioUtil::GetDefaultOutputDeviceID();
+}
+
AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ const bool core_audio_supported = CoreAudioUtil::IsSupported();
+ DLOG_IF(ERROR, !core_audio_supported && !output_device_id.empty())
+ << "CoreAudio is required to open non-default devices.";
+
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = 48000;
int buffer_size = kFallbackBufferSize;
int bits_per_sample = 16;
int input_channels = 0;
- bool use_input_params = !CoreAudioUtil::IsSupported();
- if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
- // TODO(crogers): tune these values for best possible WebAudio performance.
- // WebRTC works well at 48kHz and a buffer size of 480 samples will be used
- // for this case. Note that exclusive mode is experimental.
- // This sample rate will be combined with a buffer size of 256 samples,
- // which corresponds to an output delay of ~5.33ms.
- sample_rate = 48000;
- buffer_size = 256;
- if (input_params.IsValid())
- channel_layout = input_params.channel_layout();
- } else if (!use_input_params) {
- // Hardware sample-rate on Windows can be configured, so we must query.
- // TODO(henrika): improve possibility to specify an audio endpoint.
- // Use the default device (same as for Wave) for now to be compatible.
- int hw_sample_rate = WASAPIAudioOutputStream::HardwareSampleRate();
-
- AudioParameters params;
- HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole,
- &params);
- int hw_buffer_size =
- FAILED(hr) ? kFallbackBufferSize : params.frames_per_buffer();
- channel_layout = WASAPIAudioOutputStream::HardwareChannelLayout();
-
- // TODO(henrika): Figure out the right thing to do here.
- if (hw_sample_rate && hw_buffer_size) {
- sample_rate = hw_sample_rate;
- buffer_size = hw_buffer_size;
+ bool use_input_params = !core_audio_supported;
+ if (core_audio_supported) {
+ if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
+ // TODO(rtoy): tune these values for best possible WebAudio
+ // performance. WebRTC works well at 48kHz and a buffer size of 480
+ // samples will be used for this case. Note that exclusive mode is
+ // experimental. This sample rate will be combined with a buffer size of
+ // 256 samples, which corresponds to an output delay of ~5.33ms.
+ sample_rate = 48000;
+ buffer_size = 256;
+ if (input_params.IsValid())
+ channel_layout = input_params.channel_layout();
} else {
- use_input_params = true;
+ AudioParameters params;
+ HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
+ output_device_id.empty() ?
+ GetDefaultOutputDeviceID() : output_device_id,
+ &params);
+ if (SUCCEEDED(hr)) {
+ bits_per_sample = params.bits_per_sample();
+ buffer_size = params.frames_per_buffer();
+ channel_layout = params.channel_layout();
+ sample_rate = params.sample_rate();
+ } else {
+ use_input_params = true;
+ }
}
}
if (input_params.IsValid()) {
- if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) &&
- CoreAudioUtil::IsSupported()) {
+ if (core_audio_supported &&
+ cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts)) {
// Check if it is possible to open up at the specified input channel
// layout but avoid checking if the specified layout is the same as the
// hardware (preferred) layout. We do this extra check to avoid the
// CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases.
if (input_params.channel_layout() != channel_layout) {
+ // TODO(henrika): Use |output_device_id| here.
+ // Internally, IsChannelLayoutSupported does many of the operations
+ // that have already been done such as opening up a client and fetching
+ // the WAVEFORMATPCMEX format. Ideally we should only do that once and
+ // do it for the requested device. Then here, we can check the layout
+ // from the data we already hold.
if (CoreAudioUtil::IsChannelLayoutSupported(
eRender, eConsole, input_params.channel_layout())) {
// Open up using the same channel layout as the source if it is
@@ -413,10 +459,10 @@ AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
// equal to the input values, AudioOutputResampler will skip resampling
// and bit per sample differences (since the input parameters will match
// the output parameters).
- sample_rate = input_params.sample_rate();
bits_per_sample = input_params.bits_per_sample();
- channel_layout = input_params.channel_layout();
buffer_size = input_params.frames_per_buffer();
+ channel_layout = input_params.channel_layout();
+ sample_rate = input_params.sample_rate();
}
}
@@ -435,7 +481,7 @@ AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream(
std::string xp_device_id = device_id;
if (device_id != AudioManagerBase::kDefaultDeviceId &&
enumeration_type_ == kMMDeviceEnumeration) {
- xp_device_id = media::ConvertToWinXPDeviceId(device_id);
+ xp_device_id = ConvertToWinXPInputDeviceId(device_id);
if (xp_device_id.empty()) {
DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID "
<< device_id;
diff --git a/chromium/media/audio/win/audio_manager_win.h b/chromium/media/audio/win/audio_manager_win.h
index 65cc73bbd6e..86e22badc5f 100644
--- a/chromium/media/audio/win/audio_manager_win.h
+++ b/chromium/media/audio/win/audio_manager_win.h
@@ -25,26 +25,33 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase {
virtual bool HasAudioInputDevices() OVERRIDE;
virtual string16 GetAudioInputDeviceModel() OVERRIDE;
virtual void ShowAudioInputSettings() OVERRIDE;
- virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
- OVERRIDE;
+ virtual void GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
// Implementation of AudioManagerBase.
virtual AudioOutputStream* MakeLinearOutputStream(
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
virtual AudioInputStream* MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ virtual std::string GetDefaultOutputDeviceID() OVERRIDE;
protected:
virtual ~AudioManagerWin();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
@@ -55,7 +62,7 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase {
};
// Allow unit test to modify the utilized enumeration API.
- friend class AudioInputDeviceTest;
+ friend class AudioManagerTest;
EnumerationType enumeration_type_;
EnumerationType enumeration_type() { return enumeration_type_; }
@@ -76,6 +83,8 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase {
void CreateDeviceListener();
void DestroyDeviceListener();
+ void GetAudioDeviceNamesImpl(bool input, AudioDeviceNames* device_names);
+
// Listen for output device changes.
scoped_ptr<AudioDeviceListenerWin> output_device_listener_;
diff --git a/chromium/media/audio/win/audio_output_win_unittest.cc b/chromium/media/audio/win/audio_output_win_unittest.cc
index 4e13d84f3d6..7ce146b0ab4 100644
--- a/chromium/media/audio/win/audio_output_win_unittest.cc
+++ b/chromium/media/audio/win/audio_output_win_unittest.cc
@@ -185,7 +185,7 @@ TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 256),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
oas->Close();
}
@@ -201,29 +201,29 @@ TEST(WinAudioTest, SanityOnMakeParams) {
AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
media::limits::kMaxSamplesPerPacket + 1),
- std::string()));
+ std::string(), std::string()));
}
// Test that it can be opened and closed.
@@ -237,7 +237,7 @@ TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 256),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open());
oas->Close();
@@ -254,7 +254,7 @@ TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 1024 * 1024 * 1024),
- std::string());
+ std::string(), std::string());
EXPECT_TRUE(NULL == oas);
if (oas)
oas->Close();
@@ -273,7 +273,7 @@ TEST(WinAudioTest, PCMWaveSlowSource) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
16000, 16, 256),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
TestSourceLaggy test_laggy(2, 90);
EXPECT_TRUE(oas->Open());
@@ -302,7 +302,7 @@ TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
@@ -333,7 +333,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
@@ -362,7 +362,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate / 2, 16,
samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
@@ -402,7 +402,7 @@ TEST(WinAudioTest, PushSourceFile16KHz) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
kSampleRate, 16, kSamples100ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open());
@@ -439,7 +439,7 @@ TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
@@ -486,7 +486,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
CHANNEL_LAYOUT_MONO, sample_rate,
16, n * samples_10_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200, sample_rate);
@@ -520,7 +520,7 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
NiceMock<MockAudioSource> source;
@@ -680,7 +680,7 @@ TEST(WinAudioTest, SyncSocketBasic) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params,
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
ASSERT_TRUE(oas->Open());
diff --git a/chromium/media/audio/win/audio_unified_win_unittest.cc b/chromium/media/audio/win/audio_unified_win_unittest.cc
index cfd17aea14f..011c36348b5 100644
--- a/chromium/media/audio/win/audio_unified_win_unittest.cc
+++ b/chromium/media/audio/win/audio_unified_win_unittest.cc
@@ -196,13 +196,13 @@ class AudioUnifiedStreamWrapper {
// Creates an AudioOutputStream object using default parameters.
WASAPIUnifiedStream* Create() {
- return static_cast<WASAPIUnifiedStream*> (CreateOutputStream());
+ return static_cast<WASAPIUnifiedStream*>(CreateOutputStream());
}
// Creates an AudioOutputStream object using default parameters but a
// specified input device.
WASAPIUnifiedStream* Create(const std::string device_id) {
- return static_cast<WASAPIUnifiedStream*> (CreateOutputStream(device_id));
+ return static_cast<WASAPIUnifiedStream*>(CreateOutputStream(device_id));
}
AudioParameters::Format format() const { return params_.format(); }
@@ -223,20 +223,21 @@ class AudioUnifiedStreamWrapper {
CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole);
AudioDeviceName name;
EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device, &name)));
- const std::string& device_id = name.unique_id;
- EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, device_id));
+ const std::string& input_device_id = name.unique_id;
+ EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole,
+ input_device_id));
// Create the unified audio I/O stream using the default input device.
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_,
- device_id);
+ "", input_device_id);
EXPECT_TRUE(aos);
return aos;
}
- AudioOutputStream* CreateOutputStream(const std::string& device_id) {
+ AudioOutputStream* CreateOutputStream(const std::string& input_device_id) {
// Create the unified audio I/O stream using the specified input device.
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_,
- device_id);
+ "", input_device_id);
EXPECT_TRUE(aos);
return aos;
}
diff --git a/chromium/media/audio/win/core_audio_util_win.cc b/chromium/media/audio/win/core_audio_util_win.cc
index 392184b7a01..4adfdda090a 100644
--- a/chromium/media/audio/win/core_audio_util_win.cc
+++ b/chromium/media/audio/win/core_audio_util_win.cc
@@ -4,8 +4,9 @@
#include "media/audio/win/core_audio_util_win.h"
-#include <Audioclient.h>
-#include <Functiondiscoverykeys_devpkey.h>
+#include <audioclient.h>
+#include <devicetopology.h>
+#include <functiondiscoverykeys_devpkey.h>
#include "base/command_line.h"
#include "base/logging.h"
@@ -122,7 +123,7 @@ static std::ostream& operator<<(std::ostream& os,
return os;
}
-bool LoadAudiosesDll() {
+static bool LoadAudiosesDll() {
static const wchar_t* const kAudiosesDLL =
L"%WINDIR%\\system32\\audioses.dll";
@@ -131,7 +132,7 @@ bool LoadAudiosesDll() {
return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL);
}
-bool CanCreateDeviceEnumerator() {
+static bool CanCreateDeviceEnumerator() {
ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_INPROC_SERVER);
@@ -143,6 +144,14 @@ bool CanCreateDeviceEnumerator() {
return SUCCEEDED(hr);
}
+static std::string GetDeviceID(IMMDevice* device) {
+ ScopedCoMem<WCHAR> device_id_com;
+ std::string device_id;
+ if (SUCCEEDED(device->GetId(&device_id_com)))
+ WideToUTF8(device_id_com, wcslen(device_id_com), &device_id);
+ return device_id;
+}
+
bool CoreAudioUtil::IsSupported() {
// It is possible to force usage of WaveXxx APIs by using a command line flag.
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
@@ -262,6 +271,12 @@ ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDefaultDevice(EDataFlow data_flow,
return endpoint_device;
}
+std::string CoreAudioUtil::GetDefaultOutputDeviceID() {
+ DCHECK(IsSupported());
+ ScopedComPtr<IMMDevice> device(CreateDefaultDevice(eRender, eConsole));
+ return device ? GetDeviceID(device) : std::string();
+}
+
ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice(
const std::string& device_id) {
DCHECK(IsSupported());
@@ -288,17 +303,14 @@ HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) {
// Retrieve unique name of endpoint device.
// Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}".
AudioDeviceName device_name;
- ScopedCoMem<WCHAR> endpoint_device_id;
- HRESULT hr = device->GetId(&endpoint_device_id);
- if (FAILED(hr))
- return hr;
- WideToUTF8(endpoint_device_id, wcslen(endpoint_device_id),
- &device_name.unique_id);
+ device_name.unique_id = GetDeviceID(device);
+ if (device_name.unique_id.empty())
+ return E_FAIL;
// Retrieve user-friendly name of endpoint device.
// Example: "Microphone (Realtek High Definition Audio)".
ScopedComPtr<IPropertyStore> properties;
- hr = device->OpenPropertyStore(STGM_READ, properties.Receive());
+ HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.Receive());
if (FAILED(hr))
return hr;
base::win::ScopedPropVariant friendly_name;
@@ -317,6 +329,88 @@ HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) {
return hr;
}
+std::string CoreAudioUtil::GetAudioControllerID(IMMDevice* device,
+ IMMDeviceEnumerator* enumerator) {
+ DCHECK(IsSupported());
+
+ // Fetching the controller device id could be as simple as fetching the value
+ // of the "{B3F8FA53-0004-438E-9003-51A46E139BFC},2" property in the property
+ // store of the |device|, but that key isn't defined in any header and
+ // according to MS should not be relied upon.
+ // So, instead, we go deeper, look at the device topology and fetch the
+ // PKEY_Device_InstanceId of the associated physical audio device.
+ ScopedComPtr<IDeviceTopology> topology;
+ ScopedComPtr<IConnector> connector;
+ ScopedCoMem<WCHAR> filter_id;
+ if (FAILED(device->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL,
+ topology.ReceiveVoid()) ||
+ // For our purposes checking the first connected device should be enough
+ // and if there are cases where there are more than one device connected
+ // we're not sure how to handle that anyway. So we pass 0.
+ FAILED(topology->GetConnector(0, connector.Receive())) ||
+ FAILED(connector->GetDeviceIdConnectedTo(&filter_id)))) {
+ DLOG(ERROR) << "Failed to get the device identifier of the audio device";
+ return std::string();
+ }
+
+ // Now look at the properties of the connected device node and fetch the
+ // instance id (PKEY_Device_InstanceId) of the device node that uniquely
+ // identifies the controller.
+ ScopedComPtr<IMMDevice> device_node;
+ ScopedComPtr<IPropertyStore> properties;
+ base::win::ScopedPropVariant instance_id;
+ if (FAILED(enumerator->GetDevice(filter_id, device_node.Receive())) ||
+ FAILED(device_node->OpenPropertyStore(STGM_READ, properties.Receive())) ||
+ FAILED(properties->GetValue(PKEY_Device_InstanceId,
+ instance_id.Receive())) ||
+ instance_id.get().vt != VT_LPWSTR) {
+ DLOG(ERROR) << "Failed to get instance id of the audio device node";
+ return std::string();
+ }
+
+ std::string controller_id;
+ WideToUTF8(instance_id.get().pwszVal,
+ wcslen(instance_id.get().pwszVal),
+ &controller_id);
+
+ return controller_id;
+}
+
+std::string CoreAudioUtil::GetMatchingOutputDeviceID(
+ const std::string& input_device_id) {
+ ScopedComPtr<IMMDevice> input_device(CreateDevice(input_device_id));
+ if (!input_device)
+ return std::string();
+
+ // See if we can get id of the associated controller.
+ ScopedComPtr<IMMDeviceEnumerator> enumerator(CreateDeviceEnumerator());
+ std::string controller_id(GetAudioControllerID(input_device, enumerator));
+ if (controller_id.empty())
+ return std::string();
+
+ // Now enumerate the available (and active) output devices and see if any of
+ // them is associated with the same controller.
+ ScopedComPtr<IMMDeviceCollection> collection;
+ enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE,
+ collection.Receive());
+ if (!collection)
+ return std::string();
+
+ UINT count = 0;
+ collection->GetCount(&count);
+ ScopedComPtr<IMMDevice> output_device;
+ for (UINT i = 0; i < count; ++i) {
+ collection->Item(i, output_device.Receive());
+ std::string output_controller_id(CoreAudioUtil::GetAudioControllerID(
+ output_device, enumerator));
+ if (output_controller_id == controller_id)
+ break;
+ output_device = NULL;
+ }
+
+ return output_device ? GetDeviceID(output_device) : std::string();
+}
+
std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) {
DCHECK(IsSupported());
ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id);
@@ -339,16 +433,8 @@ bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow,
if (!device)
return false;
- ScopedCoMem<WCHAR> default_device_id;
- HRESULT hr = device->GetId(&default_device_id);
- if (FAILED(hr))
- return false;
-
- std::string str_default;
- WideToUTF8(default_device_id, wcslen(default_device_id), &str_default);
- if (device_id.compare(str_default) != 0)
- return false;
- return true;
+ std::string str_default(GetDeviceID(device));
+ return device_id.compare(str_default) == 0;
}
EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) {
diff --git a/chromium/media/audio/win/core_audio_util_win.h b/chromium/media/audio/win/core_audio_util_win.h
index 3b2734570d0..cdf6dfb11df 100644
--- a/chromium/media/audio/win/core_audio_util_win.h
+++ b/chromium/media/audio/win/core_audio_util_win.h
@@ -59,6 +59,10 @@ class MEDIA_EXPORT CoreAudioUtil {
static ScopedComPtr<IMMDevice> CreateDefaultDevice(
EDataFlow data_flow, ERole role);
+ // Returns the device id of the default output device or an empty string
+ // if no such device exists or if the default device has been disabled.
+ static std::string GetDefaultOutputDeviceID();
+
// Creates an endpoint device that is specified by a unique endpoint device-
// identification string.
static ScopedComPtr<IMMDevice> CreateDevice(const std::string& device_id);
@@ -68,6 +72,24 @@ class MEDIA_EXPORT CoreAudioUtil {
// "Microphone (Realtek High Definition Audio)".
static HRESULT GetDeviceName(IMMDevice* device, AudioDeviceName* name);
+ // Returns the device ID/path of the controller (a.k.a. physical device that
+ // |device| is connected to. This ID will be the same for all devices from
+ // the same controller so it is useful for doing things like determining
+ // whether a set of output and input devices belong to the same controller.
+ // The device enumerator is required as well as the device itself since
+ // looking at the device topology is required and we need to open up
+ // associated devices to determine the controller id.
+ // If the ID could not be determined for some reason, an empty string is
+ // returned.
+ static std::string GetAudioControllerID(IMMDevice* device,
+ IMMDeviceEnumerator* enumerator);
+
+ // Accepts an id of an input device and finds a matching output device id.
+ // If the associated hardware does not have an audio output device (e.g.
+ // a webcam with a mic), an empty string is returned.
+ static std::string GetMatchingOutputDeviceID(
+ const std::string& input_device_id);
+
// Gets the user-friendly name of the endpoint device which is represented
// by a unique id in |device_id|.
static std::string GetFriendlyName(const std::string& device_id);
diff --git a/chromium/media/audio/win/core_audio_util_win_unittest.cc b/chromium/media/audio/win/core_audio_util_win_unittest.cc
index 6d3e1fcf093..abef8682020 100644
--- a/chromium/media/audio/win/core_audio_util_win_unittest.cc
+++ b/chromium/media/audio/win/core_audio_util_win_unittest.cc
@@ -3,7 +3,9 @@
// found in the LICENSE file.
#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_handle.h"
#include "media/audio/win/core_audio_util_win.h"
@@ -140,6 +142,33 @@ TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) {
}
}
+TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) {
+ if (!CanRunAudioTest())
+ return;
+
+ ScopedComPtr<IMMDeviceEnumerator> enumerator(
+ CoreAudioUtil::CreateDeviceEnumerator());
+ ASSERT_TRUE(enumerator);
+
+ // Enumerate all active input and output devices and fetch the ID of
+ // the associated device.
+ EDataFlow flows[] = { eRender , eCapture };
+ for (int i = 0; i < arraysize(flows); ++i) {
+ ScopedComPtr<IMMDeviceCollection> collection;
+ ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(flows[i],
+ DEVICE_STATE_ACTIVE, collection.Receive())));
+ UINT count = 0;
+ collection->GetCount(&count);
+ for (UINT j = 0; j < count; ++j) {
+ ScopedComPtr<IMMDevice> device;
+ collection->Item(j, device.Receive());
+ std::string controller_id(CoreAudioUtil::GetAudioControllerID(
+ device, enumerator));
+ EXPECT_FALSE(controller_id.empty());
+ }
+ }
+}
+
TEST_F(CoreAudioUtilWinTest, GetFriendlyName) {
if (!CanRunAudioTest())
return;
@@ -448,6 +477,46 @@ TEST_F(CoreAudioUtilWinTest, FillRenderEndpointBufferWithSilence) {
EXPECT_EQ(num_queued_frames, endpoint_buffer_size);
}
-//
+// This test can only succeed on a machine that has audio hardware
+// that has both input and output devices. Currently this is the case
+// with our test bots and the CanRunAudioTest() method should make sure
+// that the test won't run in unsupported environments, but be warned.
+TEST_F(CoreAudioUtilWinTest, GetMatchingOutputDeviceID) {
+ if (!CanRunAudioTest())
+ return;
+
+ bool found_a_pair = false;
+
+ ScopedComPtr<IMMDeviceEnumerator> enumerator(
+ CoreAudioUtil::CreateDeviceEnumerator());
+ ASSERT_TRUE(enumerator);
+
+ // Enumerate all active input and output devices and fetch the ID of
+ // the associated device.
+ ScopedComPtr<IMMDeviceCollection> collection;
+ ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(eCapture,
+ DEVICE_STATE_ACTIVE, collection.Receive())));
+ UINT count = 0;
+ collection->GetCount(&count);
+ for (UINT i = 0; i < count && !found_a_pair; ++i) {
+ ScopedComPtr<IMMDevice> device;
+ collection->Item(i, device.Receive());
+ base::win::ScopedCoMem<WCHAR> wide_id;
+ device->GetId(&wide_id);
+ std::string id;
+ WideToUTF8(wide_id, wcslen(wide_id), &id);
+ found_a_pair = !CoreAudioUtil::GetMatchingOutputDeviceID(id).empty();
+ }
+
+ EXPECT_TRUE(found_a_pair);
+}
+
+TEST_F(CoreAudioUtilWinTest, GetDefaultOutputDeviceID) {
+ if (!CanRunAudioTest())
+ return;
+
+ std::string default_device_id(CoreAudioUtil::GetDefaultOutputDeviceID());
+ EXPECT_FALSE(default_device_id.empty());
+}
} // namespace media
diff --git a/chromium/media/audio/win/device_enumeration_win.cc b/chromium/media/audio/win/device_enumeration_win.cc
index 36ed2913ffe..aa66afb12b1 100644
--- a/chromium/media/audio/win/device_enumeration_win.cc
+++ b/chromium/media/audio/win/device_enumeration_win.cc
@@ -8,13 +8,13 @@
#include "media/audio/win/audio_manager_win.h"
+#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_propvariant.h"
-using media::AudioDeviceNames;
using base::win::ScopedComPtr;
using base::win::ScopedCoMem;
@@ -25,7 +25,8 @@ using base::win::ScopedCoMem;
namespace media {
-bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
+static bool GetDeviceNamesWinImpl(EDataFlow data_flow,
+ AudioDeviceNames* device_names) {
// It is assumed that this method is called from a COM thread, i.e.,
// CoInitializeEx() is not called here again to avoid STA/MTA conflicts.
ScopedComPtr<IMMDeviceEnumerator> enumerator;
@@ -37,24 +38,24 @@ bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
return false;
}
- // Generate a collection of active audio capture endpoint devices.
+ // Generate a collection of active audio endpoint devices.
// This method will succeed even if all devices are disabled.
ScopedComPtr<IMMDeviceCollection> collection;
- hr = enumerator->EnumAudioEndpoints(eCapture,
+ hr = enumerator->EnumAudioEndpoints(data_flow,
DEVICE_STATE_ACTIVE,
collection.Receive());
if (FAILED(hr))
return false;
- // Retrieve the number of active capture devices.
+ // Retrieve the number of active devices.
UINT number_of_active_devices = 0;
collection->GetCount(&number_of_active_devices);
if (number_of_active_devices == 0)
return true;
- media::AudioDeviceName device;
+ AudioDeviceName device;
- // Loop over all active capture devices and add friendly name and
+ // Loop over all active devices and add friendly name and
// unique ID to the |device_names| list.
for (UINT i = 0; i < number_of_active_devices; ++i) {
// Retrieve unique name of endpoint device.
@@ -92,14 +93,22 @@ bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
return true;
}
-bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
+// The waveform API is weird in that it has completely separate but
+// almost identical functions and structs for input devices vs. output
+// devices. We deal with this by implementing the logic as a templated
+// function that takes the functions and struct type to use as
+// template parameters.
+template <UINT (__stdcall *NumDevsFunc)(),
+ typename CAPSSTRUCT,
+ MMRESULT (__stdcall *DevCapsFunc)(UINT_PTR, CAPSSTRUCT*, UINT)>
+static bool GetDeviceNamesWinXPImpl(AudioDeviceNames* device_names) {
// Retrieve the number of active waveform input devices.
- UINT number_of_active_devices = waveInGetNumDevs();
+ UINT number_of_active_devices = NumDevsFunc();
if (number_of_active_devices == 0)
return true;
- media::AudioDeviceName device;
- WAVEINCAPS capabilities;
+ AudioDeviceName device;
+ CAPSSTRUCT capabilities;
MMRESULT err = MMSYSERR_NOERROR;
// Loop over all active capture devices and add friendly name and
@@ -108,7 +117,7 @@ bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
// there is no safe method to retrieve a unique device name on XP.
for (UINT i = 0; i < number_of_active_devices; ++i) {
// Retrieve the capabilities of the specified waveform-audio input device.
- err = waveInGetDevCaps(i, &capabilities, sizeof(capabilities));
+ err = DevCapsFunc(i, &capabilities, sizeof(capabilities));
if (err != MMSYSERR_NOERROR)
continue;
@@ -118,7 +127,7 @@ bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
device.device_name = WideToUTF8(capabilities.szPname);
// Store the "unique" name (we use same as friendly name on Windows XP).
- device.unique_id = WideToUTF8(capabilities.szPname);
+ device.unique_id = device.device_name;
// Add combination of user-friendly and unique name to the output list.
device_names->push_back(device);
@@ -127,7 +136,25 @@ bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
return true;
}
-std::string ConvertToWinXPDeviceId(const std::string& device_id) {
+bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinImpl(eCapture, device_names);
+}
+
+bool GetOutputDeviceNamesWin(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinImpl(eRender, device_names);
+}
+
+bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinXPImpl<
+ waveInGetNumDevs, WAVEINCAPSW, waveInGetDevCapsW>(device_names);
+}
+
+bool GetOutputDeviceNamesWinXP(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinXPImpl<
+ waveOutGetNumDevs, WAVEOUTCAPSW, waveOutGetDevCapsW>(device_names);
+}
+
+std::string ConvertToWinXPInputDeviceId(const std::string& device_id) {
UINT number_of_active_devices = waveInGetNumDevs();
MMRESULT result = MMSYSERR_NOERROR;
diff --git a/chromium/media/audio/win/device_enumeration_win.h b/chromium/media/audio/win/device_enumeration_win.h
index 3d44670a6d3..e61a331842a 100644
--- a/chromium/media/audio/win/device_enumeration_win.h
+++ b/chromium/media/audio/win/device_enumeration_win.h
@@ -11,28 +11,32 @@
namespace media {
-// Returns a list of audio input device structures (name and unique device ID)
-// using the MMDevice API which is supported on Windows Vista and higher.
+// Returns a list of audio input or output device structures (name and
+// unique device ID) using the MMDevice API which is supported on
+// Windows Vista and higher.
// Example record in the output list:
// - device_name: "Microphone (Realtek High Definition Audio)".
// - unique_id: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}"
// This method must be called from a COM thread using MTA.
bool GetInputDeviceNamesWin(media::AudioDeviceNames* device_names);
+bool GetOutputDeviceNamesWin(media::AudioDeviceNames* device_names);
-// Returns a list of audio input device structures (name and unique device ID)
-// using the WaveIn API which is supported on Windows XP and higher.
+// Returns a list of audio input or output device structures (name and
+// unique device ID) using the WaveIn API which is supported on
+// Windows XP and higher.
// Example record in the output list:
// - device_name: "Microphone (Realtek High Defini".
// - unique_id: "Microphone (Realtek High Defini" (same as friendly name).
bool GetInputDeviceNamesWinXP(media::AudioDeviceNames* device_names);
+bool GetOutputDeviceNamesWinXP(media::AudioDeviceNames* device_names);
-// Converts a device ID generated by |GetInputDeviceNamesWin()| to the
+// Converts an input device ID generated by |GetInputDeviceNamesWin()| to the
// corresponding ID by |GetInputDeviceNamesWinXP()|. Returns an empty string on
// failure.
// Example input and output:
// - input ID: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}"
// - output ID: "Microphone (Realtek High Defini"
-std::string ConvertToWinXPDeviceId(const std::string& device_id);
+std::string ConvertToWinXPInputDeviceId(const std::string& device_id);
} // namespace media
diff --git a/chromium/media/audio/win/wavein_input_win.h b/chromium/media/audio/win/wavein_input_win.h
index 4b830e34805..df5ce4d129b 100644
--- a/chromium/media/audio/win/wavein_input_win.h
+++ b/chromium/media/audio/win/wavein_input_win.h
@@ -56,7 +56,7 @@ class PCMWaveInAudioInputStream : public AudioInputStream {
};
// Allow unit tests to query the device ID.
- friend class AudioInputDeviceTest;
+ friend class AudioManagerTest;
// Windows calls us back with the recorded audio data here. See msdn
// documentation for 'waveInProc' for details about the parameters.