mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1729455 - Modularize RTCStatsTimestampMaker::GetNow(). r=ng,bwc
This is needed in order to provide precision reduction on timestamps from libwebrtc. Similarly useful for providing a clock adapter so libwebrtc can use our clock. Differential Revision: https://phabricator.services.mozilla.com/D125715
This commit is contained in:
parent
3d7a221d58
commit
4a1326da33
@ -2649,7 +2649,8 @@ nsTArray<RefPtr<dom::RTCStatsPromise>> PeerConnectionImpl::GetSenderStats(
|
||||
[&](RTCOutboundRtpStreamStats& aLocal) {
|
||||
ssrc.apply(
|
||||
[&](uint32_t aSsrc) { aLocal.mSsrc.Construct(aSsrc); });
|
||||
aLocal.mTimestamp.Construct(aPipeline->GetNow());
|
||||
aLocal.mTimestamp.Construct(
|
||||
aPipeline->GetTimestampMaker().GetNow());
|
||||
aLocal.mId.Construct(localId);
|
||||
aLocal.mType.Construct(RTCStatsType::Outbound_rtp);
|
||||
aLocal.mMediaType.Construct(
|
||||
|
@ -267,7 +267,8 @@ nsTArray<RefPtr<RTCStatsPromise>> RTCRtpReceiver::GetStatsInternal() {
|
||||
|
||||
auto constructCommonInboundRtpStats =
|
||||
[&](RTCInboundRtpStreamStats& aLocal) {
|
||||
aLocal.mTimestamp.Construct(pipeline->GetNow());
|
||||
aLocal.mTimestamp.Construct(
|
||||
pipeline->GetTimestampMaker().GetNow());
|
||||
aLocal.mId.Construct(localId);
|
||||
aLocal.mType.Construct(RTCStatsType::Inbound_rtp);
|
||||
ssrc.apply(
|
||||
@ -483,7 +484,8 @@ nsTArray<RefPtr<RTCStatsPromise>> RTCRtpReceiver::GetStatsInternal() {
|
||||
|
||||
if (mJsepTransceiver->mTransport.mComponents) {
|
||||
promises.AppendElement(mTransportHandler->GetIceStats(
|
||||
mJsepTransceiver->mTransport.mTransportId, mPipeline->GetNow()));
|
||||
mJsepTransceiver->mTransport.mTransportId,
|
||||
mPipeline->GetTimestampMaker().GetNow()));
|
||||
}
|
||||
|
||||
return promises;
|
||||
|
@ -5,30 +5,34 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "RTCStatsReport.h"
|
||||
#include "libwebrtcglue/SystemTime.h"
|
||||
#include "mozilla/dom/Performance.h"
|
||||
#include "mozilla/dom/PerformanceService.h"
|
||||
#include "nsRFPService.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
RTCStatsTimestampMaker::RTCStatsTimestampMaker(nsPIDOMWindowInner* aWindow)
|
||||
: mRandomTimelineSeed(aWindow && aWindow->GetPerformance() ?
|
||||
aWindow->GetPerformance()->GetRandomTimelineSeed() : 0),
|
||||
mStartMonotonic(aWindow && aWindow->GetPerformance() ?
|
||||
aWindow->GetPerformance()->CreationTimeStamp() : mozilla::TimeStamp::Now()),
|
||||
// Ugh. Performance::TimeOrigin is not constant, which means we need to
|
||||
// emulate this weird behavior so our time stamps are consistent with JS
|
||||
// timeOrigin. This is based on the code here:
|
||||
// https://searchfox.org/mozilla-central/rev/
|
||||
// 053826b10f838f77c27507e5efecc96e34718541/dom/performance/Performance.cpp#111-117
|
||||
RTCStatsTimestampMaker::RTCStatsTimestampMaker()
|
||||
: mRandomTimelineSeed(0),
|
||||
mStartRealtime(WebrtcSystemTimeBase()),
|
||||
mCrossOriginIsolated(false),
|
||||
mStartWallClockRaw(
|
||||
aWindow
|
||||
? PerformanceService::GetOrCreate()->TimeOrigin(mStartMonotonic)
|
||||
: (double)PR_Now() / PR_USEC_PER_MSEC),
|
||||
mCrossOriginIsolated(aWindow ? aWindow->AsGlobal()->CrossOriginIsolated()
|
||||
: false) {}
|
||||
PerformanceService::GetOrCreate()->TimeOrigin(mStartRealtime)) {}
|
||||
|
||||
DOMHighResTimeStamp RTCStatsTimestampMaker::GetNow() const {
|
||||
RTCStatsTimestampMaker::RTCStatsTimestampMaker(nsPIDOMWindowInner* aWindow)
|
||||
: mRandomTimelineSeed(
|
||||
aWindow && aWindow->GetPerformance()
|
||||
? aWindow->GetPerformance()->GetRandomTimelineSeed()
|
||||
: 0),
|
||||
mStartRealtime(aWindow && aWindow->GetPerformance()
|
||||
? aWindow->GetPerformance()->CreationTimeStamp()
|
||||
: WebrtcSystemTimeBase()),
|
||||
mCrossOriginIsolated(aWindow ? aWindow->AsGlobal()->CrossOriginIsolated()
|
||||
: false),
|
||||
mStartWallClockRaw(
|
||||
PerformanceService::GetOrCreate()->TimeOrigin(mStartRealtime)) {}
|
||||
|
||||
DOMHighResTimeStamp RTCStatsTimestampMaker::ReduceRealtimePrecision(
|
||||
webrtc::Timestamp aRealtime) const {
|
||||
// webrtc-pc says to use performance.timeOrigin + performance.now(), but
|
||||
// keeping a Performance object around is difficult because it is
|
||||
// main-thread-only. So, we perform the same calculation here. Note that this
|
||||
@ -36,18 +40,50 @@ DOMHighResTimeStamp RTCStatsTimestampMaker::GetNow() const {
|
||||
// to the wall clock, or monotonic clock drift over long periods of time.
|
||||
// We are very careful to do exactly what Performance does, to avoid timestamp
|
||||
// discrepancies.
|
||||
DOMHighResTimeStamp msSinceStart =
|
||||
(TimeStamp::Now() - mStartMonotonic).ToMilliseconds();
|
||||
|
||||
DOMHighResTimeStamp realtime = aRealtime.ms<double>();
|
||||
// mRandomTimelineSeed is not set in the unit-tests.
|
||||
if (mRandomTimelineSeed) {
|
||||
msSinceStart = nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
msSinceStart, mRandomTimelineSeed, /* aIsSystemPrincipal */ false,
|
||||
mCrossOriginIsolated);
|
||||
realtime = nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
realtime, mRandomTimelineSeed,
|
||||
/* aIsSystemPrincipal */ false, mCrossOriginIsolated);
|
||||
}
|
||||
return msSinceStart + nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
mStartWallClockRaw, 0,
|
||||
/* aIsSystemPrincipal */ false,
|
||||
mCrossOriginIsolated);
|
||||
|
||||
// Ugh. Performance::TimeOrigin is not constant, which means we need to
|
||||
// emulate this weird behavior so our time stamps are consistent with JS
|
||||
// timeOrigin. This is based on the code here:
|
||||
// https://searchfox.org/mozilla-central/rev/
|
||||
// 053826b10f838f77c27507e5efecc96e34718541/dom/performance/Performance.cpp#111-117
|
||||
DOMHighResTimeStamp start = nsRFPService::ReduceTimePrecisionAsMSecs(
|
||||
mStartWallClockRaw, 0, /* aIsSystemPrincipal = */ false,
|
||||
mCrossOriginIsolated);
|
||||
|
||||
return start + realtime;
|
||||
}
|
||||
|
||||
webrtc::Timestamp RTCStatsTimestampMaker::ConvertRealtimeTo1Jan1970(
|
||||
webrtc::Timestamp aRealtime) const {
|
||||
return aRealtime + webrtc::TimeDelta::Millis(mStartWallClockRaw);
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp RTCStatsTimestampMaker::ConvertNtpToDomTime(
|
||||
webrtc::Timestamp aNtpTime) const {
|
||||
const auto realtime = aNtpTime -
|
||||
webrtc::TimeDelta::Seconds(webrtc::kNtpJan1970) -
|
||||
webrtc::TimeDelta::Millis(mStartWallClockRaw);
|
||||
// Ntp times exposed by libwebrtc to stats are always **rounded** to
|
||||
// milliseconds. That means they can jump up to half a millisecond into the
|
||||
// future. We compensate for that here so that things seem consistent to js.
|
||||
return ReduceRealtimePrecision(realtime - webrtc::TimeDelta::Micros(500));
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp RTCStatsTimestampMaker::GetNow() const {
|
||||
return ReduceRealtimePrecision(GetNowRealtime());
|
||||
}
|
||||
|
||||
webrtc::Timestamp RTCStatsTimestampMaker::GetNowRealtime() const {
|
||||
return webrtc::Timestamp::Micros(
|
||||
(TimeStamp::Now() - mStartRealtime).ToMicroseconds());
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(RTCStatsReport, mParent)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef RTCStatsReport_h_
|
||||
#define RTCStatsReport_h_
|
||||
|
||||
#include "api/units/timestamp.h" // webrtc::Timestamp
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
@ -15,29 +16,54 @@
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "js/RootingAPI.h" // JS::Rooted
|
||||
#include "js/Value.h"
|
||||
#include "libwebrtcglue/SystemTime.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "prtime.h" // PR_Now
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/PerformanceService.h"
|
||||
#include "mozilla/dom/RTCStatsReportBinding.h" // RTCStatsCollection
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern TimeStamp WebrtcSystemTimeBase();
|
||||
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* Class that facilitates creating timestamps for webrtc stats by mimicking
|
||||
* dom::Performance, as well as getting and converting timestamps for libwebrtc
|
||||
* and our integration with it.
|
||||
*
|
||||
* It converts and uses time from these clocks:
|
||||
* - Realtime : Monotonic, unspecified (but constant) epoch.
|
||||
* - 1Jan1970 : Monotonic, unix epoch (00:00:00 UTC on 1 January 1970).
|
||||
* - Ntp : Monotonic, ntp epoch (00:00:00 UTC on 1 January 1900).
|
||||
* - Dom : Monotonic, milliseconds since unix epoch, as the timestamps
|
||||
* defined by webrtc-pc. Corresponds to Performance.timeOrigin +
|
||||
* Performance.now().
|
||||
* - WallClock: Non-monotonic, unix epoch.
|
||||
*/
|
||||
class RTCStatsTimestampMaker {
|
||||
public:
|
||||
RTCStatsTimestampMaker() = default;
|
||||
RTCStatsTimestampMaker();
|
||||
explicit RTCStatsTimestampMaker(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
DOMHighResTimeStamp GetNow() const;
|
||||
|
||||
private:
|
||||
const uint64_t mRandomTimelineSeed = 0;
|
||||
const TimeStamp mStartMonotonic = TimeStamp::Now();
|
||||
const DOMHighResTimeStamp mStartWallClockRaw =
|
||||
(double)PR_Now() / PR_USEC_PER_MSEC;
|
||||
const bool mCrossOriginIsolated = false;
|
||||
webrtc::Timestamp GetNowRealtime() const;
|
||||
webrtc::Timestamp ConvertRealtimeTo1Jan1970(
|
||||
webrtc::Timestamp aRealtime) const;
|
||||
DOMHighResTimeStamp ConvertNtpToDomTime(webrtc::Timestamp aNtpTime) const;
|
||||
DOMHighResTimeStamp ReduceRealtimePrecision(
|
||||
webrtc::Timestamp aRealtime) const;
|
||||
|
||||
const uint64_t mRandomTimelineSeed;
|
||||
const TimeStamp mStartRealtime;
|
||||
const bool mCrossOriginIsolated;
|
||||
const DOMHighResTimeStamp mStartWallClockRaw;
|
||||
};
|
||||
|
||||
// TODO(bug 1588303): If we ever get move semantics for webidl dictionaries, we
|
||||
|
@ -511,8 +511,9 @@ Maybe<uint16_t> WebrtcAudioConduit::RtpSendBaseSeqFor(uint32_t aSsrc) const {
|
||||
return Some(it->second);
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp WebrtcAudioConduit::GetNow() const {
|
||||
return mCall->GetNow();
|
||||
const dom::RTCStatsTimestampMaker& WebrtcAudioConduit::GetTimestampMaker()
|
||||
const {
|
||||
return mCall->GetTimestampMaker();
|
||||
}
|
||||
|
||||
void WebrtcAudioConduit::StopTransmitting() {
|
||||
|
@ -85,7 +85,7 @@ class WebrtcAudioConduit : public AudioSessionConduit,
|
||||
|
||||
Maybe<uint16_t> RtpSendBaseSeqFor(uint32_t aSsrc) const override;
|
||||
|
||||
DOMHighResTimeStamp GetNow() const override;
|
||||
const dom::RTCStatsTimestampMaker& GetTimestampMaker() const override;
|
||||
|
||||
void StopTransmitting();
|
||||
void StartTransmitting();
|
||||
|
@ -63,7 +63,7 @@ void MediaSessionConduit::UpdateRtpSources(
|
||||
// Fix up timestamps to be consistent with JS time. We assume that
|
||||
// source.timestamp_ms() was not terribly long ago, and so clock drift
|
||||
// between the libwebrtc clock and our JS clock is not that significant.
|
||||
auto jsNow = GetNow();
|
||||
auto jsNow = GetTimestampMaker().GetNow();
|
||||
double libwebrtcNow = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
|
||||
|
||||
for (const auto& source : aSources) {
|
||||
@ -141,7 +141,7 @@ void MediaSessionConduit::InsertAudioLevelForContributingSource(
|
||||
|
||||
int64_t libwebrtcNow =
|
||||
webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
|
||||
double jsNow = GetNow();
|
||||
double jsNow = GetTimestampMaker().GetNow();
|
||||
double ago = jsNow - aTimestamp;
|
||||
uint64_t convertedTimestamp = libwebrtcNow - ago;
|
||||
|
||||
|
@ -136,7 +136,8 @@ class MediaSessionConduit {
|
||||
// Sts thread only.
|
||||
virtual Maybe<uint16_t> RtpSendBaseSeqFor(uint32_t aSsrc) const = 0;
|
||||
|
||||
virtual DOMHighResTimeStamp GetNow() const = 0;
|
||||
// Any thread.
|
||||
virtual const dom::RTCStatsTimestampMaker& GetTimestampMaker() const = 0;
|
||||
|
||||
virtual Ssrcs GetLocalSSRCs() const = 0;
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "SystemTime.h"
|
||||
|
||||
#include "TimeUnits.h"
|
||||
|
||||
namespace mozilla {
|
||||
TimeStamp WebrtcSystemTimeBase() {
|
||||
static TimeStamp base = TimeStamp::Now();
|
||||
@ -17,6 +19,17 @@ webrtc::Timestamp WebrtcSystemTime() {
|
||||
const TimeStamp now = TimeStamp::Now();
|
||||
return webrtc::Timestamp::Micros((now - base).ToMicroseconds());
|
||||
}
|
||||
|
||||
webrtc::NtpTime CreateNtp(webrtc::Timestamp aTime) {
|
||||
const int64_t timeNtpUs = aTime.us();
|
||||
const uint32_t seconds = static_cast<uint32_t>(timeNtpUs / USECS_PER_S);
|
||||
|
||||
constexpr int64_t fractionsPerSec = 1LL << 32;
|
||||
const int64_t fractionsUs = timeNtpUs % USECS_PER_S;
|
||||
const uint32_t fractions = (fractionsUs * fractionsPerSec) / USECS_PER_S;
|
||||
|
||||
return webrtc::NtpTime(seconds, fractions);
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
namespace rtc {
|
||||
|
@ -1498,8 +1498,9 @@ Maybe<uint16_t> WebrtcVideoConduit::RtpSendBaseSeqFor(uint32_t aSsrc) const {
|
||||
return Some(it->second);
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp WebrtcVideoConduit::GetNow() const {
|
||||
return mCall->GetNow();
|
||||
const dom::RTCStatsTimestampMaker& WebrtcVideoConduit::GetTimestampMaker()
|
||||
const {
|
||||
return mCall->GetTimestampMaker();
|
||||
}
|
||||
|
||||
void WebrtcVideoConduit::StopTransmitting() {
|
||||
@ -1694,7 +1695,7 @@ void WebrtcVideoConduit::OnFrame(const webrtc::VideoFrame& video_frame) {
|
||||
}
|
||||
|
||||
// Record frame history
|
||||
const auto historyNow = mCall->GetNow();
|
||||
const auto historyNow = mCall->GetTimestampMaker().GetNow();
|
||||
if (needsNewHistoryElement) {
|
||||
dom::RTCVideoFrameHistoryEntryInternal frameHistoryElement;
|
||||
frameHistoryElement.mConsecutiveFrames = 0;
|
||||
|
@ -83,7 +83,7 @@ class WebrtcVideoConduit
|
||||
|
||||
Maybe<uint16_t> RtpSendBaseSeqFor(uint32_t aSsrc) const override;
|
||||
|
||||
DOMHighResTimeStamp GetNow() const override;
|
||||
const dom::RTCStatsTimestampMaker& GetTimestampMaker() const override;
|
||||
|
||||
void StopTransmitting();
|
||||
void StartTransmitting();
|
||||
|
@ -67,10 +67,6 @@ void WebrtcCallWrapper::UnregisterConduit(MediaSessionConduit* conduit) {
|
||||
mConduits.erase(conduit);
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp WebrtcCallWrapper::GetNow() const {
|
||||
return mTimestampMaker.GetNow();
|
||||
}
|
||||
|
||||
void WebrtcCallWrapper::Destroy() {
|
||||
MOZ_ASSERT(mCallThread->IsOnCurrentThread());
|
||||
mCall = nullptr;
|
||||
|
@ -54,8 +54,6 @@ class WebrtcCallWrapper {
|
||||
// Idempotent.
|
||||
void UnregisterConduit(MediaSessionConduit* conduit);
|
||||
|
||||
DOMHighResTimeStamp GetNow() const;
|
||||
|
||||
// Allow destroying the Call instance on the Call worker thread.
|
||||
//
|
||||
// Note that shutdown is blocked until the Call instance is destroyed.
|
||||
|
@ -363,7 +363,8 @@ void MediaPipeline::GetContributingSourceStats(
|
||||
FallibleTArray<dom::RTCRTPContributingSourceStats>& aArr) const {
|
||||
ASSERT_ON_THREAD(mStsThread);
|
||||
// Get the expiry from now
|
||||
DOMHighResTimeStamp expiry = RtpCSRCStats::GetExpiryFromTime(GetNow());
|
||||
DOMHighResTimeStamp expiry =
|
||||
RtpCSRCStats::GetExpiryFromTime(GetTimestampMaker().GetNow());
|
||||
for (auto info : mCsrcStats) {
|
||||
if (!info.second.Expired(expiry)) {
|
||||
RTCRTPContributingSourceStats stats;
|
||||
@ -556,7 +557,7 @@ void MediaPipeline::RtpPacketReceived(const MediaPacket& packet) {
|
||||
// Remove expired RtpCSRCStats
|
||||
if (!mCsrcStats.empty()) {
|
||||
if (!hasTime) {
|
||||
now = GetNow();
|
||||
now = GetTimestampMaker().GetNow();
|
||||
hasTime = true;
|
||||
}
|
||||
auto expiry = RtpCSRCStats::GetExpiryFromTime(now);
|
||||
@ -573,7 +574,7 @@ void MediaPipeline::RtpPacketReceived(const MediaPacket& packet) {
|
||||
if (header.numCSRCs) {
|
||||
for (auto i = 0; i < header.numCSRCs; i++) {
|
||||
if (!hasTime) {
|
||||
now = GetNow();
|
||||
now = GetTimestampMaker().GetNow();
|
||||
hasTime = true;
|
||||
}
|
||||
auto csrcInfo = mCsrcStats.find(header.arrOfCSRCs[i]);
|
||||
@ -1676,7 +1677,9 @@ void MediaPipelineReceiveVideo::UpdateListener() {
|
||||
}
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp MediaPipeline::GetNow() const { return mConduit->GetNow(); }
|
||||
const dom::RTCStatsTimestampMaker& MediaPipeline::GetTimestampMaker() const {
|
||||
return mConduit->GetTimestampMaker();
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp MediaPipeline::RtpCSRCStats::GetExpiryFromTime(
|
||||
const DOMHighResTimeStamp aTime) {
|
||||
|
@ -152,8 +152,7 @@ class MediaPipeline : public sigslot::has_slots<> {
|
||||
int64_t RtpBytesReceived() const { return mRtpBytesReceived; }
|
||||
int32_t RtcpPacketsReceived() const { return mRtcpPacketsReceived; }
|
||||
|
||||
// Gets the current time as a DOMHighResTimeStamp
|
||||
DOMHighResTimeStamp GetNow() const;
|
||||
const dom::RTCStatsTimestampMaker& GetTimestampMaker() const;
|
||||
|
||||
// Thread counting
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPipeline)
|
||||
|
@ -24,6 +24,8 @@ LOCAL_INCLUDES += [
|
||||
"/dom/media/webrtc/transport",
|
||||
"/media/webrtc",
|
||||
"/netwerk/sctp/src",
|
||||
"/third_party/libwebrtc",
|
||||
"/third_party/libwebrtc/third_party/abseil-cpp",
|
||||
]
|
||||
|
||||
DEFINES["SCTP_DEBUG"] = 1
|
||||
|
Loading…
Reference in New Issue
Block a user