diff options
author | xians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-07 15:25:51 +0000 |
---|---|---|
committer | xians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-07 15:25:51 +0000 |
commit | f34a9058aa124789ebc5b1e38d9d890c29f49ce5 (patch) | |
tree | 4002bf52e0861deb1c75b7f09cd6f601487a54d7 | |
parent | eaabba206ae14905ef3a922e7b839cab285dd940 (diff) | |
download | chromium_src-f34a9058aa124789ebc5b1e38d9d890c29f49ce5.zip chromium_src-f34a9058aa124789ebc5b1e38d9d890c29f49ce5.tar.gz chromium_src-f34a9058aa124789ebc5b1e38d9d890c29f49ce5.tar.bz2 |
Moved the implementations of ReleaseOutputStream() and ReleaseInputStream() to AudioManagerBase and let all the AudioManagerPlatforms inherit the same implementations.
Also moved the MakeAudioOutputStream() and MakeAudioInputStream() to AudioManagerBase, separate the AUDIO_PCM_LINEAR mode and AUDIO_PCM_LOW_LATENCY mode into two different functions inside the AudioManagerPlatforms. So that the structure is clearer and also easier to deprecate the AUDIO_PCM_LINEAR for the future.
Made the destructor of the AudioManagerPlatforms protected so it can be called by only the AudioManagerBase.
BUG=116064
TEST=media_unittests
Review URL: http://codereview.chromium.org/9570014
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125389 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/audio/android/audio_manager_android.cc | 49 | ||||
-rw-r--r-- | media/audio/android/audio_manager_android.h | 16 | ||||
-rw-r--r-- | media/audio/audio_input_volume_unittest.cc | 5 | ||||
-rw-r--r-- | media/audio/audio_manager_base.cc | 80 | ||||
-rw-r--r-- | media/audio/audio_manager_base.h | 42 | ||||
-rw-r--r-- | media/audio/linux/alsa_input.cc | 30 | ||||
-rw-r--r-- | media/audio/linux/alsa_input.h | 1 | ||||
-rw-r--r-- | media/audio/linux/alsa_output.cc | 25 | ||||
-rw-r--r-- | media/audio/linux/alsa_output_unittest.cc | 314 | ||||
-rw-r--r-- | media/audio/linux/audio_manager_linux.cc | 132 | ||||
-rw-r--r-- | media/audio/linux/audio_manager_linux.h | 26 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.cc | 125 | ||||
-rw-r--r-- | media/audio/mac/audio_manager_mac.h | 24 | ||||
-rw-r--r-- | media/audio/openbsd/audio_manager_openbsd.cc | 90 | ||||
-rw-r--r-- | media/audio/openbsd/audio_manager_openbsd.h | 20 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.cc | 147 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.h | 22 |
17 files changed, 627 insertions, 521 deletions
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index 0170675..9d17934 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -8,13 +8,17 @@ #include "media/audio/android/audio_track_output_android.h" #include "media/audio/audio_manager.h" #include "media/audio/fake_audio_input_stream.h" -#include "media/audio/fake_audio_output_stream.h" + +// Maximum number of output streams that can be open simultaneously. +static const int kMaxOutputStreams = 10; AudioManager* CreateAudioManager() { return new AudioManagerAndroid(); } -AudioManagerAndroid::AudioManagerAndroid() {} +AudioManagerAndroid::AudioManagerAndroid() { + SetMaxOutputStreamsAllowed(kMaxOutputStreams); +} AudioManagerAndroid::~AudioManagerAndroid() { audio_thread_->Stop(); @@ -28,29 +32,34 @@ bool AudioManagerAndroid::HasAudioInputDevices() { return false; } -AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( - const AudioParameters& params) { - if (!params.IsValid()) - return NULL; +void AudioManagerAndroid::MuteAll() { + NOTIMPLEMENTED(); +} - if (params.format == AudioParameters::AUDIO_MOCK) - return FakeAudioOutputStream::MakeFakeStream(params); - if (params.format == AudioParameters::AUDIO_PCM_LINEAR || - params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) - return AudioTrackOutputStream::MakeStream(params); +void AudioManagerAndroid::UnMuteAll() { + NOTIMPLEMENTED(); +} - return NULL; +AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return AudioTrackOutputStream::MakeStream(params); } -AudioInputStream* AudioManagerAndroid::MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) { - return FakeAudioInputStream::MakeFakeStream(params); +AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + return AudioTrackOutputStream::MakeStream(params); } -void AudioManagerAndroid::MuteAll() { - NOTIMPLEMENTED(); +AudioInputStream* AudioManagerAndroid::MakeLinearInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return FakeAudioInputStream::MakeFakeStream(params); } -void AudioManagerAndroid::UnMuteAll() { - NOTIMPLEMENTED(); +AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + return FakeAudioInputStream::MakeFakeStream(params); } diff --git a/media/audio/android/audio_manager_android.h b/media/audio/android/audio_manager_android.h index ab43a60..5d42270 100644 --- a/media/audio/android/audio_manager_android.h +++ b/media/audio/android/audio_manager_android.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -15,13 +15,19 @@ class AudioManagerAndroid : public AudioManagerBase { // Implementation of AudioManager. virtual bool HasAudioOutputDevices() OVERRIDE; virtual bool HasAudioInputDevices() OVERRIDE; - virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; - virtual AudioInputStream* MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual void MuteAll() OVERRIDE; virtual void UnMuteAll() OVERRIDE; + // Implementation of AudioManagerBase. + virtual AudioOutputStream* MakeLinearOutputStream( + const AudioParameters& params) OVERRIDE; + virtual AudioOutputStream* MakeLowLatencyOutputStream( + const AudioParameters& params) 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; + protected: virtual ~AudioManagerAndroid(); diff --git a/media/audio/audio_input_volume_unittest.cc b/media/audio/audio_input_volume_unittest.cc index 15cb7fb..febdb78 100644 --- a/media/audio/audio_input_volume_unittest.cc +++ b/media/audio/audio_input_volume_unittest.cc @@ -97,7 +97,10 @@ TEST_F(AudioInputVolumeTest, InputVolumeTest) { // Retrieve a list of all available input devices. AudioDeviceNames device_names; audio_manager_->GetAudioInputDeviceNames(&device_names); - DCHECK(!device_names.empty()); + if (device_names.empty()) { + LOG(WARNING) << "Could not find any available input device"; + return; + } // Scan all available input devices and repeat the same test for all of them. for (AudioDeviceNames::const_iterator it = device_names.begin(); diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index 2957e96..05ed044 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc @@ -9,18 +9,30 @@ #include "base/threading/thread.h" #include "media/audio/audio_output_dispatcher.h" #include "media/audio/audio_output_proxy.h" +#include "media/audio/fake_audio_input_stream.h" +#include "media/audio/fake_audio_output_stream.h" static const int kStreamCloseDelaySeconds = 5; +// Default maximum number of output streams that can be open simultaneously +// for all platforms. +static const int kDefaultMaxOutputStreams = 15; + +static const int kMaxInputChannels = 2; + const char AudioManagerBase::kDefaultDeviceName[] = "Default"; const char AudioManagerBase::kDefaultDeviceId[] = "default"; AudioManagerBase::AudioManagerBase() - : num_active_input_streams_(0) { + : num_active_input_streams_(0), + max_num_output_streams_(kDefaultMaxOutputStreams), + num_output_streams_(0) { } AudioManagerBase::~AudioManagerBase() { Shutdown(); + // All the output streams should have been deleted. + DCHECK_EQ(0, num_output_streams_); } void AudioManagerBase::Init() { @@ -39,6 +51,57 @@ scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { return audio_thread_.get() ? audio_thread_->message_loop_proxy() : NULL; } +AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( + const AudioParameters& params) { + if (!params.IsValid()) { + DLOG(ERROR) << "Audio parameters are invalid"; + return NULL; + } + + // Limit the number of audio streams opened. This is to prevent using + // excessive resources for a large number of audio streams. More + // importantly it prevents instability on certain systems. + // See bug: http://crbug.com/30242. + if (num_output_streams_ >= max_num_output_streams_) { + DLOG(ERROR) << "Number of opened audio streams " << num_output_streams_ + << " exceed the max allowed number " << max_num_output_streams_; + return NULL; + } + + AudioOutputStream* stream = NULL; + if (params.format == AudioParameters::AUDIO_MOCK) { + stream = FakeAudioOutputStream::MakeFakeStream(params); + } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { + num_output_streams_++; + stream = MakeLinearOutputStream(params); + } else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) { + num_output_streams_++; + stream = MakeLowLatencyOutputStream(params); + } + + return stream; +} + +AudioInputStream* AudioManagerBase::MakeAudioInputStream( + const AudioParameters& params, const std::string& device_id) { + if (!params.IsValid() || (params.channels > kMaxInputChannels) || + device_id.empty()) { + DLOG(ERROR) << "Audio parameters are invalid for device " << device_id; + return NULL; + } + + AudioInputStream* stream = NULL; + if (params.format == AudioParameters::AUDIO_MOCK) { + stream = FakeAudioInputStream::MakeFakeStream(params); + } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { + stream = MakeLinearInputStream(params, device_id); + } else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) { + stream = MakeLowLatencyInputStream(params, device_id); + } + + return stream; +} + AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( const AudioParameters& params) { DCHECK(GetMessageLoop()->BelongsToCurrentThread()); @@ -62,6 +125,21 @@ void AudioManagerBase::GetAudioInputDeviceNames( media::AudioDeviceNames* device_names) { } +void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) { + DCHECK(stream); + // TODO(xians) : Have a clearer destruction path for the AudioOutputStream. + // For example, pass the ownership to AudioManager so it can delete the + // streams. + num_output_streams_--; + delete stream; +} + +void AudioManagerBase::ReleaseInputStream(AudioInputStream* stream) { + DCHECK(stream); + // TODO(xians) : Have a clearer destruction path for the AudioInputStream. + delete stream; +} + void AudioManagerBase::IncreaseActiveInputStreamCount() { base::AtomicRefCountInc(&num_active_input_streams_); } diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h index 7f42ea7..ea9c78a 100644 --- a/media/audio/audio_manager_base.h +++ b/media/audio/audio_manager_base.h @@ -38,14 +38,24 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { virtual bool CanShowAudioInputSettings() OVERRIDE; virtual void ShowAudioInputSettings() OVERRIDE; - virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) - OVERRIDE; + virtual void GetAudioInputDeviceNames( + media::AudioDeviceNames* device_names) OVERRIDE; + + virtual AudioOutputStream* MakeAudioOutputStream( + const AudioParameters& params) OVERRIDE; + + virtual AudioInputStream* MakeAudioInputStream( + const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioOutputStream* MakeAudioOutputStreamProxy( const AudioParameters& params) OVERRIDE; virtual bool IsRecordingInProcess() OVERRIDE; + // Called internally by the audio stream when it has been closed. + virtual void ReleaseOutputStream(AudioOutputStream* stream); + virtual void ReleaseInputStream(AudioInputStream* stream); + void IncreaseActiveInputStreamCount(); void DecreaseActiveInputStreamCount(); @@ -54,6 +64,24 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { // Shutdown is called. void Shutdown(); + // Creates the output stream for the |AUDIO_PCM_LINEAR| format. The legacy + // name is also from |AUDIO_PCM_LINEAR|. + virtual AudioOutputStream* MakeLinearOutputStream( + const AudioParameters& params) = 0; + + // Creates the output stream for the |AUDIO_PCM_LOW_LATENCY| format. + virtual AudioOutputStream* MakeLowLatencyOutputStream( + const AudioParameters& params) = 0; + + // Creates the input stream for the |AUDIO_PCM_LINEAR| format. The legacy + // name is also from |AUDIO_PCM_LINEAR|. + virtual AudioInputStream* MakeLinearInputStream( + const AudioParameters& params, const std::string& device_id) = 0; + + // Creates the input stream for the |AUDIO_PCM_LOW_LATENCY| format. + virtual AudioInputStream* MakeLowLatencyInputStream( + const AudioParameters& params, const std::string& device_id) = 0; + protected: AudioManagerBase(); @@ -63,6 +91,8 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { void ShutdownOnAudioThread(); + void SetMaxOutputStreamsAllowed(int max) { max_num_output_streams_ = max; } + // Thread used to interact with AudioOutputStreams created by this // audio manger. scoped_ptr<base::Thread> audio_thread_; @@ -72,10 +102,18 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { // from the audio thread (no locking). AudioOutputDispatchersMap output_dispatchers_; + private: // Counts the number of active input streams to find out if something else // is currently recording in Chrome. base::AtomicRefCount num_active_input_streams_; + // Max number of open output streams, modified by + // SetMaxOutputStreamsAllowed(). + int max_num_output_streams_; + + // Number of currently open output streams. + int num_output_streams_; + DISALLOW_COPY_AND_ASSIGN(AudioManagerBase); }; diff --git a/media/audio/linux/alsa_input.cc b/media/audio/linux/alsa_input.cc index 101c198..994c065 100644 --- a/media/audio/linux/alsa_input.cc +++ b/media/audio/linux/alsa_input.cc @@ -247,25 +247,25 @@ void AlsaPcmInputStream::Stop() { } void AlsaPcmInputStream::Close() { - scoped_ptr<AlsaPcmInputStream> self_deleter(this); + if (device_handle_) { + weak_factory_.InvalidateWeakPtrs(); // Cancel the next scheduled read. + int error = alsa_util::CloseDevice(wrapper_, device_handle_); + if (error < 0) + HandleError("PcmClose", error); - // Check in case we were already closed or not initialized yet. - if (!device_handle_) - return; + if (mixer_handle_) + alsa_util::CloseMixer(wrapper_, mixer_handle_, device_name_); - weak_factory_.InvalidateWeakPtrs(); // Cancel the next scheduled read. - int error = alsa_util::CloseDevice(wrapper_, device_handle_); - if (error < 0) - HandleError("PcmClose", error); - - if (mixer_handle_) - alsa_util::CloseMixer(wrapper_, mixer_handle_, device_name_); + audio_packet_.reset(); + device_handle_ = NULL; + mixer_handle_ = NULL; + mixer_element_handle_ = NULL; - audio_packet_.reset(); - device_handle_ = NULL; + if (callback_) + callback_->OnClose(this); + } - if (callback_) - callback_->OnClose(this); + audio_manager_->ReleaseInputStream(this); } double AlsaPcmInputStream::GetMaxVolume() { diff --git a/media/audio/linux/alsa_input.h b/media/audio/linux/alsa_input.h index 4db2b9a..f5f216b 100644 --- a/media/audio/linux/alsa_input.h +++ b/media/audio/linux/alsa_input.h @@ -34,6 +34,7 @@ class AlsaPcmInputStream : public AudioInputStream { const std::string& device_name, const AudioParameters& params, AlsaWrapper* wrapper); + virtual ~AlsaPcmInputStream(); // Implementation of AudioInputStream. diff --git a/media/audio/linux/alsa_output.cc b/media/audio/linux/alsa_output.cc index a57c276..8394c56 100644 --- a/media/audio/linux/alsa_output.cc +++ b/media/audio/linux/alsa_output.cc @@ -295,14 +295,12 @@ bool AlsaPcmOutputStream::Open() { void AlsaPcmOutputStream::Close() { DCHECK(IsOnAudioThread()); - // Sanity check that the transition occurs correctly. It is safe to - // continue anyways because all operations for closing are idempotent. - if (TransitionTo(kIsClosed) != kIsClosed) { - NOTREACHED() << "Unable to transition Closed."; - } else { - // Shutdown the audio device. - if (playback_handle_ && - alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) { + if (state() != kIsClosed) + TransitionTo(kIsClosed); + + // Shutdown the audio device. + if (playback_handle_) { + if (alsa_util::CloseDevice(wrapper_, playback_handle_) < 0) { LOG(WARNING) << "Unable to close audio device. Leaking handle."; } playback_handle_ = NULL; @@ -313,12 +311,13 @@ void AlsaPcmOutputStream::Close() { // Signal anything that might already be scheduled to stop. stop_stream_ = true; // Not necessary in production, but unit tests // uses the flag to verify that stream was closed. - weak_factory_.InvalidateWeakPtrs(); - - // Signal to the manager that we're closed and can be removed. - // Should be last call in the method as it deletes "this". - manager_->ReleaseOutputStream(this); } + + weak_factory_.InvalidateWeakPtrs(); + + // Signal to the manager that we're closed and can be removed. + // Should be last call in the method as it deletes "this". + manager_->ReleaseOutputStream(this); } void AlsaPcmOutputStream::Start(AudioSourceCallback* callback) { diff --git a/media/audio/linux/alsa_output_unittest.cc b/media/audio/linux/alsa_output_unittest.cc index bcf2e3d..8658996 100644 --- a/media/audio/linux/alsa_output_unittest.cc +++ b/media/audio/linux/alsa_output_unittest.cc @@ -78,13 +78,25 @@ class MockAudioManagerLinux : public AudioManagerLinux { MOCK_METHOD0(Init, void()); MOCK_METHOD0(HasAudioOutputDevices, bool()); MOCK_METHOD0(HasAudioInputDevices, bool()); - MOCK_METHOD1(MakeAudioOutputStream, AudioOutputStream*( - const AudioParameters& params)); - MOCK_METHOD2(MakeAudioInputStream, AudioInputStream*( - const AudioParameters& params, const std::string& device_id)); MOCK_METHOD0(MuteAll, void()); MOCK_METHOD0(UnMuteAll, void()); - MOCK_METHOD1(ReleaseOutputStream, void(AudioOutputStream* stream)); + MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*( + const AudioParameters& params)); + MOCK_METHOD1(MakeLowLatencyOutputStream, AudioOutputStream*( + const AudioParameters& params)); + MOCK_METHOD2(MakeLinearOutputStream, AudioInputStream*( + const AudioParameters& params, const std::string& device_id)); + MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*( + const AudioParameters& params, const std::string& device_id)); + + // We need to override this function in order to skip the checking the number + // of active output streams. It is because the number of active streams + // is managed inside MakeAudioOutputStream, and we don't use + // MakeAudioOutputStream to create the stream in the tests. + virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE { + DCHECK(stream); + delete stream; + } // We don't mock this method since all tests will do the same thing // and use the current message loop. @@ -97,11 +109,9 @@ class AlsaPcmOutputStreamTest : public testing::Test { protected: AlsaPcmOutputStreamTest() { mock_manager_.reset(new StrictMock<MockAudioManagerLinux>()); - test_stream_.reset(CreateStream(kTestChannelLayout)); } virtual ~AlsaPcmOutputStreamTest() { - test_stream_.reset(NULL); } AlsaPcmOutputStream* CreateStream(ChannelLayout layout) { @@ -128,13 +138,14 @@ class AlsaPcmOutputStreamTest : public testing::Test { return strdup("Output"); } - // Helper function to initialize |test_stream_->buffer_|. Must be called + // Helper function to initialize |test_stream->buffer_|. Must be called // in all tests that use buffer_ without opening the stream. - void InitBuffer() { + void InitBuffer(AlsaPcmOutputStream* test_stream) { + DCHECK(test_stream); packet_ = new media::DataBuffer(kTestPacketSize); packet_->SetDataSize(kTestPacketSize); - test_stream_->buffer_.reset(new media::SeekableBuffer(0, kTestPacketSize)); - test_stream_->buffer_->Append(packet_.get()); + test_stream->buffer_.reset(new media::SeekableBuffer(0, kTestPacketSize)); + test_stream->buffer_->Append(packet_.get()); } MockAudioManagerLinux& mock_manager() { @@ -165,7 +176,6 @@ class AlsaPcmOutputStreamTest : public testing::Test { StrictMock<MockAlsaWrapper> mock_alsa_wrapper_; scoped_ptr<StrictMock<MockAudioManagerLinux> > mock_manager_; MessageLoop message_loop_; - scoped_ptr<AlsaPcmOutputStream> test_stream_; scoped_refptr<media::DataBuffer> packet_; private: @@ -203,35 +213,41 @@ void* AlsaPcmOutputStreamTest::kFakeHints[] = { kSurround70, kSurround71, NULL }; TEST_F(AlsaPcmOutputStreamTest, ConstructedState) { - EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream_->state()); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state()); + test_stream->Close(); // Should support mono. - test_stream_.reset(CreateStream(CHANNEL_LAYOUT_MONO)); - EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream_->state()); + test_stream = CreateStream(CHANNEL_LAYOUT_MONO); + EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state()); + test_stream->Close(); // Should support multi-channel. - test_stream_.reset(CreateStream(CHANNEL_LAYOUT_SURROUND)); - EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream_->state()); + test_stream = CreateStream(CHANNEL_LAYOUT_SURROUND); + EXPECT_EQ(AlsaPcmOutputStream::kCreated, test_stream->state()); + test_stream->Close(); // Bad bits per sample. AudioParameters bad_bps_params(kTestFormat, kTestChannelLayout, kTestSampleRate, kTestBitsPerSample - 1, kTestFramesPerPacket); - test_stream_.reset(new AlsaPcmOutputStream(kTestDeviceName, - bad_bps_params, - &mock_alsa_wrapper_, - mock_manager_.get())); - EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream_->state()); + test_stream = new AlsaPcmOutputStream(kTestDeviceName, + bad_bps_params, + &mock_alsa_wrapper_, + mock_manager_.get()); + EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); + test_stream->Close(); // Bad format. AudioParameters bad_format_params( AudioParameters::AUDIO_LAST_FORMAT, kTestChannelLayout, kTestSampleRate, kTestBitsPerSample, kTestFramesPerPacket); - test_stream_.reset(new AlsaPcmOutputStream(kTestDeviceName, - bad_format_params, - &mock_alsa_wrapper_, - mock_manager_.get())); - EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream_->state()); + test_stream = new AlsaPcmOutputStream(kTestDeviceName, + bad_format_params, + &mock_alsa_wrapper_, + mock_manager_.get()); + EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) { @@ -255,16 +271,15 @@ TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) { SetArgumentPointee<2>(kTestFramesPerPacket / 2), Return(0))); - test_stream_.reset(CreateStream(kTestChannelLayout, - kPacketFramesInMinLatency)); - ASSERT_TRUE(test_stream_->Open()); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout, + kPacketFramesInMinLatency); + ASSERT_TRUE(test_stream->Open()); // Now close it and test that everything was released. EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)).WillOnce(Return(0)); EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) .WillOnce(Return(kTestDeviceName)); - EXPECT_CALL(mock_manager(), ReleaseOutputStream(test_stream_.get())); - test_stream_->Close(); + test_stream->Close(); Mock::VerifyAndClear(&mock_alsa_wrapper_); Mock::VerifyAndClear(mock_manager_.get()); @@ -284,17 +299,16 @@ TEST_F(AlsaPcmOutputStreamTest, LatencyFloor) { SetArgumentPointee<2>(kTestFramesPerPacket / 2), Return(0))); - test_stream_.reset(CreateStream(kTestChannelLayout, - kOverMinLatencyPacketSize)); - ASSERT_TRUE(test_stream_->Open()); + test_stream = CreateStream(kTestChannelLayout, + kOverMinLatencyPacketSize); + ASSERT_TRUE(test_stream->Open()); // Now close it and test that everything was released. EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) .WillOnce(Return(0)); EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) .WillOnce(Return(kTestDeviceName)); - EXPECT_CALL(mock_manager(), ReleaseOutputStream(test_stream_.get())); - test_stream_->Close(); + test_stream->Close(); Mock::VerifyAndClear(&mock_alsa_wrapper_); Mock::VerifyAndClear(mock_manager_.get()); @@ -328,25 +342,21 @@ TEST_F(AlsaPcmOutputStreamTest, OpenClose) { Return(0))); // Open the stream. - ASSERT_TRUE(test_stream_->Open()); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + ASSERT_TRUE(test_stream->Open()); - EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, test_stream_->state()); - EXPECT_EQ(kFakeHandle, test_stream_->playback_handle_); - EXPECT_EQ(kTestFramesPerPacket, test_stream_->frames_per_packet_); - EXPECT_TRUE(test_stream_->buffer_.get()); - EXPECT_FALSE(test_stream_->stop_stream_); + EXPECT_EQ(AlsaPcmOutputStream::kIsOpened, test_stream->state()); + EXPECT_EQ(kFakeHandle, test_stream->playback_handle_); + EXPECT_EQ(kTestFramesPerPacket, test_stream->frames_per_packet_); + EXPECT_TRUE(test_stream->buffer_.get()); + EXPECT_FALSE(test_stream->stop_stream_); // Now close it and test that everything was released. EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) .WillOnce(Return(0)); EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) .WillOnce(Return(kTestDeviceName)); - EXPECT_CALL(mock_manager(), ReleaseOutputStream(test_stream_.get())); - test_stream_->Close(); - - EXPECT_TRUE(test_stream_->playback_handle_ == NULL); - EXPECT_FALSE(test_stream_->buffer_.get()); - EXPECT_TRUE(test_stream_->stop_stream_); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) { @@ -355,17 +365,17 @@ TEST_F(AlsaPcmOutputStreamTest, PcmOpenFailed) { EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) .WillOnce(Return(kDummyMessage)); - ASSERT_FALSE(test_stream_->Open()); - ASSERT_EQ(AlsaPcmOutputStream::kInError, test_stream_->state()); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + ASSERT_FALSE(test_stream->Open()); + ASSERT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); // Ensure internal state is set for a no-op stream if PcmOpen() failes. - EXPECT_TRUE(test_stream_->stop_stream_); - EXPECT_TRUE(test_stream_->playback_handle_ == NULL); - EXPECT_FALSE(test_stream_->buffer_.get()); + EXPECT_TRUE(test_stream->stop_stream_); + EXPECT_TRUE(test_stream->playback_handle_ == NULL); + EXPECT_FALSE(test_stream->buffer_.get()); // Close the stream since we opened it to make destruction happy. - EXPECT_CALL(mock_manager(), ReleaseOutputStream(test_stream_.get())); - test_stream_->Close(); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) { @@ -383,17 +393,17 @@ TEST_F(AlsaPcmOutputStreamTest, PcmSetParamsFailed) { // If open fails, the stream stays in kCreated because it has effectively had // no changes. - ASSERT_FALSE(test_stream_->Open()); - EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream_->state()); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + ASSERT_FALSE(test_stream->Open()); + EXPECT_EQ(AlsaPcmOutputStream::kInError, test_stream->state()); // Ensure internal state is set for a no-op stream if PcmSetParams() failes. - EXPECT_TRUE(test_stream_->stop_stream_); - EXPECT_TRUE(test_stream_->playback_handle_ == NULL); - EXPECT_FALSE(test_stream_->buffer_.get()); + EXPECT_TRUE(test_stream->stop_stream_); + EXPECT_TRUE(test_stream->playback_handle_ == NULL); + EXPECT_FALSE(test_stream->buffer_.get()); // Close the stream since we opened it to make destruction happy. - EXPECT_CALL(mock_manager(), ReleaseOutputStream(test_stream_.get())); - test_stream_->Close(); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, StartStop) { @@ -411,7 +421,8 @@ TEST_F(AlsaPcmOutputStreamTest, StartStop) { Return(0))); // Open the stream. - ASSERT_TRUE(test_stream_->Open()); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + ASSERT_TRUE(test_stream->Open()); // Expect Device setup. EXPECT_CALL(mock_alsa_wrapper_, PcmDrop(kFakeHandle)) @@ -428,7 +439,7 @@ TEST_F(AlsaPcmOutputStreamTest, StartStop) { .Times(2) .WillRepeatedly(DoAll(SetArgumentPointee<1>(0), Return(0))); EXPECT_CALL(mock_callback, - OnMoreData(test_stream_.get(), _, kTestPacketSize, _)) + OnMoreData(test_stream, _, kTestPacketSize, _)) .Times(2) .WillOnce(Return(kTestPacketSize)) .WillOnce(Return(0)); @@ -444,39 +455,41 @@ TEST_F(AlsaPcmOutputStreamTest, StartStop) { &MessageLoop::QuitNow), Return(0))); // Buffer is full. - test_stream_->Start(&mock_callback); + test_stream->Start(&mock_callback); message_loop_.RunAllPending(); - EXPECT_CALL(mock_manager(), ReleaseOutputStream(test_stream_.get())); EXPECT_CALL(mock_alsa_wrapper_, PcmClose(kFakeHandle)) .WillOnce(Return(0)); EXPECT_CALL(mock_alsa_wrapper_, PcmName(kFakeHandle)) .WillOnce(Return(kTestDeviceName)); - test_stream_->Close(); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, WritePacket_FinishedPacket) { - InitBuffer(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); // Nothing should happen. Don't set any expectations and Our strict mocks // should verify most of this. // Test empty buffer. - test_stream_->buffer_->Clear(); - test_stream_->WritePacket(); + test_stream->buffer_->Clear(); + test_stream->WritePacket(); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, WritePacket_NormalPacket) { - InitBuffer(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); // Write a little less than half the data. int written = packet_->GetDataSize() / kTestBytesPerFrame / 2 - 1; EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(_, packet_->GetData(), _)) .WillOnce(Return(written)); - test_stream_->WritePacket(); + test_stream->WritePacket(); - ASSERT_EQ(test_stream_->buffer_->forward_bytes(), + ASSERT_EQ(test_stream->buffer_->forward_bytes(), packet_->GetDataSize() - written * kTestBytesPerFrame); // Write the rest. @@ -484,12 +497,14 @@ TEST_F(AlsaPcmOutputStreamTest, WritePacket_NormalPacket) { PcmWritei(_, packet_->GetData() + written * kTestBytesPerFrame, _)) .WillOnce(Return(packet_->GetDataSize() / kTestBytesPerFrame - written)); - test_stream_->WritePacket(); - EXPECT_EQ(0u, test_stream_->buffer_->forward_bytes()); + test_stream->WritePacket(); + EXPECT_EQ(0u, test_stream->buffer_->forward_bytes()); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, WritePacket_WriteFails) { - InitBuffer(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); // Fail due to a recoverable error and see that PcmRecover code path // continues normally. @@ -498,9 +513,9 @@ TEST_F(AlsaPcmOutputStreamTest, WritePacket_WriteFails) { EXPECT_CALL(mock_alsa_wrapper_, PcmRecover(_, _, _)) .WillOnce(Return(packet_->GetDataSize() / kTestBytesPerFrame / 2 - 1)); - test_stream_->WritePacket(); + test_stream->WritePacket(); - ASSERT_EQ(test_stream_->buffer_->forward_bytes(), + ASSERT_EQ(test_stream->buffer_->forward_bytes(), packet_->GetDataSize() / 2 + kTestBytesPerFrame); // Fail the next write, and see that stop_stream_ is set. @@ -510,24 +525,28 @@ TEST_F(AlsaPcmOutputStreamTest, WritePacket_WriteFails) { .WillOnce(Return(kTestFailedErrno)); EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) .WillOnce(Return(kDummyMessage)); - test_stream_->WritePacket(); - EXPECT_EQ(test_stream_->buffer_->forward_bytes(), + test_stream->WritePacket(); + EXPECT_EQ(test_stream->buffer_->forward_bytes(), packet_->GetDataSize() / 2 + kTestBytesPerFrame); - EXPECT_TRUE(test_stream_->stop_stream_); + EXPECT_TRUE(test_stream->stop_stream_); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, WritePacket_StopStream) { - InitBuffer(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); // No expectations set on the strict mock because nothing should be called. - test_stream_->stop_stream_ = true; - test_stream_->WritePacket(); - EXPECT_EQ(0u, test_stream_->buffer_->forward_bytes()); + test_stream->stop_stream_ = true; + test_stream->WritePacket(); + EXPECT_EQ(0u, test_stream->buffer_->forward_bytes()); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, BufferPacket) { - InitBuffer(); - test_stream_->buffer_->Clear(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); + test_stream->buffer_->Clear(); MockAudioSourceCallback mock_callback; EXPECT_CALL(mock_alsa_wrapper_, PcmState(_)) @@ -539,21 +558,23 @@ TEST_F(AlsaPcmOutputStreamTest, BufferPacket) { // Return a partially filled packet. EXPECT_CALL(mock_callback, - OnMoreData(test_stream_.get(), _, _, _)) + OnMoreData(test_stream, _, _, _)) .WillOnce(Return(10)); bool source_exhausted; - test_stream_->set_source_callback(&mock_callback); - test_stream_->packet_size_ = kTestPacketSize; - test_stream_->BufferPacket(&source_exhausted); + test_stream->set_source_callback(&mock_callback); + test_stream->packet_size_ = kTestPacketSize; + test_stream->BufferPacket(&source_exhausted); - EXPECT_EQ(10u, test_stream_->buffer_->forward_bytes()); + EXPECT_EQ(10u, test_stream->buffer_->forward_bytes()); EXPECT_FALSE(source_exhausted); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Negative) { - InitBuffer(); - test_stream_->buffer_->Clear(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); + test_stream->buffer_->Clear(); // Simulate where the underrun has occurred right after checking the delay. MockAudioSourceCallback mock_callback; @@ -563,22 +584,23 @@ TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Negative) { .WillOnce(DoAll(SetArgumentPointee<1>(-1), Return(0))); EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) .WillRepeatedly(Return(0)); // Buffer is full. - EXPECT_CALL(mock_callback, - OnMoreData(test_stream_.get(), _, _, _)) + EXPECT_CALL(mock_callback, OnMoreData(test_stream, _, _, _)) .WillOnce(Return(10)); bool source_exhausted; - test_stream_->set_source_callback(&mock_callback); - test_stream_->packet_size_ = kTestPacketSize; - test_stream_->BufferPacket(&source_exhausted); + test_stream->set_source_callback(&mock_callback); + test_stream->packet_size_ = kTestPacketSize; + test_stream->BufferPacket(&source_exhausted); - EXPECT_EQ(10u, test_stream_->buffer_->forward_bytes()); + EXPECT_EQ(10u, test_stream->buffer_->forward_bytes()); EXPECT_FALSE(source_exhausted); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Underrun) { - InitBuffer(); - test_stream_->buffer_->Clear(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); + test_stream->buffer_->Clear(); // If ALSA has underrun then we should assume a delay of zero. MockAudioSourceCallback mock_callback; @@ -587,28 +609,31 @@ TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Underrun) { EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) .WillRepeatedly(Return(0)); // Buffer is full. EXPECT_CALL(mock_callback, - OnMoreData(test_stream_.get(), _, _, AllOf( + OnMoreData(test_stream, _, _, AllOf( Field(&AudioBuffersState::pending_bytes, 0), Field(&AudioBuffersState::hardware_delay_bytes, 0)))) .WillOnce(Return(10)); bool source_exhausted; - test_stream_->set_source_callback(&mock_callback); - test_stream_->packet_size_ = kTestPacketSize; - test_stream_->BufferPacket(&source_exhausted); + test_stream->set_source_callback(&mock_callback); + test_stream->packet_size_ = kTestPacketSize; + test_stream->BufferPacket(&source_exhausted); - EXPECT_EQ(10u, test_stream_->buffer_->forward_bytes()); + EXPECT_EQ(10u, test_stream->buffer_->forward_bytes()); EXPECT_FALSE(source_exhausted); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, BufferPacket_FullBuffer) { - InitBuffer(); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); // No expectations set on the strict mock because nothing should be called. bool source_exhausted; - test_stream_->packet_size_ = kTestPacketSize; - test_stream_->BufferPacket(&source_exhausted); - EXPECT_EQ(kTestPacketSize, test_stream_->buffer_->forward_bytes()); + test_stream->packet_size_ = kTestPacketSize; + test_stream->BufferPacket(&source_exhausted); + EXPECT_EQ(kTestPacketSize, test_stream->buffer_->forward_bytes()); EXPECT_FALSE(source_exhausted); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect) { @@ -670,12 +695,13 @@ TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_DeviceSelect) { EXPECT_CALL(mock_alsa_wrapper_, DeviceNameGetHint(_, StrEq("NAME"))) .WillRepeatedly(Invoke(EchoHint)); - test_stream_.reset(CreateStream(kExpectedLayouts[i])); - EXPECT_TRUE(test_stream_->AutoSelectDevice(i)); - EXPECT_EQ(kExpectedDownmix[i], test_stream_->should_downmix_); + AlsaPcmOutputStream* test_stream = CreateStream(kExpectedLayouts[i]); + EXPECT_TRUE(test_stream->AutoSelectDevice(i)); + EXPECT_EQ(kExpectedDownmix[i], test_stream->should_downmix_); Mock::VerifyAndClearExpectations(&mock_alsa_wrapper_); Mock::VerifyAndClearExpectations(mock_manager_.get()); + test_stream->Close(); } } @@ -720,8 +746,9 @@ TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_FallbackDevices) { EXPECT_CALL(mock_alsa_wrapper_, PcmOpen(_, StrEq(fourth_try.c_str()), _, _)) .WillOnce(Return(kTestFailedErrno)); - test_stream_.reset(CreateStream(CHANNEL_LAYOUT_5POINT0)); - EXPECT_FALSE(test_stream_->AutoSelectDevice(5)); + AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5POINT0); + EXPECT_FALSE(test_stream->AutoSelectDevice(5)); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail) { @@ -738,53 +765,62 @@ TEST_F(AlsaPcmOutputStreamTest, AutoSelectDevice_HintFail) { EXPECT_CALL(mock_alsa_wrapper_, StrError(kTestFailedErrno)) .WillOnce(Return(kDummyMessage)); - test_stream_.reset(CreateStream(CHANNEL_LAYOUT_5POINT0)); - EXPECT_TRUE(test_stream_->AutoSelectDevice(5)); - EXPECT_TRUE(test_stream_->should_downmix_); + AlsaPcmOutputStream* test_stream = CreateStream(CHANNEL_LAYOUT_5POINT0); + EXPECT_TRUE(test_stream->AutoSelectDevice(5)); + EXPECT_TRUE(test_stream->should_downmix_); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, BufferPacket_StopStream) { - InitBuffer(); - test_stream_->stop_stream_ = true; + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + InitBuffer(test_stream); + test_stream->stop_stream_ = true; bool source_exhausted; - test_stream_->BufferPacket(&source_exhausted); - EXPECT_EQ(0u, test_stream_->buffer_->forward_bytes()); + test_stream->BufferPacket(&source_exhausted); + EXPECT_EQ(0u, test_stream->buffer_->forward_bytes()); EXPECT_TRUE(source_exhausted); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite) { - test_stream_->TransitionTo(AlsaPcmOutputStream::kIsOpened); - test_stream_->TransitionTo(AlsaPcmOutputStream::kIsPlaying); - - InitBuffer(); - + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened); + test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); +DLOG(WARNING) << test_stream->state(); + InitBuffer(test_stream); + DLOG(WARNING) << test_stream->state(); EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_)) .WillOnce(Return(10)); - test_stream_->ScheduleNextWrite(false); - + test_stream->ScheduleNextWrite(false); + DLOG(WARNING) << test_stream->state(); // TODO(sergeyu): Figure out how to check that the task has been added to the // message loop. // Cleanup the message queue. Currently ~MessageQueue() doesn't free pending // tasks unless running on valgrind. The code below is needed to keep // heapcheck happy. - test_stream_->stop_stream_ = true; - test_stream_->TransitionTo(AlsaPcmOutputStream::kIsClosed); + test_stream->stop_stream_ = true; + DLOG(WARNING) << test_stream->state(); + test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed); + DLOG(WARNING) << test_stream->state(); + test_stream->Close(); } TEST_F(AlsaPcmOutputStreamTest, ScheduleNextWrite_StopStream) { - test_stream_->TransitionTo(AlsaPcmOutputStream::kIsOpened); - test_stream_->TransitionTo(AlsaPcmOutputStream::kIsPlaying); + AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout); + test_stream->TransitionTo(AlsaPcmOutputStream::kIsOpened); + test_stream->TransitionTo(AlsaPcmOutputStream::kIsPlaying); - InitBuffer(); + InitBuffer(test_stream); - test_stream_->stop_stream_ = true; - test_stream_->ScheduleNextWrite(true); + test_stream->stop_stream_ = true; + test_stream->ScheduleNextWrite(true); // TODO(ajwong): Find a way to test whether or not another task has been // posted so we can verify that the Alsa code will indeed break the task // posting loop. - test_stream_->TransitionTo(AlsaPcmOutputStream::kIsClosed); + test_stream->TransitionTo(AlsaPcmOutputStream::kIsClosed); + test_stream->Close(); } diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc index da24f12..3af14b2 100644 --- a/media/audio/linux/audio_manager_linux.cc +++ b/media/audio/linux/audio_manager_linux.cc @@ -11,8 +11,6 @@ #include "base/process_util.h" #include "base/stl_util.h" #include "media/audio/audio_output_dispatcher.h" -#include "media/audio/fake_audio_input_stream.h" -#include "media/audio/fake_audio_output_stream.h" #include "media/audio/linux/alsa_input.h" #include "media/audio/linux/alsa_output.h" #include "media/audio/linux/alsa_wrapper.h" @@ -23,9 +21,7 @@ #include "media/base/media_switches.h" // Maximum number of output streams that can be open simultaneously. -static const size_t kMaxOutputStreams = 50; - -static const int kMaxInputChannels = 2; +static const int kMaxOutputStreams = 50; // Since "default", "pulse" and "dmix" devices are virtual devices mapped to // real devices, we remove them from the list to avoiding duplicate counting. @@ -47,67 +43,12 @@ bool AudioManagerLinux::HasAudioInputDevices() { return HasAnyAlsaAudioDevice(kStreamCapture); } -AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream( - const AudioParameters& params) { - // Early return for testing hook. - if (params.format == AudioParameters::AUDIO_MOCK) - return FakeAudioOutputStream::MakeFakeStream(params); - - // Don't allow opening more than |kMaxOutputStreams| streams. - if (active_output_stream_count_ >= kMaxOutputStreams) - return NULL; - - AudioOutputStream* stream = NULL; -#if defined(USE_PULSEAUDIO) - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUsePulseAudio)) { - stream = new PulseAudioOutputStream(params, this); - } else { -#endif - std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice; - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAlsaOutputDevice)) { - device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kAlsaOutputDevice); - } - stream = new AlsaPcmOutputStream(device_name, params, wrapper_.get(), this); -#if defined(USE_PULSEAUDIO) - } -#endif - ++active_output_stream_count_; - DCHECK(stream); - return stream; +AudioManagerLinux::AudioManagerLinux() { + SetMaxOutputStreamsAllowed(kMaxOutputStreams); } -AudioInputStream* AudioManagerLinux::MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) { - if (!params.IsValid() || params.channels > kMaxInputChannels || - device_id.empty()) { - return NULL; - } - - if (params.format == AudioParameters::AUDIO_MOCK) { - return FakeAudioInputStream::MakeFakeStream(params); - } - - std::string device_name = (device_id == AudioManagerBase::kDefaultDeviceId) ? - AlsaPcmInputStream::kAutoSelectDevice : device_id; - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) { - device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kAlsaInputDevice); - } - - AlsaPcmInputStream* stream = new AlsaPcmInputStream(this, - device_name, params, wrapper_.get()); - - return stream; -} - -AudioManagerLinux::AudioManagerLinux() : active_output_stream_count_(0U) {} - AudioManagerLinux::~AudioManagerLinux() { Shutdown(); - // All the streams should have been deleted on the audio thread via Shutdown. - CHECK_EQ(active_output_stream_count_, 0U); } void AudioManagerLinux::Init() { @@ -123,14 +64,6 @@ void AudioManagerLinux::UnMuteAll() { NOTIMPLEMENTED(); } -void AudioManagerLinux::ReleaseOutputStream(AudioOutputStream* stream) { - if (stream) { - delete stream; - --active_output_stream_count_; - DCHECK_GE(active_output_stream_count_, 0U); - } -} - bool AudioManagerLinux::CanShowAudioInputSettings() { scoped_ptr<base::Environment> env(base::Environment::Create()); base::nix::DesktopEnvironment desktop = base::nix::GetDesktopEnvironment( @@ -303,6 +236,65 @@ bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) { return has_device; } +AudioOutputStream* AudioManagerLinux::MakeLinearOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return MakeOutputStream(params); +} + +AudioOutputStream* AudioManagerLinux::MakeLowLatencyOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + return MakeOutputStream(params); +} + +AudioInputStream* AudioManagerLinux::MakeLinearInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return MakeInputStream(params, device_id); +} + +AudioInputStream* AudioManagerLinux::MakeLowLatencyInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + return MakeInputStream(params, device_id); +} + +AudioOutputStream* AudioManagerLinux::MakeOutputStream( + const AudioParameters& params) { + AudioOutputStream* stream = NULL; +#if defined(USE_PULSEAUDIO) + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUsePulseAudio)) { + stream = new PulseAudioOutputStream(params, this); + } else { +#endif + std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice; + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAlsaOutputDevice)) { + device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kAlsaOutputDevice); + } + stream = new AlsaPcmOutputStream(device_name, params, wrapper_.get(), this); +#if defined(USE_PULSEAUDIO) + } +#endif + DCHECK(stream); + return stream; +} + +AudioInputStream* AudioManagerLinux::MakeInputStream( + const AudioParameters& params, const std::string& device_id) { + + std::string device_name = (device_id == AudioManagerBase::kDefaultDeviceId) ? + AlsaPcmInputStream::kAutoSelectDevice : device_id; + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) { + device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kAlsaInputDevice); + } + + return new AlsaPcmInputStream(this, device_name, params, wrapper_.get()); +} + AudioManager* CreateAudioManager() { return new AudioManagerLinux(); } diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/linux/audio_manager_linux.h index d4d4bb1..81e53c4 100644 --- a/media/audio/linux/audio_manager_linux.h +++ b/media/audio/linux/audio_manager_linux.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -23,19 +23,22 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { // Implementation of AudioManager. virtual bool HasAudioOutputDevices() OVERRIDE; virtual bool HasAudioInputDevices() OVERRIDE; - virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; - virtual AudioInputStream* MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual bool CanShowAudioInputSettings() OVERRIDE; virtual void ShowAudioInputSettings() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; - virtual void MuteAll() OVERRIDE; virtual void UnMuteAll() OVERRIDE; - virtual void ReleaseOutputStream(AudioOutputStream* stream); + // Implementation of AudioManagerBase. + virtual AudioOutputStream* MakeLinearOutputStream( + const AudioParameters& params) OVERRIDE; + virtual AudioOutputStream* MakeLowLatencyOutputStream( + const AudioParameters& params) 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; protected: virtual ~AudioManagerLinux(); @@ -58,9 +61,14 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { // Returns true if a device is present for the given stream type. bool HasAnyAlsaAudioDevice(StreamType stream); - scoped_ptr<AlsaWrapper> wrapper_; + // Called by MakeLinearOutputStream and MakeLowLatencyOutputStream. + AudioOutputStream* MakeOutputStream(const AudioParameters& params); - size_t active_output_stream_count_; + // Called by MakeLinearInputStream and MakeLowLatencyInputStream. + AudioInputStream* MakeInputStream(const AudioParameters& params, + const std::string& device_id); + + scoped_ptr<AlsaWrapper> wrapper_; DISALLOW_COPY_AND_ASSIGN(AudioManagerLinux); }; diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 3751460..fdaf5a1 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -8,8 +8,6 @@ #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/sys_string_conversions.h" -#include "media/audio/fake_audio_input_stream.h" -#include "media/audio/fake_audio_output_stream.h" #include "media/audio/mac/audio_input_mac.h" #include "media/audio/mac/audio_low_latency_input_mac.h" #include "media/audio/mac/audio_low_latency_output_mac.h" @@ -17,38 +15,12 @@ #include "media/audio/mac/audio_output_mac.h" #include "media/base/limits.h" -static const int kMaxInputChannels = 2; - // Maximum number of output streams that can be open simultaneously. -static const size_t kMaxOutputStreams = 50; +static const int kMaxOutputStreams = 50; // By experiment the maximum number of audio streams allowed in Leopard // is 18. But we put a slightly smaller number just to be safe. -static const size_t kMaxOutputStreamsLeopard = 15; - -// Initialized to ether |kMaxOutputStreams| or |kMaxOutputStreamsLeopard|. -static size_t g_max_output_streams = 0; - -// Returns the number of audio streams allowed. This is a practical limit to -// prevent failure caused by too many audio streams opened. -static size_t GetMaxAudioOutputStreamsAllowed() { - if (g_max_output_streams == 0) { - // We are hitting a bug in Leopard where too many audio streams will cause - // a deadlock in the AudioQueue API when starting the stream. Unfortunately - // there's no way to detect it within the AudioQueue API, so we put a - // special hard limit only for Leopard. - // See bug: http://crbug.com/30242 - if (base::mac::IsOSLeopardOrEarlier()) { - g_max_output_streams = kMaxOutputStreamsLeopard; - } else { - // In OS other than OSX Leopard, the number of audio streams - // allowed is a lot more. - g_max_output_streams = kMaxOutputStreams; - } - } - - return g_max_output_streams; -} +static const int kMaxOutputStreamsLeopard = 15; static bool HasAudioHardware(AudioObjectPropertySelector selector) { AudioDeviceID output_device_id = kAudioObjectUnknown; @@ -235,8 +207,17 @@ static AudioDeviceID GetAudioDeviceIdByUId(bool is_input, return audio_device_id; } -AudioManagerMac::AudioManagerMac() - : num_output_streams_(0) { +AudioManagerMac::AudioManagerMac() { + // We are hitting a bug in Leopard where too many audio streams will cause + // a deadlock in the AudioQueue API when starting the stream. Unfortunately + // there's no way to detect it within the AudioQueue API, so we put a + // special hard limit only for Leopard. + // See bug: http://crbug.com/30242 + // In OS other than OSX Leopard, the number of audio streams + // allowed is a lot more. + int max_output_stream = base::mac::IsOSLeopardOrEarlier() ? + kMaxOutputStreamsLeopard : kMaxOutputStreams; + SetMaxOutputStreamsAllowed(max_output_stream); } AudioManagerMac::~AudioManagerMac() { @@ -269,51 +250,6 @@ void AudioManagerMac::GetAudioInputDeviceNames( } } -AudioOutputStream* AudioManagerMac::MakeAudioOutputStream( - const AudioParameters& params) { - if (!params.IsValid()) - return NULL; - - // Limit the number of audio streams opened. This is to prevent using - // excessive resources for a large number of audio streams. More - // importantly it prevents instability on certain systems. - // See bug: http://crbug.com/30242 - if (num_output_streams_ >= GetMaxAudioOutputStreamsAllowed()) { - return NULL; - } - - if (params.format == AudioParameters::AUDIO_MOCK) { - return FakeAudioOutputStream::MakeFakeStream(params); - } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { - num_output_streams_++; - return new PCMQueueOutAudioOutputStream(this, params); - } else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) { - num_output_streams_++; - return new AUAudioOutputStream(this, params); - } - return NULL; -} - -AudioInputStream* AudioManagerMac::MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) { - if (!params.IsValid() || (params.channels > kMaxInputChannels) || - device_id.empty()) - return NULL; - - if (params.format == AudioParameters::AUDIO_MOCK) { - return FakeAudioInputStream::MakeFakeStream(params); - } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { - return new PCMQueueInAudioInputStream(this, params); - } else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) { - // Gets the AudioDeviceID that refers to the AudioDevice with the device - // unique id. This AudioDeviceID is used to set the device for Audio Unit. - AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); - if (audio_device_id != kAudioObjectUnknown) - return new AUAudioInputStream(this, params, audio_device_id); - } - return NULL; -} - void AudioManagerMac::MuteAll() { // TODO(cpu): implement. } @@ -322,16 +258,35 @@ void AudioManagerMac::UnMuteAll() { // TODO(cpu): implement. } -// Called by the stream when it has been released by calling Close(). -void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) { - DCHECK(stream); - num_output_streams_--; - delete stream; +AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return new PCMQueueOutAudioOutputStream(this, params); } -// Called by the stream when it has been released by calling Close(). -void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { - delete stream; +AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + return new AUAudioOutputStream(this, params); +} + +AudioInputStream* AudioManagerMac::MakeLinearInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return new PCMQueueInAudioInputStream(this, params); +} + +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 AudioDevice 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); + + return stream; } AudioManager* CreateAudioManager() { diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index 2060b66..f535415 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -21,27 +21,23 @@ class AudioManagerMac : public AudioManagerBase { virtual bool HasAudioInputDevices() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; - virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; - virtual AudioInputStream* MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual void MuteAll() OVERRIDE; virtual void UnMuteAll() OVERRIDE; - // Mac-only method to free the streams created by above facoty methods. - // They are called internally by the respective audio stream when it has - // been closed. - void ReleaseOutputStream(AudioOutputStream* stream); - void ReleaseInputStream(AudioInputStream* stream); + // Implementation of AudioManagerBase. + virtual AudioOutputStream* MakeLinearOutputStream( + const AudioParameters& params) OVERRIDE; + virtual AudioOutputStream* MakeLowLatencyOutputStream( + const AudioParameters& params) 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; protected: virtual ~AudioManagerMac(); private: - - // Number of currently open output streams. - size_t num_output_streams_; - DISALLOW_COPY_AND_ASSIGN(AudioManagerMac); }; diff --git a/media/audio/openbsd/audio_manager_openbsd.cc b/media/audio/openbsd/audio_manager_openbsd.cc index 7222748..1ef9398 100644 --- a/media/audio/openbsd/audio_manager_openbsd.cc +++ b/media/audio/openbsd/audio_manager_openbsd.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -7,8 +7,6 @@ #include "base/command_line.h" #include "base/stl_util.h" #include "media/audio/audio_output_dispatcher.h" -#include "media/audio/fake_audio_input_stream.h" -#include "media/audio/fake_audio_output_stream.h" #if defined(USE_PULSEAUDIO) #include "media/audio/pulse/pulse_output.h" #endif @@ -18,7 +16,7 @@ #include <fcntl.h> // Maximum number of output streams that can be open simultaneously. -static const size_t kMaxOutputStreams = 50; +static const int kMaxOutputStreams = 50; // Implementation of AudioManager. static bool HasAudioHardware() { @@ -43,43 +41,8 @@ bool AudioManagerOpenBSD::HasAudioInputDevices() { return HasAudioHardware(); } -AudioOutputStream* AudioManagerOpenBSD::MakeAudioOutputStream( - const AudioParameters& params) { - // Early return for testing hook. Do this before checking for - // |initialized_|. - if (params.format == AudioParameters::AUDIO_MOCK) { - return FakeAudioOutputStream::MakeFakeStream(params); - } - - if (!initialized()) { - return NULL; - } - - // Don't allow opening more than |kMaxOutputStreams| streams. - if (active_streams_.size() >= kMaxOutputStreams) { - return NULL; - } - - AudioOutputStream* stream; -#if defined(USE_PULSEAUDIO) - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUsePulseAudio)) { - stream = new PulseAudioOutputStream(params, this); - active_streams_.insert(stream); - return stream; - } -#endif - - NOTIMPLEMENTED(); - return NULL; -} - -AudioInputStream* AudioManagerOpenBSD::MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) { - NOTIMPLEMENTED(); - return NULL; -} - AudioManagerOpenBSD::AudioManagerOpenBSD() { + SetMaxOutputStreamsAllowed(kMaxOutputStreams); } AudioManagerOpenBSD::~AudioManagerOpenBSD() { @@ -92,10 +55,6 @@ AudioManagerOpenBSD::~AudioManagerOpenBSD() { // Free output dispatchers, closing all remaining open streams. output_dispatchers_.clear(); - - // Delete all the streams. Have to do it manually, we don't have ScopedSet<>, - // and we are not using ScopedVector<> because search there is slow. - STLDeleteElements(&active_streams_); } void AudioManagerOpenBSD::Init() { @@ -110,11 +69,46 @@ void AudioManagerOpenBSD::UnMuteAll() { NOTIMPLEMENTED(); } -void AudioManagerOpenBSD::ReleaseOutputStream(AudioOutputStream* stream) { - if (stream) { - active_streams_.erase(stream); - delete stream; +AudioOutputStream* AudioManagerOpenBSD::MakeLinearOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return MakeOutputStream(params); +} + +AudioOutputStream* AudioManagerOpenBSD::MakeLowLatencyOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + return MakeOutputStream(params); +} + +AudioInputStream* AudioManagerOpenBSD::MakeLinearInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + NOTIMPLEMENTED(); + return NULL; +} + +AudioInputStream* AudioManagerOpenBSD::MakeLowLatencyInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + NOTIMPLEMENTED(); + return NULL; +} + +AudioOutputStream* AudioManagerOpenBSD::MakeOutputStream( + const AudioParameters& params) { + if (!initialized()) { + return NULL; } + +#if defined(USE_PULSEAUDIO) + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUsePulseAudio)) { + return new PulseAudioOutputStream(params, this); + } +#endif + + NOTIMPLEMENTED(); + return NULL; } // static diff --git a/media/audio/openbsd/audio_manager_openbsd.h b/media/audio/openbsd/audio_manager_openbsd.h index fa49203..86b56c0 100644 --- a/media/audio/openbsd/audio_manager_openbsd.h +++ b/media/audio/openbsd/audio_manager_openbsd.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -20,21 +20,25 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase { // Implementation of AudioManager. virtual bool HasAudioOutputDevices() OVERRIDE; virtual bool HasAudioInputDevices() OVERRIDE; - virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; - virtual AudioInputStream* MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) OVERRIDE; - virtual void MuteAll() OVERRIDE; virtual void UnMuteAll() OVERRIDE; - virtual void ReleaseOutputStream(AudioOutputStream* stream); + // Implementation of AudioManagerBase. + virtual AudioOutputStream* MakeLinearOutputStream( + const AudioParameters& params) OVERRIDE; + virtual AudioOutputStream* MakeLowLatencyOutputStream( + const AudioParameters& params) 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; protected: virtual ~AudioManagerOpenBSD(); private: - std::set<AudioOutputStream*> active_streams_; + // Called by MakeLinearOutputStream and MakeLowLatencyOutputStream. + AudioOutputStream* MakeOutputStream(const AudioParameters& params); DISALLOW_COPY_AND_ASSIGN(AudioManagerOpenBSD); }; diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index 7ee2a76..2827d11 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -19,8 +19,6 @@ #include "base/string_number_conversions.h" #include "base/string_util.h" #include "media/audio/audio_util.h" -#include "media/audio/fake_audio_input_stream.h" -#include "media/audio/fake_audio_output_stream.h" #include "media/audio/win/audio_low_latency_input_win.h" #include "media/audio/win/audio_low_latency_output_win.h" #include "media/audio/win/audio_manager_win.h" @@ -41,14 +39,13 @@ DEFINE_GUID(AM_KSCATEGORY_AUDIO, 0x6994ad04, 0x93ef, 0x11d0, 0xa3, 0xcc, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96); // Maximum number of output streams that can be open simultaneously. -static const size_t kMaxOutputStreams = 50; +static const int kMaxOutputStreams = 50; // Up to 8 channels can be passed to the driver. // This should work, given the right drivers, but graceful error handling is // needed. static const int kWinMaxChannels = 8; -static const int kWinMaxInputChannels = 2; // We use 3 buffers for recording audio so that if a recording callback takes // some time to return we won't lose audio. More buffers while recording are // ok because they don't introduce any delay in recording, unlike in playback @@ -98,8 +95,7 @@ static string16 GetDeviceAndDriverInfo(HDEVINFO device_info, return device_and_driver_info; } -AudioManagerWin::AudioManagerWin() - : num_output_streams_(0) { +AudioManagerWin::AudioManagerWin() { if (!media::IsWASAPISupported()) { // Use the Wave API for device enumeration if XP or lower. enumeration_type_ = kWaveEnumeration; @@ -107,11 +103,11 @@ AudioManagerWin::AudioManagerWin() // Use the MMDevice API for device enumeration if Vista or higher. enumeration_type_ = kMMDeviceEnumeration; } + + SetMaxOutputStreamsAllowed(kMaxOutputStreams); } AudioManagerWin::~AudioManagerWin() { - // All output streams should be released upon termination. - DCHECK_EQ(0, num_output_streams_); } bool AudioManagerWin::HasAudioOutputDevices() { @@ -122,75 +118,6 @@ bool AudioManagerWin::HasAudioInputDevices() { return (::waveInGetNumDevs() != 0); } -// Factory for the implementations of AudioOutputStream. Two implementations -// should suffice most windows user's needs. -// - PCMWaveOutAudioOutputStream: Based on the waveOut API. -// - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. -AudioOutputStream* AudioManagerWin::MakeAudioOutputStream( - const AudioParameters& params) { - if (!params.IsValid() || (params.channels > kWinMaxChannels)) - return NULL; - - // Limit the number of audio streams opened. - if (num_output_streams_ >= kMaxOutputStreams) { - return NULL; - } - - if (params.format == AudioParameters::AUDIO_MOCK) { - return FakeAudioOutputStream::MakeFakeStream(params); - } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { - num_output_streams_++; - return new PCMWaveOutAudioOutputStream(this, params, 3, WAVE_MAPPER); - } else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) { - num_output_streams_++; - if (!media::IsWASAPISupported()) { - // Fall back to Windows Wave implementation on Windows XP or lower. - DLOG(INFO) << "Using WaveOut since WASAPI requires at least Vista."; - return new PCMWaveOutAudioOutputStream(this, params, 2, WAVE_MAPPER); - } else { - // TODO(henrika): improve possibility to specify audio endpoint. - // Use the default device (same as for Wave) for now to be compatible. - return new WASAPIAudioOutputStream(this, params, eConsole); - } - } - return NULL; -} - -// Factory for the implementations of AudioInputStream. -AudioInputStream* AudioManagerWin::MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) { - if (!params.IsValid() || (params.channels > kWinMaxInputChannels) || - device_id.empty()) - return NULL; - - if (params.format == AudioParameters::AUDIO_MOCK) { - return FakeAudioInputStream::MakeFakeStream(params); - } else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) { - return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, - AudioManagerBase::kDefaultDeviceId); - } else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) { - if (!media::IsWASAPISupported()) { - // Fall back to Windows Wave implementation on Windows XP or lower. - DLOG(INFO) << "Using WaveIn since WASAPI requires at least Vista."; - return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, - device_id); - } else { - return new WASAPIAudioInputStream(this, params, device_id); - } - } - return NULL; -} - -void AudioManagerWin::ReleaseOutputStream(AudioOutputStream* stream) { - DCHECK(stream); - num_output_streams_--; - delete stream; -} - -void AudioManagerWin::ReleaseInputStream(AudioInputStream* stream) { - delete stream; -} - void AudioManagerWin::MuteAll() { } @@ -305,6 +232,70 @@ void AudioManagerWin::GetAudioInputDeviceNames( } } +// Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR +// mode. +// - PCMWaveOutAudioOutputStream: Based on the waveOut API. +AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + if (params.channels > kWinMaxChannels) + return NULL; + + return new PCMWaveOutAudioOutputStream(this, params, 3, WAVE_MAPPER); +} + +// Factory for the implementations of AudioOutputStream for +// AUDIO_PCM_LOW_LATENCY mode. Two implementations should suffice most +// windows user's needs. +// - PCMWaveOutAudioOutputStream: Based on the waveOut API. +// - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. +AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + if (params.channels > kWinMaxChannels) + return NULL; + + AudioOutputStream* stream = NULL; + if (!media::IsWASAPISupported()) { + // Fall back to Windows Wave implementation on Windows XP or lower. + DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; + stream = new PCMWaveOutAudioOutputStream(this, params, 2, WAVE_MAPPER); + } else { + // TODO(henrika): improve possibility to specify audio endpoint. + // Use the default device (same as for Wave) for now to be compatible. + stream = new WASAPIAudioOutputStream(this, params, eConsole); + } + + return stream; +} + +// Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR +// mode. +AudioInputStream* AudioManagerWin::MakeLinearInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); + return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, + AudioManagerBase::kDefaultDeviceId); +} + +// Factory for the implementations of AudioInputStream for +// AUDIO_PCM_LOW_LATENCY mode. +AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); + AudioInputStream* stream = NULL; + if (!media::IsWASAPISupported()) { + // Fall back to Windows Wave implementation on Windows XP or lower. + DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; + stream = new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, + device_id); + } else { + stream = new WASAPIAudioInputStream(this, params, device_id); + } + + return stream; +} + /// static AudioManager* CreateAudioManager() { return new AudioManagerWin(); diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index dd41699..3539ef0 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -22,10 +22,6 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { // Implementation of AudioManager. virtual bool HasAudioOutputDevices() OVERRIDE; virtual bool HasAudioInputDevices() OVERRIDE; - virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; - virtual AudioInputStream* MakeAudioInputStream( - const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual void MuteAll() OVERRIDE; virtual void UnMuteAll() OVERRIDE; virtual string16 GetAudioInputDeviceModel() OVERRIDE; @@ -34,12 +30,15 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; - // Windows-only methods to free a stream created in MakeAudioStream. These - // are called internally by the audio stream when it has been closed. - void ReleaseOutputStream(AudioOutputStream* stream); - - // Called internally by the audio stream when it has been closed. - void ReleaseInputStream(AudioInputStream* stream); + // Implementation of AudioManagerBase. + virtual AudioOutputStream* MakeLinearOutputStream( + const AudioParameters& params) OVERRIDE; + virtual AudioOutputStream* MakeLowLatencyOutputStream( + const AudioParameters& params) 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; protected: virtual ~AudioManagerWin(); @@ -60,9 +59,6 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { enumeration_type_ = type; } - // Number of currently open output streams. - int num_output_streams_; - DISALLOW_COPY_AND_ASSIGN(AudioManagerWin); }; |