Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Side by Side Diff: media/audio/alsa/alsa_output.cc

Issue 2060833002: Implementation of 'AudioContext.getOutputTimestamp' method (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added implementation for ALSA. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698