Chromium Code Reviews| 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..bca01b02c415102f3118e54586310f9f13ec1bfe 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_) { |
|
DaleCurtis
2014/01/13 18:12:31
This will drop the the playback request if playbac
ygorshenin1
2014/01/13 18:30:51
Done.
|
| + 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,26 @@ class AudioStreamHandler::AudioStreamContainer |
| LOG(ERROR) << "Error during system sound reproduction."; |
| } |
| + void StopStream() { |
| + base::AutoLock al(state_lock_); |
|
DaleCurtis
2014/01/13 18:12:31
Add a DCHECK(AudioManager::Get()->GetTaskRunner()-
ygorshenin1
2014/01/13 18:30:51
Done.
|
| + |
| + 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 +166,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 +180,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 { |