Bug 906990: Part 10. Webidl and implementation for WebrtcGlobal. Encompasses things like global stats and logging. r=jib,bz
authorByron Campen [:bwc] <docfaraday@gmail.com>
Mon, 25 Nov 2013 11:01:03 -0800
changeset 172296 765f15f432c8f973cf03bd0fb7d2aa65858c0036
parent 172295 41e6b65a12a619217c5fda4f55f862c5a58aee20
child 172297 df21e1d3eaa28000b8539d85ddf7891ed1101ff6
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, bz
bugs906990
milestone28.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 906990: Part 10. Webidl and implementation for WebrtcGlobal. Encompasses things like global stats and logging. r=jib,bz
CLOBBER
dom/media/PeerConnection.js
dom/media/PeerConnection.manifest
dom/webidl/PeerConnectionImpl.webidl
dom/webidl/PeerConnectionObserver.webidl
dom/webidl/RTCPeerConnection.webidl
dom/webidl/RTCStatsReport.webidl
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,10 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 942207 - apparently need clobber to avoid bustage
+WebIDL dictionary modification requires clobber on Windows (bug 928195), part of
+bug 906990.
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -5,24 +5,26 @@
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1";
+const WEBRTC_GLOBAL_CONTRACT = "@mozilla.org/dom/webrtcglobalinformation1";
 const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1";
 const PC_ICE_CONTRACT = "@mozilla.org/dom/rtcicecandidate;1";
 const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
 const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1";
 const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1";
 
 const PC_CID = Components.ID("{00e0e20d-1494-4776-8e0e-0f0acbea3c79}");
-const PC_OBS_CID = Components.ID("{1d44a18e-4545-4ff3-863d-6dbd6234a583}");
+const WEBRTC_GLOBAL_CID = Components.ID("{f6063d11-f467-49ad-9765-e7923050dc08}");
+const PC_OBS_CID = Components.ID("{d1748d4c-7f6a-4dc5-add6-d55b7678537e}");
 const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}");
 const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}");
 const PC_MANAGER_CID = Components.ID("{7293e901-2be3-4c02-b4bd-cbef6fc24f78}");
 const PC_STATS_CID = Components.ID("{7fe6e18b-0da3-4056-bf3b-440ef3809e06}");
 
 // Global list of PeerConnection objects, so they can be cleaned up when
 // a page is torn down. (Maps inner window ID to an array of PC objects).
 function GlobalPCList() {
@@ -58,16 +60,20 @@ GlobalPCList.prototype = {
   },
 
   removeNullRefs: function(winID) {
     if (this._list[winID] === undefined) {
       return;
     }
     this._list[winID] = this._list[winID].filter(
       function (e,i,a) { return e.get() !== null; });
+
+    if (this._list[winID].length === 0) {
+      delete this._list[winID];
+    }
   },
 
   hasActivePeerConnection: function(winID) {
     this.removeNullRefs(winID);
     return this._list[winID] ? true : false;
   },
 
   observe: function(subject, topic, data) {
@@ -106,19 +112,70 @@ GlobalPCList.prototype = {
       if (data == "offline") {
 	// this._list shold be empty here
         this._networkdown = true;
       } else if (data == "online") {
         this._networkdown = false;
       }
     }
   },
+
+  getStatsForEachPC: function(callback, errorCallback) {
+    for (let winId in this._list) {
+      if (this._list.hasOwnProperty(winId)) {
+        this.removeNullRefs(winId);
+        if (this._list[winId]) {
+          this._list[winId].forEach(function(pcref) {
+            pcref.get().getStatsInternal(null, callback, errorCallback);
+          });
+        }
+      }
+    }
+  },
+
+  getLoggingFromFirstPC: function(pattern, callback, errorCallback) {
+    for (let winId in this._list) {
+      this.removeNullRefs(winId);
+      if (this._list[winId]) {
+        // We expect removeNullRefs to not leave us with an empty array here
+        let pcref = this._list[winId][0];
+        pcref.get().getLogging(pattern, callback, errorCallback);
+        return;
+      }
+    }
+  },
 };
 let _globalPCList = new GlobalPCList();
 
+function WebrtcGlobalInformation() {
+}
+WebrtcGlobalInformation.prototype = {
+  classDescription: "WebrtcGlobalInformation",
+  classID: WEBRTC_GLOBAL_CID,
+  contractID: WEBRTC_GLOBAL_CONTRACT,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
+
+  getAllStats: function(successCallback, failureCallback) {
+    if (_globalPCList) {
+      _globalPCList.getStatsForEachPC(successCallback, failureCallback);
+    } else {
+      failureCallback("No global PeerConnection list");
+    }
+  },
+
+  getCandPairLogs: function(candPairId, callback, errorCallback) {
+    let pattern = 'CAND-PAIR(' + candPairId + ')';
+    if (_globalPCList) {
+      _globalPCList.getLoggingFromFirstPC(pattern, callback, errorCallback);
+    } else {
+      errorCallback("No global PeerConnection list");
+    }
+  },
+};
+
 function RTCIceCandidate() {
   this.candidate = this.sdpMid = this.sdpMLineIndex = null;
 }
 RTCIceCandidate.prototype = {
   classDescription: "mozRTCIceCandidate",
   classID: PC_ICE_CID,
   contractID: PC_ICE_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
@@ -146,19 +203,20 @@ RTCSessionDescription.prototype = {
   init: function(win) { this._win = win; },
 
   __init: function(dict) {
     this.type = dict.type;
     this.sdp  = dict.sdp;
   }
 };
 
-function RTCStatsReport(win, report) {
+function RTCStatsReport(win, report, pcid) {
   this._win = win;
   this.report = report;
+  this.mozPcid = pcid;
 }
 RTCStatsReport.prototype = {
   classDescription: "RTCStatsReport",
   classID: PC_STATS_CID,
   contractID: PC_STATS_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 
@@ -199,16 +257,18 @@ function RTCPeerConnection() {
   this._closed = false;
 
   this._onCreateOfferSuccess = null;
   this._onCreateOfferFailure = null;
   this._onCreateAnswerSuccess = null;
   this._onCreateAnswerFailure = null;
   this._onGetStatsSuccess = null;
   this._onGetStatsFailure = null;
+  this._onGetLoggingSuccess = null;
+  this._onGetLoggingFailure = null;
 
   this._pendingType = null;
   this._localType = null;
   this._remoteType = null;
   this._trickleIce = false;
 
   /**
    * Everytime we get a request from content, we put it in the queue. If
@@ -731,16 +791,31 @@ RTCPeerConnection.prototype = {
 
   _getStats: function(selector, onSuccess, onError, internal) {
     this._onGetStatsSuccess = onSuccess;
     this._onGetStatsFailure = onError;
 
     this._getPC().getStats(selector, internal);
   },
 
+  getLogging: function(pattern, onSuccess, onError) {
+    this._queueOrRun({
+      func: this._getLogging,
+      args: [pattern, onSuccess, onError],
+      wait: true
+    });
+  },
+
+  _getLogging: function(pattern, onSuccess, onError) {
+    this._onGetLoggingSuccess = onSuccess;
+    this._onGetLoggingFailure = onError;
+
+    this._getPC().getLogging(pattern);
+  },
+
   createDataChannel: function(label, dict) {
     this._checkClosed();
     if (dict == undefined) {
       dict = {};
     }
     if (dict.maxRetransmitNum != undefined) {
       dict.maxRetransmits = dict.maxRetransmitNum;
       this.reportWarning("Deprecated RTCDataChannelInit dictionary entry maxRetransmitNum used!", null, 0);
@@ -1081,25 +1156,36 @@ PeerConnectionObserver.prototype = {
     appendStats(dict.iceComponentStats, report);
     appendStats(dict.iceCandidatePairStats, report);
     appendStats(dict.iceCandidateStats, report);
     appendStats(dict.codecStats, report);
 
     this.callCB(this._dompc._onGetStatsSuccess,
                 this._dompc._win.RTCStatsReport._create(this._dompc._win,
                                                         new RTCStatsReport(this._dompc._win,
-                                                                           report)));
+                                                                           report,
+                                                                           dict.pcid)));
     this._dompc._executeNext();
   },
 
   onGetStatsError: function(code, message) {
     this.callCB(this._dompc._onGetStatsFailure, new RTCError(code, message));
     this._dompc._executeNext();
   },
 
+  onGetLoggingSuccess: function(logs) {
+    this.callCB(this._dompc._onGetLoggingSuccess, logs);
+    this._dompc._executeNext();
+  },
+
+  onGetLoggingError: function(code, message) {
+    this.callCB(this._dompc._onGetLoggingFailure, new RTCError(code, message));
+    this._dompc._executeNext();
+  },
+
   onAddStream: function(stream) {
     this.dispatchEvent(new this._dompc._win.MediaStreamEvent("addstream",
                                                              { stream: stream }));
   },
 
   onRemoveStream: function(stream, type) {
     this.dispatchEvent(new this._dompc._win.MediaStreamEvent("removestream",
                                                              { stream: stream }));
@@ -1124,11 +1210,16 @@ PeerConnectionObserver.prototype = {
   },
 
   getSupportedConstraints: function(dict) {
     return dict;
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
-  [GlobalPCList, RTCIceCandidate, RTCSessionDescription, RTCPeerConnection,
-   RTCStatsReport, PeerConnectionObserver]
+  [GlobalPCList,
+   RTCIceCandidate,
+   RTCSessionDescription,
+   RTCPeerConnection,
+   RTCStatsReport,
+   PeerConnectionObserver,
+   WebrtcGlobalInformation]
 );
--- a/dom/media/PeerConnection.manifest
+++ b/dom/media/PeerConnection.manifest
@@ -1,13 +1,15 @@
 component {00e0e20d-1494-4776-8e0e-0f0acbea3c79} PeerConnection.js
-component {1d44a18e-4545-4ff3-863d-6dbd6234a583} PeerConnection.js
+component {f6063d11-f467-49ad-9765-e7923050dc08} PeerConnection.js
+component {d1748d4c-7f6a-4dc5-add6-d55b7678537e} PeerConnection.js
 component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js
 component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js
 component {7293e901-2be3-4c02-b4bd-cbef6fc24f78} PeerConnection.js
 component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js
 
 contract @mozilla.org/dom/peerconnection;1 {00e0e20d-1494-4776-8e0e-0f0acbea3c79}
-contract @mozilla.org/dom/peerconnectionobserver;1 {1d44a18e-4545-4ff3-863d-6dbd6234a583}
+contract @mozilla.org/dom/webrtcglobalinformation;1 {f6063d11-f467-49ad-9765-e7923050dc08}
+contract @mozilla.org/dom/peerconnectionobserver;1 {d1748d4c-7f6a-4dc5-add6-d55b7678537e}
 contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac66073}
 contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7}
 contract @mozilla.org/dom/peerconnectionmanager;1 {7293e901-2be3-4c02-b4bd-cbef6fc24f78}
 contract @mozilla.org/dom/rtcstatsreport;1 {7fe6e18b-0da3-4056-bf3b-440ef3809e06}
--- a/dom/webidl/PeerConnectionImpl.webidl
+++ b/dom/webidl/PeerConnectionImpl.webidl
@@ -28,20 +28,27 @@ interface PeerConnectionImpl  {
   void createOffer(optional MediaConstraintsInternal constraints);
   [Throws]
   void createAnswer(optional MediaConstraintsInternal constraints);
   [Throws]
   void setLocalDescription(long action, DOMString sdp);
   [Throws]
   void setRemoteDescription(long action, DOMString sdp);
 
-  /* Stats call */
+  /* Stats call, calls either |onGetStatsSuccess| or |onGetStatsError| on our
+     observer. (see the |PeerConnectionObserver| interface) */
   [Throws]
   void getStats(MediaStreamTrack? selector, boolean internalStats);
 
+  /* Scrapes the RLogRingbuffer, and calls either |onGetLoggingSuccess|
+     or |onGetLoggingError| on our observer.
+     (see the |PeerConnectionObserver| interface) */
+  [Throws]
+  void getLogging(DOMString pattern);
+
   /* Adds the stream created by GetUserMedia */
   [Throws]
   void addStream(MediaStream stream);
   [Throws]
   void removeStream(MediaStream stream);
   [Throws]
   void closeStreams();
 
--- a/dom/webidl/PeerConnectionObserver.webidl
+++ b/dom/webidl/PeerConnectionObserver.webidl
@@ -23,16 +23,20 @@ interface PeerConnectionObserver
   void onAddIceCandidateSuccess();
   void onAddIceCandidateError(unsigned long name, DOMString message);
   void onIceCandidate(unsigned short level, DOMString mid, DOMString candidate);
 
   /* Stats callbacks */
   void onGetStatsSuccess(optional RTCStatsReportInternal report);
   void onGetStatsError(unsigned long name, DOMString message);
 
+  /* Logging callbacks */
+  void onGetLoggingSuccess(sequence<DOMString> logs);
+  void onGetLoggingError(unsigned long name, DOMString message);
+
   /* Data channel callbacks */
   void notifyDataChannel(DataChannel channel);
   void notifyConnection();
   void notifyClosedConnection();
 
   /* Notification of one of several types of state changed */
   void onStateChange(PCObserverStateType state);
 
--- a/dom/webidl/RTCPeerConnection.webidl
+++ b/dom/webidl/RTCPeerConnection.webidl
@@ -132,8 +132,24 @@ interface mozRTCPeerConnection : EventTa
 
   // Data channel.
   RTCDataChannel createDataChannel (DOMString label,
                                     optional RTCDataChannelInit dataChannelDict);
   attribute EventHandler ondatachannel;
   attribute EventHandler onconnection;
   attribute EventHandler onclosedconnection;
 };
+
+callback RTCLogCallback = void (sequence<DOMString> logMessages);
+
+[JSImplementation="@mozilla.org/dom/webrtcglobalinformation;1",
+ ChromeOnly,
+ Constructor ()]
+interface WebrtcGlobalInformation {
+    void getAllStats(RTCStatsCallback callback,
+                     RTCPeerConnectionErrorCallback errorCallback);
+    void getCandPairLogs(DOMString candPairId,
+                         RTCLogCallback callback,
+                         RTCPeerConnectionErrorCallback errorCallback);
+};
+
+
+
--- a/dom/webidl/RTCStatsReport.webidl
+++ b/dom/webidl/RTCStatsReport.webidl
@@ -119,16 +119,17 @@ dictionary RTCCodecStats : RTCStats {
 };
 
 callback RTCStatsReportCallback = void (RTCStatsReport obj);
 
 // This is the internal representation of the report in this implementation
 // to be received from c++
 
 dictionary RTCStatsReportInternal {
+  DOMString                           pcid;
   sequence<RTCRTPStreamStats>         rtpStreamStats;
   sequence<RTCInboundRTPStreamStats>  inboundRTPStreamStats;
   sequence<RTCOutboundRTPStreamStats> outboundRTPStreamStats;
   sequence<RTCMediaStreamTrackStats>  mediaStreamTrackStats;
   sequence<RTCMediaStreamStats>       mediaStreamStats;
   sequence<RTCTransportStats>         transportStats;
   sequence<RTCIceComponentStats>      iceComponentStats;
   sequence<RTCIceCandidatePairStats>  iceCandidatePairStats;
@@ -136,12 +137,14 @@ dictionary RTCStatsReportInternal {
   sequence<RTCCodecStats>             codecStats;
 };
 
 [Pref="media.peerconnection.enabled",
 // TODO: Use MapClass here once it's available (Bug 928114)
 // MapClass(DOMString, object)
  JSImplementation="@mozilla.org/dom/rtcstatsreport;1"]
 interface RTCStatsReport {
+  [ChromeOnly]
+  readonly attribute DOMString mozPcid;
   void forEach(RTCStatsReportCallback callbackFn, optional any thisArg);
   object get(DOMString key);
   boolean has(DOMString key);
 };
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <cstdlib>
 #include <cerrno>
+#include <deque>
 
 #include "base/histogram.h"
 #include "vcm.h"
 #include "CSFLog.h"
 #include "timecard.h"
 #include "ccapi_call_info.h"
 #include "CC_SIPCCCallInfo.h"
 #include "ccapi_device_info.h"
@@ -59,16 +60,17 @@
 #include "mozilla/dom/RTCStatsReportBinding.h"
 #include "mozilla/dom/RTCPeerConnectionBinding.h"
 #include "mozilla/dom/PeerConnectionImplBinding.h"
 #include "mozilla/dom/DataChannelBinding.h"
 #include "MediaStreamList.h"
 #include "MediaStreamTrack.h"
 #include "nsIScriptGlobalObject.h"
 #include "DOMMediaStream.h"
+#include "rlogringbuffer.h"
 #endif
 
 #ifndef USE_FAKE_MEDIA_STREAMS
 #include "MediaSegment.h"
 #endif
 
 #ifdef USE_FAKE_PCOBSERVER
 #include "FakePCObserver.h"
@@ -1196,16 +1198,33 @@ PeerConnectionImpl::GetStats(MediaStream
                              internalStats,
                              now),
                 NS_DISPATCH_NORMAL);
 #endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
+PeerConnectionImpl::GetLogging(const nsAString& aPattern) {
+  PC_AUTO_ENTER_API_CALL(true);
+
+#ifdef MOZILLA_INTERNAL_API
+  std::string pattern(NS_ConvertUTF16toUTF8(aPattern).get());
+  nsRefPtr<PeerConnectionImpl> pc(this);
+  RUN_ON_THREAD(mSTSThread,
+                WrapRunnable(pc,
+                             &PeerConnectionImpl::GetLogging_s,
+                             pattern),
+                NS_DISPATCH_NORMAL);
+
+#endif
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, unsigned short aLevel) {
   PC_AUTO_ENTER_API_CALL(true);
 
   Timecard *tc = mTimeCard;
   mTimeCard = nullptr;
   STAMP_TIMECARD(tc, "Add Ice Candidate");
 
   mInternal->mCall->addICECandidate(aCandidate, aMid, aLevel, tc);
@@ -1699,31 +1718,31 @@ void PeerConnectionImpl::GetStats_s(
     bool internalStats,
     DOMHighResTimeStamp now) {
 
   nsresult result = NS_OK;
   nsAutoPtr<RTCStatsReportInternal> report(new RTCStatsReportInternal);
   if (!report) {
     result = NS_ERROR_FAILURE;
   }
+
+  report->mPcid.Construct(NS_ConvertASCIItoUTF16(mHandle.c_str()));
   if (mMedia) {
     RefPtr<NrIceMediaStream> mediaStream(
         mMedia->ice_media_stream(trackId));
     if (mediaStream) {
       std::vector<NrIceCandidatePair> candPairs;
       mediaStream->GetCandidatePairs(&candPairs);
       report->mIceCandidatePairStats.Construct();
       report->mIceCandidateStats.Construct();
       NS_ConvertASCIItoUTF16 componentId(mediaStream->name().c_str());
       for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
         NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
-        const nsString localCodeword(
-            NS_ConvertASCIItoUTF16("local_") + codeword);
-        const nsString remoteCodeword(
-            NS_ConvertASCIItoUTF16("remote_") + codeword);
+        NS_ConvertASCIItoUTF16 localCodeword(p->local.codeword.c_str());
+        NS_ConvertASCIItoUTF16 remoteCodeword(p->remote.codeword.c_str());
         // Only expose candidate-pair statistics to chrome, until we've thought
         // through the implications of exposing it to content.
 
         if (internalStats) {
           RTCIceCandidatePairStats s;
           s.mId.Construct(codeword);
           s.mComponentId.Construct(componentId);
           s.mTimestamp.Construct(now);
@@ -1793,16 +1812,55 @@ void PeerConnectionImpl::OnStatsReport_m
                            rv);
     }
 
     if (rv.Failed()) {
       CSFLogError(logTag, "Error firing stats observer callback");
     }
   }
 }
+
+void PeerConnectionImpl::GetLogging_s(const std::string& pattern) {
+  RLogRingBuffer* logs = RLogRingBuffer::GetInstance();
+  std::deque<std::string> result;
+  logs->Filter(pattern, 0, &result);
+  nsRefPtr<PeerConnectionImpl> pc(this);
+  RUN_ON_THREAD(mThread,
+                WrapRunnable(pc,
+                             &PeerConnectionImpl::OnGetLogging_m,
+                             pattern,
+                             result),
+                NS_DISPATCH_NORMAL);
+}
+
+void PeerConnectionImpl::OnGetLogging_m(const std::string& pattern,
+                                        const std::deque<std::string>& logging) {
+  nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
+  if (!pco) {
+    return;
+  }
+
+  JSErrorResult rv;
+  if (!logging.empty()) {
+    Sequence<nsString> nsLogs;
+    for (auto l = logging.begin(); l != logging.end(); ++l) {
+      nsLogs.AppendElement(ObString(l->c_str()));
+    }
+    pco->OnGetLoggingSuccess(nsLogs, rv);
+  } else {
+    pco->OnGetLoggingError(kInternalError,
+        ObString(("No logging matching pattern " + pattern).c_str()), rv);
+  }
+
+  if (rv.Failed()) {
+    CSFLogError(logTag, "Error firing stats observer callback");
+  }
+}
+
+
 #endif
 
 void
 PeerConnectionImpl::IceStreamReady(NrIceMediaStream *aStream)
 {
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
   MOZ_ASSERT(aStream);
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _PEER_CONNECTION_IMPL_H_
 #define _PEER_CONNECTION_IMPL_H_
 
+#include <deque>
 #include <string>
 #include <vector>
 #include <map>
 #include <cmath>
 
 #include "prlock.h"
 #include "mozilla/RefPtr.h"
 #include "nsWeakPtr.h"
@@ -302,16 +303,22 @@ public:
 
   NS_IMETHODIMP_TO_ERRORRESULT(GetStats, ErrorResult &rv,
                                mozilla::dom::MediaStreamTrack *aSelector,
                                bool internalStats)
   {
     rv = GetStats(aSelector, internalStats);
   }
 
+  NS_IMETHODIMP_TO_ERRORRESULT(GetLogging, ErrorResult &rv,
+                               const nsAString& pattern)
+  {
+    rv = GetLogging(pattern);
+  }
+
   NS_IMETHODIMP AddIceCandidate(const char* aCandidate, const char* aMid,
                                 unsigned short aLevel);
   void AddIceCandidate(const nsAString& aCandidate, const nsAString& aMid,
                        unsigned short aLevel, ErrorResult &rv)
   {
     rv = AddIceCandidate(NS_ConvertUTF16toUTF8(aCandidate).get(),
                          NS_ConvertUTF16toUTF8(aMid).get(), aLevel);
   }
@@ -489,16 +496,23 @@ private:
   void GetStats_s(uint32_t trackId,
                   bool internalStats,
                   DOMHighResTimeStamp now);
 
   // Sends an RTCStatsReport to JS. Must run on main thread.
   void OnStatsReport_m(uint32_t trackId,
                        nsresult result,
                        nsAutoPtr<mozilla::dom::RTCStatsReportInternal> report);
+
+  // Fetches logs matching pattern from RLogRingBuffer. Must be run on STS.
+  void GetLogging_s(const std::string& pattern);
+
+  // Sends logging to JS. Must run on main thread.
+  void OnGetLogging_m(const std::string& pattern,
+                      const std::deque<std::string>& logging);
 #endif
 
   // Timecard used to measure processing time. This should be the first class
   // attribute so that we accurately measure the time required to instantiate
   // any other attributes of this class.
   Timecard *mTimeCard;
 
   // The call