Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |