OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #include "base/synchronization/waitable_event.h" | 10 #include "base/synchronization/waitable_event.h" |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 | 130 |
131 if (!stream_->Open()) { | 131 if (!stream_->Open()) { |
132 state_ = kError; | 132 state_ = kError; |
133 DoStopCloseAndClearStream(NULL); | 133 DoStopCloseAndClearStream(NULL); |
134 | 134 |
135 // TODO(hclam): Define error types. | 135 // TODO(hclam): Define error types. |
136 handler_->OnError(this, 0); | 136 handler_->OnError(this, 0); |
137 return; | 137 return; |
138 } | 138 } |
139 | 139 |
140 // Everything started okay, so register for state change callbacks if we have | 140 // Everything started okay, so re-register for state change callbacks (the |
141 // not already done so. | 141 // call to DoStopCloseAndClearStream() above de-registered this instance). |
142 if (state_ != kRecreating) | 142 audio_manager_->AddOutputDeviceChangeListener(this); |
143 audio_manager_->AddOutputDeviceChangeListener(this); | |
144 | 143 |
145 // We have successfully opened the stream. Set the initial volume. | 144 // We have successfully opened the stream. Set the initial volume. |
146 stream_->SetVolume(volume_); | 145 stream_->SetVolume(volume_); |
147 | 146 |
148 // Finally set the state to kCreated. | 147 // Finally set the state to kCreated. |
149 State original_state = state_; | 148 State original_state = state_; |
150 state_ = kCreated; | 149 state_ = kCreated; |
151 | 150 |
152 // And then report we have been created if we haven't done so already. | 151 // And then report we have been created if we haven't done so already. |
153 if (original_state != kRecreating) | 152 if (original_state != kRecreating) |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 AudioBuffersState buffers_state) { | 296 AudioBuffersState buffers_state) { |
298 return OnMoreIOData(NULL, dest, buffers_state); | 297 return OnMoreIOData(NULL, dest, buffers_state); |
299 } | 298 } |
300 | 299 |
301 int AudioOutputController::OnMoreIOData(AudioBus* source, | 300 int AudioOutputController::OnMoreIOData(AudioBus* source, |
302 AudioBus* dest, | 301 AudioBus* dest, |
303 AudioBuffersState buffers_state) { | 302 AudioBuffersState buffers_state) { |
304 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); | 303 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); |
305 | 304 |
306 { | 305 { |
307 // Check state and do nothing if we are not playing. | 306 // Check state. When not playing, fill the destination with zeros. |
308 // We are on the hardware audio thread, so lock is needed. | 307 // We are on the hardware audio thread, so lock is needed. |
309 base::AutoLock auto_lock(lock_); | 308 base::AutoLock auto_lock(lock_); |
310 if (state_ != kPlaying) { | 309 if (state_ != kPlaying) { |
311 return 0; | 310 dest->Zero(); |
| 311 return dest->frames(); |
312 } | 312 } |
313 } | 313 } |
314 | 314 |
315 int frames = sync_reader_->Read(source, dest); | 315 int frames = sync_reader_->Read(source, dest); |
316 sync_reader_->UpdatePendingBytes( | 316 sync_reader_->UpdatePendingBytes( |
317 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); | 317 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); |
318 return frames; | 318 return frames; |
319 } | 319 } |
320 | 320 |
321 void AudioOutputController::WaitTillDataReady() { | 321 void AudioOutputController::WaitTillDataReady() { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
354 } | 354 } |
355 | 355 |
356 // Should be last in the method, do not touch "this" from here on. | 356 // Should be last in the method, do not touch "this" from here on. |
357 if (done) | 357 if (done) |
358 done->Signal(); | 358 done->Signal(); |
359 } | 359 } |
360 | 360 |
361 void AudioOutputController::OnDeviceChange() { | 361 void AudioOutputController::OnDeviceChange() { |
362 DCHECK(message_loop_->BelongsToCurrentThread()); | 362 DCHECK(message_loop_->BelongsToCurrentThread()); |
363 | 363 |
364 // We should always have a stream by this point. | 364 // Preserve the original state. |
365 CHECK(stream_); | 365 State original_state = state_; |
366 | 366 |
367 // Preserve the original state and shutdown the stream. | 367 // Recreate the stream (DoCreate() will first shut down an existing stream). |
368 State original_state = state_; | 368 // Exit if we ran into an error. |
369 stream_->Stop(); | |
370 stream_->Close(); | |
371 stream_ = NULL; | |
372 | |
373 // Recreate the stream, exit if we ran into an error. | |
374 state_ = kRecreating; | 369 state_ = kRecreating; |
375 DoCreate(); | 370 DoCreate(); |
376 if (!stream_ || state_ == kError) | 371 if (!stream_ || state_ == kError) |
377 return; | 372 return; |
378 | 373 |
379 // Get us back to the original state or an equivalent state. | 374 // Get us back to the original state or an equivalent state. |
380 switch (original_state) { | 375 switch (original_state) { |
381 case kStarting: | 376 case kStarting: |
382 case kPlaying: | 377 case kPlaying: |
383 DoPlay(); | 378 DoPlay(); |
384 return; | 379 return; |
385 case kCreated: | 380 case kCreated: |
386 case kPausedWhenStarting: | 381 case kPausedWhenStarting: |
387 case kPaused: | 382 case kPaused: |
388 // From the outside these three states are equivalent. | 383 // From the outside these three states are equivalent. |
389 return; | 384 return; |
390 default: | 385 default: |
391 NOTREACHED() << "Invalid original state."; | 386 NOTREACHED() << "Invalid original state."; |
392 } | 387 } |
393 } | 388 } |
394 | 389 |
| 390 AudioOutputStream::AudioSourceCallback* AudioOutputController::Divert() { |
| 391 // Assumption: AudioRendererHost is calling this method on the IO |
| 392 // BrowserThread. |
| 393 DCHECK(!message_loop_->BelongsToCurrentThread()); |
| 394 |
| 395 // Block until stream closure is complete because, otherwise, it's possible |
| 396 // for two entities to be pulling audio data at the same time. In addition, |
| 397 // a side effect of closing the stream is that this controller will be |
| 398 // de-registered from device change events (from AudioManager) during the |
| 399 // "divert." |
| 400 base::WaitableEvent blocker(true, false); |
| 401 message_loop_->PostTask( |
| 402 FROM_HERE, |
| 403 base::Bind(&AudioOutputController::DoStopCloseAndClearStream, this, |
| 404 &blocker)); |
| 405 blocker.Wait(); |
| 406 |
| 407 return this; |
| 408 } |
| 409 |
| 410 void AudioOutputController::Revert( |
| 411 AudioOutputStream::AudioSourceCallback* asc) { |
| 412 // Assumption: AudioRendererHost is calling this method on the IO |
| 413 // BrowserThread. |
| 414 DCHECK(!message_loop_->BelongsToCurrentThread()); |
| 415 |
| 416 DCHECK_EQ(this, asc); |
| 417 |
| 418 // The following re-creates the normal audio output stream and places it in |
| 419 // the correct playback state. It also re-registers this controller for |
| 420 // device change events from AudioManager. |
| 421 message_loop_->PostTask( |
| 422 FROM_HERE, base::Bind(&AudioOutputController::OnDeviceChange, this)); |
| 423 } |
| 424 |
395 } // namespace media | 425 } // namespace media |
OLD | NEW |