Bug 1390318 - add MID support to webrtc.org. r=drno draft
authorMichael Froman <mfroman@mozilla.com>
Thu, 27 Jul 2017 16:19:56 -0500
changeset 646105 8d575753a628b18472c3acd13ca88f5aa63c16b1
parent 645833 df9beb781895fcd0493c21e95ad313e0044515ec
child 726141 3d9019779ce5ffb68c1ab77a826fe49922656ec0
push id74009
push userbmo:mfroman@nostrum.com
push dateMon, 14 Aug 2017 21:45:20 +0000
reviewersdrno
bugs1390318
milestone57.0a1
Bug 1390318 - add MID support to webrtc.org. r=drno MozReview-Commit-ID: EHgEuhw855n
media/webrtc/trunk/webrtc/common_types.cc
media/webrtc/trunk/webrtc/common_types.h
media/webrtc/trunk/webrtc/config.cc
media/webrtc/trunk/webrtc/config.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
media/webrtc/trunk/webrtc/video/rtp_stream_receiver.h
--- a/media/webrtc/trunk/webrtc/common_types.cc
+++ b/media/webrtc/trunk/webrtc/common_types.cc
@@ -71,16 +71,18 @@ RTPHeaderExtension::operator=(const RTPH
   audioLevel = rhs.audioLevel;
 
   hasVideoRotation = rhs.hasVideoRotation;
   videoRotation = rhs.videoRotation;
 
   rtpStreamId = rhs.rtpStreamId;
   repairedRtpStreamId = rhs.repairedRtpStreamId;
 
+  mId = rhs.mId;
+
   return *this;
 }
 
 RTPHeader::RTPHeader()
     : markerBit(false),
       payloadType(0),
       sequenceNumber(0),
       timestamp(0),
--- a/media/webrtc/trunk/webrtc/common_types.h
+++ b/media/webrtc/trunk/webrtc/common_types.h
@@ -885,16 +885,18 @@ struct RTPHeaderExtension {
 
   PlayoutDelay playout_delay = {-1, -1};
 
   // For identification of a stream when ssrc is not signaled. See
   // https://tools.ietf.org/html/draft-ietf-avtext-rid-09
   // TODO(danilchap): Update url from draft to release version.
   StreamId rtpStreamId;
   StreamId repairedRtpStreamId;
+
+  StreamId mId;
 };
 
 struct RTPHeader {
   RTPHeader();
 
   bool markerBit;
   uint8_t payloadType;
   uint16_t sequenceNumber;
--- a/media/webrtc/trunk/webrtc/config.cc
+++ b/media/webrtc/trunk/webrtc/config.cc
@@ -75,16 +75,20 @@ const int RtpExtension::kPlayoutDelayDef
 const char* RtpExtension::kRtpStreamIdUri =
     "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
 const int RtpExtension::kRtpStreamIdDefaultId = 7;
 
 const char* RtpExtension::kRepairedRtpStreamIdUri =
     "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id";
 const int RtpExtension::kRepairedRtpStreamIdDefaultId = 8;
 
+const char* RtpExtension::kMIdUri =
+    "urn:ietf:params:rtp-hdrext:sdes:mid";
+const int RtpExtension::kMIdDefaultId = 9;
+
 bool RtpExtension::IsSupportedForAudio(const std::string& uri) {
   return uri == webrtc::RtpExtension::kAudioLevelUri ||
          uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
          uri == webrtc::RtpExtension::kRtpStreamIdUri ||
          uri == webrtc::RtpExtension::kRepairedRtpStreamIdUri;
 }
 
 bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
--- a/media/webrtc/trunk/webrtc/config.h
+++ b/media/webrtc/trunk/webrtc/config.h
@@ -99,16 +99,19 @@ struct RtpExtension {
   static const int kPlayoutDelayDefaultId;
 
   static const char* kRtpStreamIdUri;
   static const int kRtpStreamIdDefaultId;
 
   static const char* kRepairedRtpStreamIdUri;
   static const int kRepairedRtpStreamIdDefaultId;
 
+  static const char* kMIdUri;
+  static const int kMIdDefaultId;
+
   std::string uri;
   int id;
 };
 
 struct VideoStream {
   VideoStream();
   ~VideoStream();
   std::string ToString() const;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h
@@ -72,16 +72,17 @@ enum RTPExtensionType {
   kRtpExtensionTransmissionTimeOffset,
   kRtpExtensionAudioLevel,
   kRtpExtensionAbsoluteSendTime,
   kRtpExtensionVideoRotation,
   kRtpExtensionTransportSequenceNumber,
   kRtpExtensionPlayoutDelay,
   kRtpExtensionRtpStreamId,
   kRtpExtensionRepairedRtpStreamId,
+  kRtpExtensionMId,
   kRtpExtensionNumberOfExtensions  // Must be the last entity in the enum.
 };
 
 enum RTCPAppSubTypes { kAppSubtypeBwe = 0x00 };
 
 // TODO(sprang): Make this an enum class once rtcp_receiver has been cleaned up.
 enum RTCPPacketType : uint32_t {
   kRtcpReport = 0x0001,
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.cc
@@ -35,16 +35,17 @@ constexpr ExtensionInfo kExtensions[] = 
     CreateExtensionInfo<TransmissionOffset>(),
     CreateExtensionInfo<AudioLevel>(),
     CreateExtensionInfo<AbsoluteSendTime>(),
     CreateExtensionInfo<VideoOrientation>(),
     CreateExtensionInfo<TransportSequenceNumber>(),
     CreateExtensionInfo<PlayoutDelayLimits>(),
     CreateExtensionInfo<RtpStreamId>(),
     CreateExtensionInfo<RepairedRtpStreamId>(),
+    CreateExtensionInfo<MId>(),
 };
 
 // Because of kRtpExtensionNone, NumberOfExtension is 1 bigger than the actual
 // number of known extensions.
 static_assert(arraysize(kExtensions) ==
                   static_cast<int>(kRtpExtensionNumberOfExtensions) - 1,
               "kExtensions expect to list all known extensions");
 
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc
@@ -283,9 +283,37 @@ bool RepairedRtpStreamId::Parse(rtc::Arr
 size_t RepairedRtpStreamId::ValueSize(const std::string& rsid) {
   return RtpStreamId::ValueSize(rsid);
 }
 
 bool RepairedRtpStreamId::Write(uint8_t* data, const std::string& rsid) {
   return RtpStreamId::Write(data, rsid);
 }
 
+// MId
+constexpr RTPExtensionType MId::kId;
+constexpr const char* MId::kUri;
+
+bool MId::Parse(rtc::ArrayView<const uint8_t> data, StreamId* mid) {
+  return RtpStreamId::Parse(data, mid);
+}
+
+size_t MId::ValueSize(const StreamId& mid) {
+  return RtpStreamId::ValueSize(mid);
+}
+
+bool MId::Write(uint8_t* data, const StreamId& mid) {
+  return RtpStreamId::Write(data, mid);
+}
+
+bool MId::Parse(rtc::ArrayView<const uint8_t> data, std::string* mid) {
+  return RtpStreamId::Parse(data, mid);
+}
+
+size_t MId::ValueSize(const std::string& mid) {
+  return RtpStreamId::ValueSize(mid);
+}
+
+bool MId::Write(uint8_t* data, const std::string& mid) {
+  return RtpStreamId::Write(data, mid);
+}
+
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h
@@ -132,10 +132,25 @@ class RepairedRtpStreamId {
   static size_t ValueSize(const StreamId& rsid);
   static bool Write(uint8_t* data, const StreamId& rsid);
 
   static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* rsid);
   static size_t ValueSize(const std::string& rsid);
   static bool Write(uint8_t* data, const std::string& rsid);
 };
 
+class MId {
+ public:
+  static constexpr RTPExtensionType kId = kRtpExtensionMId;
+  static constexpr const char* kUri =
+      "urn:ietf:params:rtp-hdrext:sdes:mid";
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, StreamId* mid);
+  static size_t ValueSize(const StreamId& mid);
+  static bool Write(uint8_t* data, const StreamId& mid);
+
+  static bool Parse(rtc::ArrayView<const uint8_t> data, std::string* mid);
+  static size_t ValueSize(const std::string& mid);
+  static bool Write(uint8_t* data, const std::string& mid);
+};
+
 }  // namespace webrtc
 #endif  // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_HEADER_EXTENSIONS_H_
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet.cc
@@ -169,16 +169,17 @@ void Packet::GetHeader(RTPHeader* header
           &header->extension.transportSequenceNumber);
   header->extension.hasAudioLevel = GetExtension<AudioLevel>(
       &header->extension.voiceActivity, &header->extension.audioLevel);
   header->extension.hasVideoRotation =
       GetExtension<VideoOrientation>(&header->extension.videoRotation);
   GetExtension<RtpStreamId>(&header->extension.rtpStreamId);
   GetExtension<RepairedRtpStreamId>(&header->extension.repairedRtpStreamId);
   GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay);
+  GetExtension<MId>(&header->extension.mId);
 }
 
 size_t Packet::headers_size() const {
   return payload_offset_;
 }
 
 size_t Packet::payload_size() const {
   return payload_size_;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_packet_unittest.cc
@@ -60,16 +60,26 @@ constexpr uint8_t kPacketWithRsid[] = {
     0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0xbe, 0xde, 0x00, 0x03,
     0xa7, 's',  't',  'r',
     'e',  'a',  'm',  'i',
     'd' , 0x00, 0x00, 0x00};
 
+constexpr uint8_t kMIdExtensionId = 0xb;
+constexpr char kMId[] = "midval";
+constexpr uint8_t kPacketWithMid[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,
+    0x12, 0x34, 0x56, 0x78,
+    0xbe, 0xde, 0x00, 0x02,
+    0xb5, 'm',  'i',  'd',
+    'v',  'a',  'l',  0x00};
+
 constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465};
 constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'};
 constexpr uint8_t kPacketPaddingSize = 8;
 constexpr uint8_t kPacket[] = {
     0xb2, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,
     0x12, 0x34, 0x56, 0x78,
     0x34, 0x56, 0x78, 0x90,
@@ -137,16 +147,28 @@ TEST(RtpPacketTest, CreateWithDynamicSiz
   packet.SetPayloadType(kPayloadType);
   packet.SetSequenceNumber(kSeqNum);
   packet.SetTimestamp(kTimestamp);
   packet.SetSsrc(kSsrc);
   packet.SetExtension<RtpStreamId>(kStreamId);
   EXPECT_THAT(kPacketWithRsid, ElementsAreArray(packet.data(), packet.size()));
 }
 
+TEST(RtpPacketTest, CreateWithDynamicSizedExtensionMid) {
+  RtpPacketToSend::ExtensionManager extensions;
+  extensions.Register<RtpStreamId>(kMIdExtensionId);
+  RtpPacketToSend packet(&extensions);
+  packet.SetPayloadType(kPayloadType);
+  packet.SetSequenceNumber(kSeqNum);
+  packet.SetTimestamp(kTimestamp);
+  packet.SetSsrc(kSsrc);
+  packet.SetExtension<RtpStreamId>(kMId);
+  EXPECT_THAT(kPacketWithMid, ElementsAreArray(packet.data(), packet.size()));
+}
+
 TEST(RtpPacketTest, TryToCreateWithEmptyRsid) {
   RtpPacketToSend::ExtensionManager extensions;
   extensions.Register<RtpStreamId>(kRtpStreamIdExtensionId);
   RtpPacketToSend packet(&extensions);
   EXPECT_FALSE(packet.SetExtension<RtpStreamId>(""));
 }
 
 TEST(RtpPacketTest, TryToCreateWithLongRsid) {
@@ -417,36 +439,56 @@ TEST(RtpPacketTest, ParseDynamicSizeExte
     0x00};  // Extension padding.
   const uint8_t kPacket2[] = {
     0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
     0x65, 0x43, 0x12, 0x78,  // Timestamp.
     0x12, 0x34, 0x56, 0x79,  // Ssrc.
     0xbe, 0xde, 0x00, 0x01,  // Extensions block of size 1x32bit words.
     0x11, 'H', 'D',          // Extension with id = 1, size = (1+1).
     0x00};  // Extension padding.
+  const uint8_t kPacket3[] = {
+    0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte,
+    0x65, 0x43, 0x12, 0x78,  // Timestamp.
+    0x12, 0x34, 0x56, 0x78,  // Ssrc.
+    0xbe, 0xde, 0x00, 0x04,  // Extensions block of size 4x32bit words.
+    0x21, 'H', 'D',          // Extension with id = 2, size = (1+1).
+    0x12, 'r', 't', 'x',     // Extension with id = 1, size = (2+1).
+    0x35, 'm', 'i', 'd', 'v', 'a', 'l', // Extension with id = 3, size = (5+1).
+    0x00, 0x00};  // Extension padding.
   // clang-format on
   RtpPacketReceived::ExtensionManager extensions;
   extensions.Register<RtpStreamId>(1);
   extensions.Register<RepairedRtpStreamId>(2);
+  extensions.Register<MId>(3);
   RtpPacketReceived packet(&extensions);
   ASSERT_TRUE(packet.Parse(kPacket1, sizeof(kPacket1)));
 
   std::string rsid;
   EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
   EXPECT_EQ(rsid, "rtx");
 
   std::string repaired_rsid;
   EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
   EXPECT_EQ(repaired_rsid, "HD");
 
   // Parse another packet with RtpStreamId extension of different size.
   ASSERT_TRUE(packet.Parse(kPacket2, sizeof(kPacket2)));
   EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
   EXPECT_EQ(rsid, "HD");
   EXPECT_FALSE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+
+  // Parse another packet with RtpStreamId, RepairedRtpStreamId, MId
+  ASSERT_TRUE(packet.Parse(kPacket3, sizeof(kPacket3)));
+  EXPECT_TRUE(packet.GetExtension<RtpStreamId>(&rsid));
+  EXPECT_EQ(rsid, "rtx");
+  EXPECT_TRUE(packet.GetExtension<RepairedRtpStreamId>(&repaired_rsid));
+  EXPECT_EQ(repaired_rsid, "HD");
+  std::string mid;
+  EXPECT_TRUE(packet.GetExtension<MId>(&mid));
+  EXPECT_EQ(mid, "midval");
 }
 
 TEST(RtpPacketTest, RawExtensionFunctionsAcceptZeroIdAndReturnFalse) {
   RtpPacketReceived::ExtensionManager extensions;
   RtpPacketReceived packet(&extensions);
   // Use ExtensionManager to set kInvalidId to 0 to demonstrate natural way for
   // using zero value as a parameter to Packet::*RawExtension functions.
   const int kInvalidId = extensions.GetId(TransmissionOffset::kId);
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -40,16 +40,18 @@ RTPExtensionType StringToRtpExtensionTyp
   if (extension == RtpExtension::kTransportSequenceNumberUri)
     return kRtpExtensionTransportSequenceNumber;
   if (extension == RtpExtension::kPlayoutDelayUri)
     return kRtpExtensionPlayoutDelay;
   if (extension == RtpExtension::kRtpStreamIdUri)
     return kRtpExtensionRtpStreamId;
   if (extension == RtpExtension::kRepairedRtpStreamIdUri)
     return kRtpExtensionRepairedRtpStreamId;
+  if (extension == RtpExtension::kMIdUri)
+    return kRtpExtensionMId;
   RTC_NOTREACHED() << "Looking up unsupported RTP extension.";
   return kRtpExtensionNone;
 }
 
 RtpRtcp::Configuration::Configuration()
     : receive_statistics(NullObjectReceiveStatistics()) {}
 
 RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) {
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -215,16 +215,25 @@ int32_t RTPSender::SetRID(const char* ri
   rtc::CritScope lock(&send_critsect_);
   const size_t len = (rid && rid[0]) ? strlen(rid) : 0;
   if (len) {
     rtpStreamId.Set(rid, len);
   }
   return 0;
 }
 
+int32_t RTPSender::SetMId(const char* mid) {
+  rtc::CritScope lock(&send_critsect_);
+  const size_t len = (mid && mid[0]) ? strlen(mid) : 0;
+  if (len) {
+    mId.Set(mid, len);
+  }
+  return 0;
+}
+
 int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type,
                                               uint8_t id) {
   rtc::CritScope lock(&send_critsect_);
   return rtp_header_extension_map_.RegisterByType(id, type) ? 0 : -1;
 }
 
 bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) const {
   rtc::CritScope lock(&send_critsect_);
@@ -446,17 +455,17 @@ bool RTPSender::SendOutgoingData(FrameTy
     if (rtp_header) {
       playout_delay_oracle_.UpdateRequest(ssrc, rtp_header->playout_delay,
                                           sequence_number);
     }
 
     result = video_->SendVideo(video_type, frame_type, payload_type,
                                rtp_timestamp, capture_time_ms, payload_data,
                                payload_size, fragmentation, rtp_header,
-                               &rtpStreamId);
+                               &rtpStreamId, &mId);
   }
 
   rtc::CritScope cs(&statistics_crit_);
   // Note: This is currently only counting for video.
   if (frame_type == kVideoFrameKey) {
     ++frame_counts_.key_frames;
   } else if (frame_type == kVideoFrameDelta) {
     ++frame_counts_.delta_frames;
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h
@@ -115,16 +115,17 @@ class RTPSender {
                         int64_t capture_time_ms,
                         const uint8_t* payload_data,
                         size_t payload_size,
                         const RTPFragmentationHeader* fragmentation,
                         const RTPVideoHeader* rtp_header,
                         uint32_t* transport_frame_id_out);
 
   int32_t SetRID(const char* rid);
+  int32_t SetMId(const char* mid);
 
   // RTP header extension
   int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id);
   bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) const;
   int32_t DeregisterRtpHeaderExtension(RTPExtensionType type);
 
   bool TimeToSendPacket(uint32_t ssrc,
                         uint16_t sequence_number,
@@ -282,16 +283,18 @@ class RTPSender {
 
   int8_t payload_type_ GUARDED_BY(send_critsect_);
   std::map<int8_t, RtpUtility::Payload*> payload_type_map_;
 
   RtpHeaderExtensionMap rtp_header_extension_map_ GUARDED_BY(send_critsect_);
 
   StreamId rtpStreamId GUARDED_BY(send_critsect_);
 
+  StreamId mId GUARDED_BY(send_critsect_);
+
   // Tracks the current request for playout delay limits from application
   // and decides whether the current RTP frame should include the playout
   // delay extension on header.
   PlayoutDelayOracle playout_delay_oracle_;
 
   RtpPacketHistory packet_history_;
   // TODO(brandtr): Remove |flexfec_packet_history_| when the FlexfecSender
   // is hooked up to the PacedSender.
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -286,17 +286,18 @@ bool RTPSenderVideo::SendVideo(RtpVideoC
                                FrameType frame_type,
                                int8_t payload_type,
                                uint32_t rtp_timestamp,
                                int64_t capture_time_ms,
                                const uint8_t* payload_data,
                                size_t payload_size,
                                const RTPFragmentationHeader* fragmentation,
                                const RTPVideoHeader* video_header,
-                               const StreamId* rtpStreamId) {
+                               const StreamId* rtpStreamId,
+                               const StreamId* mId) {
   if (payload_size == 0)
     return false;
 
   // Create header that will be reused in all packets.
   std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket();
   rtp_header->SetPayloadType(payload_type);
   rtp_header->SetTimestamp(rtp_timestamp);
   rtp_header->set_capture_time_ms(capture_time_ms);
@@ -323,16 +324,19 @@ bool RTPSenderVideo::SendVideo(RtpVideoC
       if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ ||
           current_rotation != kVideoRotation_0)
         rtp_header->SetExtension<VideoOrientation>(current_rotation);
       last_rotation_ = current_rotation;
     }
     if (rtpStreamId && !rtpStreamId->empty()) {
        rtp_header->SetExtension<RtpStreamId>(*rtpStreamId);
     }
+    if (mId && !mId->empty()) {
+       rtp_header->SetExtension<MId>(*mId);
+    }
 
     // FEC settings.
     const FecProtectionParams& fec_params =
         frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_;
     if (flexfec_enabled())
       flexfec_sender_->SetFecParameters(fec_params);
     if (ulpfec_enabled())
       ulpfec_generator_.SetFecParameters(fec_params);
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h
@@ -56,17 +56,18 @@ class RTPSenderVideo {
                  FrameType frame_type,
                  int8_t payload_type,
                  uint32_t capture_timestamp,
                  int64_t capture_time_ms,
                  const uint8_t* payload_data,
                  size_t payload_size,
                  const RTPFragmentationHeader* fragmentation,
                  const RTPVideoHeader* video_header,
-                 const StreamId* rtpStreamId);
+                 const StreamId* rtpStreamId,
+                 const StreamId* mId);
 
   void SetVideoCodecType(RtpVideoCodecTypes type);
 
   // ULPFEC.
   void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type);
   void GetUlpfecConfig(int* red_payload_type, int* ulpfec_payload_type) const;
 
   // FlexFEC/ULPFEC.
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc
@@ -460,16 +460,20 @@ void RtpHeaderParser::ParseOneByteExtens
           header->extension.rtpStreamId.Set(rtc::MakeArrayView(ptr, len + 1));
           break;
         }
         case kRtpExtensionRepairedRtpStreamId: {
           header->extension.repairedRtpStreamId.Set(
               rtc::MakeArrayView(ptr, len + 1));
           break;
         }
+        case kRtpExtensionMId: {
+          header->extension.mId.Set(rtc::MakeArrayView(ptr, len + 1));
+          break;
+        }
         default:
         case kRtpExtensionNone:
         case kRtpExtensionNumberOfExtensions: {
           RTC_NOTREACHED() << "Invalid extension type: " << type;
           return;
         }
       }
     }
--- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility_unittest.cc
@@ -143,46 +143,48 @@ TEST(RtpHeaderParser, ParseWithOverSized
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   // Parse should ignore extension.
   EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(sizeof(kPacket), header.headerLength);
 }
 
-TEST(RtpHeaderParser, ParseAll8Extensions) {
+TEST(RtpHeaderParser, ParseAll9Extensions) {
   const uint8_t kAudioLevel = 0x5a;
   // clang-format off
   const uint8_t kPacket[] = {
       0x90, kPayloadType, 0x00, kSeqNum,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
-      0xbe, 0xde, 0x00, 0x08,  // Extension of size 8x32bit words.
+      0xbe, 0xde, 0x00, 0x0a,  // Extension of size 10x32bit words.
       0x40, 0x80|kAudioLevel,  // AudioLevel.
       0x22, 0x01, 0x56, 0xce,  // TransmissionOffset.
       0x62, 0x12, 0x34, 0x56,  // AbsoluteSendTime.
       0x81, 0xce, 0xab,        // TransportSequenceNumber.
       0xa0, 0x03,              // VideoRotation.
       0xb2, 0x12, 0x48, 0x76,  // PlayoutDelayLimits.
       0xc2, 'r', 't', 'x',     // RtpStreamId
       0xd5, 's', 't', 'r', 'e', 'a', 'm',  // RepairedRtpStreamId
-      0x00, 0x00,              // Padding to 32bit boundary.
+      0xe7, 'm', 'i', 'd', 'v', 'a', 'l', 'u', 'e', // MId
+      0x00,                    // Padding to 32bit boundary.
   };
   // clang-format on
   ASSERT_EQ(sizeof(kPacket) % 4, 0u);
 
   RtpHeaderExtensionMap extensions;
   extensions.Register<TransmissionOffset>(2);
   extensions.Register<AudioLevel>(4);
   extensions.Register<AbsoluteSendTime>(6);
   extensions.Register<TransportSequenceNumber>(8);
   extensions.Register<VideoOrientation>(0xa);
   extensions.Register<PlayoutDelayLimits>(0xb);
   extensions.Register<RtpStreamId>(0xc);
   extensions.Register<RepairedRtpStreamId>(0xd);
+  extensions.Register<MId>(0xe);
   RtpUtility::RtpHeaderParser parser(kPacket, sizeof(kPacket));
   RTPHeader header;
 
   EXPECT_TRUE(parser.Parse(&header, &extensions));
 
   EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
   EXPECT_EQ(0x156ce, header.extension.transmissionTimeOffset);
 
@@ -200,16 +202,17 @@ TEST(RtpHeaderParser, ParseAll8Extension
   EXPECT_EQ(kVideoRotation_270, header.extension.videoRotation);
 
   EXPECT_EQ(0x124 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.min_ms);
   EXPECT_EQ(0x876 * PlayoutDelayLimits::kGranularityMs,
             header.extension.playout_delay.max_ms);
   EXPECT_EQ(header.extension.rtpStreamId, StreamId("rtx"));
   EXPECT_EQ(header.extension.repairedRtpStreamId, StreamId("stream"));
+  EXPECT_EQ(header.extension.mId, StreamId("midvalue"));
 }
 
 TEST(RtpHeaderParser, ParseMalformedRsidExtensions) {
   // clang-format off
   const uint8_t kPacket[] = {
       0x90, kPayloadType, 0x00, kSeqNum,
       0x65, 0x43, 0x12, 0x78,  // kTimestamp.
       0x12, 0x34, 0x56, 0x78,  // kSsrc.
--- a/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
+++ b/media/webrtc/trunk/webrtc/test/fuzzers/rtp_packet_fuzzer.cc
@@ -91,12 +91,17 @@ void FuzzOneInput(const uint8_t* data, s
         packet.GetExtension<RtpStreamId>(&rsid);
         break;
       }
       case kRtpExtensionRepairedRtpStreamId: {
         std::string rsid;
         packet.GetExtension<RepairedRtpStreamId>(&rsid);
         break;
       }
+      case kRtpExtensionMId: {
+        std::string mid;
+        packet.GetExtension<MId>(&mid);
+        break;
+      }
     }
   }
 }
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
+++ b/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.cc
@@ -273,16 +273,32 @@ bool RtpStreamReceiver::SetReceiveRIDSta
       return false;
     }
   }
   receiving_rid_enabled_ = false;
   return rtp_header_parser_->DeregisterRtpHeaderExtension(
     kRtpExtensionRtpStreamId);
 }
 
+bool RtpStreamReceiver::SetReceiveMIdStatus(bool enable, int id) {
+  rtc::CritScope lock(&receive_cs_);
+  if (enable) {
+    if (rtp_header_parser_->RegisterRtpHeaderExtension(
+            kRtpExtensionMId, id)) {
+      receiving_mid_enabled_ = true;
+      return true;
+    } else {
+      return false;
+    }
+  }
+  receiving_mid_enabled_ = false;
+  return rtp_header_parser_->DeregisterRtpHeaderExtension(
+    kRtpExtensionMId);
+}
+
 int32_t RtpStreamReceiver::OnReceivedPayloadData(
     const uint8_t* payload_data,
     size_t payload_size,
     const WebRtcRTPHeader* rtp_header) {
   RTC_DCHECK(video_receiver_);
   WebRtcRTPHeader rtp_header_with_ntp = *rtp_header;
   rtp_header_with_ntp.ntp_time_ms =
       ntp_estimator_.Estimate(rtp_header->header.timestamp);
@@ -389,16 +405,18 @@ bool RtpStreamReceiver::DeliverRtp(const
       if (header.extension.hasTransmissionTimeOffset)
         ss << ", toffset: " << header.extension.transmissionTimeOffset;
       if (header.extension.hasAbsoluteSendTime)
         ss << ", abs send time: " << header.extension.absoluteSendTime;
       if (!header.extension.rtpStreamId.empty())
         ss << ", rid: " << header.extension.rtpStreamId.data();
       if (!header.extension.repairedRtpStreamId.empty())
         ss << ", repaired rid: " << header.extension.repairedRtpStreamId.data();
+      if (!header.extension.mId.empty())
+        ss << ", mid: " << header.extension.mId.data();
       LOG(LS_INFO) << ss.str();
       last_packet_log_ms_ = now_ms;
     }
   }
 
   remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_length,
                                             header);
   header.payload_type_frequency = kVideoPayloadTypeFrequency;
--- a/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.h
+++ b/media/webrtc/trunk/webrtc/video/rtp_stream_receiver.h
@@ -86,16 +86,17 @@ class RtpStreamReceiver : public RtpData
                        const std::map<std::string, std::string>& codec_params);
 
   bool AddReceiveCodec(const VideoCodec& video_codec);
 
   uint32_t GetRemoteSsrc() const;
   int GetCsrcs(uint32_t* csrcs) const;
   void GetRID(char rid[256]) const;
 	bool SetReceiveRIDStatus(bool enable, int id);
+  bool SetReceiveMIdStatus(bool enable, int id);
 
   RtpReceiver* GetRtpReceiver() const;
   RtpRtcp* rtp_rtcp() const { return rtp_rtcp_.get(); }
 
   void StartReceive();
   void StopReceive();
 
   bool DeliverRtp(const uint8_t* rtp_packet,
@@ -182,16 +183,17 @@ class RtpStreamReceiver : public RtpData
   const std::unique_ptr<ReceiveStatistics> rtp_receive_statistics_;
   std::unique_ptr<UlpfecReceiver> ulpfec_receiver_;
 
   rtc::CriticalSection receive_cs_;
   bool receiving_ GUARDED_BY(receive_cs_);
   uint8_t restored_packet_[IP_PACKET_SIZE] GUARDED_BY(receive_cs_);
   bool restored_packet_in_use_ GUARDED_BY(receive_cs_);
   bool receiving_rid_enabled_ GUARDED_BY(receive_cs_);
+  bool receiving_mid_enabled_ GUARDED_BY(receive_cs_);
   int64_t last_packet_log_ms_ GUARDED_BY(receive_cs_);
 
   const std::unique_ptr<RtpRtcp> rtp_rtcp_;
 
   // Members for the new jitter buffer experiment.
   bool jitter_buffer_experiment_;
   video_coding::OnCompleteFrameCallback* complete_frame_callback_;
   KeyFrameRequestSender* keyframe_request_sender_;