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/rtcp/rtcp_utility.h"
7 #include "base/logging.h"
8 #include "media/cast/net/cast_transport_defines.h"
13 RtcpParser::RtcpParser(uint32 local_ssrc
, uint32 remote_ssrc
) :
14 local_ssrc_(local_ssrc
),
15 remote_ssrc_(remote_ssrc
),
16 has_sender_report_(false),
17 has_last_report_(false),
18 has_cast_message_(false),
19 has_receiver_reference_time_report_(false) {
22 RtcpParser::~RtcpParser() {}
24 bool RtcpParser::Parse(base::BigEndianReader
* reader
) {
25 while (reader
->remaining()) {
26 RtcpCommonHeader header
;
27 if (!ParseCommonHeader(reader
, &header
))
30 base::StringPiece tmp
;
31 if (!reader
->ReadPiece(&tmp
, header
.length_in_octets
- 4))
33 base::BigEndianReader
chunk(tmp
.data(), tmp
.size());
36 case kPacketTypeSenderReport
:
37 if (!ParseSR(&chunk
, header
))
41 case kPacketTypeReceiverReport
:
42 if (!ParseRR(&chunk
, header
))
46 case kPacketTypeApplicationDefined
:
47 if (!ParseApplicationDefined(&chunk
, header
))
51 case kPacketTypePayloadSpecific
:
52 if (!ParseFeedbackCommon(&chunk
, header
))
57 if (!ParseExtendedReport(&chunk
, header
))
65 bool RtcpParser::ParseCommonHeader(base::BigEndianReader
* reader
,
66 RtcpCommonHeader
* parsed_header
) {
68 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
69 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 // |V=2|P| IC | PT | length |
71 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 // Common header for all Rtcp packets, 4 octets.
76 if (!reader
->ReadU8(&byte
))
78 parsed_header
->V
= byte
>> 6;
79 parsed_header
->P
= ((byte
& 0x20) == 0) ? false : true;
81 // Check if RTP version field == 2.
82 if (parsed_header
->V
!= 2)
85 parsed_header
->IC
= byte
& 0x1f;
86 if (!reader
->ReadU8(&parsed_header
->PT
))
90 if (!reader
->ReadU16(&bytes
))
93 parsed_header
->length_in_octets
= (static_cast<size_t>(bytes
) + 1) * 4;
95 if (parsed_header
->length_in_octets
== 0)
101 bool RtcpParser::ParseSR(base::BigEndianReader
* reader
,
102 const RtcpCommonHeader
& header
) {
104 if (!reader
->ReadU32(&sender_ssrc
))
107 if (sender_ssrc
!= remote_ssrc_
)
111 if (!reader
->ReadU32(&sender_report_
.ntp_seconds
) ||
112 !reader
->ReadU32(&sender_report_
.ntp_fraction
) ||
113 !reader
->ReadU32(&sender_report_
.rtp_timestamp
) ||
114 !reader
->ReadU32(&sender_report_
.send_packet_count
) ||
115 !reader
->ReadU32(&tmp
))
117 sender_report_
.send_octet_count
= tmp
;
118 has_sender_report_
= true;
120 for (size_t block
= 0; block
< header
.IC
; block
++)
121 if (!ParseReportBlock(reader
))
127 bool RtcpParser::ParseRR(base::BigEndianReader
* reader
,
128 const RtcpCommonHeader
& header
) {
129 uint32 receiver_ssrc
;
130 if (!reader
->ReadU32(&receiver_ssrc
))
133 if (receiver_ssrc
!= remote_ssrc_
)
136 for (size_t block
= 0; block
< header
.IC
; block
++)
137 if (!ParseReportBlock(reader
))
143 bool RtcpParser::ParseReportBlock(base::BigEndianReader
* reader
) {
144 uint32 ssrc
, last_report
, delay
;
145 if (!reader
->ReadU32(&ssrc
) ||
147 !reader
->ReadU32(&last_report
) ||
148 !reader
->ReadU32(&delay
))
151 if (ssrc
== local_ssrc_
) {
152 last_report_
= last_report
;
153 delay_since_last_report_
= delay
;
154 has_last_report_
= true;
160 bool RtcpParser::ParseApplicationDefined(base::BigEndianReader
* reader
,
161 const RtcpCommonHeader
& header
) {
164 if (!reader
->ReadU32(&sender_ssrc
) ||
165 !reader
->ReadU32(&name
))
168 if (sender_ssrc
!= remote_ssrc_
)
174 switch (header
.IC
/* subtype */ ) {
175 case kReceiverLogSubtype
:
176 if (!ParseCastReceiverLogFrameItem(reader
))
183 bool RtcpParser::ParseCastReceiverLogFrameItem(
184 base::BigEndianReader
* reader
) {
186 while (reader
->remaining()) {
187 uint32 rtp_timestamp
;
189 if (!reader
->ReadU32(&rtp_timestamp
) ||
190 !reader
->ReadU32(&data
))
193 // We have 24 LSB of the event timestamp base on the wire.
194 base::TimeTicks event_timestamp_base
= base::TimeTicks() +
195 base::TimeDelta::FromMilliseconds(data
& 0xffffff);
197 size_t num_events
= 1 + static_cast<uint8
>(data
>> 24);
199 RtcpReceiverFrameLogMessage
frame_log(rtp_timestamp
);
200 for (size_t event
= 0; event
< num_events
; event
++) {
201 uint16 delay_delta_or_packet_id
;
202 uint16 event_type_and_timestamp_delta
;
203 if (!reader
->ReadU16(&delay_delta_or_packet_id
) ||
204 !reader
->ReadU16(&event_type_and_timestamp_delta
))
207 RtcpReceiverEventLogMessage event_log
;
208 event_log
.type
= TranslateToLogEventFromWireFormat(
209 static_cast<uint8
>(event_type_and_timestamp_delta
>> 12));
210 event_log
.event_timestamp
=
211 event_timestamp_base
+
212 base::TimeDelta::FromMilliseconds(
213 event_type_and_timestamp_delta
& 0xfff);
214 if (event_log
.type
== PACKET_RECEIVED
) {
215 event_log
.packet_id
= delay_delta_or_packet_id
;
217 event_log
.delay_delta
= base::TimeDelta::FromMilliseconds(
218 static_cast<int16
>(delay_delta_or_packet_id
));
220 frame_log
.event_log_messages_
.push_back(event_log
);
223 receiver_log_
.push_back(frame_log
);
230 bool RtcpParser::ParseFeedbackCommon(base::BigEndianReader
* reader
,
231 const RtcpCommonHeader
& header
) {
232 // See RTC 4585 Section 6.4 for application specific feedback messages.
233 if (header
.IC
!= 15) {
238 if (!reader
->ReadU32(&remote_ssrc
) ||
239 !reader
->ReadU32(&media_ssrc
))
242 if (remote_ssrc
!= remote_ssrc_
)
246 if (!reader
->ReadU32(&name
))
253 cast_message_
.media_ssrc
= remote_ssrc
;
256 uint8 number_of_lost_fields
;
257 if (!reader
->ReadU8(&last_frame_id
) ||
258 !reader
->ReadU8(&number_of_lost_fields
) ||
259 !reader
->ReadU16(&cast_message_
.target_delay_ms
))
262 // Please note, this frame_id is still only 8-bit!
263 cast_message_
.ack_frame_id
= last_frame_id
;
265 for (size_t i
= 0; i
< number_of_lost_fields
; i
++) {
269 if (!reader
->ReadU8(&frame_id
) ||
270 !reader
->ReadU16(&packet_id
) ||
271 !reader
->ReadU8(&bitmask
))
273 cast_message_
.missing_frames_and_packets
[frame_id
].insert(packet_id
);
274 if (packet_id
!= kRtcpCastAllPacketsLost
) {
278 cast_message_
.missing_frames_and_packets
[frame_id
].insert(packet_id
);
284 has_cast_message_
= true;
288 bool RtcpParser::ParseExtendedReport(base::BigEndianReader
* reader
,
289 const RtcpCommonHeader
& header
) {
291 if (!reader
->ReadU32(&remote_ssrc
))
295 if (remote_ssrc
!= remote_ssrc_
)
298 while (reader
->remaining()) {
301 if (!reader
->ReadU8(&block_type
) ||
303 !reader
->ReadU16(&block_length
))
306 switch (block_type
) {
307 case 4: // RRTR. RFC3611 Section 4.4.
308 if (block_length
!= 2)
310 if (!ParseExtendedReportReceiverReferenceTimeReport(reader
,
316 // Skip unknown item.
317 if (!reader
->Skip(block_length
* 4))
325 bool RtcpParser::ParseExtendedReportReceiverReferenceTimeReport(
326 base::BigEndianReader
* reader
,
327 uint32 remote_ssrc
) {
328 receiver_reference_time_report_
.remote_ssrc
= remote_ssrc
;
329 if(!reader
->ReadU32(&receiver_reference_time_report_
.ntp_seconds
) ||
330 !reader
->ReadU32(&receiver_reference_time_report_
.ntp_fraction
))
333 has_receiver_reference_time_report_
= true;
337 // Converts a log event type to an integer value.
338 // NOTE: We have only allocated 4 bits to represent the type of event over the
339 // wire. Therefore, this function can only return values from 0 to 15.
340 uint8
ConvertEventTypeToWireFormat(CastLoggingEvent event
) {
348 case PACKET_RECEIVED
:
351 return 0; // Not an interesting event.
355 CastLoggingEvent
TranslateToLogEventFromWireFormat(uint8 event
) {
356 // TODO(imcheng): Remove the old mappings once they are no longer used.
358 case 1: // AudioAckSent
359 case 5: // VideoAckSent
361 return FRAME_ACK_SENT
;
362 case 2: // AudioPlayoutDelay
363 case 7: // VideoRenderDelay
365 return FRAME_PLAYOUT
;
366 case 3: // AudioFrameDecoded
367 case 6: // VideoFrameDecoded
369 return FRAME_DECODED
;
370 case 4: // AudioPacketReceived
371 case 8: // VideoPacketReceived
373 return PACKET_RECEIVED
;
374 case 9: // DuplicateAudioPacketReceived
375 case 10: // DuplicateVideoPacketReceived
377 // If the sender adds new log messages we will end up here until we add
378 // the new messages in the receiver.
379 VLOG(1) << "Unexpected log message received: " << static_cast<int>(event
);