Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / cast / net / rtp / cast_message_builder.cc
blob3d1d7a774872c330d489bd7e7d949a8ade073bba
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/net/rtp/cast_message_builder.h"
7 #include "media/cast/cast_defines.h"
8 #include "media/cast/net/rtp/framer.h"
10 namespace media {
11 namespace cast {
13 CastMessageBuilder::CastMessageBuilder(
14 base::TickClock* clock,
15 RtpPayloadFeedback* incoming_payload_feedback,
16 const Framer* framer,
17 uint32 media_ssrc,
18 bool decoder_faster_than_max_frame_rate,
19 int max_unacked_frames)
20 : clock_(clock),
21 cast_feedback_(incoming_payload_feedback),
22 framer_(framer),
23 media_ssrc_(media_ssrc),
24 decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate),
25 max_unacked_frames_(max_unacked_frames),
26 cast_msg_(media_ssrc),
27 slowing_down_ack_(false),
28 acked_last_frame_(true),
29 last_acked_frame_id_(kStartFrameId) {
30 cast_msg_.ack_frame_id = kStartFrameId;
33 CastMessageBuilder::~CastMessageBuilder() {}
35 void CastMessageBuilder::CompleteFrameReceived(uint32 frame_id) {
36 DCHECK_GE(static_cast<int32>(frame_id - last_acked_frame_id_), 0);
37 VLOG(2) << "CompleteFrameReceived: " << frame_id;
38 if (last_update_time_.is_null()) {
39 // Our first update.
40 last_update_time_ = clock_->NowTicks();
43 if (!UpdateAckMessage(frame_id)) {
44 return;
46 BuildPacketList();
48 // Send cast message.
49 VLOG(2) << "Send cast message Ack:" << static_cast<int>(frame_id);
50 cast_feedback_->CastFeedback(cast_msg_);
53 bool CastMessageBuilder::UpdateAckMessage(uint32 frame_id) {
54 if (!decoder_faster_than_max_frame_rate_) {
55 int complete_frame_count = framer_->NumberOfCompleteFrames();
56 if (complete_frame_count > max_unacked_frames_) {
57 // We have too many frames pending in our framer; slow down ACK.
58 if (!slowing_down_ack_) {
59 slowing_down_ack_ = true;
60 ack_queue_.push_back(last_acked_frame_id_);
62 } else if (complete_frame_count <= 1) {
63 // We are down to one or less frames in our framer; ACK normally.
64 slowing_down_ack_ = false;
65 ack_queue_.clear();
69 if (slowing_down_ack_) {
70 // We are slowing down acknowledgment by acknowledging every other frame.
71 // Note: frame skipping and slowdown ACK is not supported at the same
72 // time; and it's not needed since we can skip frames to catch up.
73 if (!ack_queue_.empty() && ack_queue_.back() == frame_id) {
74 return false;
76 ack_queue_.push_back(frame_id);
77 if (!acked_last_frame_) {
78 ack_queue_.pop_front();
80 frame_id = ack_queue_.front();
83 acked_last_frame_ = false;
84 // Is it a new frame?
85 if (last_acked_frame_id_ == frame_id) {
86 return false;
88 acked_last_frame_ = true;
89 last_acked_frame_id_ = frame_id;
90 cast_msg_.ack_frame_id = last_acked_frame_id_;
91 cast_msg_.missing_frames_and_packets.clear();
92 last_update_time_ = clock_->NowTicks();
93 return true;
96 bool CastMessageBuilder::TimeToSendNextCastMessage(
97 base::TimeTicks* time_to_send) {
98 // We haven't received any packets.
99 if (last_update_time_.is_null() && framer_->Empty())
100 return false;
102 *time_to_send = last_update_time_ + base::TimeDelta::FromMilliseconds(
103 kCastMessageUpdateIntervalMs);
104 return true;
107 void CastMessageBuilder::UpdateCastMessage() {
108 RtcpCastMessage message(media_ssrc_);
109 if (!UpdateCastMessageInternal(&message))
110 return;
112 // Send cast message.
113 cast_feedback_->CastFeedback(message);
116 void CastMessageBuilder::Reset() {
117 cast_msg_.ack_frame_id = kStartFrameId;
118 cast_msg_.missing_frames_and_packets.clear();
119 time_last_nacked_map_.clear();
122 bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage* message) {
123 if (last_update_time_.is_null()) {
124 if (!framer_->Empty()) {
125 // We have received packets.
126 last_update_time_ = clock_->NowTicks();
128 return false;
130 // Is it time to update the cast message?
131 base::TimeTicks now = clock_->NowTicks();
132 if (now - last_update_time_ <
133 base::TimeDelta::FromMilliseconds(kCastMessageUpdateIntervalMs)) {
134 return false;
136 last_update_time_ = now;
138 // Needed to cover when a frame is skipped.
139 UpdateAckMessage(last_acked_frame_id_);
140 BuildPacketList();
141 *message = cast_msg_;
142 return true;
145 void CastMessageBuilder::BuildPacketList() {
146 base::TimeTicks now = clock_->NowTicks();
148 // Clear message NACK list.
149 cast_msg_.missing_frames_and_packets.clear();
151 // Are we missing packets?
152 if (framer_->Empty())
153 return;
155 uint32 newest_frame_id = framer_->NewestFrameId();
156 uint32 next_expected_frame_id = cast_msg_.ack_frame_id + 1;
158 // Iterate over all frames.
159 for (; !IsNewerFrameId(next_expected_frame_id, newest_frame_id);
160 ++next_expected_frame_id) {
161 TimeLastNackMap::iterator it =
162 time_last_nacked_map_.find(next_expected_frame_id);
163 if (it != time_last_nacked_map_.end()) {
164 // We have sent a NACK in this frame before, make sure enough time have
165 // passed.
166 if (now - it->second <
167 base::TimeDelta::FromMilliseconds(kNackRepeatIntervalMs)) {
168 continue;
172 PacketIdSet missing;
173 if (framer_->FrameExists(next_expected_frame_id)) {
174 bool last_frame = (newest_frame_id == next_expected_frame_id);
175 framer_->GetMissingPackets(
176 next_expected_frame_id, last_frame, &missing);
177 if (!missing.empty()) {
178 time_last_nacked_map_[next_expected_frame_id] = now;
179 cast_msg_.missing_frames_and_packets.insert(
180 std::make_pair(next_expected_frame_id, missing));
182 } else {
183 time_last_nacked_map_[next_expected_frame_id] = now;
184 missing.insert(kRtcpCastAllPacketsLost);
185 cast_msg_.missing_frames_and_packets[next_expected_frame_id] = missing;
190 } // namespace cast
191 } // namespace media