RTCStatsReport.h (7577B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 6 7 #ifndef RTCStatsReport_h_ 8 #define RTCStatsReport_h_ 9 10 #include "api/units/timestamp.h" // webrtc::Timestamp 11 #include "js/RootingAPI.h" // JS::Rooted 12 #include "js/Value.h" 13 #include "mozilla/ErrorResult.h" 14 #include "mozilla/MozPromise.h" 15 #include "mozilla/TimeStamp.h" 16 #include "mozilla/UniquePtr.h" 17 #include "mozilla/dom/AutoEntryScript.h" 18 #include "mozilla/dom/PerformanceService.h" 19 #include "mozilla/dom/RTCStatsReportBinding.h" // RTCStatsCollection 20 #include "mozilla/dom/ToJSValue.h" 21 #include "nsCOMPtr.h" 22 #include "nsContentUtils.h" 23 #include "nsIGlobalObject.h" 24 #include "nsPIDOMWindow.h" // nsPIDOMWindowInner 25 #include "nsWrapperCache.h" 26 #include "prtime.h" // PR_Now 27 28 namespace mozilla { 29 30 extern TimeStamp WebrtcSystemTimeBase(); 31 32 namespace dom { 33 34 /** 35 * Keeps the state needed to convert RTCStatsTimestamps. 36 */ 37 struct RTCStatsTimestampState { 38 RTCStatsTimestampState(); 39 explicit RTCStatsTimestampState(Performance& aPerformance); 40 41 RTCStatsTimestampState(const RTCStatsTimestampState&) = default; 42 43 // These members are sampled when a non-copy constructor is called. 44 45 // Performance's random timeline seed. 46 const uint64_t mRandomTimelineSeed; 47 // TimeStamp::Now() when the members were sampled. This is equivalent to time 48 // 0 in DomRealtime. 49 const TimeStamp mStartDomRealtime; 50 // WebrtcSystemTime() when the members were sampled. This represents the same 51 // point in time as mStartDomRealtime, but as a webrtc timestamp. 52 const webrtc::Timestamp mStartRealtime; 53 // Performance's RTPCallerType. 54 const RTPCallerType mRTPCallerType; 55 // Performance.timeOrigin for mStartDomRealtime when the members were sampled. 56 const DOMHighResTimeStamp mStartWallClockRaw; 57 58 protected: 59 RTCStatsTimestampState(TimeStamp aStartDomRealtime, 60 webrtc::Timestamp aStartRealtime); 61 }; 62 63 /** 64 * Classes that facilitate creating timestamps for webrtc stats by mimicking 65 * dom::Performance, as well as getting and converting timestamps for libwebrtc 66 * and our integration with it. 67 * 68 * They use the same clock to avoid drift and inconsistencies, base on 69 * mozilla::TimeStamp, and convert to and from these time bases: 70 * - Moz : Monotonic, unspecified (but constant) and inaccessible epoch, 71 * as implemented by mozilla::TimeStamp 72 * - Realtime : Monotonic, unspecified (but constant) epoch. 73 * - 1Jan1970 : Monotonic, unix epoch (00:00:00 UTC on 1 January 1970). 74 * - Ntp : Monotonic, ntp epoch (00:00:00 UTC on 1 January 1900). 75 * - Dom : Monotonic, milliseconds since unix epoch, as the timestamps 76 * defined by webrtc-pc. Corresponds to Performance.timeOrigin + 77 * Performance.now(). Has reduced precision. 78 * - DomRealtime: Like Dom, but with full precision. 79 * - WallClock : Non-monotonic, unix epoch. Not used here since it is 80 * non-monotonic and cannot be correlated to the other time 81 * bases. 82 */ 83 class RTCStatsTimestampMaker; 84 class RTCStatsTimestamp { 85 public: 86 TimeStamp ToMozTime() const; 87 webrtc::Timestamp ToRealtime() const; 88 webrtc::Timestamp To1Jan1970() const; 89 webrtc::Timestamp ToNtp() const; 90 webrtc::Timestamp ToDomRealtime() const; 91 DOMHighResTimeStamp ToDom() const; 92 93 static RTCStatsTimestamp FromMozTime(const RTCStatsTimestampMaker& aMaker, 94 TimeStamp aMozTime); 95 static RTCStatsTimestamp FromRealtime(const RTCStatsTimestampMaker& aMaker, 96 webrtc::Timestamp aRealtime); 97 static RTCStatsTimestamp From1Jan1970(const RTCStatsTimestampMaker& aMaker, 98 webrtc::Timestamp aRealtime); 99 static RTCStatsTimestamp FromNtp(const RTCStatsTimestampMaker& aMaker, 100 webrtc::Timestamp aRealtime); 101 static RTCStatsTimestamp FromDomRealtime(const RTCStatsTimestampMaker& aMaker, 102 webrtc::Timestamp aDomRealtime); 103 // There is on purpose no conversion functions from DOMHighResTimeStamp 104 // because of the loss in precision of a floating point to integer conversion. 105 106 private: 107 RTCStatsTimestamp(RTCStatsTimestampState aState, TimeStamp aMozTime); 108 109 const RTCStatsTimestampState mState; 110 const TimeStamp mMozTime; 111 }; 112 113 class RTCStatsTimestampMaker { 114 public: 115 static RTCStatsTimestampMaker Create(nsPIDOMWindowInner* aWindow = nullptr); 116 117 RTCStatsTimestamp GetNow() const; 118 119 const RTCStatsTimestampState mState; 120 121 protected: 122 explicit RTCStatsTimestampMaker(RTCStatsTimestampState aState); 123 }; 124 125 // TODO(bug 1588303): If we ever get move semantics for webidl dictionaries, we 126 // can stop wrapping these in UniquePtr, which will allow us to simplify code 127 // in several places. 128 typedef MozPromise<UniquePtr<RTCStatsCollection>, nsresult, true> 129 RTCStatsPromise; 130 131 typedef MozPromise<UniquePtr<RTCStatsReportInternal>, nsresult, true> 132 RTCStatsReportPromise; 133 134 class RTCStatsReport final : public nsWrapperCache { 135 public: 136 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(RTCStatsReport) 137 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(RTCStatsReport) 138 139 explicit RTCStatsReport(nsPIDOMWindowInner* aParent); 140 141 // TODO(bug 1586109): Remove this once we no longer have to create empty 142 // RTCStatsReports from JS. 143 static already_AddRefed<RTCStatsReport> Constructor( 144 const GlobalObject& aGlobal); 145 146 void Incorporate(RTCStatsCollection& aStats); 147 148 nsPIDOMWindowInner* GetParentObject() const { return mParent; } 149 150 JSObject* WrapObject(JSContext* aCx, 151 JS::Handle<JSObject*> aGivenProto) override; 152 153 private: 154 ~RTCStatsReport() = default; 155 void Set(const nsAString& aKey, JS::Handle<JSObject*> aValue, 156 ErrorResult& aRv); 157 158 template <typename T> 159 nsresult SetRTCStats(Sequence<T>& aValues) { 160 for (T& value : aValues) { 161 nsresult rv = SetRTCStats(value); 162 if (NS_FAILED(rv)) { 163 return rv; 164 } 165 } 166 return NS_OK; 167 } 168 169 // We cannot just declare this as SetRTCStats(RTCStats&), because the 170 // conversion function that ToJSValue uses is non-virtual. 171 template <typename T> 172 nsresult SetRTCStats(T& aValue) { 173 static_assert(std::is_base_of<RTCStats, T>::value, 174 "SetRTCStats is for setting RTCStats only"); 175 176 if (!aValue.mId.WasPassed()) { 177 return NS_OK; 178 } 179 180 const nsString key(aValue.mId.Value()); 181 182 // Cargo-culted from dom::Promise; converts aValue to a JSObject 183 AutoEntryScript aes(mParent->AsGlobal()->GetGlobalJSObject(), 184 "RTCStatsReport::SetRTCStats"); 185 JSContext* cx = aes.cx(); 186 JS::Rooted<JS::Value> val(cx); 187 if (!ToJSValue(cx, std::forward<T>(aValue), &val)) { 188 return NS_ERROR_FAILURE; 189 } 190 JS::Rooted<JSObject*> jsObject(cx, &val.toObject()); 191 192 ErrorResult rv; 193 Set(key, jsObject, rv); 194 return rv.StealNSResult(); 195 } 196 197 nsCOMPtr<nsPIDOMWindowInner> mParent; 198 }; 199 200 void MergeStats(UniquePtr<dom::RTCStatsCollection> aFromStats, 201 dom::RTCStatsCollection* aIntoStats); 202 203 void FlattenStats(nsTArray<UniquePtr<dom::RTCStatsCollection>> aFromStats, 204 dom::RTCStatsCollection* aIntoStats); 205 206 } // namespace dom 207 } // namespace mozilla 208 209 #endif // RTCStatsReport_h_