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

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
« no previous file with comments | « media/audio/audio_output_controller.h ('k') | media/audio/audio_output_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 state unexpectedly changed.
201 // after DoPlay() but before DoStartStream(). 202 if ((state_ != kStarting) && (state_ != kPausedWhenStarting))
202 if (state_ != kPlaying)
203 return; 203 return;
204 204
205 if (--number_polling_attempts_left_ == 0 || sync_reader_->DataReady()) { 205 bool pausing = (state_ == kPausedWhenStarting);
206 // If we are ready to start the stream, start it.
207 // Of course we may have to stop it immediately...
208 if (--number_polling_attempts_left_ == 0 ||
209 pausing ||
210 sync_reader_->DataReady()) {
206 StartStream(); 211 StartStream();
212 if (pausing) {
213 DoPause();
214 }
207 } else { 215 } else {
208 message_loop_->PostDelayedTask( 216 message_loop_->PostDelayedTask(
209 FROM_HERE, 217 FROM_HERE,
210 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this), 218 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this),
211 kPollPauseInMilliseconds); 219 kPollPauseInMilliseconds);
212 } 220 }
213 } 221 }
214 222
215 void AudioOutputController::StartStream() { 223 void AudioOutputController::StartStream() {
216 DCHECK_EQ(message_loop_, MessageLoop::current()); 224 DCHECK_EQ(message_loop_, MessageLoop::current());
225 state_ = kPlaying;
217 226
218 // We start the AudioOutputStream lazily. 227 // We start the AudioOutputStream lazily.
219 stream_->Start(this); 228 stream_->Start(this);
220 229
221 // Tell the event handler that we are now playing. 230 // Tell the event handler that we are now playing.
222 handler_->OnPlaying(this); 231 handler_->OnPlaying(this);
223 } 232 }
224 233
225 void AudioOutputController::DoPause() { 234 void AudioOutputController::DoPause() {
226 DCHECK_EQ(message_loop_, MessageLoop::current()); 235 DCHECK_EQ(message_loop_, MessageLoop::current());
227 236
228 // We can pause from started state. 237 switch (state_) {
229 if (state_ != kPlaying) 238 case kStarting:
230 return; 239 // We were asked to pause while starting. There is delayed task that will
231 state_ = kPaused; 240 // try starting playback, and there is no way to remove that task from the
241 // queue. If we stop now that task will be executed anyway.
242 // Delay pausing, let delayed task to do pause after it start playback.
243 state_ = kPausedWhenStarting;
244 break;
245 case kPlaying:
246 state_ = kPaused;
232 247
233 // Then we stop the audio device. This is not the perfect solution because 248 // Then we stop the audio device. This is not the perfect solution
234 // it discards all the internal buffer in the audio device. 249 // because it discards all the internal buffer in the audio device.
235 // TODO(hclam): Actually pause the audio device. 250 // TODO(hclam): Actually pause the audio device.
236 stream_->Stop(); 251 stream_->Stop();
237 252
238 if (LowLatencyMode()) { 253 if (LowLatencyMode()) {
239 // Send a special pause mark to the low-latency audio thread. 254 // Send a special pause mark to the low-latency audio thread.
240 sync_reader_->UpdatePendingBytes(kPauseMark); 255 sync_reader_->UpdatePendingBytes(kPauseMark);
256 }
257
258 handler_->OnPaused(this);
259 break;
260 default:
261 return;
241 } 262 }
242
243 handler_->OnPaused(this);
244 } 263 }
245 264
246 void AudioOutputController::DoFlush() { 265 void AudioOutputController::DoFlush() {
247 DCHECK_EQ(message_loop_, MessageLoop::current()); 266 DCHECK_EQ(message_loop_, MessageLoop::current());
248 267
249 // TODO(hclam): Actually flush the audio device. 268 // TODO(hclam): Actually flush the audio device.
250 269
251 // If we are in the regular latency mode then flush the push source. 270 // If we are in the regular latency mode then flush the push source.
252 if (!sync_reader_) { 271 if (!sync_reader_) {
253 if (state_ != kPaused) 272 if (state_ != kPaused)
(...skipping 26 matching lines...) Expand all
280 closed_task.Run(); 299 closed_task.Run();
281 } 300 }
282 301
283 void AudioOutputController::DoSetVolume(double volume) { 302 void AudioOutputController::DoSetVolume(double volume) {
284 DCHECK_EQ(message_loop_, MessageLoop::current()); 303 DCHECK_EQ(message_loop_, MessageLoop::current());
285 304
286 // Saves the volume to a member first. We may not be able to set the volume 305 // 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. 306 // right away but when the stream is created we'll set the volume.
288 volume_ = volume; 307 volume_ = volume;
289 308
290 if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) 309 switch (state_) {
291 return; 310 case kCreated:
292 311 case kStarting:
293 stream_->SetVolume(volume_); 312 case kPausedWhenStarting:
313 case kPlaying:
314 case kPaused:
315 stream_->SetVolume(volume_);
316 break;
317 default:
318 return;
319 }
294 } 320 }
295 321
296 void AudioOutputController::DoReportError(int code) { 322 void AudioOutputController::DoReportError(int code) {
297 DCHECK_EQ(message_loop_, MessageLoop::current()); 323 DCHECK_EQ(message_loop_, MessageLoop::current());
298 if (state_ != kClosed) 324 if (state_ != kClosed)
299 handler_->OnError(this, code); 325 handler_->OnError(this, code);
300 } 326 }
301 327
302 uint32 AudioOutputController::OnMoreData( 328 uint32 AudioOutputController::OnMoreData(
303 AudioOutputStream* stream, uint8* dest, 329 AudioOutputStream* stream, uint8* dest,
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 buffers_state.pending_bytes += buffer_.forward_bytes(); 382 buffers_state.pending_bytes += buffer_.forward_bytes();
357 383
358 // If we need more data then call the event handler to ask for more data. 384 // 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 385 // 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. 386 // correct and in the worst case we are just asking more data than needed.
361 base::AutoUnlock auto_unlock(lock_); 387 base::AutoUnlock auto_unlock(lock_);
362 handler_->OnMoreData(this, buffers_state); 388 handler_->OnMoreData(this, buffers_state);
363 } 389 }
364 390
365 } // namespace media 391 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_controller.h ('k') | media/audio/audio_output_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698