Commit af6f4678 authored by hubbe's avatar hubbe Committed by Commit bot

Move common code and variables from audio/video sender to frame sender.

More cleanup to come.

BUG=406622

Review URL: https://codereview.chromium.org/514263002

Cr-Commit-Position: refs/heads/master@{#292496}
parent 99ae5386
...@@ -16,7 +16,6 @@ namespace cast { ...@@ -16,7 +16,6 @@ namespace cast {
namespace { namespace {
const int kNumAggressiveReportsSentAtStart = 100; const int kNumAggressiveReportsSentAtStart = 100;
const int kMinSchedulingDelayMs = 1;
// TODO(miu): This should be specified in AudioSenderConfig, but currently it is // TODO(miu): This should be specified in AudioSenderConfig, but currently it is
// fixed to 100 FPS (i.e., 10 ms per frame), and AudioEncoder assumes this as // fixed to 100 FPS (i.e., 10 ms per frame), and AudioEncoder assumes this as
...@@ -37,12 +36,8 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, ...@@ -37,12 +36,8 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
kAudioFrameRate * 2.0, // We lie to increase max outstanding frames. kAudioFrameRate * 2.0, // We lie to increase max outstanding frames.
audio_config.target_playout_delay), audio_config.target_playout_delay),
configured_encoder_bitrate_(audio_config.bitrate), configured_encoder_bitrate_(audio_config.bitrate),
num_aggressive_rtcp_reports_sent_(0),
last_sent_frame_id_(0),
latest_acked_frame_id_(0),
duplicate_ack_counter_(0),
cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED),
weak_factory_(this) { weak_factory_(this) {
cast_initialization_status_ = STATUS_AUDIO_UNINITIALIZED;
VLOG(1) << "max_unacked_frames " << max_unacked_frames_; VLOG(1) << "max_unacked_frames " << max_unacked_frames_;
DCHECK_GT(max_unacked_frames_, 0); DCHECK_GT(max_unacked_frames_, 0);
...@@ -76,7 +71,6 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, ...@@ -76,7 +71,6 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
base::Bind(&AudioSender::OnReceivedCastFeedback, base::Bind(&AudioSender::OnReceivedCastFeedback,
weak_factory_.GetWeakPtr()), weak_factory_.GetWeakPtr()),
base::Bind(&AudioSender::OnReceivedRtt, weak_factory_.GetWeakPtr())); base::Bind(&AudioSender::OnReceivedRtt, weak_factory_.GetWeakPtr()));
memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
} }
AudioSender::~AudioSender() {} AudioSender::~AudioSender() {}
...@@ -149,37 +143,6 @@ void AudioSender::SendEncodedAudioFrame( ...@@ -149,37 +143,6 @@ void AudioSender::SendEncodedAudioFrame(
transport_sender_->InsertCodedAudioFrame(*encoded_frame); transport_sender_->InsertCodedAudioFrame(*encoded_frame);
} }
void AudioSender::ScheduleNextResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
base::TimeDelta time_to_next =
last_send_time_ - cast_environment_->Clock()->NowTicks() +
target_playout_delay_;
time_to_next = std::max(
time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
cast_environment_->PostDelayedTask(
CastEnvironment::MAIN,
FROM_HERE,
base::Bind(&AudioSender::ResendCheck, weak_factory_.GetWeakPtr()),
time_to_next);
}
void AudioSender::ResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
const base::TimeDelta time_since_last_send =
cast_environment_->Clock()->NowTicks() - last_send_time_;
if (time_since_last_send > target_playout_delay_) {
if (latest_acked_frame_id_ == last_sent_frame_id_) {
// Last frame acked, no point in doing anything
} else {
VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_;
ResendForKickstart();
}
}
ScheduleNextResendCheck();
}
void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
...@@ -257,14 +220,5 @@ bool AudioSender::AreTooManyFramesInFlight() const { ...@@ -257,14 +220,5 @@ bool AudioSender::AreTooManyFramesInFlight() const {
return frames_in_flight >= max_unacked_frames_; return frames_in_flight >= max_unacked_frames_;
} }
void AudioSender::ResendForKickstart() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_
<< " to kick-start.";
last_send_time_ = cast_environment_->Clock()->NowTicks();
transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_);
}
} // namespace cast } // namespace cast
} // namespace media } // namespace media
...@@ -55,15 +55,6 @@ class AudioSender : public FrameSender, ...@@ -55,15 +55,6 @@ class AudioSender : public FrameSender,
void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback); void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback);
private: private:
// Schedule and execute periodic checks for re-sending packets. If no
// acknowledgements have been received for "too long," AudioSender will
// speculatively re-send certain packets of an unacked frame to kick-start
// re-transmission. This is a last resort tactic to prevent the session from
// getting stuck after a long outage.
void ScheduleNextResendCheck();
void ResendCheck();
void ResendForKickstart();
// Returns true if there are too many frames in flight, as defined by the // Returns true if there are too many frames in flight, as defined by the
// configured target playout delay plus simple logic. When this is true, // configured target playout delay plus simple logic. When this is true,
// InsertAudio() will silenty drop frames instead of sending them to the audio // InsertAudio() will silenty drop frames instead of sending them to the audio
...@@ -77,39 +68,6 @@ class AudioSender : public FrameSender, ...@@ -77,39 +68,6 @@ class AudioSender : public FrameSender,
scoped_ptr<AudioEncoder> audio_encoder_; scoped_ptr<AudioEncoder> audio_encoder_;
const int configured_encoder_bitrate_; const int configured_encoder_bitrate_;
// Counts how many RTCP reports are being "aggressively" sent (i.e., one per
// frame) at the start of the session. Once a threshold is reached, RTCP
// reports are instead sent at the configured interval + random drift.
int num_aggressive_rtcp_reports_sent_;
// This is "null" until the first frame is sent. Thereafter, this tracks the
// last time any frame was sent or re-sent.
base::TimeTicks last_send_time_;
// The ID of the last frame sent. Logic throughout AudioSender assumes this
// can safely wrap-around. This member is invalid until
// |!last_send_time_.is_null()|.
uint32 last_sent_frame_id_;
// The ID of the latest (not necessarily the last) frame that has been
// acknowledged. Logic throughout AudioSender assumes this can safely
// wrap-around. This member is invalid until |!last_send_time_.is_null()|.
uint32 latest_acked_frame_id_;
// Counts the number of duplicate ACK that are being received. When this
// number reaches a threshold, the sender will take this as a sign that the
// receiver hasn't yet received the first packet of the next frame. In this
// case, AudioSender will trigger a re-send of the next frame.
int duplicate_ack_counter_;
// If this sender is ready for use, this is STATUS_AUDIO_INITIALIZED.
CastInitializationStatus cast_initialization_status_;
// This is a "good enough" mapping for finding the RTP timestamp associated
// with a video frame. The key is the lowest 8 bits of frame id (which is
// what is sent via RTCP). This map is used for logging purposes.
RtpTimestamp frame_id_to_rtp_timestamp_[256];
// NOTE: Weak pointers must be invalidated before all other member variables. // NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<AudioSender> weak_factory_; base::WeakPtrFactory<AudioSender> weak_factory_;
......
...@@ -24,9 +24,14 @@ FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, ...@@ -24,9 +24,14 @@ FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment,
rtt_available_(false), rtt_available_(false),
rtcp_interval_(rtcp_interval), rtcp_interval_(rtcp_interval),
max_frame_rate_(max_frame_rate), max_frame_rate_(max_frame_rate),
num_aggressive_rtcp_reports_sent_(0),
last_sent_frame_id_(0),
latest_acked_frame_id_(0),
duplicate_ack_counter_(0),
weak_factory_(this) { weak_factory_(this) {
SetTargetPlayoutDelay(playout_delay); SetTargetPlayoutDelay(playout_delay);
send_target_playout_delay_ = false; send_target_playout_delay_ = false;
memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
} }
FrameSender::~FrameSender() { FrameSender::~FrameSender() {
...@@ -84,5 +89,45 @@ void FrameSender::SetTargetPlayoutDelay( ...@@ -84,5 +89,45 @@ void FrameSender::SetTargetPlayoutDelay(
send_target_playout_delay_ = true; send_target_playout_delay_ = true;
} }
void FrameSender::ResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
const base::TimeDelta time_since_last_send =
cast_environment_->Clock()->NowTicks() - last_send_time_;
if (time_since_last_send > target_playout_delay_) {
if (latest_acked_frame_id_ == last_sent_frame_id_) {
// Last frame acked, no point in doing anything
} else {
VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_;
ResendForKickstart();
}
}
ScheduleNextResendCheck();
}
void FrameSender::ScheduleNextResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
base::TimeDelta time_to_next =
last_send_time_ - cast_environment_->Clock()->NowTicks() +
target_playout_delay_;
time_to_next = std::max(
time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
cast_environment_->PostDelayedTask(
CastEnvironment::MAIN,
FROM_HERE,
base::Bind(&FrameSender::ResendCheck, weak_factory_.GetWeakPtr()),
time_to_next);
}
void FrameSender::ResendForKickstart() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_
<< " to kick-start.";
last_send_time_ = cast_environment_->Clock()->NowTicks();
transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_);
}
} // namespace cast } // namespace cast
} // namespace media } // namespace media
...@@ -74,6 +74,15 @@ class FrameSender { ...@@ -74,6 +74,15 @@ class FrameSender {
base::TimeDelta max_rtt_; base::TimeDelta max_rtt_;
protected: protected:
// Schedule and execute periodic checks for re-sending packets. If no
// acknowledgements have been received for "too long," AudioSender will
// speculatively re-send certain packets of an unacked frame to kick-start
// re-transmission. This is a last resort tactic to prevent the session from
// getting stuck after a long outage.
void ScheduleNextResendCheck();
void ResendCheck();
void ResendForKickstart();
const base::TimeDelta rtcp_interval_; const base::TimeDelta rtcp_interval_;
// The total amount of time between a frame's capture/recording on the sender // The total amount of time between a frame's capture/recording on the sender
...@@ -94,6 +103,40 @@ class FrameSender { ...@@ -94,6 +103,40 @@ class FrameSender {
// new frames shall halt. // new frames shall halt.
int max_unacked_frames_; int max_unacked_frames_;
// Counts how many RTCP reports are being "aggressively" sent (i.e., one per
// frame) at the start of the session. Once a threshold is reached, RTCP
// reports are instead sent at the configured interval + random drift.
int num_aggressive_rtcp_reports_sent_;
// This is "null" until the first frame is sent. Thereafter, this tracks the
// last time any frame was sent or re-sent.
base::TimeTicks last_send_time_;
// The ID of the last frame sent. Logic throughout AudioSender assumes this
// can safely wrap-around. This member is invalid until
// |!last_send_time_.is_null()|.
uint32 last_sent_frame_id_;
// The ID of the latest (not necessarily the last) frame that has been
// acknowledged. Logic throughout AudioSender assumes this can safely
// wrap-around. This member is invalid until |!last_send_time_.is_null()|.
uint32 latest_acked_frame_id_;
// Counts the number of duplicate ACK that are being received. When this
// number reaches a threshold, the sender will take this as a sign that the
// receiver hasn't yet received the first packet of the next frame. In this
// case, VideoSender will trigger a re-send of the next frame.
int duplicate_ack_counter_;
// If this sender is ready for use, this is STATUS_AUDIO_INITIALIZED or
// STATUS_VIDEO_INITIALIZED.
CastInitializationStatus cast_initialization_status_;
// This is a "good enough" mapping for finding the RTP timestamp associated
// with a video frame. The key is the lowest 8 bits of frame id (which is
// what is sent via RTCP). This map is used for logging purposes.
RtpTimestamp frame_id_to_rtp_timestamp_[256];
private: private:
// NOTE: Weak pointers must be invalidated before all other member variables. // NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<FrameSender> weak_factory_; base::WeakPtrFactory<FrameSender> weak_factory_;
......
...@@ -20,7 +20,6 @@ namespace media { ...@@ -20,7 +20,6 @@ namespace media {
namespace cast { namespace cast {
const int kNumAggressiveReportsSentAtStart = 100; const int kNumAggressiveReportsSentAtStart = 100;
const int kMinSchedulingDelayMs = 1;
namespace { namespace {
...@@ -51,17 +50,13 @@ VideoSender::VideoSender( ...@@ -51,17 +50,13 @@ VideoSender::VideoSender(
video_config.max_frame_rate, video_config.max_frame_rate,
video_config.target_playout_delay), video_config.target_playout_delay),
fixed_bitrate_(GetFixedBitrate(video_config)), fixed_bitrate_(GetFixedBitrate(video_config)),
num_aggressive_rtcp_reports_sent_(0),
frames_in_encoder_(0), frames_in_encoder_(0),
last_sent_frame_id_(0),
latest_acked_frame_id_(0),
duplicate_ack_counter_(0),
congestion_control_(cast_environment->Clock(), congestion_control_(cast_environment->Clock(),
video_config.max_bitrate, video_config.max_bitrate,
video_config.min_bitrate, video_config.min_bitrate,
max_unacked_frames_), max_unacked_frames_),
cast_initialization_status_(STATUS_VIDEO_UNINITIALIZED),
weak_factory_(this) { weak_factory_(this) {
cast_initialization_status_ = STATUS_VIDEO_UNINITIALIZED;
VLOG(1) << "max_unacked_frames is " << max_unacked_frames_ VLOG(1) << "max_unacked_frames is " << max_unacked_frames_
<< " for target_playout_delay=" << " for target_playout_delay="
<< target_playout_delay_.InMilliseconds() << " ms" << target_playout_delay_.InMilliseconds() << " ms"
...@@ -92,8 +87,6 @@ VideoSender::VideoSender( ...@@ -92,8 +87,6 @@ VideoSender::VideoSender(
base::Bind(&VideoSender::OnReceivedCastFeedback, base::Bind(&VideoSender::OnReceivedCastFeedback,
weak_factory_.GetWeakPtr()), weak_factory_.GetWeakPtr()),
base::Bind(&VideoSender::OnReceivedRtt, weak_factory_.GetWeakPtr())); base::Bind(&VideoSender::OnReceivedRtt, weak_factory_.GetWeakPtr()));
memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
} }
VideoSender::~VideoSender() { VideoSender::~VideoSender() {
...@@ -223,37 +216,6 @@ void VideoSender::SendEncodedVideoFrame( ...@@ -223,37 +216,6 @@ void VideoSender::SendEncodedVideoFrame(
transport_sender_->InsertCodedVideoFrame(*encoded_frame); transport_sender_->InsertCodedVideoFrame(*encoded_frame);
} }
void VideoSender::ResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
const base::TimeDelta time_since_last_send =
cast_environment_->Clock()->NowTicks() - last_send_time_;
if (time_since_last_send > target_playout_delay_) {
if (latest_acked_frame_id_ == last_sent_frame_id_) {
// Last frame acked, no point in doing anything
} else {
VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_;
ResendForKickstart();
}
}
ScheduleNextResendCheck();
}
void VideoSender::ScheduleNextResendCheck() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
base::TimeDelta time_to_next =
last_send_time_ - cast_environment_->Clock()->NowTicks() +
target_playout_delay_;
time_to_next = std::max(
time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
cast_environment_->PostDelayedTask(
CastEnvironment::MAIN,
FROM_HERE,
base::Bind(&VideoSender::ResendCheck, weak_factory_.GetWeakPtr()),
time_to_next);
}
void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { void VideoSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
...@@ -352,14 +314,5 @@ bool VideoSender::AreTooManyFramesInFlight() const { ...@@ -352,14 +314,5 @@ bool VideoSender::AreTooManyFramesInFlight() const {
return frames_in_flight >= max_unacked_frames_; return frames_in_flight >= max_unacked_frames_;
} }
void VideoSender::ResendForKickstart() {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!last_send_time_.is_null());
VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_
<< " to kick-start.";
last_send_time_ = cast_environment_->Clock()->NowTicks();
transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_);
}
} // namespace cast } // namespace cast
} // namespace media } // namespace media
...@@ -61,15 +61,6 @@ class VideoSender : public FrameSender, ...@@ -61,15 +61,6 @@ class VideoSender : public FrameSender,
void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback); void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback);
private: private:
// Schedule and execute periodic checks for re-sending packets. If no
// acknowledgements have been received for "too long," VideoSender will
// speculatively re-send certain packets of an unacked frame to kick-start
// re-transmission. This is a last resort tactic to prevent the session from
// getting stuck after a long outage.
void ScheduleNextResendCheck();
void ResendCheck();
void ResendForKickstart();
// Returns true if there are too many frames in flight, as defined by the // Returns true if there are too many frames in flight, as defined by the
// configured target playout delay plus simple logic. When this is true, // configured target playout delay plus simple logic. When this is true,
// InsertRawVideoFrame() will silenty drop frames instead of sending them to // InsertRawVideoFrame() will silenty drop frames instead of sending them to
...@@ -89,47 +80,14 @@ class VideoSender : public FrameSender, ...@@ -89,47 +80,14 @@ class VideoSender : public FrameSender,
// a hardware-based encoder. // a hardware-based encoder.
scoped_ptr<VideoEncoder> video_encoder_; scoped_ptr<VideoEncoder> video_encoder_;
// Counts how many RTCP reports are being "aggressively" sent (i.e., one per
// frame) at the start of the session. Once a threshold is reached, RTCP
// reports are instead sent at the configured interval + random drift.
int num_aggressive_rtcp_reports_sent_;
// The number of frames currently being processed in |video_encoder_|. // The number of frames currently being processed in |video_encoder_|.
int frames_in_encoder_; int frames_in_encoder_;
// This is "null" until the first frame is sent. Thereafter, this tracks the
// last time any frame was sent or re-sent.
base::TimeTicks last_send_time_;
// The ID of the last frame sent. Logic throughout VideoSender assumes this
// can safely wrap-around. This member is invalid until
// |!last_send_time_.is_null()|.
uint32 last_sent_frame_id_;
// The ID of the latest (not necessarily the last) frame that has been
// acknowledged. Logic throughout VideoSender assumes this can safely
// wrap-around. This member is invalid until |!last_send_time_.is_null()|.
uint32 latest_acked_frame_id_;
// Counts the number of duplicate ACK that are being received. When this
// number reaches a threshold, the sender will take this as a sign that the
// receiver hasn't yet received the first packet of the next frame. In this
// case, VideoSender will trigger a re-send of the next frame.
int duplicate_ack_counter_;
// When we get close to the max number of un-acked frames, we set lower // When we get close to the max number of un-acked frames, we set lower
// the bitrate drastically to ensure that we catch up. Without this we // the bitrate drastically to ensure that we catch up. Without this we
// risk getting stuck in a catch-up state forever. // risk getting stuck in a catch-up state forever.
CongestionControl congestion_control_; CongestionControl congestion_control_;
// If this sender is ready for use, this is STATUS_VIDEO_INITIALIZED.
CastInitializationStatus cast_initialization_status_;
// This is a "good enough" mapping for finding the RTP timestamp associated
// with a video frame. The key is the lowest 8 bits of frame id (which is
// what is sent via RTCP). This map is used for logging purposes.
RtpTimestamp frame_id_to_rtp_timestamp_[256];
// NOTE: Weak pointers must be invalidated before all other member variables. // NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<VideoSender> weak_factory_; base::WeakPtrFactory<VideoSender> weak_factory_;
......
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