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

Side by Side Diff: media/audio/audio_output_controller.cc

Issue 8371013: Harden audio output controller making it safe to call Pause() before (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 9 years, 2 months 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 (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/audio_output_controller.h" 5 #include "media/audio/audio_output_controller.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 10
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 SubmitOnMoreData_Locked(); 169 SubmitOnMoreData_Locked();
170 } 170 }
171 } 171 }
172 172
173 void AudioOutputController::DoPlay() { 173 void AudioOutputController::DoPlay() {
174 DCHECK_EQ(message_loop_, MessageLoop::current()); 174 DCHECK_EQ(message_loop_, MessageLoop::current());
175 175
176 // We can start from created or paused state. 176 // We can start from created or paused state.
177 if (state_ != kCreated && state_ != kPaused) 177 if (state_ != kCreated && state_ != kPaused)
178 return; 178 return;
179 state_ = kPlaying;
180 179
181 if (LowLatencyMode()) { 180 if (LowLatencyMode()) {
181 state_ = kStarting;
182
182 // Ask for first packet. 183 // Ask for first packet.
183 sync_reader_->UpdatePendingBytes(0); 184 sync_reader_->UpdatePendingBytes(0);
184 185
185 // Cannot start stream immediately, should give renderer some time 186 // Cannot start stream immediately, should give renderer some time
186 // to deliver data. 187 // to deliver data.
187 number_polling_attempts_left_ = kPollNumAttempts; 188 number_polling_attempts_left_ = kPollNumAttempts;
188 message_loop_->PostDelayedTask( 189 message_loop_->PostDelayedTask(
189 FROM_HERE, 190 FROM_HERE,
190 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this), 191 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this),
191 kPollPauseInMilliseconds); 192 kPollPauseInMilliseconds);
192 } else { 193 } else {
193 StartStream(); 194 StartStream();
194 } 195 }
195 } 196 }
196 197
197 void AudioOutputController::PollAndStartIfDataReady() { 198 void AudioOutputController::PollAndStartIfDataReady() {
198 DCHECK_EQ(message_loop_, MessageLoop::current()); 199 DCHECK_EQ(message_loop_, MessageLoop::current());
199 200
200 // Being paranoic: do nothing if we were stopped/paused 201 // Being paranoic: do nothing if we were stopped/paused
201 // after DoPlay() but before DoStartStream(). 202 // after DoPlay() but before DoStartStream().
202 if (state_ != kPlaying) 203 if (state_ != kStarting)
203 return; 204 return;
204 205
205 if (--number_polling_attempts_left_ == 0 || sync_reader_->DataReady()) { 206 if (--number_polling_attempts_left_ == 0 || sync_reader_->DataReady()) {
206 StartStream(); 207 StartStream();
207 } else { 208 } else {
208 message_loop_->PostDelayedTask( 209 message_loop_->PostDelayedTask(
209 FROM_HERE, 210 FROM_HERE,
210 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this), 211 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this),
211 kPollPauseInMilliseconds); 212 kPollPauseInMilliseconds);
212 } 213 }
213 } 214 }
214 215
215 void AudioOutputController::StartStream() { 216 void AudioOutputController::StartStream() {
216 DCHECK_EQ(message_loop_, MessageLoop::current()); 217 DCHECK_EQ(message_loop_, MessageLoop::current());
218 state_ = kPlaying;
217 219
218 // We start the AudioOutputStream lazily. 220 // We start the AudioOutputStream lazily.
219 stream_->Start(this); 221 stream_->Start(this);
220 222
221 // Tell the event handler that we are now playing. 223 // Tell the event handler that we are now playing.
222 handler_->OnPlaying(this); 224 handler_->OnPlaying(this);
223 } 225 }
224 226
225 void AudioOutputController::DoPause() { 227 void AudioOutputController::DoPause() {
226 DCHECK_EQ(message_loop_, MessageLoop::current()); 228 DCHECK_EQ(message_loop_, MessageLoop::current());
227 229
228 // We can pause from started state. 230 switch (state_) {
229 if (state_ != kPlaying) 231 case kStarting:
230 return; 232 // We were asked to pause while starting. There is delayed task that will
231 state_ = kPaused; 233 // try starting playback, and there is no way to remove that task from the
234 // queue. If we stop now that task will be executed anyway.
235 // We can set state to "paused" and avoid problem in the simple case,
236 // but we can be asked to start playback for 2nd time before it started
237 // for the 1st time, and there would be new set of problems.
238 // Simplest solution is to delay pause a little till playback starts.
239 message_loop_->PostDelayedTask(
acolwell GONE FROM CHROMIUM 2011/10/24 03:47:15 This doesn't smell right. Can we add a kPauseWhile
enal1 2011/10/24 16:28:29 Initially I wrote code similar to what you suggest
acolwell GONE FROM CHROMIUM 2011/10/24 16:59:58 I'm afraid I'm going to have to insist here. I REA
240 FROM_HERE,
241 base::Bind( &AudioOutputController::DoPause, this),
242 kPollPauseInMilliseconds);
243 break;
244 case kPlaying:
245 state_ = kPaused;
232 246
233 // Then we stop the audio device. This is not the perfect solution because 247 // Then we stop the audio device. This is not the perfect solution
234 // it discards all the internal buffer in the audio device. 248 // because it discards all the internal buffer in the audio device.
235 // TODO(hclam): Actually pause the audio device. 249 // TODO(hclam): Actually pause the audio device.
236 stream_->Stop(); 250 stream_->Stop();
237 251
238 if (LowLatencyMode()) { 252 if (LowLatencyMode()) {
239 // Send a special pause mark to the low-latency audio thread. 253 // Send a special pause mark to the low-latency audio thread.
240 sync_reader_->UpdatePendingBytes(kPauseMark); 254 sync_reader_->UpdatePendingBytes(kPauseMark);
255 }
256
257 handler_->OnPaused(this);
258 break;
259 default:
260 return;
241 } 261 }
242
243 handler_->OnPaused(this);
244 } 262 }
245 263
246 void AudioOutputController::DoFlush() { 264 void AudioOutputController::DoFlush() {
247 DCHECK_EQ(message_loop_, MessageLoop::current()); 265 DCHECK_EQ(message_loop_, MessageLoop::current());
248 266
249 // TODO(hclam): Actually flush the audio device. 267 // TODO(hclam): Actually flush the audio device.
250 268
251 // If we are in the regular latency mode then flush the push source. 269 // If we are in the regular latency mode then flush the push source.
252 if (!sync_reader_) { 270 if (!sync_reader_) {
253 if (state_ != kPaused) 271 if (state_ != kPaused)
(...skipping 26 matching lines...) Expand all
280 closed_task.Run(); 298 closed_task.Run();
281 } 299 }
282 300
283 void AudioOutputController::DoSetVolume(double volume) { 301 void AudioOutputController::DoSetVolume(double volume) {
284 DCHECK_EQ(message_loop_, MessageLoop::current()); 302 DCHECK_EQ(message_loop_, MessageLoop::current());
285 303
286 // Saves the volume to a member first. We may not be able to set the volume 304 // Saves the volume to a member first. We may not be able to set the volume
287 // right away but when the stream is created we'll set the volume. 305 // right away but when the stream is created we'll set the volume.
288 volume_ = volume; 306 volume_ = volume;
289 307
290 if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) 308 switch (state_) {
291 return; 309 case kCreated:
292 310 case kStarting:
293 stream_->SetVolume(volume_); 311 case kPlaying:
312 case kPaused:
313 stream_->SetVolume(volume_);
314 break;
315 default:
316 return;
317 }
294 } 318 }
295 319
296 void AudioOutputController::DoReportError(int code) { 320 void AudioOutputController::DoReportError(int code) {
297 DCHECK_EQ(message_loop_, MessageLoop::current()); 321 DCHECK_EQ(message_loop_, MessageLoop::current());
298 if (state_ != kClosed) 322 if (state_ != kClosed)
299 handler_->OnError(this, code); 323 handler_->OnError(this, code);
300 } 324 }
301 325
302 uint32 AudioOutputController::OnMoreData( 326 uint32 AudioOutputController::OnMoreData(
303 AudioOutputStream* stream, uint8* dest, 327 AudioOutputStream* stream, uint8* dest,
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 buffers_state.pending_bytes += buffer_.forward_bytes(); 380 buffers_state.pending_bytes += buffer_.forward_bytes();
357 381
358 // If we need more data then call the event handler to ask for more data. 382 // If we need more data then call the event handler to ask for more data.
359 // It is okay that we don't lock in this block because the parameters are 383 // It is okay that we don't lock in this block because the parameters are
360 // correct and in the worst case we are just asking more data than needed. 384 // correct and in the worst case we are just asking more data than needed.
361 base::AutoUnlock auto_unlock(lock_); 385 base::AutoUnlock auto_unlock(lock_);
362 handler_->OnMoreData(this, buffers_state); 386 handler_->OnMoreData(this, buffers_state);
363 } 387 }
364 388
365 } // namespace media 389 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698