OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 // THREAD SAFETY | 5 // THREAD SAFETY |
6 // | 6 // |
7 // The AlsaPcmOutputStream object's internal state is accessed by two threads: | 7 // The AlsaPcmOutputStream object's internal state is accessed by two threads: |
8 // | 8 // |
9 // client thread - creates the object and calls the public APIs. | 9 // client thread - creates the object and calls the public APIs. |
10 // message loop thread - executes all the internal tasks including querying | 10 // message loop thread - executes all the internal tasks including querying |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 // If stopped, simulate a 0-lengthed packet. | 467 // If stopped, simulate a 0-lengthed packet. |
468 if (stop_stream_) { | 468 if (stop_stream_) { |
469 packet->used = packet->size = 0; | 469 packet->used = packet->size = 0; |
470 return; | 470 return; |
471 } | 471 } |
472 | 472 |
473 // Request more data if we don't have any cached. | 473 // Request more data if we don't have any cached. |
474 if (packet->used >= packet->size) { | 474 if (packet->used >= packet->size) { |
475 // Before making a request to source for data. We need to determine the | 475 // Before making a request to source for data. We need to determine the |
476 // delay (in bytes) for the requested data to be played. | 476 // delay (in bytes) for the requested data to be played. |
477 snd_pcm_sframes_t delay; | 477 snd_pcm_sframes_t delay = 0; |
478 int error = wrapper_->PcmDelay(playback_handle_, &delay); | 478 |
479 if (error < 0) { | 479 // Don't query ALSA's delay if we have underrun since it'll be jammed at |
480 error = wrapper_->PcmRecover(playback_handle_, | 480 // some non-zero value and potentially even negative! |
481 error, | 481 if (wrapper_->PcmState(playback_handle_) != SND_PCM_STATE_XRUN) { |
482 kPcmRecoverIsSilent); | 482 int error = wrapper_->PcmDelay(playback_handle_, &delay); |
483 if (error < 0) { | 483 if (error >= 0) { |
484 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error); | 484 // Convert frames to bytes, but watch out for those negatives! |
| 485 delay = (delay < 0 ? 0 : delay) * bytes_per_output_frame_; |
| 486 } else { |
| 487 // Assume a delay of zero and attempt to recover the device. |
| 488 delay = 0; |
| 489 error = wrapper_->PcmRecover(playback_handle_, |
| 490 error, |
| 491 kPcmRecoverIsSilent); |
| 492 if (error < 0) { |
| 493 LOG(ERROR) << "Failed querying delay: " << wrapper_->StrError(error); |
| 494 } |
485 } | 495 } |
486 | |
487 // TODO(hclam): If we cannot query the delay, we may want to stop | |
488 // the playback and report an error. | |
489 delay = 0; | |
490 } else { | |
491 delay *= bytes_per_output_frame_; | |
492 } | 496 } |
493 | 497 |
494 packet->used = 0; | 498 packet->used = 0; |
495 packet->size = shared_data_.OnMoreData(this, packet->buffer.get(), | 499 packet->size = shared_data_.OnMoreData(this, packet->buffer.get(), |
496 packet->capacity, delay); | 500 packet->capacity, delay); |
497 CHECK(packet->size <= packet->capacity) << "Data source overran buffer."; | 501 CHECK(packet->size <= packet->capacity) << "Data source overran buffer."; |
498 | 502 |
499 // This should not happen, but incase it does, drop any trailing bytes | 503 // This should not happen, but incase it does, drop any trailing bytes |
500 // that aren't large enough to make a frame. Without this, packet writing | 504 // that aren't large enough to make a frame. Without this, packet writing |
501 // may stall because the last few bytes in the packet may never get used by | 505 // may stall because the last few bytes in the packet may never get used by |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
958 } | 962 } |
959 | 963 |
960 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 964 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
961 // release ownership of the currently registered callback. | 965 // release ownership of the currently registered callback. |
962 void AlsaPcmOutputStream::SharedData::set_source_callback( | 966 void AlsaPcmOutputStream::SharedData::set_source_callback( |
963 AudioSourceCallback* callback) { | 967 AudioSourceCallback* callback) { |
964 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); | 968 DCHECK_EQ(MessageLoop::current(), state_transition_loop_); |
965 AutoLock l(lock_); | 969 AutoLock l(lock_); |
966 source_callback_ = callback; | 970 source_callback_ = callback; |
967 } | 971 } |
OLD | NEW |