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 |