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

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: Fixed creation of AudioParameters. 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..7d6145d13ad06e3e2207f6a292180e3f50b7d3c7 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/message_loop/message_loop_proxy.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"
@@ -19,6 +22,9 @@ namespace {
// Volume percent.
const double kOutputVolumePercent = 0.8;
+// Delay between end of sound and call to AudioOutputStream::Stop().
+const int kStopStreamDelaySec = 3;
+
// The number of frames each OnMoreData() call will request.
const int kDefaultFrameCount = 1024;
@@ -30,36 +36,67 @@ 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),
+ replay_scheduled_(false),
+ is_stream_stopped_(true),
+ schedule_replay_request_for_testing_(0) {}
virtual ~AudioStreamContainer() {
DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
+ stop_stream_closure_.Cancel();
+
+ if (stream_) {
+ stream_->Stop();
+ stream_->Close();
+ }
}
void Play() {
DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
- if (!stream_) {
- stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params_,
- std::string(),
- std::string());
- if (!stream_ || !stream_->Open()) {
- LOG(ERROR) << "Failed to open an output stream.";
+ {
+ base::AutoLock sl(state_lock_);
+
+ if (!stream_) {
+ 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;
+ }
+ cursor_ = 0;
+ stream_->SetVolume(kOutputVolumePercent);
+ } else if (is_stream_stopped_) {
+ // If stream exists and idle, just stop the stream and start again.
+ cursor_ = 0;
+ StopStreamWithoutLock();
DaleCurtis 2014/01/02 20:11:17 Method says WithoutLock but in under state_lock_.
ygorshenin1 2014/01/09 19:26:57 Removed.
+ } else {
+ // Stream exists and not idle, so let the current sound to
+ // finish playing. If less than |wav_audio_.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())
+ replay_scheduled_ = true;
return;
}
- stream_->SetVolume(kOutputVolumePercent);
- } else {
- // TODO (ygorshenin@): implement smart stream rewind.
- stream_->Stop();
+
+ last_play_start_time_ = base::TimeTicks::Now();
+ replay_scheduled_ = false;
+ is_stream_stopped_ = false;
}
- cursor_ = 0;
if (g_audio_source_for_testing)
stream_->Start(g_audio_source_for_testing);
else
@@ -71,27 +108,43 @@ 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 {
+ base::AutoLock sl(state_lock_);
+
+ if (is_stream_stopped_)
+ 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 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 (replay_scheduled_) {
+ cursor_ = 0;
+ last_play_start_time_ = base::TimeTicks::Now();
+ replay_scheduled_ = false;
+ if (g_observer_for_testing)
+ g_observer_for_testing->OnReplay();
+ } else {
+ is_stream_stopped_ = 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,13 +162,56 @@ class AudioStreamHandler::AudioStreamContainer
LOG(ERROR) << "Error during system sound reproduction.";
}
+ void StopStreamWithoutLock() {
+ stop_stream_closure_.Cancel();
+ replay_scheduled_ = false;
+ if (stream_)
+ stream_->Stop();
+ if (g_observer_for_testing)
+ g_observer_for_testing->OnStop(cursor_);
+ }
+
+ void StopStream() {
+ base::AutoLock sl(state_lock_);
+ StopStreamWithoutLock();
+ }
+
+ bool ReplayRequestCouldBeScheduled() {
+ if (schedule_replay_request_for_testing_) {
+ --schedule_replay_request_for_testing_;
+ return true;
+ }
+ const base::TimeDelta delta =
+ base::TimeTicks::Now() - last_play_start_time_;
+ return 2 * delta > wav_audio_.params().GetBufferDuration() &&
+ !replay_scheduled_;
+ }
+
+ void AllowReplayOnceForTesting() {
+ base::AutoLock st(state_lock_);
+ ++schedule_replay_request_for_testing_;
+ }
+
AudioOutputStream* stream_;
- const WavAudioHandler wav_audio_;
- const AudioParameters params_;
+ WavAudioHandler wav_audio_;
size_t cursor_;
+ // True if replay of the current sound is scheduled.
+ bool replay_scheduled_;
+
+ base::CancelableClosure stop_stream_closure_;
+ bool is_stream_stopped_;
+
+ // Last time sound started to play from the start.
+ base::TimeTicks last_play_start_time_;
+
+ int schedule_replay_request_for_testing_;
+
+ // State lock for all fields except stream_ and wav_audio_.
+ base::Lock state_lock_;
+
DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
};
@@ -127,16 +223,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;
}
@@ -185,4 +276,11 @@ void AudioStreamHandler::SetAudioSourceForTesting(
g_audio_source_for_testing = source;
}
+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