Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / media / cast / net / rtcp / rtcp_utility.cc
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.
4
5 #include "media/cast/net/rtcp/rtcp_utility.h"
6
7 #include "base/logging.h"
8 #include "media/cast/net/cast_transport_defines.h"
9
10 namespace media {
11 namespace cast {
12
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) {
20 }
21
22 RtcpParser::~RtcpParser() {}
23
24 bool RtcpParser::Parse(base::BigEndianReader* reader) {
25   while (reader->remaining()) {
26     RtcpCommonHeader header;
27     if (!ParseCommonHeader(reader, &header))
28       return false;
29
30     base::StringPiece tmp;
31     if (!reader->ReadPiece(&tmp, header.length_in_octets - 4))
32       return false;
33     base::BigEndianReader chunk(tmp.data(), tmp.size());
34
35     switch (header.PT) {
36       case kPacketTypeSenderReport:
37         if (!ParseSR(&chunk, header))
38           return false;
39         break;
40
41       case kPacketTypeReceiverReport:
42         if (!ParseRR(&chunk, header))
43           return false;
44         break;
45
46       case kPacketTypeApplicationDefined:
47         if (!ParseApplicationDefined(&chunk, header))
48           return false;
49         break;
50
51       case kPacketTypePayloadSpecific:
52         if (!ParseFeedbackCommon(&chunk, header))
53           return false;
54         break;
55
56       case kPacketTypeXr:
57         if (!ParseExtendedReport(&chunk, header))
58           return false;
59         break;
60     }
61   }
62   return true;
63 }
64
65 bool RtcpParser::ParseCommonHeader(base::BigEndianReader* reader,
66                                    RtcpCommonHeader* parsed_header) {
67   //  0                   1                   2                   3
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   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72   //
73   // Common header for all Rtcp packets, 4 octets.
74
75   uint8 byte;
76   if (!reader->ReadU8(&byte))
77     return false;
78   parsed_header->V = byte >> 6;
79   parsed_header->P = ((byte & 0x20) == 0) ? false : true;
80
81   // Check if RTP version field == 2.
82   if (parsed_header->V != 2)
83     return false;
84
85   parsed_header->IC = byte & 0x1f;
86   if (!reader->ReadU8(&parsed_header->PT))
87     return false;
88
89   uint16 bytes;
90   if (!reader->ReadU16(&bytes))
91     return false;
92
93   parsed_header->length_in_octets = (static_cast<size_t>(bytes) + 1) * 4;
94
95   if (parsed_header->length_in_octets == 0)
96     return false;
97
98   return true;
99 }
100
101 bool RtcpParser::ParseSR(base::BigEndianReader* reader,
102                          const RtcpCommonHeader& header) {
103   uint32 sender_ssrc;
104   if (!reader->ReadU32(&sender_ssrc))
105     return false;
106
107   if (sender_ssrc != remote_ssrc_)
108     return true;
109
110   uint32 tmp;
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))
116     return false;
117   sender_report_.send_octet_count = tmp;
118   has_sender_report_ = true;
119
120   for (size_t block = 0; block < header.IC; block++)
121     if (!ParseReportBlock(reader))
122       return false;
123
124   return true;
125 }
126
127 bool RtcpParser::ParseRR(base::BigEndianReader* reader,
128                          const RtcpCommonHeader& header) {
129   uint32 receiver_ssrc;
130   if (!reader->ReadU32(&receiver_ssrc))
131     return false;
132
133   if (receiver_ssrc != remote_ssrc_)
134     return true;
135
136   for (size_t block = 0; block < header.IC; block++)
137     if (!ParseReportBlock(reader))
138       return false;
139
140   return true;
141 }
142
143 bool RtcpParser::ParseReportBlock(base::BigEndianReader* reader) {
144   uint32 ssrc, last_report, delay;
145   if (!reader->ReadU32(&ssrc) ||
146       !reader->Skip(12) ||
147       !reader->ReadU32(&last_report) ||
148       !reader->ReadU32(&delay))
149     return false;
150
151   if (ssrc == local_ssrc_) {
152     last_report_ = last_report;
153     delay_since_last_report_ = delay;
154     has_last_report_ = true;
155   }
156
157   return true;
158 }
159
160 bool RtcpParser::ParseApplicationDefined(base::BigEndianReader* reader,
161                                          const RtcpCommonHeader& header) {
162   uint32 sender_ssrc;
163   uint32 name;
164   if (!reader->ReadU32(&sender_ssrc) ||
165       !reader->ReadU32(&name))
166     return false;
167
168   if (sender_ssrc != remote_ssrc_)
169     return true;
170
171   if (name != kCast)
172     return false;
173
174   switch (header.IC /* subtype */ ) {
175     case kReceiverLogSubtype:
176       if (!ParseCastReceiverLogFrameItem(reader))
177         return false;
178       break;
179   }
180   return true;
181 }
182
183 bool RtcpParser::ParseCastReceiverLogFrameItem(
184     base::BigEndianReader* reader) {
185
186   while (reader->remaining()) {
187     uint32 rtp_timestamp;
188     uint32 data;
189     if (!reader->ReadU32(&rtp_timestamp) ||
190         !reader->ReadU32(&data))
191       return false;
192
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);
196
197     size_t num_events = 1 + static_cast<uint8>(data >> 24);
198
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))
205         return false;
206
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;
216       } else {
217         event_log.delay_delta = base::TimeDelta::FromMilliseconds(
218             static_cast<int16>(delay_delta_or_packet_id));
219       }
220       frame_log.event_log_messages_.push_back(event_log);
221     }
222
223     receiver_log_.push_back(frame_log);
224   }
225
226   return true;
227 }
228
229 // RFC 4585.
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) {
234     return true;
235   }
236   uint32 remote_ssrc;
237   uint32 media_ssrc;
238   if (!reader->ReadU32(&remote_ssrc) ||
239       !reader->ReadU32(&media_ssrc))
240     return false;
241
242   if (remote_ssrc != remote_ssrc_)
243     return true;
244
245   uint32 name;
246   if (!reader->ReadU32(&name))
247     return false;
248
249   if (name != kCast) {
250     return true;
251   }
252
253   cast_message_.media_ssrc = remote_ssrc;
254
255   uint8 last_frame_id;
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))
260     return false;
261
262   // Please note, this frame_id is still only 8-bit!
263   cast_message_.ack_frame_id = last_frame_id;
264
265   for (size_t i = 0; i < number_of_lost_fields; i++) {
266     uint8 frame_id;
267     uint16 packet_id;
268     uint8 bitmask;
269     if (!reader->ReadU8(&frame_id) ||
270         !reader->ReadU16(&packet_id) ||
271         !reader->ReadU8(&bitmask))
272       return false;
273     cast_message_.missing_frames_and_packets[frame_id].insert(packet_id);
274     if (packet_id != kRtcpCastAllPacketsLost) {
275       while (bitmask) {
276         packet_id++;
277         if (bitmask & 1)
278           cast_message_.missing_frames_and_packets[frame_id].insert(packet_id);
279         bitmask >>= 1;
280       }
281     }
282   }
283
284   has_cast_message_ = true;
285   return true;
286 }
287
288 bool RtcpParser::ParseExtendedReport(base::BigEndianReader* reader,
289                                      const RtcpCommonHeader& header) {
290   uint32 remote_ssrc;
291   if (!reader->ReadU32(&remote_ssrc))
292     return false;
293
294   // Is it for us?
295   if (remote_ssrc != remote_ssrc_)
296     return true;
297
298   while (reader->remaining()) {
299     uint8 block_type;
300     uint16 block_length;
301     if (!reader->ReadU8(&block_type) ||
302         !reader->Skip(1) ||
303         !reader->ReadU16(&block_length))
304       return false;
305
306     switch (block_type) {
307       case 4:  // RRTR. RFC3611 Section 4.4.
308         if (block_length != 2)
309           return false;
310         if (!ParseExtendedReportReceiverReferenceTimeReport(reader,
311                                                             remote_ssrc))
312           return false;
313         break;
314
315       default:
316         // Skip unknown item.
317         if (!reader->Skip(block_length * 4))
318           return false;
319     }
320   }
321
322   return true;
323 }
324
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))
331     return false;
332
333   has_receiver_reference_time_report_ = true;
334   return true;
335 }
336
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) {
341   switch (event) {
342     case FRAME_ACK_SENT:
343       return 11;
344     case FRAME_PLAYOUT:
345       return 12;
346     case FRAME_DECODED:
347       return 13;
348     case PACKET_RECEIVED:
349       return 14;
350     default:
351       return 0;  // Not an interesting event.
352   }
353 }
354
355 CastLoggingEvent TranslateToLogEventFromWireFormat(uint8 event) {
356   // TODO(imcheng): Remove the old mappings once they are no longer used.
357   switch (event) {
358     case 1:  // AudioAckSent
359     case 5:  // VideoAckSent
360     case 11:  // Unified
361       return FRAME_ACK_SENT;
362     case 2:  // AudioPlayoutDelay
363     case 7:  // VideoRenderDelay
364     case 12:  // Unified
365       return FRAME_PLAYOUT;
366     case 3:  // AudioFrameDecoded
367     case 6:  // VideoFrameDecoded
368     case 13:  // Unified
369       return FRAME_DECODED;
370     case 4:  // AudioPacketReceived
371     case 8:  // VideoPacketReceived
372     case 14:  // Unified
373       return PACKET_RECEIVED;
374     case 9:  // DuplicateAudioPacketReceived
375     case 10:  // DuplicateVideoPacketReceived
376     default:
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);
380       return UNKNOWN;
381   }
382 }
383
384 }  // namespace cast
385 }  // namespace media