Bug 1515716 - refactor the RTC RTP stats types to match spec r=jib,smaug
☠☠ backed out by 475c7fe27919 ☠ ☠
authorNico Grunbaum <na-g@nostrum.com>
Wed, 06 Mar 2019 01:50:20 +0000
changeset 520441 621207c8ef880bcee9a263fbf029fafd6a8364ea
parent 520440 8c835f11c111c813ff3471882c636949a1255453
child 520442 36052e9424f7f356a197707303874940652f4eae
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, smaug
bugs1515716
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1515716 - refactor the RTC RTP stats types to match spec r=jib,smaug realigning the RTP stats types to match spec. This involves breaking out the remote dictionary types. This shouldn't create user space visible changes. Differential Revision: https://phabricator.services.mozilla.com/D20432
dom/media/RTCStatsReport.jsm
dom/media/webrtc/WebrtcGlobal.h
dom/webidl/RTCStatsReport.webidl
media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp
--- a/dom/media/RTCStatsReport.jsm
+++ b/dom/media/RTCStatsReport.jsm
@@ -8,18 +8,20 @@ var EXPORTED_SYMBOLS = ["convertToRTCSta
 
 function convertToRTCStatsReport(dict) {
   function appendStats(stats, report) {
     stats.forEach(function(stat) {
         report[stat.id] = stat;
       });
   }
   let report = {};
-  appendStats(dict.inboundRTPStreamStats, report);
-  appendStats(dict.outboundRTPStreamStats, report);
+  appendStats(dict.inboundRtpStreamStats, report);
+  appendStats(dict.outboundRtpStreamStats, report);
+  appendStats(dict.remoteInboundRtpStreamStats, report);
+  appendStats(dict.remoteOutboundRtpStreamStats, report);
   appendStats(dict.rtpContributingSourceStats, report);
   appendStats(dict.mediaStreamTrackStats, report);
   appendStats(dict.mediaStreamStats, report);
   appendStats(dict.transportStats, report);
   appendStats(dict.iceComponentStats, report);
   appendStats(dict.iceCandidatePairStats, report);
   appendStats(dict.iceCandidateStats, report);
   appendStats(dict.codecStats, report);
--- a/dom/media/webrtc/WebrtcGlobal.h
+++ b/dom/media/webrtc/WebrtcGlobal.h
@@ -88,22 +88,24 @@ struct ParamTraits<mozilla::dom::RTCStat
   typedef mozilla::dom::RTCStatsReportInternal paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mClosed);
     WriteParam(aMsg, aParam.mCodecStats);
     WriteParam(aMsg, aParam.mIceCandidatePairStats);
     WriteParam(aMsg, aParam.mIceCandidateStats);
     WriteParam(aMsg, aParam.mIceComponentStats);
-    WriteParam(aMsg, aParam.mInboundRTPStreamStats);
+    WriteParam(aMsg, aParam.mInboundRtpStreamStats);
     WriteParam(aMsg, aParam.mLocalSdp);
     WriteParam(aMsg, aParam.mMediaStreamStats);
     WriteParam(aMsg, aParam.mMediaStreamTrackStats);
-    WriteParam(aMsg, aParam.mOutboundRTPStreamStats);
+    WriteParam(aMsg, aParam.mOutboundRtpStreamStats);
     WriteParam(aMsg, aParam.mPcid);
+    WriteParam(aMsg, aParam.mRemoteInboundRtpStreamStats);
+    WriteParam(aMsg, aParam.mRemoteOutboundRtpStreamStats);
     WriteParam(aMsg, aParam.mRemoteSdp);
     WriteParam(aMsg, aParam.mTimestamp);
     WriteParam(aMsg, aParam.mIceRestarts);
     WriteParam(aMsg, aParam.mIceRollbacks);
     WriteParam(aMsg, aParam.mTransportStats);
     WriteParam(aMsg, aParam.mRtpContributingSourceStats);
     WriteParam(aMsg, aParam.mOfferer);
     WriteParam(aMsg, aParam.mTrickledIceCandidateStats);
@@ -113,22 +115,24 @@ struct ParamTraits<mozilla::dom::RTCStat
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
     if (!ReadParam(aMsg, aIter, &(aResult->mClosed)) ||
         !ReadParam(aMsg, aIter, &(aResult->mCodecStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceCandidatePairStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceCandidateStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceComponentStats)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mInboundRTPStreamStats)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mInboundRtpStreamStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mLocalSdp)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMediaStreamStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mMediaStreamTrackStats)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mOutboundRTPStreamStats)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mOutboundRtpStreamStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPcid)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mRemoteInboundRtpStreamStats)) ||
+        !ReadParam(aMsg, aIter, &(aResult->mRemoteOutboundRtpStreamStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mRemoteSdp)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTimestamp)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceRestarts)) ||
         !ReadParam(aMsg, aIter, &(aResult->mIceRollbacks)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTransportStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mRtpContributingSourceStats)) ||
         !ReadParam(aMsg, aIter, &(aResult->mOfferer)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTrickledIceCandidateStats)) ||
@@ -286,126 +290,178 @@ struct ParamTraits<mozilla::dom::RTCIceC
     if (!ReadParam(aMsg, aIter, &(aResult->mActiveConnection)) ||
         !ReadParam(aMsg, aIter, &(aResult->mBytesReceived)) ||
         !ReadParam(aMsg, aIter, &(aResult->mBytesSent)) ||
         !ReadParam(aMsg, aIter, &(aResult->mComponent)) ||
         !ReadParam(aMsg, aIter, &(aResult->mTransportId)) ||
         !ReadRTCStats(aMsg, aIter, aResult)) {
       return false;
     }
-
     return true;
   }
 };
 
 static void WriteRTCRtpStreamStats(
     Message* aMsg, const mozilla::dom::RTCRtpStreamStats& aParam) {
-  WriteParam(aMsg, aParam.mBitrateMean);
-  WriteParam(aMsg, aParam.mBitrateStdDev);
-  WriteParam(aMsg, aParam.mCodecId);
-  WriteParam(aMsg, aParam.mFirCount);
-  WriteParam(aMsg, aParam.mFramerateMean);
-  WriteParam(aMsg, aParam.mFramerateStdDev);
+  WriteParam(aMsg, aParam.mMediaType);
   WriteParam(aMsg, aParam.mKind);
-  WriteParam(aMsg, aParam.mLocalId);
-  WriteParam(aMsg, aParam.mMediaTrackId);
-  WriteParam(aMsg, aParam.mMediaType);
-  WriteParam(aMsg, aParam.mNackCount);
-  WriteParam(aMsg, aParam.mPliCount);
-  WriteParam(aMsg, aParam.mQpSum);
-  WriteParam(aMsg, aParam.mRemoteId);
   WriteParam(aMsg, aParam.mSsrc);
   WriteParam(aMsg, aParam.mTransportId);
 }
 
 static bool ReadRTCRtpStreamStats(const Message* aMsg, PickleIterator* aIter,
                                   mozilla::dom::RTCRtpStreamStats* aResult) {
-  if (!ReadParam(aMsg, aIter, &(aResult->mBitrateMean)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mBitrateStdDev)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mCodecId)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mFirCount)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mFramerateMean)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mFramerateStdDev)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mKind)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mLocalId)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mMediaTrackId)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mMediaType)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mNackCount)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mPliCount)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mQpSum)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mRemoteId)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mSsrc)) ||
-      !ReadParam(aMsg, aIter, &(aResult->mTransportId))) {
-    return false;
-  }
+  return ReadParam(aMsg, aIter, &(aResult->mMediaType)) &&
+         ReadParam(aMsg, aIter, &(aResult->mKind)) &&
+         ReadParam(aMsg, aIter, &(aResult->mSsrc)) &&
+         ReadParam(aMsg, aIter, &(aResult->mTransportId)) &&
+         ReadRTCStats(aMsg, aIter, aResult);
+}
 
-  return true;
+static void WriteRTCReceivedRtpStreamStats(
+    Message* aMsg, const mozilla::dom::RTCReceivedRtpStreamStats& aParam) {
+  WriteParam(aMsg, aParam.mPacketsReceived);
+  WriteParam(aMsg, aParam.mPacketsLost);
+  WriteParam(aMsg, aParam.mJitter);
+  WriteParam(aMsg, aParam.mPacketsDiscarded);
+  WriteParam(aMsg, aParam.mDiscardedPackets);
+  WriteRTCRtpStreamStats(aMsg, aParam);
+}
+
+static bool ReadRTCReceivedRtpStreamStats(
+    const Message* aMsg, PickleIterator* aIter,
+    mozilla::dom::RTCReceivedRtpStreamStats* aResult) {
+  return ReadParam(aMsg, aIter, &(aResult->mPacketsReceived)) &&
+         ReadParam(aMsg, aIter, &(aResult->mPacketsLost)) &&
+         ReadParam(aMsg, aIter, &(aResult->mJitter)) &&
+         ReadParam(aMsg, aIter, &(aResult->mPacketsDiscarded)) &&
+         ReadParam(aMsg, aIter, &(aResult->mDiscardedPackets)) &&
+         ReadRTCRtpStreamStats(aMsg, aIter, aResult);
 }
 
 template <>
-struct ParamTraits<mozilla::dom::RTCInboundRTPStreamStats> {
-  typedef mozilla::dom::RTCInboundRTPStreamStats paramType;
+struct ParamTraits<mozilla::dom::RTCInboundRtpStreamStats> {
+  typedef mozilla::dom::RTCInboundRtpStreamStats paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
-    WriteParam(aMsg, aParam.mBytesReceived);
-    WriteParam(aMsg, aParam.mDiscardedPackets);
+    WriteParam(aMsg, aParam.mRemoteId);
     WriteParam(aMsg, aParam.mFramesDecoded);
-    WriteParam(aMsg, aParam.mJitter);
-    WriteParam(aMsg, aParam.mPacketsLost);
+    WriteParam(aMsg, aParam.mBytesReceived);
     WriteParam(aMsg, aParam.mPacketsReceived);
-    WriteParam(aMsg, aParam.mRoundTripTime);
-    WriteRTCRtpStreamStats(aMsg, aParam);
-    WriteRTCStats(aMsg, aParam);
+    WriteParam(aMsg, aParam.mNackCount);
+    WriteParam(aMsg, aParam.mFirCount);
+    WriteParam(aMsg, aParam.mPliCount);
+    WriteParam(aMsg, aParam.mBitrateMean);
+    WriteParam(aMsg, aParam.mBitrateStdDev);
+    WriteParam(aMsg, aParam.mFramerateMean);
+    WriteParam(aMsg, aParam.mFramerateStdDev);
+    WriteRTCReceivedRtpStreamStats(aMsg, aParam);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
-    if (!ReadParam(aMsg, aIter, &(aResult->mBytesReceived)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mDiscardedPackets)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mFramesDecoded)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mJitter)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mPacketsLost)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mPacketsReceived)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mRoundTripTime)) ||
-        !ReadRTCRtpStreamStats(aMsg, aIter, aResult) ||
-        !ReadRTCStats(aMsg, aIter, aResult)) {
-      return false;
-    }
-
-    return true;
+    return ReadParam(aMsg, aIter, &(aResult->mRemoteId)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFramesDecoded)) &&
+           ReadParam(aMsg, aIter, &(aResult->mBytesReceived)) &&
+           ReadParam(aMsg, aIter, &(aResult->mPacketsReceived)) &&
+           ReadParam(aMsg, aIter, &(aResult->mNackCount)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFirCount)) &&
+           ReadParam(aMsg, aIter, &(aResult->mPliCount)) &&
+           ReadParam(aMsg, aIter, &(aResult->mBitrateMean)) &&
+           ReadParam(aMsg, aIter, &(aResult->mBitrateStdDev)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFramerateMean)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFramerateStdDev)) &&
+           ReadRTCReceivedRtpStreamStats(aMsg, aIter, aResult);
   }
 };
 
+static void WriteRTCSentRtpStreamStats(
+    Message* aMsg, const mozilla::dom::RTCSentRtpStreamStats& aParam) {
+  WriteParam(aMsg, aParam.mPacketsSent);
+  WriteParam(aMsg, aParam.mBytesSent);
+  WriteRTCRtpStreamStats(aMsg, aParam);
+}
+
+static bool ReadRTCSentRtpStreamStats(
+    const Message* aMsg, PickleIterator* aIter,
+    mozilla::dom::RTCSentRtpStreamStats* aResult) {
+  return ReadParam(aMsg, aIter, &(aResult->mPacketsSent)) &&
+         ReadParam(aMsg, aIter, &(aResult->mBytesSent)) &&
+         ReadRTCRtpStreamStats(aMsg, aIter, aResult);
+}
+
 template <>
-struct ParamTraits<mozilla::dom::RTCOutboundRTPStreamStats> {
-  typedef mozilla::dom::RTCOutboundRTPStreamStats paramType;
+struct ParamTraits<mozilla::dom::RTCOutboundRtpStreamStats> {
+  typedef mozilla::dom::RTCOutboundRtpStreamStats paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mBytesSent);
     WriteParam(aMsg, aParam.mDroppedFrames);
     WriteParam(aMsg, aParam.mFramesEncoded);
     WriteParam(aMsg, aParam.mPacketsSent);
-    WriteParam(aMsg, aParam.mTargetBitrate);
-    WriteRTCRtpStreamStats(aMsg, aParam);
-    WriteRTCStats(aMsg, aParam);
+    WriteParam(aMsg, aParam.mBitrateMean);
+    WriteParam(aMsg, aParam.mBitrateStdDev);
+    WriteParam(aMsg, aParam.mFramerateMean);
+    WriteParam(aMsg, aParam.mFramerateStdDev);
+    WriteRTCSentRtpStreamStats(aMsg, aParam);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter,
                    paramType* aResult) {
-    if (!ReadParam(aMsg, aIter, &(aResult->mBytesSent)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mDroppedFrames)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mFramesEncoded)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mPacketsSent)) ||
-        !ReadParam(aMsg, aIter, &(aResult->mTargetBitrate)) ||
-        !ReadRTCRtpStreamStats(aMsg, aIter, aResult) ||
-        !ReadRTCStats(aMsg, aIter, aResult)) {
-      return false;
-    }
+    return ReadParam(aMsg, aIter, &(aResult->mRemoteId)) &&
+           ReadParam(aMsg, aIter, &(aResult->mBytesSent)) &&
+           ReadParam(aMsg, aIter, &(aResult->mDroppedFrames)) &&
+           ReadParam(aMsg, aIter, &(aResult->mPacketsSent)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFramesEncoded)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFirCount)) &&
+           ReadParam(aMsg, aIter, &(aResult->mNackCount)) &&
+           ReadParam(aMsg, aIter, &(aResult->mPliCount)) &&
+           ReadParam(aMsg, aIter, &(aResult->mBitrateMean)) &&
+           ReadParam(aMsg, aIter, &(aResult->mBitrateStdDev)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFramerateMean)) &&
+           ReadParam(aMsg, aIter, &(aResult->mFramerateStdDev)) &&
+           ReadRTCSentRtpStreamStats(aMsg, aIter, aResult);
+  }
+};
+
+template <>
+struct ParamTraits<mozilla::dom::RTCRemoteInboundRtpStreamStats> {
+  typedef mozilla::dom::RTCRemoteInboundRtpStreamStats paramType;
 
-    return true;
+  static void Write(Message* aMsg, const paramType& aParam) {
+    WriteParam(aMsg, aParam.mLocalId);
+    WriteParam(aMsg, aParam.mBytesReceived);  // To be removed in Bug 1529405
+    WriteParam(aMsg, aParam.mRoundTripTime);
+    WriteRTCReceivedRtpStreamStats(aMsg, aParam);
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter,
+                   paramType* aResult) {
+    return ReadParam(aMsg, aIter, &(aResult->mLocalId)) &&
+           ReadParam(
+               aMsg, aIter,
+               &(aResult->mBytesReceived)) &&  // To be removed in Bug 1529405
+           ReadParam(aMsg, aIter, &(aResult->mRoundTripTime)) &&
+           ReadRTCReceivedRtpStreamStats(aMsg, aIter, aResult);
+  }
+};
+
+template <>
+struct ParamTraits<mozilla::dom::RTCRemoteOutboundRtpStreamStats> {
+  typedef mozilla::dom::RTCRemoteOutboundRtpStreamStats paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam) {
+    WriteParam(aMsg, aParam.mLocalId);
+    WriteRTCSentRtpStreamStats(aMsg, aParam);
+  }
+
+  static bool Read(const Message* aMsg, PickleIterator* aIter,
+                   paramType* aResult) {
+    return ReadParam(aMsg, aIter, &(aResult->mLocalId)) &&
+           ReadRTCSentRtpStreamStats(aMsg, aIter, aResult);
   }
 };
 
 template <>
 struct ParamTraits<mozilla::dom::RTCMediaStreamStats> {
   typedef mozilla::dom::RTCMediaStreamStats paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
--- a/dom/webidl/RTCStatsReport.webidl
+++ b/dom/webidl/RTCStatsReport.webidl
@@ -28,56 +28,67 @@ dictionary RTCStats {
   DOMString id;
 };
 
 dictionary RTCRtpStreamStats : RTCStats {
   unsigned long ssrc;
   DOMString mediaType;
   DOMString kind;
   DOMString transportId;
-  DOMString codecId;
-  // Local only measurements, RTCP related but not communicated via RTCP. Not
-  // present in RTCP case. See Bug 1367562
+};
+
+dictionary RTCReceivedRtpStreamStats: RTCRtpStreamStats {
+  unsigned long packetsReceived;
+  unsigned long packetsLost;
+  double jitter;
+  unsigned long discardedPackets; // non-standard alias for packetsDiscarded
+  unsigned long packetsDiscarded;
+};
+
+dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+  DOMString remoteId;
+  unsigned long framesDecoded;
+  unsigned long long bytesReceived;
+  unsigned long nackCount;
   unsigned long firCount;
   unsigned long pliCount;
-  unsigned long nackCount;
-  unsigned long long qpSum;
-
-  DOMString remoteId; // See Bug 1515716
-  DOMString localId;  // See Bug 1515716
-  DOMString mediaTrackId;
-
-  // Video encoder/decoder measurements, not present in RTCP case
-  double bitrateMean;
-  double bitrateStdDev;
-  double framerateMean;
-  double framerateStdDev;
+  double bitrateMean; // deprecated, to be removed in Bug 1367562
+  double bitrateStdDev; // deprecated, to be removed in Bug 1367562
+  double framerateMean; // deprecated, to be removed in Bug 1367562
+  double framerateStdDev; // deprecated, to be removed in Bug 1367562
 };
 
-dictionary RTCInboundRTPStreamStats : RTCRtpStreamStats {
-  unsigned long packetsReceived;
-  unsigned long long bytesReceived;
-  double jitter;
-  unsigned long packetsLost;
+dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+  DOMString localId;
+  long long bytesReceived; // Deprecated, to be removed in Bug 1529405
   double roundTripTime;
+};
 
-  // Video decoder measurement, not present in RTCP case
-  unsigned long discardedPackets;
-  unsigned long framesDecoded;
+dictionary RTCSentRtpStreamStats : RTCRtpStreamStats {
+  unsigned long packetsSent;
+  unsigned long long bytesSent;
 };
 
+dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
+  DOMString remoteId;
+  unsigned long framesEncoded;
+  unsigned long long qpSum;
+  unsigned long nackCount;
+  unsigned long firCount;
+  unsigned long pliCount;
+  double bitrateMean; // deprecated, to be removed in Bug 1367562
+  double bitrateStdDev; // deprecated, to be removed in Bug 1367562
+  double framerateMean; // deprecated, to be removed in Bug 1367562
+  double framerateStdDev; // deprecated, to be removed in Bug 1367562
+  unsigned long droppedFrames; // non-spec alias for framesDropped
+  							   // to be deprecated in Bug 1225720
+};
 
-dictionary RTCOutboundRTPStreamStats : RTCRtpStreamStats {
-  unsigned long packetsSent;
-  unsigned long long bytesSent;
-  double targetBitrate;  // config encoder bitrate target of this SSRC in bits/s
-
-  // Video encoder measurements, not present in RTCP case
-  unsigned long droppedFrames;
-  unsigned long framesEncoded;
+dictionary RTCRemoteOutboundRtpStreamStats : RTCSentRtpStreamStats {
+  DOMString localId;
 };
 
 dictionary RTCMediaStreamTrackStats : RTCStats {
   DOMString trackIdentifier;      // track.id property
   boolean remoteSource;
   sequence<DOMString> ssrcIds;
   // Stuff that makes sense for video
   unsigned long frameWidth;
@@ -172,37 +183,39 @@ dictionary RTCCodecStats : RTCStats {
   unsigned long channels;          // 2=stereo, missing for most other cases.
   DOMString parameters;            // From SDP description line
 };
 
 // This is the internal representation of the report in this implementation
 // to be received from c++
 
 dictionary RTCStatsReportInternal {
-  DOMString                               pcid = "";
-  sequence<RTCInboundRTPStreamStats>      inboundRTPStreamStats;
-  sequence<RTCOutboundRTPStreamStats>     outboundRTPStreamStats;
-  sequence<RTCRTPContributingSourceStats> rtpContributingSourceStats;
-  sequence<RTCMediaStreamTrackStats>      mediaStreamTrackStats;
-  sequence<RTCMediaStreamStats>           mediaStreamStats;
-  sequence<RTCTransportStats>             transportStats;
-  sequence<RTCIceComponentStats>          iceComponentStats;
-  sequence<RTCIceCandidatePairStats>      iceCandidatePairStats;
-  sequence<RTCIceCandidateStats>          iceCandidateStats;
-  sequence<RTCCodecStats>                 codecStats;
-  DOMString                               localSdp;
-  DOMString                               remoteSdp;
-  DOMHighResTimeStamp                     timestamp;
-  unsigned long                           iceRestarts;
-  unsigned long                           iceRollbacks;
-  boolean                                 offerer; // Is the PC the offerer
-  boolean                                 closed; // Is the PC now closed
-  sequence<RTCIceCandidateStats>          trickledIceCandidateStats;
-  sequence<DOMString>                     rawLocalCandidates;
-  sequence<DOMString>                     rawRemoteCandidates;
+  DOMString                                 pcid = "";
+  sequence<RTCInboundRtpStreamStats>        inboundRtpStreamStats;
+  sequence<RTCOutboundRtpStreamStats>       outboundRtpStreamStats;
+  sequence<RTCRemoteInboundRtpStreamStats>  remoteInboundRtpStreamStats;
+  sequence<RTCRemoteOutboundRtpStreamStats> remoteOutboundRtpStreamStats;
+  sequence<RTCRTPContributingSourceStats>   rtpContributingSourceStats;
+  sequence<RTCMediaStreamTrackStats>        mediaStreamTrackStats;
+  sequence<RTCMediaStreamStats>             mediaStreamStats;
+  sequence<RTCTransportStats>               transportStats;
+  sequence<RTCIceComponentStats>            iceComponentStats;
+  sequence<RTCIceCandidatePairStats>        iceCandidatePairStats;
+  sequence<RTCIceCandidateStats>            iceCandidateStats;
+  sequence<RTCCodecStats>                   codecStats;
+  DOMString                                 localSdp;
+  DOMString                                 remoteSdp;
+  DOMHighResTimeStamp                       timestamp;
+  unsigned long                             iceRestarts;
+  unsigned long                             iceRollbacks;
+  boolean                                   offerer; // Is the PC the offerer
+  boolean                                   closed; // Is the PC now closed
+  sequence<RTCIceCandidateStats>            trickledIceCandidateStats;
+  sequence<DOMString>                       rawLocalCandidates;
+  sequence<DOMString>                       rawRemoteCandidates;
 };
 
 [Pref="media.peerconnection.enabled",
  JSImplementation="@mozilla.org/dom/rtcstatsreport;1"]
 interface RTCStatsReport {
   readonly maplike<DOMString, object>;
   [ChromeOnly]
   readonly attribute DOMString mozPcid;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
@@ -169,113 +169,108 @@ void PeerConnectionCtx::Destroy() {
     gInstance->Cleanup();
     delete gInstance;
     gInstance = nullptr;
   }
 
   StopWebRtcLog();
 }
 
+template <typename T>
+static void RecordCommonRtpTelemetry(const T& list, const T& lastList,
+                                     const bool isRemote) {
+  using namespace Telemetry;
+  if (!list.WasPassed()) {
+    return;
+  }
+  for (const auto& s : list.Value()) {
+    const bool isAudio = s.mKind.Value().Find("audio") != -1;
+    if (s.mPacketsLost.WasPassed() && s.mPacketsReceived.WasPassed()) {
+      if (const uint64_t total =
+              s.mPacketsLost.Value() + s.mPacketsReceived.Value()) {
+        HistogramID id =
+            isRemote ? (isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_PACKETLOSS_RATE
+                                : WEBRTC_VIDEO_QUALITY_OUTBOUND_PACKETLOSS_RATE)
+                     : (isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_PACKETLOSS_RATE
+                                : WEBRTC_VIDEO_QUALITY_INBOUND_PACKETLOSS_RATE);
+        Accumulate(id, (s.mPacketsLost.Value() * 1000) / total);
+      }
+    }
+    if (s.mJitter.WasPassed()) {
+      HistogramID id = isRemote
+                           ? (isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_JITTER
+                                      : WEBRTC_VIDEO_QUALITY_OUTBOUND_JITTER)
+                           : (isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_JITTER
+                                      : WEBRTC_VIDEO_QUALITY_INBOUND_JITTER);
+      Accumulate(id, s.mJitter.Value() * 1000);
+    }
+    // Record bandwidth telemetry
+    if (s.mBytesReceived.WasPassed() && lastList.WasPassed()) {
+      for (const auto& lastS : lastList.Value()) {
+        if (lastS.mId == s.mId) {
+          int32_t deltaMs = s.mTimestamp.Value() - lastS.mTimestamp.Value();
+          // In theory we're called every second, so delta *should* be in that
+          // range. Small deltas could cause errors due to division
+          if (deltaMs < 500 || deltaMs > 60000 ||
+              !lastS.mBytesReceived.WasPassed()) {
+            break;
+          }
+          HistogramID id =
+              isRemote
+                  ? (isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS
+                             : WEBRTC_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS)
+                  : (isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS
+                             : WEBRTC_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS);
+          // We could accumulate values until enough time has passed
+          // and then Accumulate() but this isn't that important
+          Accumulate(
+              id,
+              ((s.mBytesReceived.Value() - lastS.mBytesReceived.Value()) * 8) /
+                  deltaMs);
+          break;
+        }
+      }
+    }
+  }
+}
+
 // Telemetry reporting every second after start of first call.
 // The threading model around the media pipelines is weird:
 // - The pipelines are containers,
 // - containers that are only safe on main thread, with members only safe on
 //   STS,
 // - hence the there and back again approach.
 
-static auto FindId(const Sequence<RTCInboundRTPStreamStats>& aArray,
-                   const nsString& aId) -> decltype(aArray.Length()) {
-  for (decltype(aArray.Length()) i = 0; i < aArray.Length(); i++) {
-    if (aArray[i].mId.Value() == aId) {
-      return i;
-    }
-  }
-  return aArray.NoIndex;
-}
-
 void PeerConnectionCtx::DeliverStats(RTCStatsQuery& aQuery) {
   using namespace Telemetry;
 
   std::unique_ptr<dom::RTCStatsReportInternal> report(std::move(aQuery.report));
   // First, get reports from a second ago, if any, for calculations below
   std::unique_ptr<dom::RTCStatsReportInternal> lastReport;
   {
     auto i = mLastReports.find(report->mPcid);
     if (i != mLastReports.end()) {
       lastReport = std::move(i->second);
+    } else {
+      lastReport = std::make_unique<dom::RTCStatsReportInternal>();
     }
   }
-
-  if (report->mInboundRTPStreamStats.WasPassed()) {
-    // Then, look for the things we want telemetry on
-    for (auto& s : report->mInboundRTPStreamStats.Value()) {
-      bool isRemote = s.mType.Value() == dom::RTCStatsType::Remote_inbound_rtp;
-      bool isAudio = (s.mId.Value().Find("audio") != -1);
-      if (s.mPacketsLost.WasPassed() && s.mPacketsReceived.WasPassed() &&
-          (s.mPacketsLost.Value() + s.mPacketsReceived.Value()) != 0) {
-        HistogramID id;
-        if (isRemote) {
-          id = isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_PACKETLOSS_RATE
-                       : WEBRTC_VIDEO_QUALITY_OUTBOUND_PACKETLOSS_RATE;
-        } else {
-          id = isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_PACKETLOSS_RATE
-                       : WEBRTC_VIDEO_QUALITY_INBOUND_PACKETLOSS_RATE;
-        }
-        // *1000 so we can read in 10's of a percent (permille)
-        Accumulate(id,
-                   (s.mPacketsLost.Value() * 1000) /
-                       (s.mPacketsLost.Value() + s.mPacketsReceived.Value()));
-      }
-      if (s.mJitter.WasPassed()) {
-        HistogramID id;
-        if (isRemote) {
-          id = isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_JITTER
-                       : WEBRTC_VIDEO_QUALITY_OUTBOUND_JITTER;
-        } else {
-          id = isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_JITTER
-                       : WEBRTC_VIDEO_QUALITY_INBOUND_JITTER;
-        }
-        Accumulate(id, s.mJitter.Value());
-      }
+  // Record Telemetery
+  RecordCommonRtpTelemetry(report->mInboundRtpStreamStats,
+                           lastReport->mInboundRtpStreamStats, false);
+  RecordCommonRtpTelemetry(report->mRemoteInboundRtpStreamStats,
+                           lastReport->mRemoteInboundRtpStreamStats, true);
+  if (report->mRemoteInboundRtpStreamStats.WasPassed()) {
+    for (const auto& s : report->mRemoteInboundRtpStreamStats.Value()) {
       if (s.mRoundTripTime.WasPassed()) {
-        MOZ_ASSERT(isRemote);
+        const bool isAudio = s.mKind.Value().Find("audio") != -1;
         HistogramID id = isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_RTT
                                  : WEBRTC_VIDEO_QUALITY_OUTBOUND_RTT;
         Accumulate(id, s.mRoundTripTime.Value() * 1000);
       }
-      if (lastReport && lastReport->mInboundRTPStreamStats.WasPassed() &&
-          s.mBytesReceived.WasPassed()) {
-        auto& laststats = lastReport->mInboundRTPStreamStats.Value();
-        auto i = FindId(laststats, s.mId.Value());
-        if (i != laststats.NoIndex) {
-          auto& lasts = laststats[i];
-          if (lasts.mBytesReceived.WasPassed()) {
-            auto delta_ms =
-                int32_t(s.mTimestamp.Value() - lasts.mTimestamp.Value());
-            // In theory we're called every second, so delta *should* be in that
-            // range. Small deltas could cause errors due to division
-            if (delta_ms > 500 && delta_ms < 60000) {
-              HistogramID id;
-              if (isRemote) {
-                id = isAudio ? WEBRTC_AUDIO_QUALITY_OUTBOUND_BANDWIDTH_KBITS
-                             : WEBRTC_VIDEO_QUALITY_OUTBOUND_BANDWIDTH_KBITS;
-              } else {
-                id = isAudio ? WEBRTC_AUDIO_QUALITY_INBOUND_BANDWIDTH_KBITS
-                             : WEBRTC_VIDEO_QUALITY_INBOUND_BANDWIDTH_KBITS;
-              }
-              Accumulate(id, ((s.mBytesReceived.Value() -
-                               lasts.mBytesReceived.Value()) *
-                              8) /
-                                 delta_ms);
-            }
-            // We could accumulate values until enough time has passed
-            // and then Accumulate() but this isn't that important.
-          }
-        }
-      }
     }
   }
 
   mLastReports[report->mPcid] = std::move(report);
 }
 
 void PeerConnectionCtx::EverySecondTelemetryCallback_m(nsITimer* timer,
                                                        void* closure) {
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1554,18 +1554,20 @@ nsresult PeerConnectionImpl::GetTimeSinc
 }
 
 class RTCStatsReportInternalConstruct : public RTCStatsReportInternal {
  public:
   RTCStatsReportInternalConstruct(const nsString& pcid,
                                   DOMHighResTimeStamp now) {
     mPcid = pcid;
     mRtpContributingSourceStats.Construct();
-    mInboundRTPStreamStats.Construct();
-    mOutboundRTPStreamStats.Construct();
+    mInboundRtpStreamStats.Construct();
+    mOutboundRtpStreamStats.Construct();
+    mRemoteInboundRtpStreamStats.Construct();
+    mRemoteOutboundRtpStreamStats.Construct();
     mMediaStreamTrackStats.Construct();
     mMediaStreamStats.Construct();
     mTransportStats.Construct();
     mIceComponentStats.Construct();
     mIceCandidatePairStats.Construct();
     mIceCandidateStats.Construct();
     mCodecStats.Construct();
     mTimestamp.Construct(now);
@@ -2829,57 +2831,57 @@ RefPtr<RTCStatsQueryPromise> PeerConnect
           uint32_t packetsReceived;
           uint64_t bytesReceived;
           uint32_t packetsLost;
           int32_t rtt;
           if (mp.Conduit()->GetRTCPReceiverReport(&jitterMs, &packetsReceived,
                                                   &bytesReceived, &packetsLost,
                                                   &rtt)) {
             remoteId = NS_LITERAL_STRING("outbound_rtcp_") + idstr;
-            RTCInboundRTPStreamStats s;
+            RTCRemoteInboundRtpStreamStats s;
             // TODO Bug 1496533 - use reception time not query time
             s.mTimestamp.Construct(query->now);
             s.mId.Construct(remoteId);
             s.mType.Construct(RTCStatsType::Remote_inbound_rtp);
             ssrc.apply([&s](uint32_t aSsrc) { s.mSsrc.Construct(aSsrc); });
             s.mMediaType.Construct(
                 kind);  // mediaType is the old name for kind.
             s.mKind.Construct(kind);
             s.mJitter.Construct(double(jitterMs) / 1000);
             s.mLocalId.Construct(localId);
             s.mPacketsReceived.Construct(packetsReceived);
             s.mBytesReceived.Construct(bytesReceived);
             s.mPacketsLost.Construct(packetsLost);
             if (rtt > 0) {  // RTT is not reported when it is zero
               s.mRoundTripTime.Construct(static_cast<double>(rtt) / 1000);
             }
-            query->report->mInboundRTPStreamStats.Value().AppendElement(
+            query->report->mRemoteInboundRtpStreamStats.Value().AppendElement(
                 s, fallible);
           }
         }
         // Then, fill in local side (with cross-link to remote only if present)
         {
-          RTCOutboundRTPStreamStats s;
+          RTCOutboundRtpStreamStats s;
           // TODO Bug 1496533 - use reception time not query time
           s.mTimestamp.Construct(query->now);
           s.mId.Construct(localId);
           s.mType.Construct(RTCStatsType::Outbound_rtp);
           ssrc.apply([&s](uint32_t aSsrc) { s.mSsrc.Construct(aSsrc); });
           s.mMediaType.Construct(kind);  // mediaType is the old name for kind.
           s.mKind.Construct(kind);
           s.mRemoteId.Construct(remoteId);
           s.mPacketsSent.Construct(mp.RtpPacketsSent());
           s.mBytesSent.Construct(mp.RtpBytesSent());
 
           // Fill in packet type statistics
           webrtc::RtcpPacketTypeCounter counters;
           if (mp.Conduit()->GetSendPacketTypeStats(&counters)) {
             s.mNackCount.Construct(counters.nack_packets);
             // Fill in video only packet type stats
-            if(asVideo) {
+            if (asVideo) {
               s.mFirCount.Construct(counters.fir_packets);
               s.mPliCount.Construct(counters.pli_packets);
             }
           }
 
           // Lastly, fill in video encoder stats if this is video
           asVideo.apply([&s](auto conduit) {
             double framerateMean;
@@ -2896,17 +2898,17 @@ RefPtr<RTCStatsQueryPromise> PeerConnect
               s.mFramerateStdDev.Construct(framerateStdDev);
               s.mBitrateMean.Construct(bitrateMean);
               s.mBitrateStdDev.Construct(bitrateStdDev);
               s.mDroppedFrames.Construct(droppedFrames);
               s.mFramesEncoded.Construct(framesEncoded);
               qpSum.apply([&s](uint64_t aQp) { s.mQpSum.Construct(aQp); });
             }
           });
-          query->report->mOutboundRTPStreamStats.Value().AppendElement(
+          query->report->mOutboundRtpStreamStats.Value().AppendElement(
               s, fallible);
         }
         break;
       }
       case MediaPipeline::DirectionType::RECEIVE: {
         nsString localId = NS_LITERAL_STRING("inbound_rtp_") + idstr;
         nsString remoteId;
         Maybe<uint32_t> ssrc;
@@ -2915,34 +2917,34 @@ RefPtr<RTCStatsQueryPromise> PeerConnect
           ssrc = Some(ssrcval);
         }
         {
           // First, fill in remote stat with rtcp sender data, if present.
           uint32_t packetsSent;
           uint64_t bytesSent;
           if (mp.Conduit()->GetRTCPSenderReport(&packetsSent, &bytesSent)) {
             remoteId = NS_LITERAL_STRING("inbound_rtcp_") + idstr;
-            RTCOutboundRTPStreamStats s;
+            RTCRemoteOutboundRtpStreamStats s;
             // TODO Bug 1496533 - use reception time not query time
             s.mTimestamp.Construct(query->now);
             s.mId.Construct(remoteId);
             s.mType.Construct(RTCStatsType::Remote_outbound_rtp);
             ssrc.apply([&s](uint32_t aSsrc) { s.mSsrc.Construct(aSsrc); });
             s.mMediaType.Construct(
                 kind);  // mediaType is the old name for kind.
             s.mKind.Construct(kind);
             s.mLocalId.Construct(localId);
             s.mPacketsSent.Construct(packetsSent);
             s.mBytesSent.Construct(bytesSent);
-            query->report->mOutboundRTPStreamStats.Value().AppendElement(
+            query->report->mRemoteOutboundRtpStreamStats.Value().AppendElement(
                 s, fallible);
           }
         }
         // Then, fill in local side (with cross-link to remote only if present)
-        RTCInboundRTPStreamStats s;
+        RTCInboundRtpStreamStats s;
         s.mTimestamp.Construct(query->now);
         s.mId.Construct(localId);
         s.mType.Construct(RTCStatsType::Inbound_rtp);
         ssrc.apply([&s](uint32_t aSsrc) { s.mSsrc.Construct(aSsrc); });
         s.mMediaType.Construct(kind);  // mediaType is the old name for kind.
         s.mKind.Construct(kind);
         unsigned int jitterMs, packetsLost;
         if (mp.Conduit()->GetRTPReceiverStats(&jitterMs, &packetsLost)) {
@@ -2979,17 +2981,17 @@ RefPtr<RTCStatsQueryPromise> PeerConnect
             s.mFramerateMean.Construct(framerateMean);
             s.mFramerateStdDev.Construct(framerateStdDev);
             s.mBitrateMean.Construct(bitrateMean);
             s.mBitrateStdDev.Construct(bitrateStdDev);
             s.mDiscardedPackets.Construct(discardedPackets);
             s.mFramesDecoded.Construct(framesDecoded);
           }
         });
-        query->report->mInboundRTPStreamStats.Value().AppendElement(s,
+        query->report->mInboundRtpStreamStats.Value().AppendElement(s,
                                                                     fallible);
         // Fill in Contributing Source statistics
         mp.GetContributingSourceStats(
             localId, query->report->mRtpContributingSourceStats.Value());
         break;
       }
     }
   }
--- a/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp
+++ b/media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp
@@ -939,23 +939,22 @@ static void StoreLongTermICEStatisticsIm
   for (auto& streamResult : streamResults) {
     Telemetry::RecordWebrtcIceCandidates(
         streamResult.second.candidateTypeBitpattern,
         streamResult.second.streamSucceeded);
   }
 
   // Beyond ICE, accumulate telemetry for various PER_CALL settings here.
 
-  if (query->report->mOutboundRTPStreamStats.WasPassed()) {
-    auto& array = query->report->mOutboundRTPStreamStats.Value();
+  if (query->report->mOutboundRtpStreamStats.WasPassed()) {
+    auto& array = query->report->mOutboundRtpStreamStats.Value();
     for (decltype(array.Length()) i = 0; i < array.Length(); i++) {
       auto& s = array[i];
       bool isVideo = (s.mId.Value().Find("video") != -1);
-      bool isRemote = s.mType.Value() == dom::RTCStatsType::Remote_outbound_rtp;
-      if (!isVideo || isRemote) {
+      if (!isVideo) {
         continue;
       }
       if (s.mBitrateMean.WasPassed()) {
         Accumulate(WEBRTC_VIDEO_ENCODER_BITRATE_AVG_PER_CALL_KBPS,
                    uint32_t(s.mBitrateMean.Value() / 1000));
       }
       if (s.mBitrateStdDev.WasPassed()) {
         Accumulate(WEBRTC_VIDEO_ENCODER_BITRATE_STD_DEV_PER_CALL_KBPS,
@@ -974,23 +973,22 @@ static void StoreLongTermICEStatisticsIm
         if (mins > 0) {
           Accumulate(WEBRTC_VIDEO_ENCODER_DROPPED_FRAMES_PER_CALL_FPM,
                      uint32_t(double(s.mDroppedFrames.Value()) / mins));
         }
       }
     }
   }
 
-  if (query->report->mInboundRTPStreamStats.WasPassed()) {
-    auto& array = query->report->mInboundRTPStreamStats.Value();
+  if (query->report->mInboundRtpStreamStats.WasPassed()) {
+    auto& array = query->report->mInboundRtpStreamStats.Value();
     for (decltype(array.Length()) i = 0; i < array.Length(); i++) {
       auto& s = array[i];
       bool isVideo = (s.mId.Value().Find("video") != -1);
-      bool isRemote = s.mType.Value() == dom::RTCStatsType::Remote_inbound_rtp;
-      if (!isVideo || isRemote) {
+      if (!isVideo) {
         continue;
       }
       if (s.mBitrateMean.WasPassed()) {
         Accumulate(WEBRTC_VIDEO_DECODER_BITRATE_AVG_PER_CALL_KBPS,
                    uint32_t(s.mBitrateMean.Value() / 1000));
       }
       if (s.mBitrateStdDev.WasPassed()) {
         Accumulate(WEBRTC_VIDEO_DECODER_BITRATE_STD_DEV_PER_CALL_KBPS,