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"
13 CastMessageBuilder::CastMessageBuilder(
14 base::TickClock
* clock
,
15 RtpPayloadFeedback
* incoming_payload_feedback
,
18 bool decoder_faster_than_max_frame_rate
,
19 int max_unacked_frames
)
21 cast_feedback_(incoming_payload_feedback
),
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()) {
40 last_update_time_
= clock_
->NowTicks();
43 if (!UpdateAckMessage(frame_id
)) {
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;
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
) {
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;
85 if (last_acked_frame_id_
== frame_id
) {
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();
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())
102 *time_to_send
= last_update_time_
+ base::TimeDelta::FromMilliseconds(
103 kCastMessageUpdateIntervalMs
);
107 void CastMessageBuilder::UpdateCastMessage() {
108 RtcpCastMessage
message(media_ssrc_
);
109 if (!UpdateCastMessageInternal(&message
))
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();
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
)) {
136 last_update_time_
= now
;
138 // Needed to cover when a frame is skipped.
139 UpdateAckMessage(last_acked_frame_id_
);
141 *message
= cast_msg_
;
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())
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
166 if (now
- it
->second
<
167 base::TimeDelta::FromMilliseconds(kNackRepeatIntervalMs
)) {
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
));
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
;