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

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

Issue 2101303004: Pass delay and timestamp to AudioSourceCallback::OnMoreData. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Fix Mac CQ errors. Created 4 years, 2 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 19 matching lines...) Expand all
30 // When |stop_stream_| is set, no more commands will be made against the 30 // When |stop_stream_| is set, no more commands will be made against the
31 // ALSA device, and playback will effectively stop. From the client's point of 31 // ALSA device, and playback will effectively stop. From the client's point of
32 // view, it will seem that the device has just clogged and stopped requesting 32 // view, it will seem that the device has just clogged and stopped requesting
33 // data. 33 // data.
34 34
35 #include "media/audio/alsa/alsa_output.h" 35 #include "media/audio/alsa/alsa_output.h"
36 36
37 #include <stddef.h> 37 #include <stddef.h>
38 38
39 #include <algorithm> 39 #include <algorithm>
40 #include <utility>
40 41
41 #include "base/bind.h" 42 #include "base/bind.h"
42 #include "base/logging.h" 43 #include "base/logging.h"
43 #include "base/memory/free_deleter.h" 44 #include "base/memory/free_deleter.h"
44 #include "base/stl_util.h" 45 #include "base/stl_util.h"
45 #include "base/threading/thread_task_runner_handle.h" 46 #include "base/threading/thread_task_runner_handle.h"
47 #include "base/time/default_tick_clock.h"
46 #include "base/trace_event/trace_event.h" 48 #include "base/trace_event/trace_event.h"
47 #include "media/audio/alsa/alsa_util.h" 49 #include "media/audio/alsa/alsa_util.h"
48 #include "media/audio/alsa/alsa_wrapper.h" 50 #include "media/audio/alsa/alsa_wrapper.h"
49 #include "media/audio/alsa/audio_manager_alsa.h" 51 #include "media/audio/alsa/audio_manager_alsa.h"
52 #include "media/base/audio_timestamp_helper.h"
50 #include "media/base/channel_mixer.h" 53 #include "media/base/channel_mixer.h"
51 #include "media/base/data_buffer.h" 54 #include "media/base/data_buffer.h"
52 #include "media/base/seekable_buffer.h" 55 #include "media/base/seekable_buffer.h"
53 56
54 namespace media { 57 namespace media {
55 58
56 // Set to 0 during debugging if you want error messages due to underrun 59 // Set to 0 during debugging if you want error messages due to underrun
57 // events or other recoverable errors. 60 // events or other recoverable errors.
58 #if defined(NDEBUG) 61 #if defined(NDEBUG)
59 static const int kPcmRecoverIsSilent = 1; 62 static const int kPcmRecoverIsSilent = 1;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 break; 121 break;
119 case AlsaPcmOutputStream::kIsPlaying: 122 case AlsaPcmOutputStream::kIsPlaying:
120 os << "kIsPlaying"; 123 os << "kIsPlaying";
121 break; 124 break;
122 case AlsaPcmOutputStream::kIsStopped: 125 case AlsaPcmOutputStream::kIsStopped:
123 os << "kIsStopped"; 126 os << "kIsStopped";
124 break; 127 break;
125 case AlsaPcmOutputStream::kIsClosed: 128 case AlsaPcmOutputStream::kIsClosed:
126 os << "kIsClosed"; 129 os << "kIsClosed";
127 break; 130 break;
128 }; 131 }
129 return os; 132 return os;
130 } 133 }
131 134
132 const char AlsaPcmOutputStream::kDefaultDevice[] = "default"; 135 const char AlsaPcmOutputStream::kDefaultDevice[] = "default";
133 const char AlsaPcmOutputStream::kAutoSelectDevice[] = ""; 136 const char AlsaPcmOutputStream::kAutoSelectDevice[] = "";
134 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:"; 137 const char AlsaPcmOutputStream::kPlugPrefix[] = "plug:";
135 138
136 // We use 40ms as our minimum required latency. If it is needed, we may be able 139 // We use 40ms as our minimum required latency. If it is needed, we may be able
137 // to get it down to 20ms. 140 // to get it down to 20ms.
138 const uint32_t AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000; 141 const uint32_t AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000;
139 142
140 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, 143 AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name,
141 const AudioParameters& params, 144 const AudioParameters& params,
142 AlsaWrapper* wrapper, 145 AlsaWrapper* wrapper,
143 AudioManagerBase* manager) 146 AudioManagerBase* manager)
144 : requested_device_name_(device_name), 147 : requested_device_name_(device_name),
145 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())), 148 pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())),
146 channels_(params.channels()), 149 channels_(params.channels()),
147 channel_layout_(params.channel_layout()), 150 channel_layout_(params.channel_layout()),
148 sample_rate_(params.sample_rate()), 151 sample_rate_(params.sample_rate()),
149 bytes_per_sample_(params.bits_per_sample() / 8), 152 bytes_per_sample_(params.bits_per_sample() / 8),
150 bytes_per_frame_(params.GetBytesPerFrame()), 153 bytes_per_frame_(params.GetBytesPerFrame()),
151 packet_size_(params.GetBytesPerBuffer()), 154 packet_size_(params.GetBytesPerBuffer()),
152 latency_(std::max( 155 latency_(std::max(
153 base::TimeDelta::FromMicroseconds(kMinLatencyMicros), 156 base::TimeDelta::FromMicroseconds(kMinLatencyMicros),
154 FramesToTimeDelta(params.frames_per_buffer() * 2, sample_rate_))), 157 AudioTimestampHelper::FramesToTime(params.frames_per_buffer() * 2,
158 sample_rate_))),
155 bytes_per_output_frame_(bytes_per_frame_), 159 bytes_per_output_frame_(bytes_per_frame_),
156 alsa_buffer_frames_(0), 160 alsa_buffer_frames_(0),
157 stop_stream_(false), 161 stop_stream_(false),
158 wrapper_(wrapper), 162 wrapper_(wrapper),
159 manager_(manager), 163 manager_(manager),
160 task_runner_(base::ThreadTaskRunnerHandle::Get()), 164 task_runner_(base::ThreadTaskRunnerHandle::Get()),
161 playback_handle_(NULL), 165 playback_handle_(NULL),
162 frames_per_packet_(packet_size_ / bytes_per_frame_), 166 frames_per_packet_(packet_size_ / bytes_per_frame_),
163 state_(kCreated), 167 state_(kCreated),
164 volume_(1.0f), 168 volume_(1.0f),
165 source_callback_(NULL), 169 source_callback_(NULL),
166 audio_bus_(AudioBus::Create(params)), 170 audio_bus_(AudioBus::Create(params)),
171 tick_clock_(new base::DefaultTickClock()),
167 weak_factory_(this) { 172 weak_factory_(this) {
168 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); 173 DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
169 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_); 174 DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_);
170 175
171 // Sanity check input values. 176 // Sanity check input values.
172 if (!params.IsValid()) { 177 if (!params.IsValid()) {
173 LOG(WARNING) << "Unsupported audio parameters."; 178 LOG(WARNING) << "Unsupported audio parameters.";
174 TransitionTo(kInError); 179 TransitionTo(kInError);
175 } 180 }
176 181
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 343
339 volume_ = static_cast<float>(volume); 344 volume_ = static_cast<float>(volume);
340 } 345 }
341 346
342 void AlsaPcmOutputStream::GetVolume(double* volume) { 347 void AlsaPcmOutputStream::GetVolume(double* volume) {
343 DCHECK(CalledOnValidThread()); 348 DCHECK(CalledOnValidThread());
344 349
345 *volume = volume_; 350 *volume = volume_;
346 } 351 }
347 352
353 void AlsaPcmOutputStream::SetTickClockForTesting(
354 std::unique_ptr<base::TickClock> tick_clock) {
355 DCHECK(tick_clock);
356 tick_clock_ = std::move(tick_clock);
357 }
358
348 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) { 359 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
349 DCHECK(CalledOnValidThread()); 360 DCHECK(CalledOnValidThread());
350 361
351 // If stopped, simulate a 0-length packet. 362 // If stopped, simulate a 0-length packet.
352 if (stop_stream_) { 363 if (stop_stream_) {
353 buffer_->Clear(); 364 buffer_->Clear();
354 *source_exhausted = true; 365 *source_exhausted = true;
355 return; 366 return;
356 } 367 }
357 368
358 *source_exhausted = false; 369 *source_exhausted = false;
359 370
360 // Request more data only when we run out of data in the buffer, because 371 // Request more data only when we run out of data in the buffer, because
361 // WritePacket() consumes only the current chunk of data. 372 // WritePacket() consumes only the current chunk of data.
362 if (!buffer_->forward_bytes()) { 373 if (!buffer_->forward_bytes()) {
363 // Before making a request to source for data we need to determine the 374 // Before making a request to source for data we need to determine the
364 // delay (in bytes) for the requested data to be played. 375 // delay for the requested data to be played.
365 const uint32_t hardware_delay = GetCurrentDelay() * bytes_per_frame_; 376 const base::TimeDelta delay =
377 AudioTimestampHelper::FramesToTime(GetCurrentDelay(), sample_rate_);
366 378
367 scoped_refptr<media::DataBuffer> packet = 379 scoped_refptr<media::DataBuffer> packet =
368 new media::DataBuffer(packet_size_); 380 new media::DataBuffer(packet_size_);
369 int frames_filled = RunDataCallback( 381 int frames_filled =
370 audio_bus_.get(), hardware_delay); 382 RunDataCallback(delay, tick_clock_->NowTicks(), audio_bus_.get());
371 383
372 size_t packet_size = frames_filled * bytes_per_frame_; 384 size_t packet_size = frames_filled * bytes_per_frame_;
373 DCHECK_LE(packet_size, packet_size_); 385 DCHECK_LE(packet_size, packet_size_);
374 386
375 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer; 387 // TODO(dalecurtis): Channel downmixing, upmixing, should be done in mixer;
376 // volume adjust should use SSE optimized vector_fmul() prior to interleave. 388 // volume adjust should use SSE optimized vector_fmul() prior to interleave.
377 AudioBus* output_bus = audio_bus_.get(); 389 AudioBus* output_bus = audio_bus_.get();
378 ChannelLayout output_channel_layout = channel_layout_; 390 ChannelLayout output_channel_layout = channel_layout_;
379 if (channel_mixer_) { 391 if (channel_mixer_) {
380 output_bus = mixed_audio_bus_.get(); 392 output_bus = mixed_audio_bus_.get();
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 next_fill_time = base::TimeDelta(); 521 next_fill_time = base::TimeDelta();
510 } else if (buffer_->forward_bytes()) { 522 } else if (buffer_->forward_bytes()) {
511 // If we've got data available and no room, poll until room is available. 523 // If we've got data available and no room, poll until room is available.
512 // Polling in this manner allows us to ensure a more consistent callback 524 // Polling in this manner allows us to ensure a more consistent callback
513 // schedule. In testing this yields a variance of +/- 5ms versus the non- 525 // schedule. In testing this yields a variance of +/- 5ms versus the non-
514 // polling strategy which is around +/- 30ms and bimodal. 526 // polling strategy which is around +/- 30ms and bimodal.
515 next_fill_time = base::TimeDelta::FromMilliseconds(5); 527 next_fill_time = base::TimeDelta::FromMilliseconds(5);
516 } else if (available_frames < kTargetFramesAvailable) { 528 } else if (available_frames < kTargetFramesAvailable) {
517 // Schedule the next write for the moment when the available buffer of the 529 // Schedule the next write for the moment when the available buffer of the
518 // sound card hits |kTargetFramesAvailable|. 530 // sound card hits |kTargetFramesAvailable|.
519 next_fill_time = FramesToTimeDelta( 531 next_fill_time = AudioTimestampHelper::FramesToTime(
520 kTargetFramesAvailable - available_frames, sample_rate_); 532 kTargetFramesAvailable - available_frames, sample_rate_);
521 } else if (!source_exhausted) { 533 } else if (!source_exhausted) {
522 // The sound card has |kTargetFramesAvailable| or more frames available. 534 // The sound card has |kTargetFramesAvailable| or more frames available.
523 // Invoke the next write immediately to avoid underrun. 535 // Invoke the next write immediately to avoid underrun.
524 next_fill_time = base::TimeDelta(); 536 next_fill_time = base::TimeDelta();
525 } else { 537 } else {
526 // The sound card has frames available, but our source is exhausted, so 538 // The sound card has frames available, but our source is exhausted, so
527 // avoid busy looping by delaying a bit. 539 // avoid busy looping by delaying a bit.
528 next_fill_time = base::TimeDelta::FromMilliseconds(10); 540 next_fill_time = base::TimeDelta::FromMilliseconds(10);
529 } 541 }
530 542
531 task_runner_->PostDelayedTask( 543 task_runner_->PostDelayedTask(
532 FROM_HERE, 544 FROM_HERE,
533 base::Bind(&AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()), 545 base::Bind(&AlsaPcmOutputStream::WriteTask, weak_factory_.GetWeakPtr()),
534 next_fill_time); 546 next_fill_time);
535 } 547 }
536 548
537 // static
538 base::TimeDelta AlsaPcmOutputStream::FramesToTimeDelta(int frames,
539 double sample_rate) {
540 return base::TimeDelta::FromMicroseconds(
541 frames * base::Time::kMicrosecondsPerSecond / sample_rate);
542 }
543
544 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32_t channels) { 549 std::string AlsaPcmOutputStream::FindDeviceForChannels(uint32_t channels) {
545 // Constants specified by the ALSA API for device hints. 550 // Constants specified by the ALSA API for device hints.
546 static const int kGetAllDevices = -1; 551 static const int kGetAllDevices = -1;
547 static const char kPcmInterfaceName[] = "pcm"; 552 static const char kPcmInterfaceName[] = "pcm";
548 static const char kIoHintName[] = "IOID"; 553 static const char kIoHintName[] = "IOID";
549 static const char kNameHintName[] = "NAME"; 554 static const char kNameHintName[] = "NAME";
550 555
551 const char* wanted_device = GuessSpecificDeviceName(channels); 556 const char* wanted_device = GuessSpecificDeviceName(channels);
552 if (!wanted_device) 557 if (!wanted_device)
553 return std::string(); 558 return std::string();
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 } else { 775 } else {
771 state_ = to; 776 state_ = to;
772 } 777 }
773 return state_; 778 return state_;
774 } 779 }
775 780
776 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() { 781 AlsaPcmOutputStream::InternalState AlsaPcmOutputStream::state() {
777 return state_; 782 return state_;
778 } 783 }
779 784
780 int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus, 785 int AlsaPcmOutputStream::RunDataCallback(base::TimeDelta delay,
781 uint32_t total_bytes_delay) { 786 base::TimeTicks delay_timestamp,
787 AudioBus* audio_bus) {
782 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback"); 788 TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback");
783 789
784 if (source_callback_) 790 if (source_callback_)
785 return source_callback_->OnMoreData(audio_bus, total_bytes_delay, 0); 791 return source_callback_->OnMoreData(delay, delay_timestamp, 0, audio_bus);
786 792
787 return 0; 793 return 0;
788 } 794 }
789 795
790 void AlsaPcmOutputStream::RunErrorCallback(int code) { 796 void AlsaPcmOutputStream::RunErrorCallback(int code) {
791 if (source_callback_) 797 if (source_callback_)
792 source_callback_->OnError(this); 798 source_callback_->OnError(this);
793 } 799 }
794 800
795 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to 801 // Changes the AudioSourceCallback to proxy calls to. Pass in NULL to
796 // release ownership of the currently registered callback. 802 // release ownership of the currently registered callback.
797 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) { 803 void AlsaPcmOutputStream::set_source_callback(AudioSourceCallback* callback) {
798 DCHECK(CalledOnValidThread()); 804 DCHECK(CalledOnValidThread());
799 source_callback_ = callback; 805 source_callback_ = callback;
800 } 806 }
801 807
802 } // namespace media 808 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698