Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / media / cast / rtp_receiver / rtp_parser / rtp_parser.cc
index 31fae9a..d75696a 100644 (file)
 namespace media {
 namespace cast {
 
-static const size_t kRtpCommonHeaderLength = 12;
-static const size_t kRtpCastHeaderLength = 7;
+static const size_t kRtpHeaderLength = 12;
+static const size_t kCastHeaderLength = 7;
+static const uint8 kRtpExtensionBitMask = 0x10;
+static const uint8 kRtpMarkerBitMask = 0x80;
 static const uint8 kCastKeyFrameBitMask = 0x80;
 static const uint8 kCastReferenceFrameIdBitMask = 0x40;
 
-RtpParser::RtpParser(const RtpParserConfig parser_config)
-    : parser_config_(parser_config) {}
+RtpParser::RtpParser(uint32 expected_sender_ssrc, uint8 expected_payload_type)
+    : expected_sender_ssrc_(expected_sender_ssrc),
+      expected_payload_type_(expected_payload_type) {}
 
 RtpParser::~RtpParser() {}
 
 bool RtpParser::ParsePacket(const uint8* packet,
                             size_t length,
-                            RtpCastHeader* rtp_header) {
-  if (length == 0)
+                            RtpCastHeader* header,
+                            const uint8** payload_data,
+                            size_t* payload_size) {
+  DCHECK(packet);
+  DCHECK(header);
+  DCHECK(payload_data);
+  DCHECK(payload_size);
+
+  if (length < (kRtpHeaderLength + kCastHeaderLength))
     return false;
-  // Get RTP general header.
-  if (!ParseCommon(packet, length, rtp_header))
-    return false;
-  if (rtp_header->webrtc.header.payloadType == parser_config_.payload_type &&
-      rtp_header->webrtc.header.ssrc == parser_config_.ssrc) {
-    return ParseCast(packet + kRtpCommonHeaderLength,
-                     length - kRtpCommonHeaderLength,
-                     rtp_header);
-  }
-  // Not a valid payload type / ssrc combination.
-  return false;
-}
 
-bool RtpParser::ParseCommon(const uint8* packet,
-                            size_t length,
-                            RtpCastHeader* rtp_header) {
-  if (length < kRtpCommonHeaderLength)
+  base::BigEndianReader reader(reinterpret_cast<const char*>(packet), length);
+
+  // Parse the RTP header.  See
+  // http://en.wikipedia.org/wiki/Real-time_Transport_Protocol for an
+  // explanation of the standard RTP packet header.
+  uint8 bits;
+  if (!reader.ReadU8(&bits))
     return false;
-  uint8 version = packet[0] >> 6;
+  const uint8 version = bits >> 6;
   if (version != 2)
     return false;
-  uint8 cc = packet[0] & 0x0f;
-  bool marker = ((packet[1] & 0x80) != 0);
-  int payload_type = packet[1] & 0x7f;
-
-  uint16 sequence_number;
-  uint32 rtp_timestamp, ssrc;
-  base::BigEndianReader big_endian_reader(
-      reinterpret_cast<const char*>(packet + 2), 10);
-  big_endian_reader.ReadU16(&sequence_number);
-  big_endian_reader.ReadU32(&rtp_timestamp);
-  big_endian_reader.ReadU32(&ssrc);
-
-  if (ssrc != parser_config_.ssrc)
+  if (bits & kRtpExtensionBitMask)
+    return false;  // We lack the implementation to skip over an extension.
+  if (!reader.ReadU8(&bits))
     return false;
-
-  rtp_header->webrtc.header.markerBit = marker;
-  rtp_header->webrtc.header.payloadType = payload_type;
-  rtp_header->webrtc.header.sequenceNumber = sequence_number;
-  rtp_header->webrtc.header.timestamp = rtp_timestamp;
-  rtp_header->webrtc.header.ssrc = ssrc;
-  rtp_header->webrtc.header.numCSRCs = cc;
-
-  uint8 csrc_octs = cc * 4;
-  rtp_header->webrtc.type.Audio.numEnergy = rtp_header->webrtc.header.numCSRCs;
-  rtp_header->webrtc.header.headerLength = kRtpCommonHeaderLength + csrc_octs;
-  rtp_header->webrtc.type.Audio.isCNG = false;
-  rtp_header->webrtc.type.Audio.channel = parser_config_.audio_channels;
-  // TODO(pwestin): look at x bit and skip data.
-  return true;
-}
-
-bool RtpParser::ParseCast(const uint8* packet,
-                          size_t length,
-                          RtpCastHeader* rtp_header) {
-  if (length < kRtpCastHeaderLength)
+  header->marker = !!(bits & kRtpMarkerBitMask);
+  header->payload_type = bits & ~kRtpMarkerBitMask;
+  if (header->payload_type != expected_payload_type_)
+    return false;  // Punt: Unexpected payload type.
+  if (!reader.ReadU16(&header->sequence_number) ||
+      !reader.ReadU32(&header->rtp_timestamp) ||
+      !reader.ReadU32(&header->sender_ssrc)) {
     return false;
-
-  // Extract header.
-  const uint8* data_ptr = packet;
-  size_t data_length = length;
-  rtp_header->is_key_frame = (data_ptr[0] & kCastKeyFrameBitMask);
-  rtp_header->is_reference = (data_ptr[0] & kCastReferenceFrameIdBitMask);
-  rtp_header->frame_id = frame_id_wrap_helper_.MapTo32bitsFrameId(data_ptr[1]);
-
-  base::BigEndianReader big_endian_reader(
-      reinterpret_cast<const char*>(data_ptr + 2), 4);
-  big_endian_reader.ReadU16(&rtp_header->packet_id);
-  big_endian_reader.ReadU16(&rtp_header->max_packet_id);
-
-  if (rtp_header->is_reference) {
-    rtp_header->reference_frame_id =
-        reference_frame_id_wrap_helper_.MapTo32bitsFrameId(data_ptr[6]);
-    data_ptr += kRtpCastHeaderLength;
-    data_length -= kRtpCastHeaderLength;
-  } else {
-    data_ptr += kRtpCastHeaderLength - 1;
-    data_length -= kRtpCastHeaderLength - 1;
   }
+  if (header->sender_ssrc != expected_sender_ssrc_)
+    return false;  // Punt: Sender's SSRC does not match the expected one.
 
-  if (rtp_header->max_packet_id < rtp_header->packet_id)
+  // Parse the Cast header.  Note that, from the RTP protocol's perspective, the
+  // Cast header is part of the payload (and not meant to be an extension
+  // header).
+  if (!reader.ReadU8(&bits))
+    return false;
+  header->is_key_frame = !!(bits & kCastKeyFrameBitMask);
+  const bool includes_specific_frame_reference =
+      !!(bits & kCastReferenceFrameIdBitMask);
+  uint8 truncated_frame_id;
+  if (!reader.ReadU8(&truncated_frame_id) ||
+      !reader.ReadU16(&header->packet_id) ||
+      !reader.ReadU16(&header->max_packet_id)) {
     return false;
+  }
+  // Sanity-check: Do the packet ID values make sense w.r.t. each other?
+  if (header->max_packet_id < header->packet_id)
+    return false;
+  uint8 truncated_reference_frame_id;
+  if (!includes_specific_frame_reference) {
+    // By default, a key frame only references itself; and non-key frames
+    // reference their direct predecessor.
+    truncated_reference_frame_id = truncated_frame_id;
+    if (!header->is_key_frame)
+      --truncated_reference_frame_id;
+  } else if (!reader.ReadU8(&truncated_reference_frame_id)) {
+    return false;
+  }
+
+  // Only the lower 8 bits of the |frame_id| were serialized, so do some magic
+  // to restore the upper 24 bits.
+  //
+  // Note: The call to |frame_id_wrap_helper_| has side effects, so we must not
+  // call it until we know the entire deserialization will succeed.
+  header->frame_id =
+      frame_id_wrap_helper_.MapTo32bitsFrameId(truncated_frame_id);
+  // When the upper 24 bits are restored to |reference_frame_id|, make sure
+  // |reference_frame_id| will be strictly less than or equal to |frame_id|.
+  if (truncated_reference_frame_id <= truncated_frame_id)
+    header->reference_frame_id = header->frame_id & 0xffffff00;
+  else
+    header->reference_frame_id = (header->frame_id & 0xffffff00) - 0x00000100;
+  header->reference_frame_id |= truncated_reference_frame_id;
+
+  // All remaining data in the packet is the payload.
+  *payload_data = reinterpret_cast<const uint8*>(reader.ptr());
+  *payload_size = reader.remaining();
 
-  OnReceivedPayloadData(data_ptr, data_length, *rtp_header);
   return true;
 }