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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/sounds/audio_stream_handler.h" 5 #include "media/audio/sounds/audio_stream_handler.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/cancelable_callback.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/time/time.h"
11 #include "media/audio/audio_manager.h" 13 #include "media/audio/audio_manager.h"
12 #include "media/audio/audio_manager_base.h" 14 #include "media/audio/audio_manager_base.h"
15 #include "media/audio/sounds/wav_reader.h"
13 #include "media/base/channel_layout.h" 16 #include "media/base/channel_layout.h"
14 17
15 namespace media { 18 namespace media {
16 19
17 namespace { 20 namespace {
18 21
19 // Volume percent. 22 // Volume percent.
20 const double kOutputVolumePercent = 0.8; 23 const double kOutputVolumePercent = 0.8;
21 24
22 // The number of frames each OnMoreData() call will request. 25 // The number of frames each OnMoreData() call will request.
23 const int kDefaultFrameCount = 1024; 26 const int kDefaultFrameCount = 1024;
24 27
28 // Delay between end of sound and call to AudioOutputStream::Stop().
29 const int kStopStreamDelaySec = 3;
30
25 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL; 31 AudioStreamHandler::TestObserver* g_observer_for_testing = NULL;
26 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL; 32 AudioOutputStream::AudioSourceCallback* g_audio_source_for_testing = NULL;
27 33
28 } // namespace 34 } // namespace
29 35
30 class AudioStreamHandler::AudioStreamContainer 36 class AudioStreamHandler::AudioStreamContainer
31 : public AudioOutputStream::AudioSourceCallback { 37 : public AudioOutputStream::AudioSourceCallback {
32 public: 38 public:
33 AudioStreamContainer(const WavAudioHandler& wav_audio, 39 AudioStreamContainer(const WavParser& wav_parser,
34 const AudioParameters& params) 40 const AudioParameters& params)
35 : stream_(NULL), 41 : stream_(NULL),
36 wav_audio_(wav_audio), 42 wav_reader_(new WavReaderImpl(wav_parser)),
43 duration_(wav_parser.duration()),
37 params_(params), 44 params_(params),
38 cursor_(0) { 45 cursor_(0),
39 } 46 num_replay_requests_(0),
47 is_stream_idle_(true),
48 schedule_replay_request_for_testing_(0) {}
40 49
41 virtual ~AudioStreamContainer() { 50 virtual ~AudioStreamContainer() {
42 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread()); 51 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
52 stop_stream_closure_.Cancel();
53 StopAndCloseStream();
43 } 54 }
44 55
45 void Play() { 56 void Play() {
46 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread()); 57 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
47 58
48 if (!stream_) { 59 if (!stream_) {
49 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(params_, 60 stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy(
50 std::string(), 61 params_, std::string(), std::string());
51 std::string());
52 if (!stream_ || !stream_->Open()) { 62 if (!stream_ || !stream_->Open()) {
53 LOG(ERROR) << "Failed to open an output stream."; 63 LOG(ERROR) << "Failed to open an output stream.";
54 return; 64 return;
55 } 65 }
66 cursor_ = 0;
56 stream_->SetVolume(kOutputVolumePercent); 67 stream_->SetVolume(kOutputVolumePercent);
68 } else if (is_stream_idle_) {
69 // If stream exists and idle, just stop the stream and start again.
70 cursor_ = 0;
71 StopStream();
57 } else { 72 } else {
58 // TODO (ygorshenin@): implement smart stream rewind. 73 // Stream exists and not idle, so let the current sound to
59 stream_->Stop(); 74 // finish playing. If less than |wav_parser_.duration()| / 2
75 // until the end (including all replay requests), then replay is
76 // sheduled. The main purpose of this strategy is to smooth
77 // sound reproduction when multiple requests are made, for
78 // instance, when user presses volume(up|down) button for a long
79 // time.
80 if (ReplayRequestCouldBeScheduled())
81 ++num_replay_requests_;
82 return;
60 } 83 }
61 84
62 cursor_ = 0; 85 last_play_start_time_ = base::TimeTicks::Now();
86 num_replay_requests_ = 0;
87 is_stream_idle_ = false;
63 if (g_audio_source_for_testing) 88 if (g_audio_source_for_testing)
64 stream_->Start(g_audio_source_for_testing); 89 stream_->Start(g_audio_source_for_testing);
65 else 90 else
66 stream_->Start(this); 91 stream_->Start(this);
67 92
68 if (g_observer_for_testing) 93 if (g_observer_for_testing)
69 g_observer_for_testing->OnPlay(); 94 g_observer_for_testing->OnPlay();
70 } 95 }
71 96
72 void Stop() { 97 void Stop() {
73 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread()); 98 DCHECK(AudioManager::Get()->GetMessageLoop()->BelongsToCurrentThread());
74 if (!stream_) 99 StopStream();
75 return;
76 stream_->Stop();
77 stream_->Close();
78 stream_ = NULL;
79
80 if (g_observer_for_testing)
81 g_observer_for_testing->OnStop(cursor_);
82 } 100 }
83 101
84 private: 102 private:
103 friend class AudioStreamHandler;
104
85 // AudioOutputStream::AudioSourceCallback overrides: 105 // AudioOutputStream::AudioSourceCallback overrides:
86 // Following methods could be called from *ANY* thread. 106 // Following methods could be called from *ANY* thread.
87 virtual int OnMoreData(AudioBus* dest, 107 virtual int OnMoreData(AudioBus* dest,
88 AudioBuffersState /* state */) OVERRIDE { 108 AudioBuffersState /* state */) OVERRIDE {
109 if (is_stream_idle_)
110 return 0;
111
89 size_t bytes_written = 0; 112 size_t bytes_written = 0;
90 if (wav_audio_.AtEnd(cursor_) || 113 if (wav_reader_->AtEnd(cursor_) ||
91 !wav_audio_.CopyTo(dest, cursor_, &bytes_written)) { 114 !wav_reader_->CopyTo(dest, cursor_, &bytes_written)) {
92 AudioManager::Get()->GetMessageLoop()->PostTask( 115 // If there are replay requests, |cursor_| is reset and will
93 FROM_HERE, 116 // continue to play from the start. Otherwise, stream will be
94 base::Bind(&AudioStreamContainer::Stop, base::Unretained(this))); 117 // stopped (not closed!) in |kStopStreamDelaySec| seconds,
118 // unless new Play() requests arrive during this time period.
119 if (num_replay_requests_) {
120 cursor_ = 0;
121 --num_replay_requests_;
122 if (g_observer_for_testing)
123 g_observer_for_testing->OnReplay();
124 } else {
125 is_stream_idle_ = true;
126 stop_stream_closure_.Reset(base::Bind(&AudioStreamContainer::StopStream,
127 base::Unretained(this)));
128 AudioManager::Get()->GetMessageLoop()->PostDelayedTask(
129 FROM_HERE,
130 stop_stream_closure_.callback(),
131 base::TimeDelta::FromSeconds(kStopStreamDelaySec));
132 }
95 return 0; 133 return 0;
96 } 134 }
97 cursor_ += bytes_written; 135 cursor_ += bytes_written;
98 136
99 return dest->frames(); 137 return dest->frames();
100 } 138 }
101 139
102 virtual int OnMoreIOData(AudioBus* /* source */, 140 virtual int OnMoreIOData(AudioBus* /* source */,
103 AudioBus* dest, 141 AudioBus* dest,
104 AudioBuffersState state) OVERRIDE { 142 AudioBuffersState state) OVERRIDE {
105 return OnMoreData(dest, state); 143 return OnMoreData(dest, state);
106 } 144 }
107 145
108 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE { 146 virtual void OnError(AudioOutputStream* /* stream */) OVERRIDE {
109 LOG(ERROR) << "Error during system sound reproduction."; 147 LOG(ERROR) << "Error during system sound reproduction.";
110 } 148 }
111 149
150 void StopStream() {
151 stop_stream_closure_.Cancel();
152 num_replay_requests_ = 0;
153 if (stream_)
154 stream_->Stop();
155 if (g_observer_for_testing)
156 g_observer_for_testing->OnStop(cursor_);
157 }
158
159 void StopAndCloseStream() {
160 StopStream();
161 if (stream_) {
162 stream_->Close();
163 stream_ = NULL;
164 }
165 }
166
167 bool ReplayRequestCouldBeScheduled() {
168 if (schedule_replay_request_for_testing_) {
169 --schedule_replay_request_for_testing_;
170 return true;
171 }
172 return 2 * (base::TimeTicks::Now() - last_play_start_time_) >
173 (2 * num_replay_requests_ + 1) * duration_;
174 }
175
176 void SetWavReaderForTesting(WavReader* reader) {
177 wav_reader_.reset(reader);
178 }
179
180 void AllowReplayOnceForTesting() {
181 ++schedule_replay_request_for_testing_;
182 }
183
112 AudioOutputStream* stream_; 184 AudioOutputStream* stream_;
113 185
114 const WavAudioHandler wav_audio_; 186 scoped_ptr<WavReader> wav_reader_;
187 const base::TimeDelta duration_;
115 const AudioParameters params_; 188 const AudioParameters params_;
116 189
117 size_t cursor_; 190 size_t cursor_;
118 191
192 // Number of pending play requests, which should be processed after
193 // the current request.
194 int num_replay_requests_;
195
196 base::CancelableClosure stop_stream_closure_;
197 bool is_stream_idle_;
198
199 // Last time sound started to play from the start.
200 base::TimeTicks last_play_start_time_;
201
202 int schedule_replay_request_for_testing_;
203
119 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer); 204 DISALLOW_COPY_AND_ASSIGN(AudioStreamContainer);
120 }; 205 };
121 206
122 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data) 207 AudioStreamHandler::AudioStreamHandler(const base::StringPiece& wav_data)
123 : wav_audio_(wav_data), 208 : wav_parser_(wav_data),
124 initialized_(false) { 209 initialized_(false) {
125 AudioManager* manager = AudioManager::Get(); 210 AudioManager* manager = AudioManager::Get();
126 if (!manager) { 211 if (!manager) {
127 LOG(ERROR) << "Can't get access to audio manager."; 212 LOG(ERROR) << "Can't get access to audio manager.";
128 return; 213 return;
129 } 214 }
130 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, 215 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
131 GuessChannelLayout(wav_audio_.num_channels()), 216 GuessChannelLayout(wav_parser_.num_channels()),
132 wav_audio_.sample_rate(), 217 wav_parser_.sample_rate(),
133 wav_audio_.bits_per_sample(), 218 wav_parser_.bits_per_sample(),
134 kDefaultFrameCount); 219 kDefaultFrameCount);
135 if (!params.IsValid()) { 220 if (!params.IsValid()) {
136 LOG(ERROR) << "Audio params are invalid."; 221 LOG(ERROR) << "Audio params are invalid.";
137 return; 222 return;
138 } 223 }
139 stream_.reset(new AudioStreamContainer(wav_audio_, params)); 224 stream_.reset(new AudioStreamContainer(wav_parser_, params));
140 initialized_ = true; 225 initialized_ = true;
141 } 226 }
142 227
143 AudioStreamHandler::~AudioStreamHandler() { 228 AudioStreamHandler::~AudioStreamHandler() {
144 DCHECK(CalledOnValidThread()); 229 DCHECK(CalledOnValidThread());
145 AudioManager::Get()->GetMessageLoop()->PostTask( 230 AudioManager::Get()->GetMessageLoop()->PostTask(
146 FROM_HERE, 231 FROM_HERE,
147 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get()))); 232 base::Bind(&AudioStreamContainer::Stop, base::Unretained(stream_.get())));
148 AudioManager::Get()->GetMessageLoop()->DeleteSoon(FROM_HERE, 233 AudioManager::Get()->GetMessageLoop()->DeleteSoon(FROM_HERE,
149 stream_.release()); 234 stream_.release());
(...skipping 28 matching lines...) Expand all
178 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) { 263 void AudioStreamHandler::SetObserverForTesting(TestObserver* observer) {
179 g_observer_for_testing = observer; 264 g_observer_for_testing = observer;
180 } 265 }
181 266
182 // static 267 // static
183 void AudioStreamHandler::SetAudioSourceForTesting( 268 void AudioStreamHandler::SetAudioSourceForTesting(
184 AudioOutputStream::AudioSourceCallback* source) { 269 AudioOutputStream::AudioSourceCallback* source) {
185 g_audio_source_for_testing = source; 270 g_audio_source_for_testing = source;
186 } 271 }
187 272
273 void AudioStreamHandler::SetWavReaderForTesting(WavReader* reader) {
274 AudioManager::Get()->GetMessageLoop()->PostTask(
275 FROM_HERE,
276 base::Bind(&AudioStreamContainer::SetWavReaderForTesting,
277 base::Unretained(stream_.get()), reader));
278 }
279
280 void AudioStreamHandler::AllowReplayOnceForTesting() {
281 AudioManager::Get()->GetMessageLoop()->PostTask(
282 FROM_HERE,
283 base::Bind(&AudioStreamContainer::AllowReplayOnceForTesting,
284 base::Unretained(stream_.get())));
285 }
286
188 } // namespace media 287 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698