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

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

Issue 8465018: Reland 7976047 to fix the alsa output scheduling for low latency audio. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: update Created 9 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 -- we assume that 7 // AlsaPcmOutputStream object is *not* thread-safe -- we assume that
8 // client thread - creates the object and calls the public APIs. 8 // client thread - creates the object and calls the public APIs.
9 // message loop thread - executes all the internal tasks including querying 9 // message loop thread - executes all the internal tasks including querying
10 // the data source for more data, writing to the alsa device, and closing 10 // the data source for more data, writing to the alsa device, and closing
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 #include "media/audio/linux/alsa_util.h" 51 #include "media/audio/linux/alsa_util.h"
52 #include "media/audio/linux/alsa_wrapper.h" 52 #include "media/audio/linux/alsa_wrapper.h"
53 #include "media/audio/linux/audio_manager_linux.h" 53 #include "media/audio/linux/audio_manager_linux.h"
54 #include "media/base/data_buffer.h" 54 #include "media/base/data_buffer.h"
55 #include "media/base/seekable_buffer.h" 55 #include "media/base/seekable_buffer.h"
56 56
57 // Amount of time to wait if we've exhausted the data source. This is to avoid 57 // Amount of time to wait if we've exhausted the data source. This is to avoid
58 // busy looping. 58 // busy looping.
59 static const uint32 kNoDataSleepMilliseconds = 10; 59 static const uint32 kNoDataSleepMilliseconds = 10;
60 60
61 // Mininum interval between OnMoreData() calls.
62 const uint32 kMinIntervalBetweenOnMoreDataCallsInMs = 5;
63
61 // According to the linux nanosleep manpage, nanosleep on linux can miss the 64 // According to the linux nanosleep manpage, nanosleep on linux can miss the
62 // deadline by up to 10ms because the kernel timeslice is 10ms. Give a 2x 65 // deadline by up to 10ms because the kernel timeslice is 10ms. Give a 2x
63 // buffer to compensate for the timeslice, and any additional slowdowns. 66 // buffer to compensate for the timeslice, and any additional slowdowns.
64 static const uint32 kSleepErrorMilliseconds = 20; 67 static const uint32 kSleepErrorMilliseconds = 20;
65 68
66 // Set to 0 during debugging if you want error messages due to underrun 69 // Set to 0 during debugging if you want error messages due to underrun
67 // events or other recoverable errors. 70 // events or other recoverable errors.
68 #if defined(NDEBUG) 71 #if defined(NDEBUG)
69 static const int kPcmRecoverIsSilent = 1; 72 static const int kPcmRecoverIsSilent = 1;
70 #else 73 #else
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 buffer_.reset(new media::SeekableBuffer(0, output_packet_size)); 343 buffer_.reset(new media::SeekableBuffer(0, output_packet_size));
341 344
342 // Get alsa buffer size. 345 // Get alsa buffer size.
343 snd_pcm_uframes_t buffer_size; 346 snd_pcm_uframes_t buffer_size;
344 snd_pcm_uframes_t period_size; 347 snd_pcm_uframes_t period_size;
345 int error = wrapper_->PcmGetParams(playback_handle_, &buffer_size, 348 int error = wrapper_->PcmGetParams(playback_handle_, &buffer_size,
346 &period_size); 349 &period_size);
347 if (error < 0) { 350 if (error < 0) {
348 LOG(ERROR) << "Failed to get playback buffer size from ALSA: " 351 LOG(ERROR) << "Failed to get playback buffer size from ALSA: "
349 << wrapper_->StrError(error); 352 << wrapper_->StrError(error);
350 alsa_buffer_frames_ = frames_per_packet_; 353 // Buffer size is at least twice of packet size.
354 alsa_buffer_frames_ = frames_per_packet_ * 2;
351 } else { 355 } else {
352 alsa_buffer_frames_ = buffer_size; 356 alsa_buffer_frames_ = buffer_size;
353 } 357 }
354 } 358 }
355 } 359 }
356 360
357 void AlsaPcmOutputStream::StartTask() { 361 void AlsaPcmOutputStream::StartTask() {
358 DCHECK_EQ(message_loop_, MessageLoop::current()); 362 DCHECK_EQ(message_loop_, MessageLoop::current());
359 363
360 if (stop_stream_) { 364 if (stop_stream_) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 424
421 // If stopped, simulate a 0-lengthed packet. 425 // If stopped, simulate a 0-lengthed packet.
422 if (stop_stream_) { 426 if (stop_stream_) {
423 buffer_->Clear(); 427 buffer_->Clear();
424 *source_exhausted = true; 428 *source_exhausted = true;
425 return; 429 return;
426 } 430 }
427 431
428 *source_exhausted = false; 432 *source_exhausted = false;
429 433
430 // Request more data if we have capacity. 434 // Request more data only when we run out of data in the buffer, because
431 if (buffer_->forward_capacity() > buffer_->forward_bytes()) { 435 // WritePacket() comsumes only the current chunk of data.
436 if (!buffer_->forward_bytes()) {
432 // Before making a request to source for data we need to determine the 437 // Before making a request to source for data we need to determine the
433 // delay (in bytes) for the requested data to be played. 438 // delay (in bytes) for the requested data to be played.
434 439
435 uint32 buffer_delay = buffer_->forward_bytes() * bytes_per_frame_ / 440 uint32 buffer_delay = buffer_->forward_bytes() * bytes_per_frame_ /
436 bytes_per_output_frame_; 441 bytes_per_output_frame_;
437 442
438 uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_; 443 uint32 hardware_delay = GetCurrentDelay() * bytes_per_frame_;
439 444
440 scoped_refptr<media::DataBuffer> packet = 445 scoped_refptr<media::DataBuffer> packet =
441 new media::DataBuffer(packet_size_); 446 new media::DataBuffer(packet_size_);
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 ScheduleNextWrite(source_exhausted); 595 ScheduleNextWrite(source_exhausted);
591 } 596 }
592 597
593 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) { 598 void AlsaPcmOutputStream::ScheduleNextWrite(bool source_exhausted) {
594 DCHECK_EQ(message_loop_, MessageLoop::current()); 599 DCHECK_EQ(message_loop_, MessageLoop::current());
595 600
596 if (stop_stream_) { 601 if (stop_stream_) {
597 return; 602 return;
598 } 603 }
599 604
600 // Next write is scheduled for the moment when half of the buffer is
601 // available.
602 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2; 605 uint32 frames_avail_wanted = alsa_buffer_frames_ / 2;
603 uint32 available_frames = GetAvailableFrames(); 606 uint32 available_frames = GetAvailableFrames();
604 uint32 next_fill_time_ms = 0; 607 uint32 frames_in_buffer = buffer_->forward_bytes() / bytes_per_output_frame_;
605 608
606 // It's possible to have more frames available than what we want, in which 609 // Next write is initially scheduled for the moment when half of a packet
607 // case we'll leave our |next_fill_time_ms| at 0ms. 610 // has been played out.
608 if (available_frames < frames_avail_wanted) { 611 uint32 next_fill_time_ms =
609 uint32 frames_until_empty_enough = frames_avail_wanted - available_frames; 612 FramesToMillis(frames_per_packet_ / 2, sample_rate_);
610 next_fill_time_ms =
611 FramesToMillis(frames_until_empty_enough, sample_rate_);
612 }
613 613
614 // Adjust for timer resolution issues. 614 if (frames_in_buffer && (frames_in_buffer <= available_frames)) {
615 if (next_fill_time_ms < kSleepErrorMilliseconds) { 615 // There is data in the current buffer, consume them immediately if we have
616 // enough space in the soundcard.
616 next_fill_time_ms = 0; 617 next_fill_time_ms = 0;
617 } else { 618 } else {
618 next_fill_time_ms -= kSleepErrorMilliseconds; 619 // Otherwise schedule the next write for the moment when half of the alsa
620 // buffer becomes available.
621 if (available_frames < frames_avail_wanted) {
622 uint32 frames_until_empty_enough = frames_avail_wanted - available_frames;
623 next_fill_time_ms =
624 FramesToMillis(frames_until_empty_enough, sample_rate_);
625
626 // Adjust for time resolution.
627 if (next_fill_time_ms > kNoDataSleepMilliseconds)
628 next_fill_time_ms -= kNoDataSleepMilliseconds;
629
630 // Avoid back-to-back writing.
631 if (next_fill_time_ms < kMinIntervalBetweenOnMoreDataCallsInMs)
632 next_fill_time_ms = kMinIntervalBetweenOnMoreDataCallsInMs;
633 } else if (available_frames == alsa_buffer_frames_) {
634 // Buffer is empty, invoke next write immediately.
635 next_fill_time_ms = 0;
636 }
619 } 637 }
620 638
621 // Avoid busy looping if the data source is exhausted. 639 // Avoid busy looping if the data source is exhausted.
622 if (source_exhausted) { 640 if (source_exhausted) {
623 next_fill_time_ms = std::max(next_fill_time_ms, kNoDataSleepMilliseconds); 641 next_fill_time_ms = std::max(next_fill_time_ms, kNoDataSleepMilliseconds);
624 } 642 }
625 643
626 // Only schedule more reads/writes if we are still in the playing state. 644 // Only schedule more reads/writes if we are still in the playing state.
627 if (state() == kIsPlaying) { 645 if (state() == kIsPlaying) {
628 if (next_fill_time_ms == 0) { 646 if (next_fill_time_ms == 0) {
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
870 source_callback_->OnError(this, code); 888 source_callback_->OnError(this, code);
871 } 889 }
872 } 890 }
873 891
874 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to 892 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
875 // release ownership of the currently registered callback. 893 // release ownership of the currently registered callback.
876 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { 894 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
877 DCHECK_EQ(MessageLoop::current(), message_loop_); 895 DCHECK_EQ(MessageLoop::current(), message_loop_);
878 source_callback_ = callback; 896 source_callback_ = callback;
879 } 897 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698