| Index: media/audio/sounds/audio_stream_handler.cc
|
| diff --git a/media/audio/sounds/audio_stream_handler.cc b/media/audio/sounds/audio_stream_handler.cc
|
| index 49709769f7c54fde19caabc05c1afc303cf1886d..f28635645a4873d51fc72f32f661e3716e7dfbe0 100644
|
| --- a/media/audio/sounds/audio_stream_handler.cc
|
| +++ b/media/audio/sounds/audio_stream_handler.cc
|
| @@ -6,8 +6,11 @@
|
|
|
| #include <string>
|
|
|
| +#include "base/cancelable_callback.h"
|
| #include "base/logging.h"
|
| #include "base/single_thread_task_runner.h"
|
| +#include "base/synchronization/lock.h"
|
| +#include "base/time/time.h"
|
| #include "media/audio/audio_manager.h"
|
| #include "media/audio/audio_manager_base.h"
|
| #include "media/base/channel_layout.h"
|
| @@ -22,6 +25,9 @@ const double kOutputVolumePercent = 0.8;
|
| // The number of frames each OnMoreData() call will request.
|
| const int kDefaultFrameCount = 1024;
|
|
|
| +// Keep alive timeout for audio stream.
|
| +const int kKeepAliveMs = 1500;
|
| +
|
| AudioStreamHandler::TestObserver* g_observer_for_testing = NULL;
|
| AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
|
|
|
| @@ -30,12 +36,12 @@ AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
|
| class AudioStreamHandler::AudioStreamContainer
|
| : public AudioOutputStream::AudioSourceCallback {
|
| public:
|
| - AudioStreamContainer(const WavAudioHandler& wav_audio,
|
| - const AudioParameters& params)
|
| + AudioStreamContainer(const WavAudioHandler& wav_audio)
|
| : stream_(NULL),
|
| wav_audio_(wav_audio),
|
| - params_(params),
|
| - cursor_(0) {
|
| + cursor_(0),
|
| + started_(false),
|
| + delayed_stop_posted_(false) {
|
| }
|
|
|
| virtual ~AudioStreamContainer() {
|
| @@ -46,20 +52,38 @@ class AudioStreamHandler::AudioStreamContainer
|
| DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
|
|
|
| if (!stream_) {
|
| - stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params_,
|
| - std::string(),
|
| - std::string());
|
| + const AudioParameters& p = wav_audio_.params();
|
| + const AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
|
| + p.channel_layout(),
|
| + p.sample_rate(),
|
| + p.bits_per_sample(),
|
| + kDefaultFrameCount);
|
| + stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(
|
| + params, std::string(), std::string());
|
| if (!stream_ || !stream_->Open()) {
|
| LOG(ERROR) << "Failed to open an output stream.";
|
| return;
|
| }
|
| stream_->SetVolume(kOutputVolumePercent);
|
| - } else {
|
| - // TODO (ygorshenin@): implement smart stream rewind.
|
| - stream_->Stop();
|
| }
|
|
|
| - cursor_ = 0;
|
| + {
|
| + base::AutoLock al(state_lock_);
|
| +
|
| + delayed_stop_posted_ = false;
|
| + stop_closure_.Reset(base::Bind(
|
| + &AudioStreamContainer::StopStream, base::Unretained(this)));
|
| +
|
| + if (started_) {
|
| + if (wav_audio_.AtEnd(cursor_))
|
| + cursor_ = 0;
|
| + return;
|
| + }
|
| +
|
| + cursor_ = 0;
|
| + started_ = true;
|
| + }
|
| +
|
| if (g_audio_source_for_testing)
|
| stream_->Start(g_audio_source_for_testing);
|
| else
|
| @@ -71,14 +95,10 @@ class AudioStreamHandler::AudioStreamContainer
|
|
|
| void Stop() {
|
| DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
|
| - if (!stream_)
|
| - return;
|
| - stream_->Stop();
|
| - stream_->Close();
|
| + StopStream();
|
| + if (stream_)
|
| + stream_->Close();
|
| stream_ = NULL;
|
| -
|
| - if (g_observer_for_testing)
|
| - g_observer_for_testing->OnStop(cursor_);
|
| }
|
|
|
| private:
|
| @@ -86,16 +106,21 @@ class AudioStreamHandler::AudioStreamContainer
|
| // Following methods could be called from *ANY* thread.
|
| virtual int OnMoreData(AudioBus* dest,
|
| AudioBuffersState /* state */) OVERRIDE {
|
| + base::AutoLock al(state_lock_);
|
| size_t bytes_written = 0;
|
| +
|
| if (wav_audio_.AtEnd(cursor_) ||
|
| !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) {
|
| - AudioManager::Get()->GetTaskRunner()->PostTask(
|
| + if (delayed_stop_posted_)
|
| + return 0;
|
| + delayed_stop_posted_ = true;
|
| + AudioManager::Get()->GetTaskRunner()->PostDelayedTask(
|
| FROM_HERE,
|
| - base::Bind(&AudioStreamContainer::Stop, base::Unretained(this)));
|
| + stop_closure_.callback(),
|
| + base::TimeDelta::FromMilliseconds(kKeepAliveMs));
|
| return 0;
|
| }
|
| cursor_ += bytes_written;
|
| -
|
| return dest->frames();
|
| }
|
|
|
| @@ -109,12 +134,28 @@ class AudioStreamHandler::AudioStreamContainer
|
| LOG(ERROR) << "Error during system sound reproduction.";
|
| }
|
|
|
| + void StopStream() {
|
| + DCHECK(AudioManager::Get()->GetTaskRunner()->BelongsToCurrentThread());
|
| +
|
| + base::AutoLock al(state_lock_);
|
| +
|
| + if (stream_ && started_) {
|
| + stream_->Stop();
|
| + if (g_observer_for_testing)
|
| + g_observer_for_testing->OnStop(cursor_);
|
| + }
|
| + started_ = false;
|
| + }
|
| +
|
| AudioOutputStream* stream_;
|
|
|
| const WavAudioHandler wav_audio_;
|
| - const AudioParameters params_;
|
|
|
| + base::Lock state_lock_;
|
| size_t cursor_;
|
| + bool started_;
|
| + bool delayed_stop_posted_;
|
| + base::CancelableClosure stop_closure_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
|
| };
|
| @@ -127,16 +168,11 @@ AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
|
| LOG(ERROR) << "Can't get access to audio manager.";
|
| return;
|
| }
|
| - AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
|
| - GuessChannelLayout(wav_audio_.num_channels()),
|
| - wav_audio_.sample_rate(),
|
| - wav_audio_.bits_per_sample(),
|
| - kDefaultFrameCount);
|
| - if (!params.IsValid()) {
|
| + if (!wav_audio_.params().IsValid()) {
|
| LOG(ERROR) << "Audio params are invalid.";
|
| return;
|
| }
|
| - stream_.reset(new AudioStreamContainer(wav_audio_, params));
|
| + stream_.reset(new AudioStreamContainer(wav_audio_));
|
| initialized_ = true;
|
| }
|
|
|
| @@ -146,7 +182,7 @@ AudioStreamHandler::~AudioStreamHandler() {
|
| FROM_HERE,
|
| base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
|
| AudioManager::Get()->GetTaskRunner()->DeleteSoon(FROM_HERE,
|
| - stream_.release());
|
| + stream_.release());
|
| }
|
|
|
| bool AudioStreamHandler::IsInitialized() const {
|
|
|