summaryrefslogtreecommitdiffstats
path: root/media/audio
diff options
context:
space:
mode:
Diffstat (limited to 'media/audio')
-rw-r--r--media/audio/audio_manager_base.cc18
-rw-r--r--media/audio/audio_manager_base.h1
-rw-r--r--media/audio/audio_output_dispatcher.cc154
-rw-r--r--media/audio/audio_output_dispatcher.h105
-rw-r--r--media/audio/audio_output_dispatcher_impl.cc200
-rw-r--r--media/audio/audio_output_dispatcher_impl.h102
-rw-r--r--media/audio/audio_output_mixer.cc251
-rw-r--r--media/audio/audio_output_mixer.h92
-rw-r--r--media/audio/audio_output_proxy.cc23
-rw-r--r--media/audio/audio_output_proxy.h4
-rw-r--r--media/audio/audio_output_proxy_unittest.cc372
11 files changed, 346 insertions, 976 deletions
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc
index a0c1c4c..45bf0fc 100644
--- a/media/audio/audio_manager_base.cc
+++ b/media/audio/audio_manager_base.cc
@@ -5,15 +5,12 @@
#include "media/audio/audio_manager_base.h"
#include "base/bind.h"
-#include "base/command_line.h"
#include "base/message_loop_proxy.h"
#include "base/threading/thread.h"
-#include "media/audio/audio_output_dispatcher_impl.h"
-#include "media/audio/audio_output_mixer.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"
-#include "media/base/media_switches.h"
namespace media {
@@ -139,16 +136,9 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
scoped_refptr<AudioOutputDispatcher>& dispatcher =
output_dispatchers_[params];
- if (!dispatcher) {
- base::TimeDelta close_delay =
- base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds);
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- if (cmd_line->HasSwitch(switches::kEnableAudioMixer)) {
- dispatcher = new AudioOutputMixer(this, params, close_delay);
- } else {
- dispatcher = new AudioOutputDispatcherImpl(this, params, close_delay);
- }
- }
+ if (!dispatcher)
+ dispatcher = new AudioOutputDispatcher(
+ this, params, base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds));
return new AudioOutputProxy(dispatcher);
}
diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h
index 498b44c..acb85b6 100644
--- a/media/audio/audio_manager_base.h
+++ b/media/audio/audio_manager_base.h
@@ -6,7 +6,6 @@
#define MEDIA_AUDIO_AUDIO_MANAGER_BASE_H_
#include <map>
-#include <string>
#include "base/atomic_ref_count.h"
#include "base/compiler_specific.h"
diff --git a/media/audio/audio_output_dispatcher.cc b/media/audio/audio_output_dispatcher.cc
index bfd3fb8..998fc1b 100644
--- a/media/audio/audio_output_dispatcher.cc
+++ b/media/audio/audio_output_dispatcher.cc
@@ -4,16 +4,29 @@
#include "media/audio/audio_output_dispatcher.h"
+#include "base/bind.h"
+#include "base/compiler_specific.h"
#include "base/message_loop.h"
+#include "base/time.h"
+#include "media/audio/audio_io.h"
namespace media {
AudioOutputDispatcher::AudioOutputDispatcher(
- AudioManager* audio_manager,
- const AudioParameters& params)
+ AudioManager* audio_manager, const AudioParameters& params,
+ base::TimeDelta close_delay)
: audio_manager_(audio_manager),
message_loop_(MessageLoop::current()),
- params_(params) {
+ params_(params),
+ pause_delay_(base::TimeDelta::FromMilliseconds(
+ 2 * params.frames_per_buffer() *
+ base::Time::kMillisecondsPerSecond / params.sample_rate())),
+ paused_proxies_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
+ close_timer_(FROM_HERE,
+ close_delay,
+ weak_this_.GetWeakPtr(),
+ &AudioOutputDispatcher::ClosePendingStreams) {
// We expect to be instantiated on the audio thread. Otherwise the
// message_loop_ member will point to the wrong message loop!
DCHECK(audio_manager->GetMessageLoop()->BelongsToCurrentThread());
@@ -23,4 +36,139 @@ AudioOutputDispatcher::~AudioOutputDispatcher() {
DCHECK_EQ(MessageLoop::current(), message_loop_);
}
+bool AudioOutputDispatcher::StreamOpened() {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+ paused_proxies_++;
+
+ // Ensure that there is at least one open stream.
+ if (idle_streams_.empty() && !CreateAndOpenStream()) {
+ return false;
+ }
+
+ close_timer_.Reset();
+
+ return true;
+}
+
+AudioOutputStream* AudioOutputDispatcher::StreamStarted() {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+
+ if (idle_streams_.empty() && !CreateAndOpenStream()) {
+ return NULL;
+ }
+
+ AudioOutputStream* stream = idle_streams_.back();
+ idle_streams_.pop_back();
+
+ DCHECK_GT(paused_proxies_, 0u);
+ paused_proxies_--;
+
+ close_timer_.Reset();
+
+ // Schedule task to allocate streams for other proxies if we need to.
+ message_loop_->PostTask(FROM_HERE, base::Bind(
+ &AudioOutputDispatcher::OpenTask, weak_this_.GetWeakPtr()));
+
+ return stream;
+}
+
+void AudioOutputDispatcher::StreamStopped(AudioOutputStream* stream) {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+
+ paused_proxies_++;
+
+ pausing_streams_.push_front(stream);
+
+ // Don't recycle stream until two buffers worth of time has elapsed.
+ message_loop_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&AudioOutputDispatcher::StopStreamTask,
+ weak_this_.GetWeakPtr()),
+ pause_delay_);
+}
+
+void AudioOutputDispatcher::StopStreamTask() {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+
+ if (pausing_streams_.empty())
+ return;
+
+ AudioOutputStream* stream = pausing_streams_.back();
+ pausing_streams_.pop_back();
+ idle_streams_.push_back(stream);
+ close_timer_.Reset();
+}
+
+void AudioOutputDispatcher::StreamClosed() {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+
+ while (!pausing_streams_.empty()) {
+ idle_streams_.push_back(pausing_streams_.back());
+ pausing_streams_.pop_back();
+ }
+
+ DCHECK_GT(paused_proxies_, 0u);
+ paused_proxies_--;
+
+ while (idle_streams_.size() > paused_proxies_) {
+ idle_streams_.back()->Close();
+ idle_streams_.pop_back();
+ }
+}
+
+void AudioOutputDispatcher::Shutdown() {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+
+ // Cancel any pending tasks to close paused streams or create new ones.
+ weak_this_.InvalidateWeakPtrs();
+
+ // No AudioOutputProxy objects should hold a reference to us when we get
+ // to this stage.
+ DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
+
+ AudioOutputStreamList::iterator it = idle_streams_.begin();
+ for (; it != idle_streams_.end(); ++it)
+ (*it)->Close();
+ idle_streams_.clear();
+
+ it = pausing_streams_.begin();
+ for (; it != pausing_streams_.end(); ++it)
+ (*it)->Close();
+ pausing_streams_.clear();
+}
+
+bool AudioOutputDispatcher::CreateAndOpenStream() {
+ AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
+ if (!stream)
+ return false;
+
+ if (!stream->Open()) {
+ stream->Close();
+ return false;
+ }
+ idle_streams_.push_back(stream);
+ return true;
+}
+
+void AudioOutputDispatcher::OpenTask() {
+ // Make sure that we have at least one stream allocated if there
+ // are paused streams.
+ if (paused_proxies_ > 0 && idle_streams_.empty() &&
+ pausing_streams_.empty()) {
+ CreateAndOpenStream();
+ }
+
+ close_timer_.Reset();
+}
+
+// This method is called by |close_timer_|.
+void AudioOutputDispatcher::ClosePendingStreams() {
+ DCHECK_EQ(MessageLoop::current(), message_loop_);
+
+ while (!idle_streams_.empty()) {
+ idle_streams_.back()->Close();
+ idle_streams_.pop_back();
+ }
+}
+
} // namespace media
diff --git a/media/audio/audio_output_dispatcher.h b/media/audio/audio_output_dispatcher.h
index 5c96873..79474a4 100644
--- a/media/audio/audio_output_dispatcher.h
+++ b/media/audio/audio_output_dispatcher.h
@@ -2,26 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// AudioOutputDispatcher is a single-threaded base class that dispatches
-// creation and deletion of audio output streams. AudioOutputProxy objects use
-// this class to allocate and recycle actual audio output streams. When playback
-// is started, the proxy calls StartStream() to get an output stream that it
-// uses to play audio. When playback is stopped, the proxy returns the stream
-// back to the dispatcher by calling StopStream().
+// AudioOutputDispatcher is a single-threaded class that dispatches creation and
+// deletion of audio output streams. AudioOutputProxy objects use this class to
+// allocate and recycle actual audio output streams. When playback is started,
+// the proxy calls StreamStarted() to get an output stream that it uses to play
+// audio. When playback is stopped, the proxy returns the stream back to the
+// dispatcher by calling StreamStopped().
//
-// AudioManagerBase creates one specialization of AudioOutputDispatcher on the
-// audio thread for each possible set of audio parameters. I.e streams with
-// different parameters are managed independently. The AudioOutputDispatcher
-// instance is then deleted on the audio thread when the AudioManager shuts
-// down.
+// To avoid opening and closing audio devices more frequently than necessary,
+// each dispatcher has a pool of inactive physical streams. A stream is closed
+// only if it hasn't been used for a certain period of time (specified via the
+// constructor).
+//
+// AudioManagerBase creates one AudioOutputDispatcher on the audio thread for
+// each possible set of audio parameters. I.e streams with different parameters
+// are managed independently. The AudioOutputDispatcher instance is then
+// deleted on the audio thread when the AudioManager shuts down.
#ifndef MEDIA_AUDIO_AUDIO_OUTPUT_DISPATCHER_H_
#define MEDIA_AUDIO_AUDIO_OUTPUT_DISPATCHER_H_
+#include <vector>
+#include <list>
+
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/timer.h"
-#include "media/audio/audio_io.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_parameters.h"
@@ -29,43 +36,60 @@ class MessageLoop;
namespace media {
-class AudioOutputProxy;
+class AudioOutputStream;
class MEDIA_EXPORT AudioOutputDispatcher
: public base::RefCountedThreadSafe<AudioOutputDispatcher> {
public:
+ // |close_delay_ms| specifies delay after the stream is paused until
+ // the audio device is closed.
AudioOutputDispatcher(AudioManager* audio_manager,
- const AudioParameters& params);
+ const AudioParameters& params,
+ base::TimeDelta close_delay);
+ ~AudioOutputDispatcher();
- // Called by AudioOutputProxy to open the stream.
+ // Called by AudioOutputProxy when the stream is closed. Opens a new
+ // physical stream if there are no pending streams in |idle_streams_|.
// Returns false, if it fails to open it.
- virtual bool OpenStream() = 0;
-
- // Called by AudioOutputProxy when the stream is started.
- // Uses |callback| to get source data and report errors, if any.
- // Does *not* take ownership of this callback.
- // Returns true if started successfully, false otherwise.
- virtual bool StartStream(AudioOutputStream::AudioSourceCallback* callback,
- AudioOutputProxy* stream_proxy) = 0;
+ bool StreamOpened();
- // Called by AudioOutputProxy when the stream is stopped.
- // Ownership of the |stream_proxy| is passed to the dispatcher.
- virtual void StopStream(AudioOutputProxy* stream_proxy) = 0;
+ // Called by AudioOutputProxy when the stream is started. If there
+ // are pending streams in |idle_streams_| then it returns one of them,
+ // otherwise creates a new one. Returns a physical stream that must
+ // be used, or NULL if it fails to open audio device. Ownership of
+ // the result is passed to the caller.
+ AudioOutputStream* StreamStarted();
-
- // Called by AudioOutputProxy when the volume is set.
- virtual void StreamVolumeSet(AudioOutputProxy* stream_proxy,
- double volume) = 0;
+ // Called by AudioOutputProxy when the stream is stopped. Holds the
+ // stream temporarily in |pausing_streams_| and then |stream| is
+ // added to the pool of pending streams (i.e. |idle_streams_|).
+ // Ownership of the |stream| is passed to the dispatcher.
+ void StreamStopped(AudioOutputStream* stream);
// Called by AudioOutputProxy when the stream is closed.
- virtual void CloseStream(AudioOutputProxy* stream_proxy) = 0;
+ void StreamClosed();
// Called on the audio thread when the AudioManager is shutting down.
- virtual void Shutdown() = 0;
+ void Shutdown();
+
+ private:
+ friend class AudioOutputProxyTest;
- protected:
- friend class base::RefCountedThreadSafe<AudioOutputDispatcher>;
- virtual ~AudioOutputDispatcher();
+ // Creates a new physical output stream, opens it and pushes to
+ // |idle_streams_|. Returns false if the stream couldn't be created or
+ // opened.
+ bool CreateAndOpenStream();
+
+ // A task scheduled by StreamStarted(). Opens a new stream and puts
+ // it in |idle_streams_|.
+ void OpenTask();
+
+ // Before a stream is reused, it should sit idle for a bit. This task is
+ // called once that time has elapsed.
+ void StopStreamTask();
+
+ // Called by |close_timer_|. Closes all pending stream.
+ void ClosePendingStreams();
// A no-reference-held pointer (we don't want circular references) back to the
// AudioManager that owns this object.
@@ -73,7 +97,16 @@ class MEDIA_EXPORT AudioOutputDispatcher
MessageLoop* message_loop_;
AudioParameters params_;
- private:
+ base::TimeDelta pause_delay_;
+ size_t paused_proxies_;
+ typedef std::list<AudioOutputStream*> AudioOutputStreamList;
+ AudioOutputStreamList idle_streams_;
+ AudioOutputStreamList pausing_streams_;
+
+ // Used to post delayed tasks to ourselves that we cancel inside Shutdown().
+ base::WeakPtrFactory<AudioOutputDispatcher> weak_this_;
+ base::DelayTimer<AudioOutputDispatcher> close_timer_;
+
DISALLOW_COPY_AND_ASSIGN(AudioOutputDispatcher);
};
diff --git a/media/audio/audio_output_dispatcher_impl.cc b/media/audio/audio_output_dispatcher_impl.cc
deleted file mode 100644
index 8a060b7..0000000
--- a/media/audio/audio_output_dispatcher_impl.cc
+++ /dev/null
@@ -1,200 +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/audio_output_dispatcher_impl.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop.h"
-#include "base/time.h"
-#include "media/audio/audio_io.h"
-#include "media/audio/audio_output_proxy.h"
-#include "media/audio/audio_util.h"
-
-namespace media {
-
-AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
- AudioManager* audio_manager,
- const AudioParameters& params,
- const base::TimeDelta& close_delay)
- : AudioOutputDispatcher(audio_manager, params),
- pause_delay_(base::TimeDelta::FromMilliseconds(
- 2 * params.frames_per_buffer() *
- base::Time::kMillisecondsPerSecond / params.sample_rate())),
- paused_proxies_(0),
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
- close_timer_(FROM_HERE,
- close_delay,
- weak_this_.GetWeakPtr(),
- &AudioOutputDispatcherImpl::ClosePendingStreams) {
-}
-
-AudioOutputDispatcherImpl::~AudioOutputDispatcherImpl() {
- DCHECK(proxy_to_physical_map_.empty());
- DCHECK(idle_streams_.empty());
- DCHECK(pausing_streams_.empty());
-}
-
-bool AudioOutputDispatcherImpl::OpenStream() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- paused_proxies_++;
-
- // Ensure that there is at least one open stream.
- if (idle_streams_.empty() && !CreateAndOpenStream())
- return false;
-
- close_timer_.Reset();
- return true;
-}
-
-bool AudioOutputDispatcherImpl::StartStream(
- AudioOutputStream::AudioSourceCallback* callback,
- AudioOutputProxy* stream_proxy) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- if (idle_streams_.empty() && !CreateAndOpenStream())
- return false;
-
- AudioOutputStream* physical_stream = idle_streams_.back();
- DCHECK(physical_stream);
- idle_streams_.pop_back();
-
- DCHECK_GT(paused_proxies_, 0u);
- --paused_proxies_;
-
- close_timer_.Reset();
-
- // Schedule task to allocate streams for other proxies if we need to.
- message_loop_->PostTask(FROM_HERE, base::Bind(
- &AudioOutputDispatcherImpl::OpenTask, weak_this_.GetWeakPtr()));
-
- double volume = 0;
- stream_proxy->GetVolume(&volume);
- physical_stream->SetVolume(volume);
- physical_stream->Start(callback);
- proxy_to_physical_map_[stream_proxy] = physical_stream;
- return true;
-}
-
-void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
- DCHECK(it != proxy_to_physical_map_.end());
- AudioOutputStream* physical_stream = it->second;
- proxy_to_physical_map_.erase(it);
-
- physical_stream->Stop();
-
- ++paused_proxies_;
-
- pausing_streams_.push_front(physical_stream);
-
- // Don't recycle stream until two buffers worth of time has elapsed.
- message_loop_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&AudioOutputDispatcherImpl::StopStreamTask,
- weak_this_.GetWeakPtr()),
- pause_delay_);
-}
-
-void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
- double volume) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
- AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
- if (it != proxy_to_physical_map_.end()) {
- AudioOutputStream* physical_stream = it->second;
- physical_stream->SetVolume(volume);
- }
-}
-
-void AudioOutputDispatcherImpl::StopStreamTask() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- if (pausing_streams_.empty())
- return;
-
- AudioOutputStream* stream = pausing_streams_.back();
- pausing_streams_.pop_back();
- idle_streams_.push_back(stream);
- close_timer_.Reset();
-}
-
-void AudioOutputDispatcherImpl::CloseStream(AudioOutputProxy* stream_proxy) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- while (!pausing_streams_.empty()) {
- idle_streams_.push_back(pausing_streams_.back());
- pausing_streams_.pop_back();
- }
-
- DCHECK_GT(paused_proxies_, 0u);
- paused_proxies_--;
-
- while (idle_streams_.size() > paused_proxies_) {
- idle_streams_.back()->Close();
- idle_streams_.pop_back();
- }
-}
-
-void AudioOutputDispatcherImpl::Shutdown() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- // Cancel any pending tasks to close paused streams or create new ones.
- weak_this_.InvalidateWeakPtrs();
-
- // No AudioOutputProxy objects should hold a reference to us when we get
- // to this stage.
- DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
-
- AudioOutputStreamList::iterator it = idle_streams_.begin();
- for (; it != idle_streams_.end(); ++it)
- (*it)->Close();
- idle_streams_.clear();
-
- it = pausing_streams_.begin();
- for (; it != pausing_streams_.end(); ++it)
- (*it)->Close();
- pausing_streams_.clear();
-}
-
-bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
- AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
- if (!stream)
- return false;
-
- if (!stream->Open()) {
- stream->Close();
- return false;
- }
- idle_streams_.push_back(stream);
- return true;
-}
-
-void AudioOutputDispatcherImpl::OpenTask() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
- // Make sure that we have at least one stream allocated if there
- // are paused streams.
- if (paused_proxies_ > 0 && idle_streams_.empty() &&
- pausing_streams_.empty()) {
- CreateAndOpenStream();
- }
-
- close_timer_.Reset();
-}
-
-// This method is called by |close_timer_|.
-void AudioOutputDispatcherImpl::ClosePendingStreams() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
- while (!idle_streams_.empty()) {
- idle_streams_.back()->Close();
- idle_streams_.pop_back();
- }
-}
-
-} // namespace media
diff --git a/media/audio/audio_output_dispatcher_impl.h b/media/audio/audio_output_dispatcher_impl.h
deleted file mode 100644
index 8ad7dda..0000000
--- a/media/audio/audio_output_dispatcher_impl.h
+++ /dev/null
@@ -1,102 +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.
-
-// AudioOutputDispatcherImpl is an implementation of AudioOutputDispatcher.
-//
-// To avoid opening and closing audio devices more frequently than necessary,
-// each dispatcher has a pool of inactive physical streams. A stream is closed
-// only if it hasn't been used for a certain period of time (specified via the
-// constructor).
-//
-
-#ifndef MEDIA_AUDIO_AUDIO_OUTPUT_DISPATCHER_IMPL_H_
-#define MEDIA_AUDIO_AUDIO_OUTPUT_DISPATCHER_IMPL_H_
-
-#include <list>
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/timer.h"
-#include "media/audio/audio_io.h"
-#include "media/audio/audio_manager.h"
-#include "media/audio/audio_output_dispatcher.h"
-#include "media/audio/audio_parameters.h"
-
-class MessageLoop;
-
-namespace media {
-
-class AudioOutputProxy;
-
-class MEDIA_EXPORT AudioOutputDispatcherImpl : public AudioOutputDispatcher {
- public:
- // |close_delay_ms| specifies delay after the stream is paused until
- // the audio device is closed.
- AudioOutputDispatcherImpl(AudioManager* audio_manager,
- const AudioParameters& params,
- const base::TimeDelta& close_delay);
-
- // Opens a new physical stream if there are no pending streams in
- // |idle_streams_|.
- virtual bool OpenStream() OVERRIDE;
-
- // If there are pending streams in |idle_streams_| then it reuses one of
- // them, otherwise creates a new one.
- virtual bool StartStream(AudioOutputStream::AudioSourceCallback* callback,
- AudioOutputProxy* stream_proxy) OVERRIDE;
-
- // Holds the physical stream temporarily in |pausing_streams_| and then
- // |stream| is added to the pool of pending streams (i.e. |idle_streams_|).
- virtual void StopStream(AudioOutputProxy* stream_proxy) OVERRIDE;
-
- virtual void StreamVolumeSet(AudioOutputProxy* stream_proxy,
- double volume) OVERRIDE;
-
- virtual void CloseStream(AudioOutputProxy* stream_proxy) OVERRIDE;
-
- virtual void Shutdown() OVERRIDE;
-
- private:
- typedef std::map<AudioOutputProxy*, AudioOutputStream*> AudioStreamMap;
- friend class base::RefCountedThreadSafe<AudioOutputDispatcherImpl>;
- virtual ~AudioOutputDispatcherImpl();
-
- friend class AudioOutputProxyTest;
-
- // Creates a new physical output stream, opens it and pushes to
- // |idle_streams_|. Returns false if the stream couldn't be created or
- // opened.
- bool CreateAndOpenStream();
-
- // A task scheduled by StartStream(). Opens a new stream and puts
- // it in |idle_streams_|.
- void OpenTask();
-
- // Before a stream is reused, it should sit idle for a bit. This task is
- // called once that time has elapsed.
- void StopStreamTask();
-
- // Called by |close_timer_|. Closes all pending streams.
- void ClosePendingStreams();
-
- base::TimeDelta pause_delay_;
- size_t paused_proxies_;
- typedef std::list<AudioOutputStream*> AudioOutputStreamList;
- AudioOutputStreamList idle_streams_;
- AudioOutputStreamList pausing_streams_;
-
- // Used to post delayed tasks to ourselves that we cancel inside Shutdown().
- base::WeakPtrFactory<AudioOutputDispatcherImpl> weak_this_;
- base::DelayTimer<AudioOutputDispatcherImpl> close_timer_;
-
- AudioStreamMap proxy_to_physical_map_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioOutputDispatcherImpl);
-};
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_AUDIO_OUTPUT_DISPATCHER_IMPL_H_
diff --git a/media/audio/audio_output_mixer.cc b/media/audio/audio_output_mixer.cc
deleted file mode 100644
index d091672..0000000
--- a/media/audio/audio_output_mixer.cc
+++ /dev/null
@@ -1,251 +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/audio_output_mixer.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop.h"
-#include "base/time.h"
-#include "media/audio/audio_io.h"
-#include "media/audio/audio_output_proxy.h"
-#include "media/audio/audio_util.h"
-
-namespace media {
-
-AudioOutputMixer::AudioOutputMixer(AudioManager* audio_manager,
- const AudioParameters& params,
- const base::TimeDelta& close_delay)
- : AudioOutputDispatcher(audio_manager, params),
- ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)),
- close_timer_(FROM_HERE,
- close_delay,
- weak_this_.GetWeakPtr(),
- &AudioOutputMixer::ClosePhysicalStream) {
- // TODO(enal): align data.
- mixer_data_.reset(new uint8[params_.GetBytesPerBuffer()]);
-}
-
-AudioOutputMixer::~AudioOutputMixer() {
-}
-
-bool AudioOutputMixer::OpenStream() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- if (physical_stream_.get())
- return true;
- AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_);
- if (!stream)
- return false;
- if (!stream->Open()) {
- stream->Close();
- return false;
- }
- physical_stream_.reset(stream);
- close_timer_.Reset();
- return true;
-}
-
-bool AudioOutputMixer::StartStream(
- AudioOutputStream::AudioSourceCallback* callback,
- AudioOutputProxy* stream_proxy) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- // May need to re-open the physical stream if no active proxies and
- // enough time had pass.
- OpenStream();
- if (!physical_stream_.get())
- return false;
-
- double volume = 0.0;
- stream_proxy->GetVolume(&volume);
- bool should_start = proxies_.empty();
- {
- base::AutoLock lock(lock_);
- ProxyData* proxy_data = &proxies_[stream_proxy];
- proxy_data->audio_source_callback = callback;
- proxy_data->volume = volume;
- proxy_data->pending_bytes = 0;
- }
- // We cannot start physical stream under the lock,
- // OnMoreData() would try acquiring it...
- if (should_start) {
- physical_stream_->SetVolume(1.0);
- physical_stream_->Start(this);
- }
- return true;
-}
-
-void AudioOutputMixer::StopStream(AudioOutputProxy* stream_proxy) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- // Because of possible deadlock we cannot stop physical stream under the lock
- // (physical_stream_->Stop() can call OnError(), and it acquires the lock to
- // iterate through proxies), so acquire the lock, update proxy list, release
- // the lock, and only then stop physical stream if necessary.
- bool stop_physical_stream = false;
- {
- base::AutoLock lock(lock_);
- ProxyMap::iterator it = proxies_.find(stream_proxy);
- if (it != proxies_.end()) {
- proxies_.erase(it);
- stop_physical_stream = proxies_.empty();
- }
- }
- if (physical_stream_.get()) {
- if (stop_physical_stream)
- physical_stream_->Stop();
- close_timer_.Reset();
- }
-}
-
-void AudioOutputMixer::StreamVolumeSet(AudioOutputProxy* stream_proxy,
- double volume) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- ProxyMap::iterator it = proxies_.find(stream_proxy);
-
- // Do nothing if stream is not currently playing.
- if (it != proxies_.end()) {
- base::AutoLock lock(lock_);
- it->second.volume = volume;
- }
-}
-
-void AudioOutputMixer::CloseStream(AudioOutputProxy* stream_proxy) {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- StopStream(stream_proxy);
-}
-
-void AudioOutputMixer::Shutdown() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- // Cancel any pending tasks to close physical stream.
- weak_this_.InvalidateWeakPtrs();
-
- while (!proxies_.empty()) {
- CloseStream(proxies_.begin()->first);
- }
- ClosePhysicalStream();
-
- // No AudioOutputProxy objects should hold a reference to us when we get
- // to this stage.
- DCHECK(HasOneRef()) << "Only the AudioManager should hold a reference";
-}
-
-void AudioOutputMixer::ClosePhysicalStream() {
- DCHECK_EQ(MessageLoop::current(), message_loop_);
-
- if (proxies_.empty() && physical_stream_.get() != NULL)
- physical_stream_.release()->Close();
-}
-
-// AudioSourceCallback implementation.
-uint32 AudioOutputMixer::OnMoreData(AudioOutputStream* stream,
- uint8* dest,
- uint32 max_size,
- AudioBuffersState buffers_state) {
- max_size = std::min(max_size,
- static_cast<uint32>(params_.GetBytesPerBuffer()));
- // TODO(enal): consider getting rid of lock as it is in time-critical code.
- // E.g. swap |proxies_| with local variable, and merge 2 lists
- // at the end. That would speed things up but complicate stopping
- // the stream.
- base::AutoLock lock(lock_);
- if (proxies_.empty())
- return 0;
- uint32 actual_total_size = 0;
- uint32 bytes_per_sample = params_.bits_per_sample() >> 3;
-
- // Go through all the streams, getting data for every one of them
- // and mixing it into destination.
- // Minor optimization: for the first stream we are writing data directly into
- // destination. This way we don't have to mix the data when there is only one
- // active stream, and net win in other cases, too.
- bool first_stream = true;
- uint8* actual_dest = dest;
- for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
- AudioOutputProxy* stream_proxy = it->first;
- ProxyData* proxy_data = &it->second;
- // TODO(enal): We don't know |pending _bytes| for individual stream, and we
- // should give that value to individual stream's OnMoreData(). I believe it
- // can be used there to evaluate exact position of data it should return.
- // Current code "sorta works" if everything works perfectly, but would have
- // problems if some of the buffers are only partially filled -- we don't
- // know how how much data was in the buffer OS returned to us, so we cannot
- // correctly calculate new value. If we know number of buffers we can solve
- // the problem by storing not one value but vector of them.
- int pending_bytes = std::min(proxy_data->pending_bytes,
- buffers_state.pending_bytes);
- // Note: there is no way we can deduce hardware_delay_bytes for the
- // particular proxy stream. Use zero instead.
- uint32 actual_size = proxy_data->audio_source_callback->OnMoreData(
- stream_proxy,
- actual_dest,
- max_size,
- AudioBuffersState(pending_bytes, 0));
-
- // Should update pending_bytes for each proxy.
- // If stream ended, pending_bytes goes down by max_size.
- if (actual_size == 0) {
- pending_bytes -= max_size;
- proxy_data->pending_bytes = std::max(pending_bytes, 0);
- continue;
- }
-
- // Otherwise, it goes up by amount of data. It cannot exceed max amount of
- // data we can buffer, but we don't know that value. So we increment
- // pending_bytes unconditionally but adjust it before actual use (which
- // would be on a next OnMoreData() call).
- proxy_data->pending_bytes = pending_bytes + actual_size;
-
- // No need to mix muted stream.
- double volume = proxy_data->volume;
- if (volume == 0.0)
- continue;
-
- // Different handling for first and all subsequent streams.
- if (first_stream) {
- if (volume != 1.0) {
- media::AdjustVolume(actual_dest,
- actual_size,
- params_.channels(),
- bytes_per_sample,
- volume);
- }
- if (actual_size < max_size)
- memset(dest + actual_size, 0, max_size - actual_size);
- first_stream = false;
- actual_dest = mixer_data_.get();
- actual_total_size = actual_size;
- } else {
- media::MixStreams(dest,
- actual_dest,
- actual_size,
- bytes_per_sample,
- volume);
- actual_total_size = std::max(actual_size, actual_total_size);
- }
- }
- return actual_total_size;
-}
-
-void AudioOutputMixer::OnError(AudioOutputStream* stream, int code) {
- base::AutoLock lock(lock_);
- for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
- it->second.audio_source_callback->OnError(it->first, code);
- }
-}
-
-void AudioOutputMixer::WaitTillDataReady() {
- base::AutoLock lock(lock_);
- for (ProxyMap::iterator it = proxies_.begin(); it != proxies_.end(); ++it) {
- it->second.audio_source_callback->WaitTillDataReady();
- }
-}
-
-} // namespace media
diff --git a/media/audio/audio_output_mixer.h b/media/audio/audio_output_mixer.h
deleted file mode 100644
index ae94b5f..0000000
--- a/media/audio/audio_output_mixer.h
+++ /dev/null
@@ -1,92 +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.
-
-// AudioOutputMixer is a class that implements browser-side audio mixer.
-// AudioOutputMixer implements both AudioOutputDispatcher and
-// AudioSourceCallback interfaces.
-
-#ifndef MEDIA_AUDIO_AUDIO_OUTPUT_MIXER_H_
-#define MEDIA_AUDIO_AUDIO_OUTPUT_MIXER_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/timer.h"
-#include "media/audio/audio_io.h"
-#include "media/audio/audio_manager.h"
-#include "media/audio/audio_output_dispatcher.h"
-#include "media/audio/audio_parameters.h"
-
-namespace media {
-
-class MEDIA_EXPORT AudioOutputMixer
- : public AudioOutputDispatcher,
- public AudioOutputStream::AudioSourceCallback {
- public:
- AudioOutputMixer(AudioManager* audio_manager,
- const AudioParameters& params,
- const base::TimeDelta& close_delay);
-
- // AudioOutputDispatcher interface.
- virtual bool OpenStream() OVERRIDE;
- virtual bool StartStream(AudioOutputStream::AudioSourceCallback* callback,
- AudioOutputProxy* stream_proxy) OVERRIDE;
- virtual void StopStream(AudioOutputProxy* stream_proxy) OVERRIDE;
- virtual void StreamVolumeSet(AudioOutputProxy* stream_proxy,
- double volume) OVERRIDE;
- virtual void CloseStream(AudioOutputProxy* stream_proxy) OVERRIDE;
- virtual void Shutdown() OVERRIDE;
-
- // AudioSourceCallback interface.
- virtual uint32 OnMoreData(AudioOutputStream* stream,
- uint8* dest,
- uint32 max_size,
- AudioBuffersState buffers_state) OVERRIDE;
- virtual void OnError(AudioOutputStream* stream, int code) OVERRIDE;
- virtual void WaitTillDataReady() OVERRIDE;
-
- private:
- friend class base::RefCountedThreadSafe<AudioOutputMixer>;
- virtual ~AudioOutputMixer();
-
- // Called by |close_timer_|. Closes physical stream.
- void ClosePhysicalStream();
-
- // The |lock_| must be acquired whenever we modify |proxies_| in the audio
- // manager thread or accessing it in the hardware audio thread. Read in the
- // audio manager thread is safe.
- base::Lock lock_;
-
- // List of audio output proxies currently being played.
- // For every proxy we store aux structure containing data necessary for
- // mixing.
- struct ProxyData {
- AudioOutputStream::AudioSourceCallback* audio_source_callback;
- double volume;
- int pending_bytes;
- };
- typedef std::map<AudioOutputProxy*, ProxyData> ProxyMap;
- ProxyMap proxies_;
-
- // Physical stream for this mixer.
- scoped_ptr<AudioOutputStream> physical_stream_;
-
- // Temporary buffer used when mixing. Allocated in the constructor
- // to avoid constant allocation/deallocation in the callback.
- scoped_array<uint8> mixer_data_;
-
- // Used to post delayed tasks to ourselves that we cancel inside Shutdown().
- base::WeakPtrFactory<AudioOutputMixer> weak_this_;
- base::DelayTimer<AudioOutputMixer> close_timer_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioOutputMixer);
-};
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_AUDIO_OUTPUT_MIXER_H_
diff --git a/media/audio/audio_output_proxy.cc b/media/audio/audio_output_proxy.cc
index a9cfe68..b1d65ba 100644
--- a/media/audio/audio_output_proxy.cc
+++ b/media/audio/audio_output_proxy.cc
@@ -14,19 +14,21 @@ namespace media {
AudioOutputProxy::AudioOutputProxy(AudioOutputDispatcher* dispatcher)
: dispatcher_(dispatcher),
state_(kCreated),
+ physical_stream_(NULL),
volume_(1.0) {
}
AudioOutputProxy::~AudioOutputProxy() {
DCHECK(CalledOnValidThread());
DCHECK(state_ == kCreated || state_ == kClosed);
+ DCHECK(!physical_stream_);
}
bool AudioOutputProxy::Open() {
DCHECK(CalledOnValidThread());
DCHECK_EQ(state_, kCreated);
- if (!dispatcher_->OpenStream()) {
+ if (!dispatcher_->StreamOpened()) {
state_ = kError;
return false;
}
@@ -37,13 +39,18 @@ bool AudioOutputProxy::Open() {
void AudioOutputProxy::Start(AudioSourceCallback* callback) {
DCHECK(CalledOnValidThread());
+ DCHECK(physical_stream_ == NULL);
DCHECK_EQ(state_, kOpened);
- if (!dispatcher_->StartStream(callback, this)) {
+ physical_stream_= dispatcher_->StreamStarted();
+ if (!physical_stream_) {
state_ = kError;
callback->OnError(this, 0);
return;
}
+
+ physical_stream_->SetVolume(volume_);
+ physical_stream_->Start(callback);
state_ = kPlaying;
}
@@ -52,14 +59,19 @@ void AudioOutputProxy::Stop() {
if (state_ != kPlaying)
return;
- dispatcher_->StopStream(this);
+ DCHECK(physical_stream_);
+ physical_stream_->Stop();
+ dispatcher_->StreamStopped(physical_stream_);
+ physical_stream_ = NULL;
state_ = kOpened;
}
void AudioOutputProxy::SetVolume(double volume) {
DCHECK(CalledOnValidThread());
volume_ = volume;
- dispatcher_->StreamVolumeSet(this, volume);
+ if (physical_stream_) {
+ physical_stream_->SetVolume(volume);
+ }
}
void AudioOutputProxy::GetVolume(double* volume) {
@@ -70,9 +82,10 @@ void AudioOutputProxy::GetVolume(double* volume) {
void AudioOutputProxy::Close() {
DCHECK(CalledOnValidThread());
DCHECK(state_ == kCreated || state_ == kError || state_ == kOpened);
+ DCHECK(!physical_stream_);
if (state_ != kCreated)
- dispatcher_->CloseStream(this);
+ dispatcher_->StreamClosed();
state_ = kClosed;
diff --git a/media/audio/audio_output_proxy.h b/media/audio/audio_output_proxy.h
index 1fb35a3..d34f81f 100644
--- a/media/audio/audio_output_proxy.h
+++ b/media/audio/audio_output_proxy.h
@@ -53,6 +53,10 @@ class MEDIA_EXPORT AudioOutputProxy
scoped_refptr<AudioOutputDispatcher> dispatcher_;
State state_;
+ // The actual audio stream. Must be set to NULL in any state other
+ // than kPlaying.
+ AudioOutputStream* physical_stream_;
+
// Need to save volume here, so that we can restore it in case the stream
// is stopped, and then started again.
double volume_;
diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc
index a3adbac..3dbfd2f2 100644
--- a/media/audio/audio_output_proxy_unittest.cc
+++ b/media/audio/audio_output_proxy_unittest.cc
@@ -2,13 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <string>
-
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#include "base/threading/platform_thread.h"
-#include "media/audio/audio_output_dispatcher_impl.h"
-#include "media/audio/audio_output_mixer.h"
+#include "media/audio/audio_output_dispatcher.h"
#include "media/audio/audio_output_proxy.h"
#include "media/audio/audio_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -91,7 +88,7 @@ class AudioOutputProxyTest : public testing::Test {
virtual void TearDown() {
// All paused proxies should have been closed at this point.
- EXPECT_EQ(0u, dispatcher_impl_->paused_proxies_);
+ EXPECT_EQ(0u, dispatcher_->paused_proxies_);
// This is necessary to free all proxy objects that have been
// closed by the test.
@@ -101,166 +98,42 @@ class AudioOutputProxyTest : public testing::Test {
void InitDispatcher(base::TimeDelta close_delay) {
AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
CHANNEL_LAYOUT_STEREO, 44100, 16, 1024);
- dispatcher_impl_ = new AudioOutputDispatcherImpl(&manager(),
- params,
- close_delay);
- mixer_ = new AudioOutputMixer(&manager(), params, close_delay);
+ dispatcher_ = new AudioOutputDispatcher(&manager(), params, close_delay);
// Necessary to know how long the dispatcher will wait before posting
// StopStreamTask.
- pause_delay_ = dispatcher_impl_->pause_delay_;
+ pause_delay_ = dispatcher_->pause_delay_;
}
MockAudioManager& manager() {
return manager_;
}
- // Wait for the close timer to fire.
- void WaitForCloseTimer(const int timer_delay_ms) {
- message_loop_.RunAllPending(); // OpenTask() may reset the timer.
- base::PlatformThread::Sleep(
- base::TimeDelta::FromMilliseconds(timer_delay_ms) * 2);
- message_loop_.RunAllPending();
- }
-
- // Methods that do actual tests.
- void OpenAndClose(AudioOutputDispatcher* dispatcher) {
- MockAudioOutputStream stream;
-
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(&stream));
- EXPECT_CALL(stream, Open())
- .WillOnce(Return(true));
- EXPECT_CALL(stream, Close())
- .Times(1);
-
- AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher);
- EXPECT_TRUE(proxy->Open());
- proxy->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
- }
-
- // Create a stream, and then calls Start() and Stop().
- void StartAndStop(AudioOutputDispatcher* dispatcher) {
- MockAudioOutputStream stream;
-
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(&stream));
- EXPECT_CALL(stream, Open())
- .WillOnce(Return(true));
- EXPECT_CALL(stream, Start(_))
- .Times(1);
- EXPECT_CALL(stream, SetVolume(_))
- .Times(1);
- EXPECT_CALL(stream, Stop())
- .Times(1);
- EXPECT_CALL(stream, Close())
- .Times(1);
-
- AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher);
- EXPECT_TRUE(proxy->Open());
-
- proxy->Start(&callback_);
- proxy->Stop();
-
- proxy->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
- }
-
- // Verify that the stream is closed after Stop is called.
- void CloseAfterStop(AudioOutputDispatcher* dispatcher) {
- MockAudioOutputStream stream;
-
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(&stream));
- EXPECT_CALL(stream, Open())
- .WillOnce(Return(true));
- EXPECT_CALL(stream, Start(_))
- .Times(1);
- EXPECT_CALL(stream, SetVolume(_))
- .Times(1);
- EXPECT_CALL(stream, Stop())
- .Times(1);
- EXPECT_CALL(stream, Close())
- .Times(1);
-
- AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher);
- EXPECT_TRUE(proxy->Open());
-
- proxy->Start(&callback_);
- proxy->Stop();
-
- // Wait for StopStream() to post StopStreamTask().
- base::PlatformThread::Sleep(pause_delay_ * 2);
- WaitForCloseTimer(kTestCloseDelayMs);
-
- // Verify expectation before calling Close().
- Mock::VerifyAndClear(&stream);
-
- proxy->Close();
- }
-
- // Create two streams, but don't start them. Only one device must be open.
- void TwoStreams(AudioOutputDispatcher* dispatcher) {
- MockAudioOutputStream stream;
-
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(&stream));
- EXPECT_CALL(stream, Open())
- .WillOnce(Return(true));
- EXPECT_CALL(stream, Close())
- .Times(1);
-
- AudioOutputProxy* proxy1 = new AudioOutputProxy(dispatcher);
- AudioOutputProxy* proxy2 = new AudioOutputProxy(dispatcher);
- EXPECT_TRUE(proxy1->Open());
- EXPECT_TRUE(proxy2->Open());
- proxy1->Close();
- proxy2->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
- }
-
- // Open() method failed.
- void OpenFailed(AudioOutputDispatcher* dispatcher) {
- MockAudioOutputStream stream;
-
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(&stream));
- EXPECT_CALL(stream, Open())
- .WillOnce(Return(false));
- EXPECT_CALL(stream, Close())
- .Times(1);
-
- AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher);
- EXPECT_FALSE(proxy->Open());
- proxy->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
- }
-
MessageLoop message_loop_;
- scoped_refptr<AudioOutputDispatcherImpl> dispatcher_impl_;
- scoped_refptr<AudioOutputMixer> mixer_;
+ scoped_refptr<AudioOutputDispatcher> dispatcher_;
base::TimeDelta pause_delay_;
MockAudioManager manager_;
MockAudioSourceCallback callback_;
};
TEST_F(AudioOutputProxyTest, CreateAndClose) {
- AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_impl_);
- proxy->Close();
-}
-
-TEST_F(AudioOutputProxyTest, CreateAndClose_Mixer) {
- AudioOutputProxy* proxy = new AudioOutputProxy(mixer_);
+ AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_);
proxy->Close();
}
TEST_F(AudioOutputProxyTest, OpenAndClose) {
- OpenAndClose(dispatcher_impl_);
-}
+ MockAudioOutputStream stream;
+
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_))
+ .WillOnce(Return(&stream));
+ EXPECT_CALL(stream, Open())
+ .WillOnce(Return(true));
+ EXPECT_CALL(stream, Close())
+ .Times(1);
-TEST_F(AudioOutputProxyTest, OpenAndClose_Mixer) {
- OpenAndClose(mixer_);
+ AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_);
+ EXPECT_TRUE(proxy->Open());
+ proxy->Close();
}
// Create a stream, and verify that it is closed after kTestCloseDelayMs.
@@ -275,7 +148,7 @@ TEST_F(AudioOutputProxyTest, CreateAndWait) {
EXPECT_CALL(stream, Close())
.Times(1);
- AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_impl_);
+ AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_);
EXPECT_TRUE(proxy->Open());
// Simulate a delay.
@@ -289,28 +162,87 @@ TEST_F(AudioOutputProxyTest, CreateAndWait) {
proxy->Close();
}
+// Create a stream, and then calls Start() and Stop().
TEST_F(AudioOutputProxyTest, StartAndStop) {
- StartAndStop(dispatcher_impl_);
-}
+ MockAudioOutputStream stream;
+
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_))
+ .WillOnce(Return(&stream));
+ EXPECT_CALL(stream, Open())
+ .WillOnce(Return(true));
+ EXPECT_CALL(stream, Start(_))
+ .Times(1);
+ EXPECT_CALL(stream, SetVolume(_))
+ .Times(1);
+ EXPECT_CALL(stream, Stop())
+ .Times(1);
+ EXPECT_CALL(stream, Close())
+ .Times(1);
+
+ AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_);
+ EXPECT_TRUE(proxy->Open());
-TEST_F(AudioOutputProxyTest, StartAndStop_Mixer) {
- StartAndStop(mixer_);
+ proxy->Start(&callback_);
+ proxy->Stop();
+
+ proxy->Close();
}
+// Verify that the stream is closed after Stop is called.
TEST_F(AudioOutputProxyTest, CloseAfterStop) {
- CloseAfterStop(dispatcher_impl_);
-}
+ MockAudioOutputStream stream;
+
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_))
+ .WillOnce(Return(&stream));
+ EXPECT_CALL(stream, Open())
+ .WillOnce(Return(true));
+ EXPECT_CALL(stream, Start(_))
+ .Times(1);
+ EXPECT_CALL(stream, SetVolume(_))
+ .Times(1);
+ EXPECT_CALL(stream, Stop())
+ .Times(1);
+ EXPECT_CALL(stream, Close())
+ .Times(1);
+
+ AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_);
+ EXPECT_TRUE(proxy->Open());
+
+ proxy->Start(&callback_);
+ proxy->Stop();
+
+ // Wait for StreamStopped() to post StopStreamTask().
+ base::PlatformThread::Sleep(pause_delay_ * 2);
+ message_loop_.RunAllPending();
+
+ // Wait for the close timer to fire.
+ base::PlatformThread::Sleep(
+ base::TimeDelta::FromMilliseconds(kTestCloseDelayMs) * 2);
+ message_loop_.RunAllPending();
-TEST_F(AudioOutputProxyTest, CloseAfterStop_Mixer) {
- CloseAfterStop(mixer_);
+ // Verify expectation before calling Close().
+ Mock::VerifyAndClear(&stream);
+
+ proxy->Close();
}
+// Create two streams, but don't start them. Only one device must be open.
TEST_F(AudioOutputProxyTest, TwoStreams) {
- TwoStreams(dispatcher_impl_);
-}
+ MockAudioOutputStream stream;
-TEST_F(AudioOutputProxyTest, TwoStreams_Mixer) {
- TwoStreams(mixer_);
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_))
+ .WillOnce(Return(&stream));
+ EXPECT_CALL(stream, Open())
+ .WillOnce(Return(true));
+ EXPECT_CALL(stream, Close())
+ .Times(1);
+
+ AudioOutputProxy* proxy1 = new AudioOutputProxy(dispatcher_);
+ AudioOutputProxy* proxy2 = new AudioOutputProxy(dispatcher_);
+ EXPECT_TRUE(proxy1->Open());
+ EXPECT_TRUE(proxy2->Open());
+ proxy1->Close();
+ proxy2->Close();
}
// Two streams: verify that second stream is allocated when the first
@@ -341,8 +273,8 @@ TEST_F(AudioOutputProxyTest, TwoStreams_OnePlaying) {
EXPECT_CALL(stream2, Close())
.Times(1);
- AudioOutputProxy* proxy1 = new AudioOutputProxy(dispatcher_impl_);
- AudioOutputProxy* proxy2 = new AudioOutputProxy(dispatcher_impl_);
+ AudioOutputProxy* proxy1 = new AudioOutputProxy(dispatcher_);
+ AudioOutputProxy* proxy2 = new AudioOutputProxy(dispatcher_);
EXPECT_TRUE(proxy1->Open());
EXPECT_TRUE(proxy2->Open());
@@ -354,39 +286,6 @@ TEST_F(AudioOutputProxyTest, TwoStreams_OnePlaying) {
proxy2->Close();
}
-// Two streams: verify that only one device will be created.
-TEST_F(AudioOutputProxyTest, TwoStreams_OnePlaying_Mixer) {
- MockAudioOutputStream stream;
-
- InitDispatcher(base::TimeDelta::FromMilliseconds(kTestCloseDelayMs));
-
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(&stream));
-
- EXPECT_CALL(stream, Open())
- .WillOnce(Return(true));
- EXPECT_CALL(stream, Start(_))
- .Times(1);
- EXPECT_CALL(stream, SetVolume(_))
- .Times(1);
- EXPECT_CALL(stream, Stop())
- .Times(1);
- EXPECT_CALL(stream, Close())
- .Times(1);
-
- AudioOutputProxy* proxy1 = new AudioOutputProxy(mixer_);
- AudioOutputProxy* proxy2 = new AudioOutputProxy(mixer_);
- EXPECT_TRUE(proxy1->Open());
- EXPECT_TRUE(proxy2->Open());
-
- proxy1->Start(&callback_);
- proxy1->Stop();
-
- proxy1->Close();
- proxy2->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
-}
-
// Two streams, both are playing. Dispatcher should not open a third stream.
TEST_F(AudioOutputProxyTest, TwoStreams_BothPlaying) {
MockAudioOutputStream stream1;
@@ -420,8 +319,8 @@ TEST_F(AudioOutputProxyTest, TwoStreams_BothPlaying) {
EXPECT_CALL(stream2, Close())
.Times(1);
- AudioOutputProxy* proxy1 = new AudioOutputProxy(dispatcher_impl_);
- AudioOutputProxy* proxy2 = new AudioOutputProxy(dispatcher_impl_);
+ AudioOutputProxy* proxy1 = new AudioOutputProxy(dispatcher_);
+ AudioOutputProxy* proxy2 = new AudioOutputProxy(dispatcher_);
EXPECT_TRUE(proxy1->Open());
EXPECT_TRUE(proxy2->Open());
@@ -434,47 +333,20 @@ TEST_F(AudioOutputProxyTest, TwoStreams_BothPlaying) {
proxy2->Close();
}
-// Two streams, both are playing. Still have to use single device.
-TEST_F(AudioOutputProxyTest, TwoStreams_BothPlaying_Mixer) {
+// Open() method failed.
+TEST_F(AudioOutputProxyTest, OpenFailed) {
MockAudioOutputStream stream;
- InitDispatcher(base::TimeDelta::FromMilliseconds(kTestCloseDelayMs));
-
EXPECT_CALL(manager(), MakeAudioOutputStream(_))
.WillOnce(Return(&stream));
-
EXPECT_CALL(stream, Open())
- .WillOnce(Return(true));
- EXPECT_CALL(stream, Start(_))
- .Times(1);
- EXPECT_CALL(stream, SetVolume(_))
- .Times(1);
- EXPECT_CALL(stream, Stop())
- .Times(1);
+ .WillOnce(Return(false));
EXPECT_CALL(stream, Close())
.Times(1);
- AudioOutputProxy* proxy1 = new AudioOutputProxy(mixer_);
- AudioOutputProxy* proxy2 = new AudioOutputProxy(mixer_);
- EXPECT_TRUE(proxy1->Open());
- EXPECT_TRUE(proxy2->Open());
-
- proxy1->Start(&callback_);
- proxy2->Start(&callback_);
- proxy1->Stop();
- proxy2->Stop();
-
- proxy1->Close();
- proxy2->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
-}
-
-TEST_F(AudioOutputProxyTest, OpenFailed) {
- OpenFailed(dispatcher_impl_);
-}
-
-TEST_F(AudioOutputProxyTest, OpenFailed_Mixer) {
- OpenFailed(mixer_);
+ AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_);
+ EXPECT_FALSE(proxy->Open());
+ proxy->Close();
}
// Start() method failed.
@@ -488,7 +360,7 @@ TEST_F(AudioOutputProxyTest, StartFailed) {
EXPECT_CALL(stream, Close())
.Times(1);
- AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_impl_);
+ AudioOutputProxy* proxy = new AudioOutputProxy(dispatcher_);
EXPECT_TRUE(proxy->Open());
// Simulate a delay.
@@ -513,48 +385,4 @@ TEST_F(AudioOutputProxyTest, StartFailed) {
proxy->Close();
}
-// Start() method failed.
-TEST_F(AudioOutputProxyTest, StartFailed_Mixer) {
- MockAudioOutputStream stream;
-
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(&stream));
- EXPECT_CALL(stream, Open())
- .WillOnce(Return(true));
- EXPECT_CALL(stream, Close())
- .Times(1);
- EXPECT_CALL(stream, Start(_))
- .Times(1);
- EXPECT_CALL(stream, SetVolume(_))
- .Times(1);
- EXPECT_CALL(stream, Stop())
- .Times(1);
-
- AudioOutputProxy* proxy1 = new AudioOutputProxy(mixer_);
- AudioOutputProxy* proxy2 = new AudioOutputProxy(mixer_);
- EXPECT_TRUE(proxy1->Open());
- EXPECT_TRUE(proxy2->Open());
- proxy1->Start(&callback_);
- proxy1->Stop();
- proxy1->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
-
- // Verify expectation before continueing.
- Mock::VerifyAndClear(&stream);
-
- // |stream| is closed at this point. Start() should reopen it again.
- EXPECT_CALL(manager(), MakeAudioOutputStream(_))
- .WillOnce(Return(reinterpret_cast<AudioOutputStream*>(NULL)));
-
- EXPECT_CALL(callback_, OnError(_, _))
- .Times(1);
-
- proxy2->Start(&callback_);
-
- Mock::VerifyAndClear(&callback_);
-
- proxy2->Close();
- WaitForCloseTimer(kTestCloseDelayMs);
-}
-
} // namespace media