| 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 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
| 11 #include "base/time.h" | 11 #include "base/time.h" |
| 12 | 12 |
| 13 using base::Time; | 13 using base::Time; |
| 14 | 14 |
| 15 namespace media { | 15 namespace media { |
| 16 | 16 |
| 17 // Signal a pause in low-latency mode. | 17 // Signal a pause in low-latency mode. |
| 18 const int AudioOutputController::kPauseMark = -1; | 18 const int AudioOutputController::kPauseMark = -1; |
| 19 | 19 |
| 20 // Polling-related constants. | 20 // Polling-related constants. |
| 21 const int AudioOutputController::kPollNumAttempts = 3; | 21 const int AudioOutputController::kPollNumAttempts = 3; |
| 22 const int AudioOutputController::kPollPauseInMilliseconds = 3; | 22 const int AudioOutputController::kPollPauseInMilliseconds = 3; |
| 23 | 23 |
| 24 AudioOutputController::AudioOutputController(EventHandler* handler, | 24 AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
| 25 EventHandler* handler, |
| 25 uint32 capacity, | 26 uint32 capacity, |
| 26 SyncReader* sync_reader) | 27 SyncReader* sync_reader) |
| 27 : handler_(handler), | 28 : audio_manager_(audio_manager), |
| 29 handler_(handler), |
| 28 stream_(NULL), | 30 stream_(NULL), |
| 29 volume_(1.0), | 31 volume_(1.0), |
| 30 state_(kEmpty), | 32 state_(kEmpty), |
| 31 buffer_(0, capacity), | 33 buffer_(0, capacity), |
| 32 pending_request_(false), | 34 pending_request_(false), |
| 33 sync_reader_(sync_reader), | 35 sync_reader_(sync_reader), |
| 34 message_loop_(NULL), | 36 message_loop_(NULL), |
| 35 number_polling_attempts_left_(0) { | 37 number_polling_attempts_left_(0), |
| 38 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { |
| 36 } | 39 } |
| 37 | 40 |
| 38 AudioOutputController::~AudioOutputController() { | 41 AudioOutputController::~AudioOutputController() { |
| 39 DCHECK_EQ(kClosed, state_); | 42 DCHECK_EQ(kClosed, state_); |
| 40 StopCloseAndClearStream(); | 43 StopCloseAndClearStream(); |
| 41 } | 44 } |
| 42 | 45 |
| 43 // static | 46 // static |
| 44 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 47 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
| 48 AudioManager* audio_manager, |
| 45 EventHandler* event_handler, | 49 EventHandler* event_handler, |
| 46 const AudioParameters& params, | 50 const AudioParameters& params, |
| 47 uint32 buffer_capacity) { | 51 uint32 buffer_capacity) { |
| 48 | 52 DCHECK(audio_manager); |
| 49 if (!params.IsValid()) | 53 if (!params.IsValid() || !audio_manager) |
| 50 return NULL; | |
| 51 | |
| 52 if (!AudioManager::GetAudioManager()) | |
| 53 return NULL; | 54 return NULL; |
| 54 | 55 |
| 55 // Starts the audio controller thread. | 56 // Starts the audio controller thread. |
| 56 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 57 scoped_refptr<AudioOutputController> controller(new AudioOutputController( |
| 57 event_handler, buffer_capacity, NULL)); | 58 audio_manager, event_handler, buffer_capacity, NULL)); |
| 58 | 59 |
| 59 controller->message_loop_ = | 60 controller->message_loop_ = audio_manager->GetMessageLoop(); |
| 60 AudioManager::GetAudioManager()->GetMessageLoop(); | |
| 61 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 61 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
| 62 &AudioOutputController::DoCreate, controller.get(), params)); | 62 &AudioOutputController::DoCreate, base::Unretained(controller.get()), |
| 63 params)); |
| 63 return controller; | 64 return controller; |
| 64 } | 65 } |
| 65 | 66 |
| 66 // static | 67 // static |
| 67 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( | 68 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( |
| 69 AudioManager* audio_manager, |
| 68 EventHandler* event_handler, | 70 EventHandler* event_handler, |
| 69 const AudioParameters& params, | 71 const AudioParameters& params, |
| 70 SyncReader* sync_reader) { | 72 SyncReader* sync_reader) { |
| 71 | 73 DCHECK(audio_manager); |
| 72 DCHECK(sync_reader); | 74 DCHECK(sync_reader); |
| 73 | 75 |
| 74 if (!params.IsValid()) | 76 if (!params.IsValid() || !audio_manager) |
| 75 return NULL; | |
| 76 | |
| 77 if (!AudioManager::GetAudioManager()) | |
| 78 return NULL; | 77 return NULL; |
| 79 | 78 |
| 80 // Starts the audio controller thread. | 79 // Starts the audio controller thread. |
| 81 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 80 scoped_refptr<AudioOutputController> controller(new AudioOutputController( |
| 82 event_handler, 0, sync_reader)); | 81 audio_manager, event_handler, 0, sync_reader)); |
| 83 | 82 |
| 84 controller->message_loop_ = | 83 controller->message_loop_ = audio_manager->GetMessageLoop(); |
| 85 AudioManager::GetAudioManager()->GetMessageLoop(); | |
| 86 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 84 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
| 87 &AudioOutputController::DoCreate, controller.get(), params)); | 85 &AudioOutputController::DoCreate, base::Unretained(controller.get()), |
| 86 params)); |
| 88 return controller; | 87 return controller; |
| 89 } | 88 } |
| 90 | 89 |
| 91 void AudioOutputController::Play() { | 90 void AudioOutputController::Play() { |
| 92 DCHECK(message_loop_); | 91 DCHECK(message_loop_); |
| 93 message_loop_->PostTask(FROM_HERE, base::Bind( | 92 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 94 &AudioOutputController::DoPlay, this)); | 93 &AudioOutputController::DoPlay, base::Unretained(this))); |
| 95 } | 94 } |
| 96 | 95 |
| 97 void AudioOutputController::Pause() { | 96 void AudioOutputController::Pause() { |
| 98 DCHECK(message_loop_); | 97 DCHECK(message_loop_); |
| 99 message_loop_->PostTask(FROM_HERE, base::Bind( | 98 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 100 &AudioOutputController::DoPause, this)); | 99 &AudioOutputController::DoPause, base::Unretained(this))); |
| 101 } | 100 } |
| 102 | 101 |
| 103 void AudioOutputController::Flush() { | 102 void AudioOutputController::Flush() { |
| 104 DCHECK(message_loop_); | 103 DCHECK(message_loop_); |
| 105 message_loop_->PostTask(FROM_HERE, base::Bind( | 104 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 106 &AudioOutputController::DoFlush, this)); | 105 &AudioOutputController::DoFlush, base::Unretained(this))); |
| 107 } | 106 } |
| 108 | 107 |
| 109 void AudioOutputController::Close(const base::Closure& closed_task) { | 108 void AudioOutputController::Close(const base::Closure& closed_task) { |
| 110 DCHECK(!closed_task.is_null()); | 109 DCHECK(!closed_task.is_null()); |
| 111 DCHECK(message_loop_); | 110 DCHECK(message_loop_); |
| 112 message_loop_->PostTask(FROM_HERE, base::Bind( | 111 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 113 &AudioOutputController::DoClose, this, closed_task)); | 112 &AudioOutputController::DoClose, base::Unretained(this), closed_task)); |
| 114 } | 113 } |
| 115 | 114 |
| 116 void AudioOutputController::SetVolume(double volume) { | 115 void AudioOutputController::SetVolume(double volume) { |
| 117 DCHECK(message_loop_); | 116 DCHECK(message_loop_); |
| 118 message_loop_->PostTask(FROM_HERE, base::Bind( | 117 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 119 &AudioOutputController::DoSetVolume, this, volume)); | 118 &AudioOutputController::DoSetVolume, base::Unretained(this), volume)); |
| 120 } | 119 } |
| 121 | 120 |
| 122 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) { | 121 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) { |
| 123 // Write data to the push source and ask for more data if needed. | 122 // Write data to the push source and ask for more data if needed. |
| 124 base::AutoLock auto_lock(lock_); | 123 base::AutoLock auto_lock(lock_); |
| 125 pending_request_ = false; | 124 pending_request_ = false; |
| 126 // If |size| is set to 0, it indicates that the audio source doesn't have | 125 // If |size| is set to 0, it indicates that the audio source doesn't have |
| 127 // more data right now, and so it doesn't make sense to send additional | 126 // more data right now, and so it doesn't make sense to send additional |
| 128 // request. | 127 // request. |
| 129 if (size) { | 128 if (size) { |
| 130 buffer_.Append(data, size); | 129 buffer_.Append(data, size); |
| 131 SubmitOnMoreData_Locked(); | 130 SubmitOnMoreData_Locked(); |
| 132 } | 131 } |
| 133 } | 132 } |
| 134 | 133 |
| 135 void AudioOutputController::DoCreate(const AudioParameters& params) { | 134 void AudioOutputController::DoCreate(const AudioParameters& params) { |
| 136 DCHECK_EQ(message_loop_, MessageLoop::current()); | 135 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 137 | 136 |
| 138 // Close() can be called before DoCreate() is executed. | 137 // Close() can be called before DoCreate() is executed. |
| 139 if (state_ == kClosed) | 138 if (state_ == kClosed) |
| 140 return; | 139 return; |
| 141 DCHECK_EQ(kEmpty, state_); | 140 DCHECK_EQ(kEmpty, state_); |
| 142 | 141 |
| 143 if (!AudioManager::GetAudioManager()) | |
| 144 return; | |
| 145 | |
| 146 StopCloseAndClearStream(); | 142 StopCloseAndClearStream(); |
| 147 stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStreamProxy(params); | 143 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params); |
| 148 if (!stream_) { | 144 if (!stream_) { |
| 149 // TODO(hclam): Define error types. | 145 // TODO(hclam): Define error types. |
| 150 handler_->OnError(this, 0); | 146 handler_->OnError(this, 0); |
| 151 return; | 147 return; |
| 152 } | 148 } |
| 153 | 149 |
| 154 if (!stream_->Open()) { | 150 if (!stream_->Open()) { |
| 155 StopCloseAndClearStream(); | 151 StopCloseAndClearStream(); |
| 156 | 152 |
| 157 // TODO(hclam): Define error types. | 153 // TODO(hclam): Define error types. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 186 state_ = kStarting; | 182 state_ = kStarting; |
| 187 | 183 |
| 188 // Ask for first packet. | 184 // Ask for first packet. |
| 189 sync_reader_->UpdatePendingBytes(0); | 185 sync_reader_->UpdatePendingBytes(0); |
| 190 | 186 |
| 191 // Cannot start stream immediately, should give renderer some time | 187 // Cannot start stream immediately, should give renderer some time |
| 192 // to deliver data. | 188 // to deliver data. |
| 193 number_polling_attempts_left_ = kPollNumAttempts; | 189 number_polling_attempts_left_ = kPollNumAttempts; |
| 194 message_loop_->PostDelayedTask( | 190 message_loop_->PostDelayedTask( |
| 195 FROM_HERE, | 191 FROM_HERE, |
| 196 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this), | 192 base::Bind(&AudioOutputController::PollAndStartIfDataReady, |
| 193 weak_this_.GetWeakPtr()), |
| 197 kPollPauseInMilliseconds); | 194 kPollPauseInMilliseconds); |
| 198 } else { | 195 } else { |
| 199 StartStream(); | 196 StartStream(); |
| 200 } | 197 } |
| 201 } | 198 } |
| 202 | 199 |
| 203 void AudioOutputController::PollAndStartIfDataReady() { | 200 void AudioOutputController::PollAndStartIfDataReady() { |
| 204 DCHECK_EQ(message_loop_, MessageLoop::current()); | 201 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 205 | 202 |
| 206 // Being paranoic: do nothing if state unexpectedly changed. | 203 // Being paranoid: do nothing if state unexpectedly changed. |
| 207 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) | 204 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) |
| 208 return; | 205 return; |
| 209 | 206 |
| 210 bool pausing = (state_ == kPausedWhenStarting); | 207 bool pausing = (state_ == kPausedWhenStarting); |
| 211 // If we are ready to start the stream, start it. | 208 // If we are ready to start the stream, start it. |
| 212 // Of course we may have to stop it immediately... | 209 // Of course we may have to stop it immediately... |
| 213 if (--number_polling_attempts_left_ == 0 || | 210 if (--number_polling_attempts_left_ == 0 || |
| 214 pausing || | 211 pausing || |
| 215 sync_reader_->DataReady()) { | 212 sync_reader_->DataReady()) { |
| 216 StartStream(); | 213 StartStream(); |
| 217 if (pausing) { | 214 if (pausing) { |
| 218 DoPause(); | 215 DoPause(); |
| 219 } | 216 } |
| 220 } else { | 217 } else { |
| 221 message_loop_->PostDelayedTask( | 218 message_loop_->PostDelayedTask( |
| 222 FROM_HERE, | 219 FROM_HERE, |
| 223 base::Bind(&AudioOutputController::PollAndStartIfDataReady, this), | 220 base::Bind(&AudioOutputController::PollAndStartIfDataReady, |
| 221 weak_this_.GetWeakPtr()), |
| 224 kPollPauseInMilliseconds); | 222 kPollPauseInMilliseconds); |
| 225 } | 223 } |
| 226 } | 224 } |
| 227 | 225 |
| 228 void AudioOutputController::StartStream() { | 226 void AudioOutputController::StartStream() { |
| 229 DCHECK_EQ(message_loop_, MessageLoop::current()); | 227 DCHECK_EQ(message_loop_, MessageLoop::current()); |
| 230 state_ = kPlaying; | 228 state_ = kPlaying; |
| 231 | 229 |
| 232 // We start the AudioOutputStream lazily. | 230 // We start the AudioOutputStream lazily. |
| 233 stream_->Start(this); | 231 stream_->Start(this); |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 do { | 370 do { |
| 373 base::PlatformThread::Sleep(1); | 371 base::PlatformThread::Sleep(1); |
| 374 } while (!sync_reader_->DataReady() && | 372 } while (!sync_reader_->DataReady() && |
| 375 (Time::Now() - start_time).InMilliseconds() < kMaxPollingDelayMs); | 373 (Time::Now() - start_time).InMilliseconds() < kMaxPollingDelayMs); |
| 376 } | 374 } |
| 377 } | 375 } |
| 378 | 376 |
| 379 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { | 377 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { |
| 380 // Handle error on the audio controller thread. | 378 // Handle error on the audio controller thread. |
| 381 message_loop_->PostTask(FROM_HERE, base::Bind( | 379 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 382 &AudioOutputController::DoReportError, this, code)); | 380 &AudioOutputController::DoReportError, base::Unretained(this), code)); |
| 383 } | 381 } |
| 384 | 382 |
| 385 void AudioOutputController::SubmitOnMoreData_Locked() { | 383 void AudioOutputController::SubmitOnMoreData_Locked() { |
| 386 lock_.AssertAcquired(); | 384 lock_.AssertAcquired(); |
| 387 | 385 |
| 388 if (buffer_.forward_bytes() > buffer_.forward_capacity()) | 386 if (buffer_.forward_bytes() > buffer_.forward_capacity()) |
| 389 return; | 387 return; |
| 390 | 388 |
| 391 if (pending_request_) | 389 if (pending_request_) |
| 392 return; | 390 return; |
| 393 pending_request_ = true; | 391 pending_request_ = true; |
| 394 | 392 |
| 395 AudioBuffersState buffers_state = buffers_state_; | 393 AudioBuffersState buffers_state = buffers_state_; |
| 396 buffers_state.pending_bytes += buffer_.forward_bytes(); | 394 buffers_state.pending_bytes += buffer_.forward_bytes(); |
| 397 | 395 |
| 398 // If we need more data then call the event handler to ask for more data. | 396 // If we need more data then call the event handler to ask for more data. |
| 399 // It is okay that we don't lock in this block because the parameters are | 397 // It is okay that we don't lock in this block because the parameters are |
| 400 // correct and in the worst case we are just asking more data than needed. | 398 // correct and in the worst case we are just asking more data than needed. |
| 401 base::AutoUnlock auto_unlock(lock_); | 399 base::AutoUnlock auto_unlock(lock_); |
| 402 handler_->OnMoreData(this, buffers_state); | 400 handler_->OnMoreData(this, buffers_state); |
| 403 } | 401 } |
| 404 | 402 |
| 405 void AudioOutputController::StopCloseAndClearStream() { | 403 void AudioOutputController::StopCloseAndClearStream() { |
| 406 // Allow calling unconditionally and bail if we don't have a stream_ to close. | 404 // Allow calling unconditionally and bail if we don't have a stream_ to close. |
| 407 if (!stream_) | 405 if (!stream_) |
| 408 return; | 406 return; |
| 409 stream_->Stop(); | 407 stream_->Stop(); |
| 410 stream_->Close(); | 408 stream_->Close(); |
| 411 stream_ = NULL; | 409 stream_ = NULL; |
| 410 weak_this_.InvalidateWeakPtrs(); |
| 412 } | 411 } |
| 413 | 412 |
| 414 } // namespace media | 413 } // namespace media |
| OLD | NEW |