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"
12 CastMessageBuilder::CastMessageBuilder(
13 base::TickClock
* clock
,
14 RtpPayloadFeedback
* incoming_payload_feedback
,
15 FrameIdMap
* frame_id_map
,
17 bool decoder_faster_than_max_frame_rate
,
18 int max_unacked_frames
)
20 cast_feedback_(incoming_payload_feedback
),
21 frame_id_map_(frame_id_map
),
22 media_ssrc_(media_ssrc
),
23 decoder_faster_than_max_frame_rate_(decoder_faster_than_max_frame_rate
),
24 max_unacked_frames_(max_unacked_frames
),
25 cast_msg_(media_ssrc
),
26 slowing_down_ack_(false),
27 acked_last_frame_(true),
28 last_acked_frame_id_(kStartFrameId
) {
29 cast_msg_
.ack_frame_id
= kStartFrameId
;
32 CastMessageBuilder::~CastMessageBuilder() {}
34 void CastMessageBuilder::CompleteFrameReceived(uint32 frame_id
) {
35 DCHECK_GE(static_cast<int32
>(frame_id
- last_acked_frame_id_
), 0);
36 VLOG(2) << "CompleteFrameReceived: " << frame_id
;
37 if (last_update_time_
.is_null()) {
39 last_update_time_
= clock_
->NowTicks();
42 if (!UpdateAckMessage(frame_id
)) {
48 VLOG(2) << "Send cast message Ack:" << static_cast<int>(frame_id
);
49 cast_feedback_
->CastFeedback(cast_msg_
);
52 bool CastMessageBuilder::UpdateAckMessage(uint32 frame_id
) {
53 if (!decoder_faster_than_max_frame_rate_
) {
54 int complete_frame_count
= frame_id_map_
->NumberOfCompleteFrames();
55 if (complete_frame_count
> max_unacked_frames_
) {
56 // We have too many frames pending in our framer; slow down ACK.
57 if (!slowing_down_ack_
) {
58 slowing_down_ack_
= true;
59 ack_queue_
.push_back(last_acked_frame_id_
);
61 } else if (complete_frame_count
<= 1) {
62 // We are down to one or less frames in our framer; ACK normally.
63 slowing_down_ack_
= false;
68 if (slowing_down_ack_
) {
69 // We are slowing down acknowledgment by acknowledging every other frame.
70 // Note: frame skipping and slowdown ACK is not supported at the same
71 // time; and it's not needed since we can skip frames to catch up.
72 if (!ack_queue_
.empty() && ack_queue_
.back() == frame_id
) {
75 ack_queue_
.push_back(frame_id
);
76 if (!acked_last_frame_
) {
77 ack_queue_
.pop_front();
79 frame_id
= ack_queue_
.front();
82 acked_last_frame_
= false;
84 if (last_acked_frame_id_
== frame_id
) {
87 acked_last_frame_
= true;
88 last_acked_frame_id_
= frame_id
;
89 cast_msg_
.ack_frame_id
= last_acked_frame_id_
;
90 cast_msg_
.missing_frames_and_packets
.clear();
91 last_update_time_
= clock_
->NowTicks();
95 bool CastMessageBuilder::TimeToSendNextCastMessage(
96 base::TimeTicks
* time_to_send
) {
97 // We haven't received any packets.
98 if (last_update_time_
.is_null() && frame_id_map_
->Empty())
101 *time_to_send
= last_update_time_
+ base::TimeDelta::FromMilliseconds(
102 kCastMessageUpdateIntervalMs
);
106 void CastMessageBuilder::UpdateCastMessage() {
107 RtcpCastMessage
message(media_ssrc_
);
108 if (!UpdateCastMessageInternal(&message
))
111 // Send cast message.
112 cast_feedback_
->CastFeedback(message
);
115 void CastMessageBuilder::Reset() {
116 cast_msg_
.ack_frame_id
= kStartFrameId
;
117 cast_msg_
.missing_frames_and_packets
.clear();
118 time_last_nacked_map_
.clear();
121 bool CastMessageBuilder::UpdateCastMessageInternal(RtcpCastMessage
* message
) {
122 if (last_update_time_
.is_null()) {
123 if (!frame_id_map_
->Empty()) {
124 // We have received packets.
125 last_update_time_
= clock_
->NowTicks();
129 // Is it time to update the cast message?
130 base::TimeTicks now
= clock_
->NowTicks();
131 if (now
- last_update_time_
<
132 base::TimeDelta::FromMilliseconds(kCastMessageUpdateIntervalMs
)) {
135 last_update_time_
= now
;
137 // Needed to cover when a frame is skipped.
138 UpdateAckMessage(last_acked_frame_id_
);
140 *message
= cast_msg_
;
144 void CastMessageBuilder::BuildPacketList() {
145 base::TimeTicks now
= clock_
->NowTicks();
147 // Clear message NACK list.
148 cast_msg_
.missing_frames_and_packets
.clear();
150 // Are we missing packets?
151 if (frame_id_map_
->Empty())
154 uint32 newest_frame_id
= frame_id_map_
->NewestFrameId();
155 uint32 next_expected_frame_id
= cast_msg_
.ack_frame_id
+ 1;
157 // Iterate over all frames.
158 for (; !IsNewerFrameId(next_expected_frame_id
, newest_frame_id
);
159 ++next_expected_frame_id
) {
160 TimeLastNackMap::iterator it
=
161 time_last_nacked_map_
.find(next_expected_frame_id
);
162 if (it
!= time_last_nacked_map_
.end()) {
163 // We have sent a NACK in this frame before, make sure enough time have
165 if (now
- it
->second
<
166 base::TimeDelta::FromMilliseconds(kNackRepeatIntervalMs
)) {
172 if (frame_id_map_
->FrameExists(next_expected_frame_id
)) {
173 bool last_frame
= (newest_frame_id
== next_expected_frame_id
);
174 frame_id_map_
->GetMissingPackets(
175 next_expected_frame_id
, last_frame
, &missing
);
176 if (!missing
.empty()) {
177 time_last_nacked_map_
[next_expected_frame_id
] = now
;
178 cast_msg_
.missing_frames_and_packets
.insert(
179 std::make_pair(next_expected_frame_id
, missing
));
182 time_last_nacked_map_
[next_expected_frame_id
] = now
;
183 missing
.insert(kRtcpCastAllPacketsLost
);
184 cast_msg_
.missing_frames_and_packets
[next_expected_frame_id
] = missing
;