summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/libwebrtcglue/MediaConduitInterface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/libwebrtcglue/MediaConduitInterface.cpp')
-rw-r--r--dom/media/webrtc/libwebrtcglue/MediaConduitInterface.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/dom/media/webrtc/libwebrtcglue/MediaConduitInterface.cpp b/dom/media/webrtc/libwebrtcglue/MediaConduitInterface.cpp
new file mode 100644
index 0000000000..28079b2478
--- /dev/null
+++ b/dom/media/webrtc/libwebrtcglue/MediaConduitInterface.cpp
@@ -0,0 +1,151 @@
+/* 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 "MediaConduitInterface.h"
+
+#include "nsTArray.h"
+#include "mozilla/Assertions.h"
+#include "MainThreadUtils.h"
+#include "SystemTime.h"
+
+#include "system_wrappers/include/clock.h"
+
+namespace mozilla {
+
+void MediaSessionConduit::GetRtpSources(
+ nsTArray<dom::RTCRtpSourceEntry>& outSources) const {
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mSourcesUpdateNeeded) {
+ UpdateRtpSources(GetUpstreamRtpSources());
+ OnSourcesUpdated();
+ }
+ outSources.Clear();
+ for (auto& [key, entry] : mSourcesCache) {
+ (void)key;
+ outSources.AppendElement(entry);
+ }
+
+ struct TimestampComparator {
+ bool LessThan(const dom::RTCRtpSourceEntry& aLhs,
+ const dom::RTCRtpSourceEntry& aRhs) const {
+ // Sort descending!
+ return aLhs.mTimestamp > aRhs.mTimestamp;
+ }
+
+ bool Equals(const dom::RTCRtpSourceEntry& aLhs,
+ const dom::RTCRtpSourceEntry& aRhs) const {
+ return aLhs.mTimestamp == aRhs.mTimestamp;
+ }
+ };
+
+ // *sigh* We have to re-sort this by JS timestamp; we can run into cases
+ // where the libwebrtc timestamps are not in exactly the same order as JS
+ // timestamps due to clock differences (wibbly-wobbly, timey-wimey stuff)
+ outSources.Sort(TimestampComparator());
+}
+
+static double rtpToDomAudioLevel(uint8_t aAudioLevel) {
+ if (aAudioLevel == 127) {
+ // Spec indicates that a value of 127 should be set to 0
+ return 0;
+ }
+
+ // All other values are calculated as 10^(-rfc_level/20)
+ return std::pow(10, -aAudioLevel / 20.0);
+}
+
+void MediaSessionConduit::UpdateRtpSources(
+ const std::vector<webrtc::RtpSource>& aSources) const {
+ MOZ_ASSERT(NS_IsMainThread());
+ // Empty out the cache; we'll copy things back as needed
+ auto cache = std::move(mSourcesCache);
+
+ for (const auto& source : aSources) {
+ SourceKey key(source);
+ auto it = cache.find(key);
+ if (it != cache.end()) {
+ // This source entry was already in the cache, and should continue to be
+ // present in exactly the same form as before. This means we do _not_
+ // want to perform the timestamp adjustment again, since it might yield a
+ // slightly different result. This is why we copy this entry from the old
+ // cache instead of simply rebuilding it, and is also why we key the
+ // cache based on timestamp (keying the cache based on timestamp also
+ // gets us the ordering we want, conveniently).
+ mSourcesCache[key] = it->second;
+ continue;
+ }
+
+ // This is something we did not already have in the cache.
+ dom::RTCRtpSourceEntry domEntry;
+ domEntry.mSource = source.source_id();
+ switch (source.source_type()) {
+ case webrtc::RtpSourceType::SSRC:
+ domEntry.mSourceType = dom::RTCRtpSourceEntryType::Synchronization;
+ break;
+ case webrtc::RtpSourceType::CSRC:
+ domEntry.mSourceType = dom::RTCRtpSourceEntryType::Contributing;
+ break;
+ default:
+ MOZ_CRASH("Unexpected RTCRtpSourceEntryType");
+ }
+
+ if (source.audio_level()) {
+ domEntry.mAudioLevel.Construct(rtpToDomAudioLevel(*source.audio_level()));
+ }
+
+ // These timestamps 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.
+ domEntry.mTimestamp = dom::RTCStatsTimestamp::FromRealtime(
+ GetTimestampMaker(),
+ webrtc::Timestamp::Millis(source.timestamp_ms()) -
+ webrtc::TimeDelta::Micros(500))
+ .ToDom();
+ domEntry.mRtpTimestamp = source.rtp_timestamp();
+ mSourcesCache[key] = domEntry;
+ }
+}
+
+void MediaSessionConduit::OnSourcesUpdated() const {
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(mSourcesUpdateNeeded);
+ mSourcesUpdateNeeded = false;
+ // Reset the updateNeeded flag and clear the cache in a direct task, i.e.,
+ // as soon as the current task has finished.
+ AbstractThread::GetCurrent()->TailDispatcher().AddDirectTask(
+ NS_NewRunnableFunction(
+ __func__, [this, self = RefPtr<const MediaSessionConduit>(this)] {
+ mSourcesUpdateNeeded = true;
+ mSourcesCache.clear();
+ }));
+}
+
+void MediaSessionConduit::InsertAudioLevelForContributingSource(
+ const uint32_t aCsrcSource, const int64_t aTimestamp,
+ const uint32_t aRtpTimestamp, const bool aHasAudioLevel,
+ const uint8_t aAudioLevel) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (mSourcesUpdateNeeded) {
+ OnSourcesUpdated();
+ }
+
+ dom::RTCRtpSourceEntry domEntry;
+ domEntry.mSource = aCsrcSource;
+ domEntry.mSourceType = dom::RTCRtpSourceEntryType::Contributing;
+ domEntry.mTimestamp = aTimestamp;
+ domEntry.mRtpTimestamp = aRtpTimestamp;
+ if (aHasAudioLevel) {
+ domEntry.mAudioLevel.Construct(rtpToDomAudioLevel(aAudioLevel));
+ }
+
+ auto now = GetTimestampMaker().GetNow();
+ webrtc::Timestamp convertedTimestamp =
+ now.ToRealtime() - webrtc::TimeDelta::Millis(now.ToDom() - aTimestamp);
+
+ SourceKey key(convertedTimestamp.ms<uint32_t>(), aCsrcSource);
+ mSourcesCache[key] = domEntry;
+}
+
+} // namespace mozilla