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