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 |