| 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" |
| 11 #include "base/threading/platform_thread.h" | 11 #include "base/threading/platform_thread.h" |
| 12 #include "base/time.h" | 12 #include "base/time.h" |
| 13 | 13 |
| 14 using base::Time; | 14 using base::Time; |
| 15 using base::WaitableEvent; | 15 using base::WaitableEvent; |
| 16 | 16 |
| 17 namespace media { | 17 namespace media { |
| 18 | 18 |
| 19 // Signal a pause in low-latency mode. | 19 // Signal a pause in low-latency mode. |
| 20 const int AudioOutputController::kPauseMark = -1; | 20 const int AudioOutputController::kPauseMark = -1; |
| 21 | 21 |
| 22 // Polling-related constants. | 22 // Polling-related constants. |
| 23 const int AudioOutputController::kPollNumAttempts = 3; | 23 const int AudioOutputController::kPollNumAttempts = 3; |
| 24 const int AudioOutputController::kPollPauseInMilliseconds = 3; | 24 const int AudioOutputController::kPollPauseInMilliseconds = 3; |
| 25 | 25 |
| 26 AudioOutputController::AudioOutputController(AudioManager* audio_manager, | 26 AudioOutputController::AudioOutputController(AudioManager* audio_manager, |
| 27 EventHandler* handler, | 27 EventHandler* handler, |
| 28 uint32 capacity, | |
| 29 SyncReader* sync_reader) | 28 SyncReader* sync_reader) |
| 30 : audio_manager_(audio_manager), | 29 : audio_manager_(audio_manager), |
| 31 handler_(handler), | 30 handler_(handler), |
| 32 stream_(NULL), | 31 stream_(NULL), |
| 33 volume_(1.0), | 32 volume_(1.0), |
| 34 state_(kEmpty), | 33 state_(kEmpty), |
| 35 buffer_(0, capacity), | |
| 36 pending_request_(false), | |
| 37 sync_reader_(sync_reader), | 34 sync_reader_(sync_reader), |
| 38 message_loop_(NULL), | 35 message_loop_(NULL), |
| 39 number_polling_attempts_left_(0), | 36 number_polling_attempts_left_(0), |
| 40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { | 37 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { |
| 41 } | 38 } |
| 42 | 39 |
| 43 AudioOutputController::~AudioOutputController() { | 40 AudioOutputController::~AudioOutputController() { |
| 44 DCHECK_EQ(kClosed, state_); | 41 DCHECK_EQ(kClosed, state_); |
| 45 DCHECK(message_loop_); | 42 DCHECK(message_loop_); |
| 46 | 43 |
| 47 if (!message_loop_.get() || message_loop_->BelongsToCurrentThread()) { | 44 if (!message_loop_.get() || message_loop_->BelongsToCurrentThread()) { |
| 48 DoStopCloseAndClearStream(NULL); | 45 DoStopCloseAndClearStream(NULL); |
| 49 } else { | 46 } else { |
| 50 WaitableEvent completion(true /* manual reset */, | 47 WaitableEvent completion(true /* manual reset */, |
| 51 false /* initial state */); | 48 false /* initial state */); |
| 52 message_loop_->PostTask(FROM_HERE, | 49 message_loop_->PostTask(FROM_HERE, |
| 53 base::Bind(&AudioOutputController::DoStopCloseAndClearStream, | 50 base::Bind(&AudioOutputController::DoStopCloseAndClearStream, |
| 54 base::Unretained(this), | 51 base::Unretained(this), |
| 55 &completion)); | 52 &completion)); |
| 56 completion.Wait(); | 53 completion.Wait(); |
| 57 } | 54 } |
| 58 } | 55 } |
| 59 | 56 |
| 60 // static | 57 // static |
| 61 scoped_refptr<AudioOutputController> AudioOutputController::Create( | 58 scoped_refptr<AudioOutputController> AudioOutputController::Create( |
| 62 AudioManager* audio_manager, | 59 AudioManager* audio_manager, |
| 63 EventHandler* event_handler, | 60 EventHandler* event_handler, |
| 64 const AudioParameters& params, | 61 const AudioParameters& params, |
| 65 uint32 buffer_capacity) { | |
| 66 DCHECK(audio_manager); | |
| 67 if (!params.IsValid() || !audio_manager) | |
| 68 return NULL; | |
| 69 | |
| 70 // Starts the audio controller thread. | |
| 71 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | |
| 72 audio_manager, event_handler, buffer_capacity, NULL)); | |
| 73 | |
| 74 controller->message_loop_ = audio_manager->GetMessageLoop(); | |
| 75 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | |
| 76 &AudioOutputController::DoCreate, base::Unretained(controller.get()), | |
| 77 params)); | |
| 78 return controller; | |
| 79 } | |
| 80 | |
| 81 // static | |
| 82 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( | |
| 83 AudioManager* audio_manager, | |
| 84 EventHandler* event_handler, | |
| 85 const AudioParameters& params, | |
| 86 SyncReader* sync_reader) { | 62 SyncReader* sync_reader) { |
| 87 DCHECK(audio_manager); | 63 DCHECK(audio_manager); |
| 88 DCHECK(sync_reader); | 64 DCHECK(sync_reader); |
| 89 | 65 |
| 90 if (!params.IsValid() || !audio_manager) | 66 if (!params.IsValid() || !audio_manager) |
| 91 return NULL; | 67 return NULL; |
| 92 | 68 |
| 93 // Starts the audio controller thread. | 69 // Starts the audio controller thread. |
| 94 scoped_refptr<AudioOutputController> controller(new AudioOutputController( | 70 scoped_refptr<AudioOutputController> controller(new AudioOutputController( |
| 95 audio_manager, event_handler, 0, sync_reader)); | 71 audio_manager, event_handler, sync_reader)); |
| 96 | 72 |
| 97 controller->message_loop_ = audio_manager->GetMessageLoop(); | 73 controller->message_loop_ = audio_manager->GetMessageLoop(); |
| 98 controller->message_loop_->PostTask(FROM_HERE, base::Bind( | 74 controller->message_loop_->PostTask(FROM_HERE, base::Bind( |
| 99 &AudioOutputController::DoCreate, base::Unretained(controller.get()), | 75 &AudioOutputController::DoCreate, base::Unretained(controller.get()), |
| 100 params)); | 76 params)); |
| 101 return controller; | 77 return controller; |
| 102 } | 78 } |
| 103 | 79 |
| 104 void AudioOutputController::Play() { | 80 void AudioOutputController::Play() { |
| 105 DCHECK(message_loop_); | 81 DCHECK(message_loop_); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 125 message_loop_->PostTask(FROM_HERE, base::Bind( | 101 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 126 &AudioOutputController::DoClose, base::Unretained(this), closed_task)); | 102 &AudioOutputController::DoClose, base::Unretained(this), closed_task)); |
| 127 } | 103 } |
| 128 | 104 |
| 129 void AudioOutputController::SetVolume(double volume) { | 105 void AudioOutputController::SetVolume(double volume) { |
| 130 DCHECK(message_loop_); | 106 DCHECK(message_loop_); |
| 131 message_loop_->PostTask(FROM_HERE, base::Bind( | 107 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 132 &AudioOutputController::DoSetVolume, base::Unretained(this), volume)); | 108 &AudioOutputController::DoSetVolume, base::Unretained(this), volume)); |
| 133 } | 109 } |
| 134 | 110 |
| 135 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) { | |
| 136 // Write data to the push source and ask for more data if needed. | |
| 137 base::AutoLock auto_lock(lock_); | |
| 138 pending_request_ = false; | |
| 139 // If |size| is set to 0, it indicates that the audio source doesn't have | |
| 140 // more data right now, and so it doesn't make sense to send additional | |
| 141 // request. | |
| 142 if (size) { | |
| 143 buffer_.Append(data, size); | |
| 144 SubmitOnMoreData_Locked(); | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 void AudioOutputController::DoCreate(const AudioParameters& params) { | 111 void AudioOutputController::DoCreate(const AudioParameters& params) { |
| 149 DCHECK(message_loop_->BelongsToCurrentThread()); | 112 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 150 | 113 |
| 151 // Close() can be called before DoCreate() is executed. | 114 // Close() can be called before DoCreate() is executed. |
| 152 if (state_ == kClosed) | 115 if (state_ == kClosed) |
| 153 return; | 116 return; |
| 154 DCHECK_EQ(kEmpty, state_); | 117 DCHECK_EQ(kEmpty, state_); |
| 155 | 118 |
| 156 DoStopCloseAndClearStream(NULL); | 119 DoStopCloseAndClearStream(NULL); |
| 157 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params); | 120 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 170 } | 133 } |
| 171 | 134 |
| 172 // We have successfully opened the stream. Set the initial volume. | 135 // We have successfully opened the stream. Set the initial volume. |
| 173 stream_->SetVolume(volume_); | 136 stream_->SetVolume(volume_); |
| 174 | 137 |
| 175 // Finally set the state to kCreated. | 138 // Finally set the state to kCreated. |
| 176 state_ = kCreated; | 139 state_ = kCreated; |
| 177 | 140 |
| 178 // And then report we have been created. | 141 // And then report we have been created. |
| 179 handler_->OnCreated(this); | 142 handler_->OnCreated(this); |
| 180 | |
| 181 // If in normal latency mode then start buffering. | |
| 182 if (!LowLatencyMode()) { | |
| 183 base::AutoLock auto_lock(lock_); | |
| 184 SubmitOnMoreData_Locked(); | |
| 185 } | |
| 186 } | 143 } |
| 187 | 144 |
| 188 void AudioOutputController::DoPlay() { | 145 void AudioOutputController::DoPlay() { |
| 189 DCHECK(message_loop_->BelongsToCurrentThread()); | 146 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 190 | 147 |
| 191 // We can start from created or paused state. | 148 // We can start from created or paused state. |
| 192 if (state_ != kCreated && state_ != kPaused) | 149 if (state_ != kCreated && state_ != kPaused) |
| 193 return; | 150 return; |
| 194 | 151 |
| 195 if (LowLatencyMode()) { | 152 state_ = kStarting; |
| 196 state_ = kStarting; | |
| 197 | 153 |
| 198 // Ask for first packet. | 154 // Ask for first packet. |
| 199 sync_reader_->UpdatePendingBytes(0); | 155 sync_reader_->UpdatePendingBytes(0); |
| 200 | 156 |
| 201 // Cannot start stream immediately, should give renderer some time | 157 // Cannot start stream immediately, should give renderer some time |
| 202 // to deliver data. | 158 // to deliver data. |
| 203 number_polling_attempts_left_ = kPollNumAttempts; | 159 // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky. |
| 204 message_loop_->PostDelayedTask( | 160 // Refine the API such that polling is no longer needed. (crbug.com/112196) |
| 205 FROM_HERE, | 161 number_polling_attempts_left_ = kPollNumAttempts; |
| 206 base::Bind(&AudioOutputController::PollAndStartIfDataReady, | 162 message_loop_->PostDelayedTask( |
| 207 weak_this_.GetWeakPtr()), | 163 FROM_HERE, |
| 208 kPollPauseInMilliseconds); | 164 base::Bind(&AudioOutputController::PollAndStartIfDataReady, |
| 209 } else { | 165 weak_this_.GetWeakPtr()), |
| 210 StartStream(); | 166 kPollPauseInMilliseconds); |
| 211 } | |
| 212 } | 167 } |
| 213 | 168 |
| 214 void AudioOutputController::PollAndStartIfDataReady() { | 169 void AudioOutputController::PollAndStartIfDataReady() { |
| 215 DCHECK(message_loop_->BelongsToCurrentThread()); | 170 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 216 | 171 |
| 217 // Being paranoid: do nothing if state unexpectedly changed. | 172 // Being paranoid: do nothing if state unexpectedly changed. |
| 218 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) | 173 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) |
| 219 return; | 174 return; |
| 220 | 175 |
| 221 bool pausing = (state_ == kPausedWhenStarting); | 176 bool pausing = (state_ == kPausedWhenStarting); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 state_ = kPausedWhenStarting; | 218 state_ = kPausedWhenStarting; |
| 264 break; | 219 break; |
| 265 case kPlaying: | 220 case kPlaying: |
| 266 state_ = kPaused; | 221 state_ = kPaused; |
| 267 | 222 |
| 268 // Then we stop the audio device. This is not the perfect solution | 223 // Then we stop the audio device. This is not the perfect solution |
| 269 // because it discards all the internal buffer in the audio device. | 224 // because it discards all the internal buffer in the audio device. |
| 270 // TODO(hclam): Actually pause the audio device. | 225 // TODO(hclam): Actually pause the audio device. |
| 271 stream_->Stop(); | 226 stream_->Stop(); |
| 272 | 227 |
| 273 if (LowLatencyMode()) { | 228 // Send a special pause mark to the low-latency audio thread. |
| 274 // Send a special pause mark to the low-latency audio thread. | 229 sync_reader_->UpdatePendingBytes(kPauseMark); |
| 275 sync_reader_->UpdatePendingBytes(kPauseMark); | |
| 276 } | |
| 277 | 230 |
| 278 handler_->OnPaused(this); | 231 handler_->OnPaused(this); |
| 279 break; | 232 break; |
| 280 default: | 233 default: |
| 281 return; | 234 return; |
| 282 } | 235 } |
| 283 } | 236 } |
| 284 | 237 |
| 285 void AudioOutputController::DoFlush() { | 238 void AudioOutputController::DoFlush() { |
| 286 DCHECK(message_loop_->BelongsToCurrentThread()); | 239 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 287 | 240 |
| 288 // TODO(hclam): Actually flush the audio device. | 241 // TODO(hclam): Actually flush the audio device. |
| 289 | |
| 290 // If we are in the regular latency mode then flush the push source. | |
| 291 if (!sync_reader_) { | |
| 292 if (state_ != kPaused) | |
| 293 return; | |
| 294 base::AutoLock auto_lock(lock_); | |
| 295 buffer_.Clear(); | |
| 296 } | |
| 297 } | 242 } |
| 298 | 243 |
| 299 void AudioOutputController::DoClose(const base::Closure& closed_task) { | 244 void AudioOutputController::DoClose(const base::Closure& closed_task) { |
| 300 DCHECK(message_loop_->BelongsToCurrentThread()); | 245 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 301 | 246 |
| 302 if (state_ != kClosed) { | 247 if (state_ != kClosed) { |
| 303 DoStopCloseAndClearStream(NULL); | 248 DoStopCloseAndClearStream(NULL); |
| 304 | 249 sync_reader_->Close(); |
| 305 if (LowLatencyMode()) { | |
| 306 sync_reader_->Close(); | |
| 307 } | |
| 308 | |
| 309 state_ = kClosed; | 250 state_ = kClosed; |
| 310 } | 251 } |
| 311 | 252 |
| 312 closed_task.Run(); | 253 closed_task.Run(); |
| 313 } | 254 } |
| 314 | 255 |
| 315 void AudioOutputController::DoSetVolume(double volume) { | 256 void AudioOutputController::DoSetVolume(double volume) { |
| 316 DCHECK(message_loop_->BelongsToCurrentThread()); | 257 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 317 | 258 |
| 318 // Saves the volume to a member first. We may not be able to set the volume | 259 // Saves the volume to a member first. We may not be able to set the volume |
| (...skipping 17 matching lines...) Expand all Loading... |
| 336 DCHECK(message_loop_->BelongsToCurrentThread()); | 277 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 337 if (state_ != kClosed) | 278 if (state_ != kClosed) |
| 338 handler_->OnError(this, code); | 279 handler_->OnError(this, code); |
| 339 } | 280 } |
| 340 | 281 |
| 341 uint32 AudioOutputController::OnMoreData( | 282 uint32 AudioOutputController::OnMoreData( |
| 342 AudioOutputStream* stream, uint8* dest, | 283 AudioOutputStream* stream, uint8* dest, |
| 343 uint32 max_size, AudioBuffersState buffers_state) { | 284 uint32 max_size, AudioBuffersState buffers_state) { |
| 344 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); | 285 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); |
| 345 | 286 |
| 346 // If regular latency mode is used. | |
| 347 if (!sync_reader_) { | |
| 348 base::AutoLock auto_lock(lock_); | |
| 349 | |
| 350 // Save current buffers state. | |
| 351 buffers_state_ = buffers_state; | |
| 352 | |
| 353 if (state_ != kPlaying) { | |
| 354 // Don't read anything. Save the number of bytes in the hardware buffer. | |
| 355 return 0; | |
| 356 } | |
| 357 | |
| 358 uint32 size = buffer_.Read(dest, max_size); | |
| 359 buffers_state_.pending_bytes += size; | |
| 360 SubmitOnMoreData_Locked(); | |
| 361 return size; | |
| 362 } | |
| 363 | |
| 364 // Low latency mode. | |
| 365 { | 287 { |
| 366 // Check state and do nothing if we are not playing. | 288 // Check state and do nothing if we are not playing. |
| 367 // We are on the hardware audio thread, so lock is needed. | 289 // We are on the hardware audio thread, so lock is needed. |
| 368 base::AutoLock auto_lock(lock_); | 290 base::AutoLock auto_lock(lock_); |
| 369 if (state_ != kPlaying) { | 291 if (state_ != kPlaying) { |
| 370 return 0; | 292 return 0; |
| 371 } | 293 } |
| 372 } | 294 } |
| 373 uint32 size = sync_reader_->Read(dest, max_size); | 295 uint32 size = sync_reader_->Read(dest, max_size); |
| 374 sync_reader_->UpdatePendingBytes(buffers_state.total_bytes() + size); | 296 sync_reader_->UpdatePendingBytes(buffers_state.total_bytes() + size); |
| 375 return size; | 297 return size; |
| 376 } | 298 } |
| 377 | 299 |
| 378 void AudioOutputController::WaitTillDataReady() { | 300 void AudioOutputController::WaitTillDataReady() { |
| 379 if (LowLatencyMode() && !sync_reader_->DataReady()) { | 301 if (!sync_reader_->DataReady()) { |
| 380 // In the different place we use different mechanism to poll, get max | 302 // In the different place we use different mechanism to poll, get max |
| 381 // polling delay from constants used there. | 303 // polling delay from constants used there. |
| 382 const base::TimeDelta kMaxPollingDelay = base::TimeDelta::FromMilliseconds( | 304 const base::TimeDelta kMaxPollingDelay = base::TimeDelta::FromMilliseconds( |
| 383 kPollNumAttempts * kPollPauseInMilliseconds); | 305 kPollNumAttempts * kPollPauseInMilliseconds); |
| 384 Time start_time = Time::Now(); | 306 Time start_time = Time::Now(); |
| 385 do { | 307 do { |
| 386 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); | 308 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); |
| 387 } while (!sync_reader_->DataReady() && | 309 } while (!sync_reader_->DataReady() && |
| 388 Time::Now() - start_time < kMaxPollingDelay); | 310 Time::Now() - start_time < kMaxPollingDelay); |
| 389 } | 311 } |
| 390 } | 312 } |
| 391 | 313 |
| 392 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { | 314 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { |
| 393 // Handle error on the audio controller thread. | 315 // Handle error on the audio controller thread. |
| 394 message_loop_->PostTask(FROM_HERE, base::Bind( | 316 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 395 &AudioOutputController::DoReportError, base::Unretained(this), code)); | 317 &AudioOutputController::DoReportError, base::Unretained(this), code)); |
| 396 } | 318 } |
| 397 | 319 |
| 398 void AudioOutputController::SubmitOnMoreData_Locked() { | |
| 399 lock_.AssertAcquired(); | |
| 400 | |
| 401 if (buffer_.forward_bytes() > buffer_.forward_capacity()) | |
| 402 return; | |
| 403 | |
| 404 if (pending_request_) | |
| 405 return; | |
| 406 pending_request_ = true; | |
| 407 | |
| 408 AudioBuffersState buffers_state = buffers_state_; | |
| 409 buffers_state.pending_bytes += buffer_.forward_bytes(); | |
| 410 | |
| 411 // If we need more data then call the event handler to ask for more data. | |
| 412 // It is okay that we don't lock in this block because the parameters are | |
| 413 // correct and in the worst case we are just asking more data than needed. | |
| 414 base::AutoUnlock auto_unlock(lock_); | |
| 415 handler_->OnMoreData(this, buffers_state); | |
| 416 } | |
| 417 | |
| 418 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) { | 320 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) { |
| 419 DCHECK(message_loop_->BelongsToCurrentThread()); | 321 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 420 | 322 |
| 421 // Allow calling unconditionally and bail if we don't have a stream_ to close. | 323 // Allow calling unconditionally and bail if we don't have a stream_ to close. |
| 422 if (stream_ != NULL) { | 324 if (stream_ != NULL) { |
| 423 stream_->Stop(); | 325 stream_->Stop(); |
| 424 stream_->Close(); | 326 stream_->Close(); |
| 425 stream_ = NULL; | 327 stream_ = NULL; |
| 426 weak_this_.InvalidateWeakPtrs(); | 328 weak_this_.InvalidateWeakPtrs(); |
| 427 } | 329 } |
| 428 | 330 |
| 429 // Should be last in the method, do not touch "this" from here on. | 331 // Should be last in the method, do not touch "this" from here on. |
| 430 if (done != NULL) | 332 if (done != NULL) |
| 431 done->Signal(); | 333 done->Signal(); |
| 432 } | 334 } |
| 433 | 335 |
| 434 } // namespace media | 336 } // namespace media |
| OLD | NEW |