| Index: media/audio/audio_output_controller.cc
|
| ===================================================================
|
| --- media/audio/audio_output_controller.cc (revision 106670)
|
| +++ media/audio/audio_output_controller.cc (working copy)
|
| @@ -176,9 +176,10 @@
|
| // We can start from created or paused state.
|
| if (state_ != kCreated && state_ != kPaused)
|
| return;
|
| - state_ = kPlaying;
|
|
|
| if (LowLatencyMode()) {
|
| + state_ = kStarting;
|
| +
|
| // Ask for first packet.
|
| sync_reader_->UpdatePendingBytes(0);
|
|
|
| @@ -197,13 +198,20 @@
|
| void AudioOutputController::PollAndStartIfDataReady() {
|
| DCHECK_EQ(message_loop_, MessageLoop::current());
|
|
|
| - // Being paranoic: do nothing if we were stopped/paused
|
| - // after DoPlay() but before DoStartStream().
|
| - if (state_ != kPlaying)
|
| + // Being paranoic: do nothing if state unexpectedly changed.
|
| + if ((state_ != kStarting) && (state_ != kPausedWhenStarting))
|
| return;
|
|
|
| - if (--number_polling_attempts_left_ == 0 || sync_reader_->DataReady()) {
|
| + bool pausing = (state_ == kPausedWhenStarting);
|
| + // If we are ready to start the stream, start it.
|
| + // Of course we may have to stop it immediately...
|
| + if (--number_polling_attempts_left_ == 0 ||
|
| + pausing ||
|
| + sync_reader_->DataReady()) {
|
| StartStream();
|
| + if (pausing) {
|
| + DoPause();
|
| + }
|
| } else {
|
| message_loop_->PostDelayedTask(
|
| FROM_HERE,
|
| @@ -214,6 +222,7 @@
|
|
|
| void AudioOutputController::StartStream() {
|
| DCHECK_EQ(message_loop_, MessageLoop::current());
|
| + state_ = kPlaying;
|
|
|
| // We start the AudioOutputStream lazily.
|
| stream_->Start(this);
|
| @@ -225,22 +234,32 @@
|
| void AudioOutputController::DoPause() {
|
| DCHECK_EQ(message_loop_, MessageLoop::current());
|
|
|
| - // We can pause from started state.
|
| - if (state_ != kPlaying)
|
| - return;
|
| - state_ = kPaused;
|
| + switch (state_) {
|
| + case kStarting:
|
| + // We were asked to pause while starting. There is delayed task that will
|
| + // try starting playback, and there is no way to remove that task from the
|
| + // queue. If we stop now that task will be executed anyway.
|
| + // Delay pausing, let delayed task to do pause after it start playback.
|
| + state_ = kPausedWhenStarting;
|
| + break;
|
| + case kPlaying:
|
| + state_ = kPaused;
|
|
|
| - // Then we stop the audio device. This is not the perfect solution because
|
| - // it discards all the internal buffer in the audio device.
|
| - // TODO(hclam): Actually pause the audio device.
|
| - stream_->Stop();
|
| + // Then we stop the audio device. This is not the perfect solution
|
| + // because it discards all the internal buffer in the audio device.
|
| + // TODO(hclam): Actually pause the audio device.
|
| + stream_->Stop();
|
|
|
| - if (LowLatencyMode()) {
|
| - // Send a special pause mark to the low-latency audio thread.
|
| - sync_reader_->UpdatePendingBytes(kPauseMark);
|
| + if (LowLatencyMode()) {
|
| + // Send a special pause mark to the low-latency audio thread.
|
| + sync_reader_->UpdatePendingBytes(kPauseMark);
|
| + }
|
| +
|
| + handler_->OnPaused(this);
|
| + break;
|
| + default:
|
| + return;
|
| }
|
| -
|
| - handler_->OnPaused(this);
|
| }
|
|
|
| void AudioOutputController::DoFlush() {
|
| @@ -287,10 +306,17 @@
|
| // right away but when the stream is created we'll set the volume.
|
| volume_ = volume;
|
|
|
| - if (state_ != kPlaying && state_ != kPaused && state_ != kCreated)
|
| - return;
|
| -
|
| - stream_->SetVolume(volume_);
|
| + switch (state_) {
|
| + case kCreated:
|
| + case kStarting:
|
| + case kPausedWhenStarting:
|
| + case kPlaying:
|
| + case kPaused:
|
| + stream_->SetVolume(volume_);
|
| + break;
|
| + default:
|
| + return;
|
| + }
|
| }
|
|
|
| void AudioOutputController::DoReportError(int code) {
|
|
|