Commit d7131480 authored by Ken MacKay's avatar Ken MacKay Committed by Commit Bot

[Chromecast] Use thread annotations instead of custom lock manager

Now that thread annotations are available, we should use them.

Change-Id: I06a516f76ebffbd56ec3c7d68666f34c6012da8b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1759899
Commit-Queue: Kenneth MacKay <kmackay@chromium.org>
Reviewed-by: default avatarYuchen Liu <yucliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#688353}
parent ee1a08ab
...@@ -99,67 +99,6 @@ int StartThreshold(const std::string& device_id, int sample_rate) { ...@@ -99,67 +99,6 @@ int StartThreshold(const std::string& device_id, int sample_rate) {
} // namespace } // namespace
BufferingMixerSource::LockedMembers::Members::Members(
BufferingMixerSource* source,
int input_samples_per_second,
int num_channels,
int64_t playback_start_timestamp,
int64_t playback_start_pts)
: fader_(source,
kFadeTime,
num_channels,
input_samples_per_second,
1.0 /* playback_rate */),
playback_start_timestamp_(playback_start_timestamp),
playback_start_pts_(playback_start_pts),
audio_resampler_(num_channels) {
buffers_to_be_freed_.reserve(kFreeBufferListSize);
}
BufferingMixerSource::LockedMembers::Members::~Members() = default;
BufferingMixerSource::LockedMembers::AcquiredLock::AcquiredLock(
LockedMembers* members)
: locked_(members) {
DCHECK(locked_);
locked_->member_lock_.Acquire();
}
BufferingMixerSource::LockedMembers::AcquiredLock::~AcquiredLock() {
locked_->member_lock_.Release();
}
BufferingMixerSource::LockedMembers::AssertedLock::AssertedLock(
LockedMembers* members)
: locked_(members) {
DCHECK(locked_);
locked_->member_lock_.AssertAcquired();
}
BufferingMixerSource::LockedMembers::LockedMembers(
BufferingMixerSource* source,
int input_samples_per_second,
int num_channels,
int64_t playback_start_timestamp,
int64_t playback_start_pts)
: members_(source,
input_samples_per_second,
num_channels,
playback_start_timestamp,
playback_start_pts) {}
BufferingMixerSource::LockedMembers::~LockedMembers() = default;
BufferingMixerSource::LockedMembers::AcquiredLock
BufferingMixerSource::LockedMembers::Lock() {
return AcquiredLock(this);
}
BufferingMixerSource::LockedMembers::AssertedLock
BufferingMixerSource::LockedMembers::AssertAcquired() {
return AssertedLock(this);
}
BufferingMixerSource::BufferingMixerSource(Delegate* delegate, BufferingMixerSource::BufferingMixerSource(Delegate* delegate,
int num_channels, int num_channels,
int input_samples_per_second, int input_samples_per_second,
...@@ -181,11 +120,14 @@ BufferingMixerSource::BufferingMixerSource(Delegate* delegate, ...@@ -181,11 +120,14 @@ BufferingMixerSource::BufferingMixerSource(Delegate* delegate,
max_queued_frames_(MaxQueuedFrames(device_id, input_samples_per_second)), max_queued_frames_(MaxQueuedFrames(device_id, input_samples_per_second)),
start_threshold_frames_( start_threshold_frames_(
StartThreshold(device_id, input_samples_per_second)), StartThreshold(device_id, input_samples_per_second)),
locked_members_(this, fader_(this,
input_samples_per_second, kFadeTime,
num_channels_, num_channels_,
start_playback_asap ? INT64_MIN : INT64_MAX, input_samples_per_second_,
playback_start_pts), 1.0 /* playback_rate */),
playback_start_timestamp_(start_playback_asap ? INT64_MIN : INT64_MAX),
playback_start_pts_(playback_start_pts),
audio_resampler_(num_channels_),
weak_factory_(this) { weak_factory_(this) {
LOG(INFO) << "Create " << device_id_ << " (" << this LOG(INFO) << "Create " << device_id_ << " (" << this
<< "), content type = " << AudioContentTypeToString(content_type_) << "), content type = " << AudioContentTypeToString(content_type_)
...@@ -196,6 +138,7 @@ BufferingMixerSource::BufferingMixerSource(Delegate* delegate, ...@@ -196,6 +138,7 @@ BufferingMixerSource::BufferingMixerSource(Delegate* delegate,
DCHECK_LE(start_threshold_frames_, max_queued_frames_); DCHECK_LE(start_threshold_frames_, max_queued_frames_);
weak_this_ = weak_factory_.GetWeakPtr(); weak_this_ = weak_factory_.GetWeakPtr();
buffers_to_be_freed_.reserve(kFreeBufferListSize);
old_buffers_to_be_freed_.reserve(kFreeBufferListSize); old_buffers_to_be_freed_.reserve(kFreeBufferListSize);
pcm_completion_task_ = pcm_completion_task_ =
...@@ -217,10 +160,10 @@ void BufferingMixerSource::StartPlaybackAt(int64_t playback_start_timestamp) { ...@@ -217,10 +160,10 @@ void BufferingMixerSource::StartPlaybackAt(int64_t playback_start_timestamp) {
LOG(INFO) << __func__ LOG(INFO) << __func__
<< " playback_start_timestamp=" << playback_start_timestamp; << " playback_start_timestamp=" << playback_start_timestamp;
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
DCHECK(!locked->started_); DCHECK(!started_);
DCHECK(locked->playback_start_timestamp_ == INT64_MAX); DCHECK_EQ(playback_start_timestamp_, INT64_MAX);
locked->playback_start_timestamp_ = playback_start_timestamp; playback_start_timestamp_ = playback_start_timestamp;
} }
void BufferingMixerSource::RestartPlaybackAt(int64_t timestamp, int64_t pts) { void BufferingMixerSource::RestartPlaybackAt(int64_t timestamp, int64_t pts) {
...@@ -228,17 +171,17 @@ void BufferingMixerSource::RestartPlaybackAt(int64_t timestamp, int64_t pts) { ...@@ -228,17 +171,17 @@ void BufferingMixerSource::RestartPlaybackAt(int64_t timestamp, int64_t pts) {
LOG(INFO) << __func__ << " timestamp=" << timestamp << " pts=" << pts; LOG(INFO) << __func__ << " timestamp=" << timestamp << " pts=" << pts;
{ {
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
DCHECK(locked->started_); DCHECK(started_);
locked->playback_start_pts_ = pts; playback_start_pts_ = pts;
locked->playback_start_timestamp_ = timestamp; playback_start_timestamp_ = timestamp;
locked->started_ = false; started_ = false;
locked->queued_frames_ += locked->current_buffer_offset_; queued_frames_ += current_buffer_offset_;
locked->current_buffer_offset_ = 0; current_buffer_offset_ = 0;
while (!locked->queue_.empty()) { while (!queue_.empty()) {
DecoderBufferBase* data = locked->queue_.front().get(); DecoderBufferBase* data = queue_.front().get();
int64_t frames = DataToFrames(data->data_size()); int64_t frames = DataToFrames(data->data_size());
if (data->timestamp() + if (data->timestamp() +
SamplesToMicroseconds(frames, input_samples_per_second_) >= SamplesToMicroseconds(frames, input_samples_per_second_) >=
...@@ -246,8 +189,8 @@ void BufferingMixerSource::RestartPlaybackAt(int64_t timestamp, int64_t pts) { ...@@ -246,8 +189,8 @@ void BufferingMixerSource::RestartPlaybackAt(int64_t timestamp, int64_t pts) {
break; break;
} }
locked->queued_frames_ -= frames; queued_frames_ -= frames;
locked->queue_.pop_front(); queue_.pop_front();
} }
} }
} }
...@@ -257,22 +200,22 @@ void BufferingMixerSource::SetMediaPlaybackRate(double rate) { ...@@ -257,22 +200,22 @@ void BufferingMixerSource::SetMediaPlaybackRate(double rate) {
LOG(INFO) << __func__ << " rate=" << rate; LOG(INFO) << __func__ << " rate=" << rate;
DCHECK_GT(rate, 0); DCHECK_GT(rate, 0);
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
locked->playback_rate_ = rate; playback_rate_ = rate;
} }
float BufferingMixerSource::SetAvSyncPlaybackRate(float rate) { float BufferingMixerSource::SetAvSyncPlaybackRate(float rate) {
DCHECK(caller_task_runner_->BelongsToCurrentThread()); DCHECK(caller_task_runner_->BelongsToCurrentThread());
LOG(INFO) << __func__ << " rate=" << rate; LOG(INFO) << __func__ << " rate=" << rate;
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
return locked->audio_resampler_.SetMediaClockRate(rate); return audio_resampler_.SetMediaClockRate(rate);
} }
BufferingMixerSource::RenderingDelay BufferingMixerSource::RenderingDelay
BufferingMixerSource::GetMixerRenderingDelay() { BufferingMixerSource::GetMixerRenderingDelay() {
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
return locked->mixer_rendering_delay_; return mixer_rendering_delay_;
} }
int BufferingMixerSource::num_channels() { int BufferingMixerSource::num_channels() {
...@@ -303,13 +246,12 @@ void BufferingMixerSource::WritePcm(scoped_refptr<DecoderBufferBase> data) { ...@@ -303,13 +246,12 @@ void BufferingMixerSource::WritePcm(scoped_refptr<DecoderBufferBase> data) {
RenderingDelay delay; RenderingDelay delay;
bool queued; bool queued;
{ {
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
old_buffers_to_be_freed_.swap(locked->buffers_to_be_freed_); old_buffers_to_be_freed_.swap(buffers_to_be_freed_);
if (locked->state_ == State::kUninitialized || if (state_ == State::kUninitialized ||
locked->queued_frames_ + locked->fader_.buffered_frames() >= queued_frames_ + fader_.buffered_frames() >= max_queued_frames_) {
max_queued_frames_) { DCHECK(!pending_data_);
DCHECK(!locked->pending_data_); pending_data_ = std::move(data);
locked->pending_data_ = std::move(data);
queued = false; queued = false;
} else { } else {
delay = QueueData(std::move(data)); delay = QueueData(std::move(data));
...@@ -324,37 +266,34 @@ void BufferingMixerSource::WritePcm(scoped_refptr<DecoderBufferBase> data) { ...@@ -324,37 +266,34 @@ void BufferingMixerSource::WritePcm(scoped_refptr<DecoderBufferBase> data) {
BufferingMixerSource::RenderingDelay BufferingMixerSource::QueueData( BufferingMixerSource::RenderingDelay BufferingMixerSource::QueueData(
scoped_refptr<DecoderBufferBase> data) { scoped_refptr<DecoderBufferBase> data) {
auto locked = locked_members_.AssertAcquired();
if (data->end_of_stream()) { if (data->end_of_stream()) {
LOG(INFO) << "End of stream for " << device_id_ << " (" << this << ")"; LOG(INFO) << "End of stream for " << device_id_ << " (" << this << ")";
locked->state_ = State::kGotEos; state_ = State::kGotEos;
if (!locked->started_ && locked->playback_start_timestamp_ != INT64_MIN) { if (!started_ && playback_start_timestamp_ != INT64_MIN) {
caller_task_runner_->PostTask(FROM_HERE, ready_for_playback_task_); caller_task_runner_->PostTask(FROM_HERE, ready_for_playback_task_);
} }
} else if (locked->started_ || } else if (started_ ||
data->timestamp() + data->timestamp() +
SamplesToMicroseconds(DataToFrames(data->data_size()), SamplesToMicroseconds(DataToFrames(data->data_size()),
input_samples_per_second_) >= input_samples_per_second_) >=
locked->playback_start_pts_) { playback_start_pts_) {
scoped_refptr<DecoderBufferBase> buffer = scoped_refptr<DecoderBufferBase> buffer =
locked->audio_resampler_.ResampleBuffer(std::move(data)); audio_resampler_.ResampleBuffer(std::move(data));
locked->queued_frames_ += DataToFrames(buffer->data_size()); queued_frames_ += DataToFrames(buffer->data_size());
locked->queue_.push_back(std::move(buffer)); queue_.push_back(std::move(buffer));
if (!locked->started_ && if (!started_ && queued_frames_ >= start_threshold_frames_ &&
locked->queued_frames_ >= start_threshold_frames_ && playback_start_timestamp_ != INT64_MIN) {
locked->playback_start_timestamp_ != INT64_MIN) {
caller_task_runner_->PostTask(FROM_HERE, ready_for_playback_task_); caller_task_runner_->PostTask(FROM_HERE, ready_for_playback_task_);
} }
} }
// Otherwise, drop |data| since it is before the start PTS. // Otherwise, drop |data| since it is before the start PTS.
RenderingDelay delay; RenderingDelay delay;
if (locked->started_ && !locked->paused_) { if (started_ && !paused_) {
delay = locked->mixer_rendering_delay_; delay = mixer_rendering_delay_;
delay.delay_microseconds += SamplesToMicroseconds( delay.delay_microseconds += SamplesToMicroseconds(
locked->queued_frames_ + locked->extra_delay_frames_, queued_frames_ + extra_delay_frames_, input_samples_per_second_);
input_samples_per_second_);
} }
return delay; return delay;
} }
...@@ -362,13 +301,13 @@ BufferingMixerSource::RenderingDelay BufferingMixerSource::QueueData( ...@@ -362,13 +301,13 @@ BufferingMixerSource::RenderingDelay BufferingMixerSource::QueueData(
void BufferingMixerSource::SetPaused(bool paused) { void BufferingMixerSource::SetPaused(bool paused) {
LOG(INFO) << (paused ? "Pausing " : "Unpausing ") << device_id_ << " (" LOG(INFO) << (paused ? "Pausing " : "Unpausing ") << device_id_ << " ("
<< this << ")"; << this << ")";
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
// Clear start timestamp, since a pause should invalidate the start timestamp // Clear start timestamp, since a pause should invalidate the start timestamp
// anyway. The AV sync code can restart (hard correction) on resume if // anyway. The AV sync code can restart (hard correction) on resume if
// needed. // needed.
locked->playback_start_timestamp_ = INT64_MIN; playback_start_timestamp_ = INT64_MIN;
locked->mixer_rendering_delay_ = RenderingDelay(); mixer_rendering_delay_ = RenderingDelay();
locked->paused_ = paused; paused_ = paused;
} }
void BufferingMixerSource::SetVolumeMultiplier(float multiplier) { void BufferingMixerSource::SetVolumeMultiplier(float multiplier) {
...@@ -381,18 +320,17 @@ void BufferingMixerSource::InitializeAudioPlayback( ...@@ -381,18 +320,17 @@ void BufferingMixerSource::InitializeAudioPlayback(
// Start accepting buffers into the queue. // Start accepting buffers into the queue.
bool queued_data = false; bool queued_data = false;
{ {
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
locked->mixer_rendering_delay_ = initial_rendering_delay; mixer_rendering_delay_ = initial_rendering_delay;
if (locked->state_ == State::kUninitialized) { if (state_ == State::kUninitialized) {
locked->state_ = State::kNormalPlayback; state_ = State::kNormalPlayback;
} else { } else {
DCHECK(locked->state_ == State::kRemoved); DCHECK_EQ(state_, State::kRemoved);
} }
if (locked->pending_data_ && if (pending_data_ &&
locked->queued_frames_ + locked->fader_.buffered_frames() < queued_frames_ + fader_.buffered_frames() < max_queued_frames_) {
max_queued_frames_) { last_buffer_delay_ = QueueData(std::move(pending_data_));
locked->last_buffer_delay_ = QueueData(std::move(locked->pending_data_));
queued_data = true; queued_data = true;
} }
} }
...@@ -405,64 +343,58 @@ void BufferingMixerSource::InitializeAudioPlayback( ...@@ -405,64 +343,58 @@ void BufferingMixerSource::InitializeAudioPlayback(
void BufferingMixerSource::CheckAndStartPlaybackIfNecessary( void BufferingMixerSource::CheckAndStartPlaybackIfNecessary(
int num_frames, int num_frames,
int64_t playback_absolute_timestamp) { int64_t playback_absolute_timestamp) {
auto locked = locked_members_.AssertAcquired(); DCHECK(state_ == State::kNormalPlayback || state_ == State::kGotEos);
DCHECK(!started_);
DCHECK(locked->state_ == State::kNormalPlayback ||
locked->state_ == State::kGotEos);
DCHECK(!locked->started_);
const bool have_enough_queued_frames = const bool have_enough_queued_frames =
(locked->state_ == State::kGotEos || (state_ == State::kGotEos ||
(locked->queued_frames_ >= start_threshold_frames_ && (queued_frames_ >= start_threshold_frames_ &&
locked->queued_frames_ >= queued_frames_ >= fader_.FramesNeededFromSource(num_frames)));
locked->fader_.FramesNeededFromSource(num_frames)));
if (!have_enough_queued_frames) { if (!have_enough_queued_frames) {
return; return;
} }
remaining_silence_frames_ = 0; remaining_silence_frames_ = 0;
if (locked->playback_start_timestamp_ == INT64_MIN || if (playback_start_timestamp_ == INT64_MIN ||
(locked->queue_.empty() && locked->state_ == State::kGotEos)) { (queue_.empty() && state_ == State::kGotEos)) {
// No start timestamp, so start as soon as there are enough queued frames. // No start timestamp, so start as soon as there are enough queued frames.
locked->started_ = true; started_ = true;
return; return;
} }
if (playback_absolute_timestamp + if (playback_absolute_timestamp +
SamplesToMicroseconds(num_frames, input_samples_per_second_) < SamplesToMicroseconds(num_frames, input_samples_per_second_) <
locked->playback_start_timestamp_) { playback_start_timestamp_) {
// Haven't reached the start timestamp yet. // Haven't reached the start timestamp yet.
return; return;
} }
DCHECK(!locked->queue_.empty()); DCHECK(!queue_.empty());
// Reset the current buffer offset to 0 so we can ignore it below. We need to // Reset the current buffer offset to 0 so we can ignore it below. We need to
// do this here because we may not have started playback even after dropping // do this here because we may not have started playback even after dropping
// all necessary frames the last time we checked. // all necessary frames the last time we checked.
locked->queued_frames_ += locked->current_buffer_offset_; queued_frames_ += current_buffer_offset_;
locked->current_buffer_offset_ = 0; current_buffer_offset_ = 0;
int64_t desired_pts_now = int64_t desired_pts_now = playback_start_pts_ + (playback_absolute_timestamp -
locked->playback_start_pts_ + playback_start_timestamp_) *
(playback_absolute_timestamp - locked->playback_start_timestamp_) * playback_rate_;
locked->playback_rate_; int64_t actual_pts_now = queue_.front()->timestamp();
int64_t actual_pts_now = locked->queue_.front()->timestamp(); int64_t drop_us = (desired_pts_now - actual_pts_now) / playback_rate_;
int64_t drop_us = (desired_pts_now - actual_pts_now) / locked->playback_rate_;
if (drop_us >= 0) { if (drop_us >= 0) {
LOG(INFO) << "Dropping audio, duration = " << drop_us; LOG(INFO) << "Dropping audio, duration = " << drop_us;
DropAudio(::media::AudioTimestampHelper::TimeToFrames( DropAudio(::media::AudioTimestampHelper::TimeToFrames(
base::TimeDelta::FromMicroseconds(drop_us), input_samples_per_second_)); base::TimeDelta::FromMicroseconds(drop_us), input_samples_per_second_));
// Only start if we still have enough data to do so. // Only start if we still have enough data to do so.
locked->started_ = (locked->queued_frames_ >= start_threshold_frames_ && started_ = (queued_frames_ >= start_threshold_frames_ &&
locked->queued_frames_ >= queued_frames_ >= fader_.FramesNeededFromSource(num_frames));
locked->fader_.FramesNeededFromSource(num_frames));
if (locked->started_) { if (started_) {
int64_t start_pts = locked->queue_.front()->timestamp() + int64_t start_pts = queue_.front()->timestamp() +
SamplesToMicroseconds(locked->current_buffer_offset_, SamplesToMicroseconds(current_buffer_offset_,
input_samples_per_second_) * input_samples_per_second_) *
locked->playback_rate_; playback_rate_;
LOG(INFO) << "Start playback of PTS " << start_pts << " at " LOG(INFO) << "Start playback of PTS " << start_pts << " at "
<< playback_absolute_timestamp; << playback_absolute_timestamp;
} }
...@@ -472,30 +404,27 @@ void BufferingMixerSource::CheckAndStartPlaybackIfNecessary( ...@@ -472,30 +404,27 @@ void BufferingMixerSource::CheckAndStartPlaybackIfNecessary(
remaining_silence_frames_ = ::media::AudioTimestampHelper::TimeToFrames( remaining_silence_frames_ = ::media::AudioTimestampHelper::TimeToFrames(
base::TimeDelta::FromMicroseconds(silence_duration), base::TimeDelta::FromMicroseconds(silence_duration),
input_samples_per_second_); input_samples_per_second_);
locked->started_ = true; started_ = true;
LOG(INFO) << "Should start playback of PTS " LOG(INFO) << "Should start playback of PTS " << queue_.front()->timestamp()
<< locked->queue_.front()->timestamp() << " at " << " at " << (playback_absolute_timestamp + silence_duration);
<< (playback_absolute_timestamp + silence_duration);
} }
} }
void BufferingMixerSource::DropAudio(int64_t frames_to_drop) { void BufferingMixerSource::DropAudio(int64_t frames_to_drop) {
auto locked = locked_members_.AssertAcquired(); DCHECK_EQ(current_buffer_offset_, 0);
DCHECK_EQ(locked->current_buffer_offset_, 0);
while (frames_to_drop && !locked->queue_.empty()) { while (frames_to_drop && !queue_.empty()) {
int64_t first_buffer_frames = int64_t first_buffer_frames = DataToFrames(queue_.front()->data_size());
DataToFrames(locked->queue_.front()->data_size());
if (first_buffer_frames > frames_to_drop) { if (first_buffer_frames > frames_to_drop) {
locked->current_buffer_offset_ = frames_to_drop; current_buffer_offset_ = frames_to_drop;
locked->queued_frames_ -= frames_to_drop; queued_frames_ -= frames_to_drop;
frames_to_drop = 0; frames_to_drop = 0;
break; break;
} }
locked->queued_frames_ -= first_buffer_frames; queued_frames_ -= first_buffer_frames;
frames_to_drop -= first_buffer_frames; frames_to_drop -= first_buffer_frames;
locked->queue_.pop_front(); queue_.pop_front();
} }
if (frames_to_drop > 0) { if (frames_to_drop > 0) {
...@@ -519,28 +448,27 @@ int BufferingMixerSource::FillAudioPlaybackFrames( ...@@ -519,28 +448,27 @@ int BufferingMixerSource::FillAudioPlaybackFrames(
bool signal_eos = false; bool signal_eos = false;
bool remove_self = false; bool remove_self = false;
{ {
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
// Playback start check. // Playback start check.
if (!locked->started_ && (locked->state_ == State::kNormalPlayback || if (!started_ &&
locked->state_ == State::kGotEos)) { (state_ == State::kNormalPlayback || state_ == State::kGotEos)) {
CheckAndStartPlaybackIfNecessary(num_frames, playback_absolute_timestamp); CheckAndStartPlaybackIfNecessary(num_frames, playback_absolute_timestamp);
} }
// In normal playback, don't pass data to the fader if we can't satisfy the // In normal playback, don't pass data to the fader if we can't satisfy the
// full request. This will allow us to buffer up more data so we can fully // full request. This will allow us to buffer up more data so we can fully
// fade in. // fade in.
if (locked->state_ == State::kNormalPlayback && locked->started_ && if (state_ == State::kNormalPlayback && started_ &&
locked->queued_frames_ < queued_frames_ < fader_.FramesNeededFromSource(num_frames)) {
locked->fader_.FramesNeededFromSource(num_frames)) { LOG_IF(INFO, !zero_fader_frames_)
LOG_IF(INFO, !locked->zero_fader_frames_)
<< "Stream underrun for " << device_id_ << " (" << this << ")"; << "Stream underrun for " << device_id_ << " (" << this << ")";
locked->zero_fader_frames_ = true; zero_fader_frames_ = true;
} else { } else {
LOG_IF(INFO, locked->started_ && locked->zero_fader_frames_) LOG_IF(INFO, started_ && zero_fader_frames_)
<< "Stream underrun recovered for " << device_id_ << " (" << this << "Stream underrun recovered for " << device_id_ << " (" << this
<< ")"; << ")";
locked->zero_fader_frames_ = false; zero_fader_frames_ = false;
} }
DCHECK_GE(remaining_silence_frames_, 0); DCHECK_GE(remaining_silence_frames_, 0);
...@@ -562,29 +490,27 @@ int BufferingMixerSource::FillAudioPlaybackFrames( ...@@ -562,29 +490,27 @@ int BufferingMixerSource::FillAudioPlaybackFrames(
for (int c = 0; c < num_channels_; ++c) { for (int c = 0; c < num_channels_; ++c) {
channels[c] = buffer->channel(c) + write_offset; channels[c] = buffer->channel(c) + write_offset;
} }
filled = locked->fader_.FillFrames(num_frames, rendering_delay, channels); filled = fader_.FillFrames(num_frames, rendering_delay, channels);
locked->mixer_rendering_delay_ = rendering_delay; mixer_rendering_delay_ = rendering_delay;
locked->extra_delay_frames_ = num_frames + locked->fader_.buffered_frames(); extra_delay_frames_ = num_frames + fader_.buffered_frames();
// See if we can accept more data into the queue. // See if we can accept more data into the queue.
if (locked->pending_data_ && if (pending_data_ &&
locked->queued_frames_ + locked->fader_.buffered_frames() < queued_frames_ + fader_.buffered_frames() < max_queued_frames_) {
max_queued_frames_) { last_buffer_delay_ = QueueData(std::move(pending_data_));
locked->last_buffer_delay_ = QueueData(std::move(locked->pending_data_));
queued_more_data = true; queued_more_data = true;
} }
// Check if we have played out EOS. // Check if we have played out EOS.
if (locked->state_ == State::kGotEos && locked->queued_frames_ == 0 && if (state_ == State::kGotEos && queued_frames_ == 0 &&
locked->fader_.buffered_frames() == 0) { fader_.buffered_frames() == 0) {
signal_eos = true; signal_eos = true;
locked->state_ = State::kSignaledEos; state_ = State::kSignaledEos;
} }
// If the caller has removed this source, delete once we have faded out. // If the caller has removed this source, delete once we have faded out.
if (locked->state_ == State::kRemoved && if (state_ == State::kRemoved && fader_.buffered_frames() == 0) {
locked->fader_.buffered_frames() == 0) {
remove_self = true; remove_self = true;
} }
} }
...@@ -610,46 +536,44 @@ int BufferingMixerSource::FillFaderFrames(int num_frames, ...@@ -610,46 +536,44 @@ int BufferingMixerSource::FillFaderFrames(int num_frames,
RenderingDelay rendering_delay, RenderingDelay rendering_delay,
float* const* channels) { float* const* channels) {
DCHECK(channels); DCHECK(channels);
auto locked = locked_members_.AssertAcquired();
if (locked->zero_fader_frames_ || !locked->started_ || locked->paused_ || if (zero_fader_frames_ || !started_ || paused_ || state_ == State::kRemoved) {
locked->state_ == State::kRemoved) {
return 0; return 0;
} }
int num_filled = 0; int num_filled = 0;
while (num_frames) { while (num_frames) {
if (locked->queue_.empty()) { if (queue_.empty()) {
return num_filled; return num_filled;
} }
DecoderBufferBase* buffer = locked->queue_.front().get(); DecoderBufferBase* buffer = queue_.front().get();
const int buffer_frames = DataToFrames(buffer->data_size()); const int buffer_frames = DataToFrames(buffer->data_size());
const int frames_to_copy = const int frames_to_copy =
std::min(num_frames, buffer_frames - locked->current_buffer_offset_); std::min(num_frames, buffer_frames - current_buffer_offset_);
DCHECK(frames_to_copy >= 0 && frames_to_copy <= num_frames) DCHECK(frames_to_copy >= 0 && frames_to_copy <= num_frames)
<< " frames_to_copy=" << frames_to_copy << " num_frames=" << num_frames << " frames_to_copy=" << frames_to_copy << " num_frames=" << num_frames
<< " buffer_frames=" << buffer_frames << " num_filled=" << num_filled << " buffer_frames=" << buffer_frames << " num_filled=" << num_filled
<< " locked->current_buffer_offset_=" << locked->current_buffer_offset_ << " current_buffer_offset_=" << current_buffer_offset_
<< " buffer=" << buffer->data_size(); << " buffer=" << buffer->data_size();
const float* buffer_samples = const float* buffer_samples =
reinterpret_cast<const float*>(buffer->data()); reinterpret_cast<const float*>(buffer->data());
for (int c = 0; c < num_channels_; ++c) { for (int c = 0; c < num_channels_; ++c) {
const float* buffer_channel = buffer_samples + (buffer_frames * c); const float* buffer_channel = buffer_samples + (buffer_frames * c);
std::copy_n(buffer_channel + locked->current_buffer_offset_, std::copy_n(buffer_channel + current_buffer_offset_, frames_to_copy,
frames_to_copy, channels[c] + num_filled); channels[c] + num_filled);
} }
num_frames -= frames_to_copy; num_frames -= frames_to_copy;
locked->queued_frames_ -= frames_to_copy; queued_frames_ -= frames_to_copy;
num_filled += frames_to_copy; num_filled += frames_to_copy;
locked->current_buffer_offset_ += frames_to_copy; current_buffer_offset_ += frames_to_copy;
if (locked->current_buffer_offset_ == buffer_frames) { if (current_buffer_offset_ == buffer_frames) {
locked->buffers_to_be_freed_.push_back(std::move(locked->queue_.front())); buffers_to_be_freed_.push_back(std::move(queue_.front()));
locked->queue_.pop_front(); queue_.pop_front();
locked->current_buffer_offset_ = 0; current_buffer_offset_ = 0;
} }
} }
...@@ -660,8 +584,8 @@ void BufferingMixerSource::PostPcmCompletion() { ...@@ -660,8 +584,8 @@ void BufferingMixerSource::PostPcmCompletion() {
DCHECK(caller_task_runner_->BelongsToCurrentThread()); DCHECK(caller_task_runner_->BelongsToCurrentThread());
RenderingDelay delay; RenderingDelay delay;
{ {
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
delay = locked->last_buffer_delay_; delay = last_buffer_delay_;
} }
delegate_->OnWritePcmCompletion(delay); delegate_->OnWritePcmCompletion(delay);
} }
...@@ -690,9 +614,9 @@ void BufferingMixerSource::OnAudioPlaybackError(MixerError error) { ...@@ -690,9 +614,9 @@ void BufferingMixerSource::OnAudioPlaybackError(MixerError error) {
FROM_HERE, FROM_HERE,
base::BindOnce(&BufferingMixerSource::PostError, weak_this_, error)); base::BindOnce(&BufferingMixerSource::PostError, weak_this_, error));
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
locked->mixer_error_ = true; mixer_error_ = true;
if (locked->state_ == State::kRemoved) { if (state_ == State::kRemoved) {
mixer_->RemoveInput(this); mixer_->RemoveInput(this);
} }
} }
...@@ -709,10 +633,10 @@ void BufferingMixerSource::Remove() { ...@@ -709,10 +633,10 @@ void BufferingMixerSource::Remove() {
LOG(INFO) << "Remove " << device_id_ << " (" << this << ")"; LOG(INFO) << "Remove " << device_id_ << " (" << this << ")";
bool remove_self = false; bool remove_self = false;
{ {
auto locked = locked_members_.Lock(); base::AutoLock lock(lock_);
locked->pending_data_ = nullptr; pending_data_ = nullptr;
locked->state_ = State::kRemoved; state_ = State::kRemoved;
remove_self = locked->mixer_error_; remove_self = mixer_error_;
} }
if (remove_self) { if (remove_self) {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "chromecast/media/cma/backend/audio_fader.h" #include "chromecast/media/cma/backend/audio_fader.h"
#include "chromecast/media/cma/backend/audio_resampler.h" #include "chromecast/media/cma/backend/audio_resampler.h"
#include "chromecast/media/cma/backend/mixer_input.h" #include "chromecast/media/cma/backend/mixer_input.h"
...@@ -130,93 +131,6 @@ class BufferingMixerSource : public MixerInput::Source, ...@@ -130,93 +131,6 @@ class BufferingMixerSource : public MixerInput::Source,
kRemoved, // The caller has removed this source; finish playing out. kRemoved, // The caller has removed this source; finish playing out.
}; };
// Class to wrap members that must be used only when a lock is held. Usage:
// {
// auto locked = locked_members_.Lock();
// locked->paused_ = true; // or other member access
// }
class LockedMembers {
public:
struct Members {
Members(BufferingMixerSource* source,
int input_samples_per_second,
int num_channels,
int64_t playback_start_timestamp,
int64_t playback_start_pts);
~Members();
State state_ = State::kUninitialized;
bool paused_ = false;
bool mixer_error_ = false;
scoped_refptr<DecoderBufferBase> pending_data_;
base::circular_deque<scoped_refptr<DecoderBufferBase>> queue_;
// We let the caller thread free audio buffers since freeing memory can
// be expensive sometimes; we want to avoid potentially long-running
// operations on the mixer thread.
std::vector<scoped_refptr<DecoderBufferBase>> buffers_to_be_freed_;
int queued_frames_ = 0;
RenderingDelay mixer_rendering_delay_;
RenderingDelay last_buffer_delay_;
int extra_delay_frames_ = 0;
int current_buffer_offset_ = 0;
AudioFader fader_;
bool zero_fader_frames_ = false;
bool started_ = false;
double playback_rate_ = 1.0;
// The absolute timestamp relative to clock monotonic (raw) at which the
// playback should start. INT64_MIN indicates playback should start ASAP.
// INT64_MAX indicates playback should start at a specified timestamp,
// but we don't know what that timestamp is.
int64_t playback_start_timestamp_ = INT64_MIN;
// The PTS the playback should start at. We will drop audio pushed to us
// with PTS values below this value. If the audio doesn't have a starting
// PTS, then this value can be INT64_MIN, to play whatever audio is sent
// to us.
int64_t playback_start_pts_ = INT64_MIN;
AudioResampler audio_resampler_;
private:
DISALLOW_COPY_AND_ASSIGN(Members);
};
class AcquiredLock {
public:
explicit AcquiredLock(LockedMembers* locked);
~AcquiredLock();
Members* operator->() { return &(locked_->members_); }
private:
LockedMembers* const locked_;
};
class AssertedLock {
public:
explicit AssertedLock(LockedMembers* locked);
Members* operator->() { return &(locked_->members_); }
private:
LockedMembers* const locked_;
};
LockedMembers(BufferingMixerSource* source,
int input_samples_per_second,
int num_channels,
int64_t playback_start_timestamp,
int64_t playback_start_pts);
~LockedMembers();
AcquiredLock Lock();
AssertedLock AssertAcquired();
private:
base::Lock member_lock_;
Members members_;
DISALLOW_COPY_AND_ASSIGN(LockedMembers);
};
~BufferingMixerSource() override; ~BufferingMixerSource() override;
// MixerInput::Source implementation: // MixerInput::Source implementation:
...@@ -239,18 +153,21 @@ class BufferingMixerSource : public MixerInput::Source, ...@@ -239,18 +153,21 @@ class BufferingMixerSource : public MixerInput::Source,
// AudioFader::Source implementation: // AudioFader::Source implementation:
int FillFaderFrames(int num_frames, int FillFaderFrames(int num_frames,
RenderingDelay rendering_delay, RenderingDelay rendering_delay,
float* const* channels) override; float* const* channels)
EXCLUSIVE_LOCKS_REQUIRED(lock_) override;
RenderingDelay QueueData(scoped_refptr<DecoderBufferBase> data); RenderingDelay QueueData(scoped_refptr<DecoderBufferBase> data)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
void PostPcmCompletion(); void PostPcmCompletion();
void PostEos(); void PostEos();
void PostError(MixerError error); void PostError(MixerError error);
void PostAudioReadyForPlayback(); void PostAudioReadyForPlayback();
void DropAudio(int64_t frames); void DropAudio(int64_t frames) EXCLUSIVE_LOCKS_REQUIRED(lock_);
int64_t DataToFrames(int64_t size); int64_t DataToFrames(int64_t size);
void CheckAndStartPlaybackIfNecessary(int num_frames, void CheckAndStartPlaybackIfNecessary(int num_frames,
int64_t playback_absolute_timestamp); int64_t playback_absolute_timestamp)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
Delegate* const delegate_; Delegate* const delegate_;
const int num_channels_; const int num_channels_;
const int input_samples_per_second_; const int input_samples_per_second_;
...@@ -263,14 +180,44 @@ class BufferingMixerSource : public MixerInput::Source, ...@@ -263,14 +180,44 @@ class BufferingMixerSource : public MixerInput::Source,
const int max_queued_frames_; const int max_queued_frames_;
// Minimum number of frames buffered before starting to fill data. // Minimum number of frames buffered before starting to fill data.
const int start_threshold_frames_; const int start_threshold_frames_;
bool audio_ready_for_playback_fired_ = false;
// Only used on the caller thread. // Only used on the caller thread.
std::vector<scoped_refptr<DecoderBufferBase>> old_buffers_to_be_freed_; std::vector<scoped_refptr<DecoderBufferBase>> old_buffers_to_be_freed_;
bool audio_ready_for_playback_fired_ = false;
LockedMembers locked_members_; base::Lock lock_;
State state_ GUARDED_BY(lock_) = State::kUninitialized;
int remaining_silence_frames_ = 0; bool paused_ GUARDED_BY(lock_) = false;
bool mixer_error_ GUARDED_BY(lock_) = false;
scoped_refptr<DecoderBufferBase> pending_data_ GUARDED_BY(lock_);
base::circular_deque<scoped_refptr<DecoderBufferBase>> queue_
GUARDED_BY(lock_);
// We let the caller thread free audio buffers since freeing memory can
// be expensive sometimes; we want to avoid potentially long-running
// operations on the mixer thread.
std::vector<scoped_refptr<DecoderBufferBase>> buffers_to_be_freed_
GUARDED_BY(lock_);
int queued_frames_ GUARDED_BY(lock_) = 0;
RenderingDelay mixer_rendering_delay_ GUARDED_BY(lock_);
RenderingDelay last_buffer_delay_ GUARDED_BY(lock_);
int extra_delay_frames_ GUARDED_BY(lock_) = 0;
int current_buffer_offset_ GUARDED_BY(lock_) = 0;
AudioFader fader_ GUARDED_BY(lock_);
bool zero_fader_frames_ GUARDED_BY(lock_) = false;
bool started_ GUARDED_BY(lock_) = false;
double playback_rate_ GUARDED_BY(lock_) = 1.0;
// The absolute timestamp relative to clock monotonic (raw) at which the
// playback should start. INT64_MIN indicates playback should start ASAP.
// INT64_MAX indicates playback should start at a specified timestamp,
// but we don't know what that timestamp is.
int64_t playback_start_timestamp_ GUARDED_BY(lock_) = INT64_MIN;
// The PTS the playback should start at. We will drop audio pushed to us
// with PTS values below this value. If the audio doesn't have a starting
// PTS, then this value can be INT64_MIN, to play whatever audio is sent
// to us.
int64_t playback_start_pts_ GUARDED_BY(lock_) = INT64_MIN;
AudioResampler audio_resampler_ GUARDED_BY(lock_);
int remaining_silence_frames_ GUARDED_BY(lock_) = 0;
base::RepeatingClosure pcm_completion_task_; base::RepeatingClosure pcm_completion_task_;
base::RepeatingClosure eos_task_; base::RepeatingClosure eos_task_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment