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 |