Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(467)

Unified Diff: media/audio/sounds/audio_stream_handler.cc

Issue 115693004: Added volume adjust sound behind the flag. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 08608ac4187aa0863b777e5e42701f2b7a327f69..d82829189a80fde0da24aa28d01611d821ee290a 100644
--- a/media/audio/sounds/audio_stream_handler.cc
+++ b/media/audio/sounds/audio_stream_handler.cc
@@ -6,10 +6,13 @@
#include <string>
+#include "base/cancelable_callback.h"
#include "base/logging.h"
#include "base/message_loop/message_loop_proxy.h"
+#include "base/time/time.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_manager_base.h"
+#include "media/audio/sounds/wav_reader.h"
#include "media/base/channel_layout.h"
namespace media {
@@ -22,6 +25,9 @@ const double kOutputVolumePercent = 0.8;
// The number of frames each OnMoreData() call will request.
const int kDefaultFrameCount = 1024;
+// Delay between end of sound and call to AudioOutputStream::Stop().
+const int kStopStreamDelaySec = 3;
+
AudioStreamHandler::TestObserver* g_observer_for_testing = NULL;
AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
@@ -30,36 +36,55 @@ AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
class AudioStreamHandler::AudioStreamContainer
: public AudioOutputStream::AudioSourceCallback {
public:
- AudioStreamContainer(const WavAudioHandler& wav_audio,
+ AudioStreamContainer(const WavParser& wav_parser,
const AudioParameters& params)
: stream_(NULL),
- wav_audio_(wav_audio),
+ wav_reader_(new WavReaderImpl(wav_parser)),
+ duration_(wav_parser.duration()),
params_(params),
- cursor_(0) {
- }
+ cursor_(0),
+ num_replay_requests_(0),
+ is_stream_idle_(true),
+ schedule_replay_request_for_testing_(0) {}
virtual ~AudioStreamContainer() {
DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
+ stop_stream_closure_.Cancel();
+ StopAndCloseStream();
}
void Play() {
DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
if (!stream_) {
- stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params_,
- std::string(),
- std::string());
+ stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(
+ params_, std::string(), std::string());
if (!stream_ || !stream_->Open()) {
LOG(ERROR) << "Failed to open an output stream.";
return;
}
+ cursor_ = 0;
stream_->SetVolume(kOutputVolumePercent);
+ } else if (is_stream_idle_) {
+ // If stream exists and idle, just stop the stream and start again.
+ cursor_ = 0;
+ StopStream();
} else {
- // TODO (ygorshenin@): implement smart stream rewind.
- stream_->Stop();
+ // Stream exists and not idle, so let the current sound to
+ // finish playing. If less than |wav_parser_.duration()| / 2
+ // until the end (including all replay requests), then replay is
+ // sheduled. The main purpose of this strategy is to smooth
+ // sound reproduction when multiple requests are made, for
+ // instance, when user presses volume(up|down) button for a long
+ // time.
+ if (ReplayRequestCouldBeScheduled())
+ ++num_replay_requests_;
+ return;
}
- cursor_ = 0;
+ last_play_start_time_ = base::TimeTicks::Now();
+ num_replay_requests_ = 0;
+ is_stream_idle_ = false;
if (g_audio_source_for_testing)
stream_->Start(g_audio_source_for_testing);
else
@@ -71,27 +96,40 @@ class AudioStreamHandler::AudioStreamContainer
void Stop() {
DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
- if (!stream_)
- return;
- stream_->Stop();
- stream_->Close();
- stream_ = NULL;
-
- if (g_observer_for_testing)
- g_observer_for_testing->OnStop(cursor_);
+ StopStream();
}
private:
+ friend class AudioStreamHandler;
+
// AudioOutputStream::AudioSourceCallback overrides:
// Following methods could be called from *ANY* thread.
virtual int OnMoreData(AudioBus* dest,
AudioBuffersState /* state */) OVERRIDE {
+ if (is_stream_idle_)
+ return 0;
+
size_t bytes_written = 0;
- if (wav_audio_.AtEnd(cursor_) ||
- !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) {
- AudioManager::Get()->GetMessageLoop()->PostTask(
- FROM_HERE,
- base::Bind(&AudioStreamContainer::Stop, base::Unretained(this)));
+ if (wav_reader_->AtEnd(cursor_) ||
+ !wav_reader_->CopyTo(dest, cursor_, &bytes_written)) {
+ // If there are replay requests, |cursor_| is reset and will
+ // continue to play from the start. Otherwise, stream will be
+ // stopped (not closed!) in |kStopStreamDelaySec| seconds,
+ // unless new Play() requests arrive during this time period.
+ if (num_replay_requests_) {
+ cursor_ = 0;
+ --num_replay_requests_;
+ if (g_observer_for_testing)
+ g_observer_for_testing->OnReplay();
+ } else {
+ is_stream_idle_ = true;
+ stop_stream_closure_.Reset(base::Bind(&AudioStreamContainer::StopStream,
+ base::Unretained(this)));
+ AudioManager::Get()->GetMessageLoop()->PostDelayedTask(
+ FROM_HERE,
+ stop_stream_closure_.callback(),
+ base::TimeDelta::FromSeconds(kStopStreamDelaySec));
+ }
return 0;
}
cursor_ += bytes_written;
@@ -109,18 +147,65 @@ class AudioStreamHandler::AudioStreamContainer
LOG(ERROR) << "Error during system sound reproduction.";
}
+ void StopStream() {
+ stop_stream_closure_.Cancel();
+ num_replay_requests_ = 0;
+ if (stream_)
+ stream_->Stop();
+ if (g_observer_for_testing)
+ g_observer_for_testing->OnStop(cursor_);
+ }
+
+ void StopAndCloseStream() {
+ StopStream();
+ if (stream_) {
+ stream_->Close();
+ stream_ = NULL;
+ }
+ }
+
+ bool ReplayRequestCouldBeScheduled() {
+ if (schedule_replay_request_for_testing_) {
+ --schedule_replay_request_for_testing_;
+ return true;
+ }
+ return 2 * (base::TimeTicks::Now() - last_play_start_time_) >
+ (2 * num_replay_requests_ + 1) * duration_;
+ }
+
+ void SetWavReaderForTesting(WavReader* reader) {
+ wav_reader_.reset(reader);
+ }
+
+ void AllowReplayOnceForTesting() {
+ ++schedule_replay_request_for_testing_;
+ }
+
AudioOutputStream* stream_;
- const WavAudioHandler wav_audio_;
+ scoped_ptr<WavReader> wav_reader_;
+ const base::TimeDelta duration_;
const AudioParameters params_;
size_t cursor_;
+ // Number of pending play requests, which should be processed after
+ // the current request.
+ int num_replay_requests_;
+
+ base::CancelableClosure stop_stream_closure_;
+ bool is_stream_idle_;
+
+ // Last time sound started to play from the start.
+ base::TimeTicks last_play_start_time_;
+
+ int schedule_replay_request_for_testing_;
+
DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
};
AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
- : wav_audio_(wav_data),
+ : wav_parser_(wav_data),
initialized_(false) {
AudioManager* manager = AudioManager::Get();
if (!manager) {
@@ -128,15 +213,15 @@ AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
return;
}
AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
- GuessChannelLayout(wav_audio_.num_channels()),
- wav_audio_.sample_rate(),
- wav_audio_.bits_per_sample(),
+ GuessChannelLayout(wav_parser_.num_channels()),
+ wav_parser_.sample_rate(),
+ wav_parser_.bits_per_sample(),
kDefaultFrameCount);
if (!params.IsValid()) {
LOG(ERROR) << "Audio params are invalid.";
return;
}
- stream_.reset(new AudioStreamContainer(wav_audio_, params));
+ stream_.reset(new AudioStreamContainer(wav_parser_, params));
initialized_ = true;
}
@@ -185,4 +270,18 @@ void AudioStreamHandler::SetAudioSourceForTesting(
g_audio_source_for_testing = source;
}
+void AudioStreamHandler::SetWavReaderForTesting(WavReader* reader) {
+ AudioManager::Get()->GetMessageLoop()->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioStreamContainer::SetWavReaderForTesting,
+ base::Unretained(stream_.get()), reader));
+}
+
+void AudioStreamHandler::AllowReplayOnceForTesting() {
+ AudioManager::Get()->GetMessageLoop()->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioStreamContainer::AllowReplayOnceForTesting,
+ base::Unretained(stream_.get())));
+}
+
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698