| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 // AlsaPcmOutputStream object is *not* thread-safe and should only be used | 7 // AlsaPcmOutputStream object is *not* thread-safe and should only be used |
| 8 // from the audio thread. We DCHECK on this assumption whenever we can. | 8 // from the audio thread. We DCHECK on this assumption whenever we can. |
| 9 // | 9 // |
| 10 // SEMANTICS OF Close() | 10 // SEMANTICS OF Close() |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 bytes_per_output_frame_(bytes_per_frame_), | 154 bytes_per_output_frame_(bytes_per_frame_), |
| 155 alsa_buffer_frames_(0), | 155 alsa_buffer_frames_(0), |
| 156 stop_stream_(false), | 156 stop_stream_(false), |
| 157 wrapper_(wrapper), | 157 wrapper_(wrapper), |
| 158 manager_(manager), | 158 manager_(manager), |
| 159 message_loop_(base::MessageLoop::current()), | 159 message_loop_(base::MessageLoop::current()), |
| 160 playback_handle_(NULL), | 160 playback_handle_(NULL), |
| 161 frames_per_packet_(packet_size_ / bytes_per_frame_), | 161 frames_per_packet_(packet_size_ / bytes_per_frame_), |
| 162 state_(kCreated), | 162 state_(kCreated), |
| 163 volume_(1.0f), | 163 volume_(1.0f), |
| 164 elapsed_written_frames_(0), |
| 164 source_callback_(NULL), | 165 source_callback_(NULL), |
| 165 audio_bus_(AudioBus::Create(params)), | 166 audio_bus_(AudioBus::Create(params)), |
| 166 weak_factory_(this) { | 167 weak_factory_(this) { |
| 167 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); | 168 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| 168 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); | 169 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); |
| 169 | 170 |
| 170 // Sanity check input values. | 171 // Sanity check input values. |
| 171 if (!params.IsValid()) { | 172 if (!params.IsValid()) { |
| 172 LOG(WARNING) << "Unsupported audio parameters."; | 173 LOG(WARNING) << "Unsupported audio parameters."; |
| 173 TransitionTo(kInError); | 174 TransitionTo(kInError); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 return; | 283 return; |
| 283 | 284 |
| 284 // Only post the task if we can enter the playing state. | 285 // Only post the task if we can enter the playing state. |
| 285 if (TransitionTo(kIsPlaying) != kIsPlaying) | 286 if (TransitionTo(kIsPlaying) != kIsPlaying) |
| 286 return; | 287 return; |
| 287 | 288 |
| 288 // Before starting, the buffer might have audio from previous user of this | 289 // Before starting, the buffer might have audio from previous user of this |
| 289 // device. | 290 // device. |
| 290 buffer_->Clear(); | 291 buffer_->Clear(); |
| 291 | 292 |
| 293 // Invalidate written frames count. |
| 294 elapsed_written_frames_ = 0; |
| 295 |
| 292 // When starting again, drop all packets in the device and prepare it again | 296 // When starting again, drop all packets in the device and prepare it again |
| 293 // in case we are restarting from a pause state and need to flush old data. | 297 // in case we are restarting from a pause state and need to flush old data. |
| 294 int error = wrapper_->PcmDrop(playback_handle_); | 298 int error = wrapper_->PcmDrop(playback_handle_); |
| 295 if (error < 0 && error != -EAGAIN) { | 299 if (error < 0 && error != -EAGAIN) { |
| 296 LOG(ERROR) << "Failure clearing playback device (" | 300 LOG(ERROR) << "Failure clearing playback device (" |
| 297 << wrapper_->PcmName(playback_handle_) << "): " | 301 << wrapper_->PcmName(playback_handle_) << "): " |
| 298 << wrapper_->StrError(error); | 302 << wrapper_->StrError(error); |
| 299 stop_stream_ = true; | 303 stop_stream_ = true; |
| 300 return; | 304 return; |
| 301 } | 305 } |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 RunErrorCallback(frames_written); | 463 RunErrorCallback(frames_written); |
| 460 stop_stream_ = true; | 464 stop_stream_ = true; |
| 461 } | 465 } |
| 462 } | 466 } |
| 463 } else { | 467 } else { |
| 464 DCHECK_EQ(frames_written, frames); | 468 DCHECK_EQ(frames_written, frames); |
| 465 | 469 |
| 466 // Seek forward in the buffer after we've written some data to ALSA. | 470 // Seek forward in the buffer after we've written some data to ALSA. |
| 467 buffer_->Seek(frames_written * bytes_per_output_frame_); | 471 buffer_->Seek(frames_written * bytes_per_output_frame_); |
| 468 } | 472 } |
| 473 if (frames_written) |
| 474 elapsed_written_frames_ += frames_written; |
| 469 } else { | 475 } else { |
| 470 // If nothing left to write and playback hasn't started yet, start it now. | 476 // If nothing left to write and playback hasn't started yet, start it now. |
| 471 // This ensures that shorter sounds will still play. | 477 // This ensures that shorter sounds will still play. |
| 472 if (playback_handle_ && | 478 if (playback_handle_ && |
| 473 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) && | 479 (wrapper_->PcmState(playback_handle_) == SND_PCM_STATE_PREPARED) && |
| 474 GetCurrentDelay() > 0) { | 480 GetCurrentDelay() > 0) { |
| 475 wrapper_->PcmStart(playback_handle_); | 481 wrapper_->PcmStart(playback_handle_); |
| 476 } | 482 } |
| 477 } | 483 } |
| 478 } | 484 } |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 } | 782 } |
| 777 | 783 |
| 778 bool AlsaPcmOutputStream::IsOnAudioThread() const { | 784 bool AlsaPcmOutputStream::IsOnAudioThread() const { |
| 779 return message_loop_ && message_loop_ == base::MessageLoop::current(); | 785 return message_loop_ && message_loop_ == base::MessageLoop::current(); |
| 780 } | 786 } |
| 781 | 787 |
| 782 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, | 788 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, |
| 783 uint32_t total_bytes_delay) { | 789 uint32_t total_bytes_delay) { |
| 784 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); | 790 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); |
| 785 | 791 |
| 792 AudioTimestamp output_timestamp; |
| 793 // This is quite a raugh estimation, we need to consider using |
| 794 // snd_pcm_status_get_audio* API when it is accessible. |
| 795 output_timestamp.frames = elapsed_written_frames_ - GetCurrentDelay(); |
| 796 output_timestamp.ticks = base::TimeTicks::Now().ToInternalValue(); |
| 797 DCHECK(output_timestamp.frames >= 0); |
| 798 |
| 786 if (source_callback_) | 799 if (source_callback_) |
| 787 return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0); | 800 return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0, |
| 801 output_timestamp); |
| 788 | 802 |
| 789 return 0; | 803 return 0; |
| 790 } | 804 } |
| 791 | 805 |
| 792 void AlsaPcmOutputStream::RunErrorCallback(int code) { | 806 void AlsaPcmOutputStream::RunErrorCallback(int code) { |
| 793 if (source_callback_) | 807 if (source_callback_) |
| 794 source_callback_->OnError(this); | 808 source_callback_->OnError(this); |
| 795 } | 809 } |
| 796 | 810 |
| 797 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to | 811 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to |
| 798 // release ownership of the currently registered callback. | 812 // release ownership of the currently registered callback. |
| 799 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { | 813 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { |
| 800 DCHECK(IsOnAudioThread()); | 814 DCHECK(IsOnAudioThread()); |
| 801 source_callback_ = callback; | 815 source_callback_ = callback; |
| 802 } | 816 } |
| 803 | 817 |
| 804 } // namespace media | 818 } // namespace media |
| OLD | NEW |