tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MediaConduitInterface.cpp (5299B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "MediaConduitInterface.h"
      6 
      7 #include "MainThreadUtils.h"
      8 #include "SystemTime.h"
      9 #include "mozilla/Assertions.h"
     10 #include "nsTArray.h"
     11 #include "system_wrappers/include/clock.h"
     12 
     13 namespace mozilla {
     14 
     15 void MediaSessionConduit::GetRtpSources(
     16    nsTArray<dom::RTCRtpSourceEntry>& outSources) const {
     17  MOZ_ASSERT(NS_IsMainThread());
     18  if (mSourcesUpdateNeeded) {
     19    UpdateRtpSources(GetUpstreamRtpSources());
     20    OnSourcesUpdated();
     21  }
     22  outSources.Clear();
     23  for (auto& [key, entry] : mSourcesCache) {
     24    (void)key;
     25    outSources.AppendElement(entry);
     26  }
     27 
     28  struct TimestampComparator {
     29    bool LessThan(const dom::RTCRtpSourceEntry& aLhs,
     30                  const dom::RTCRtpSourceEntry& aRhs) const {
     31      // Sort descending!
     32      return aLhs.mTimestamp > aRhs.mTimestamp;
     33    }
     34 
     35    bool Equals(const dom::RTCRtpSourceEntry& aLhs,
     36                const dom::RTCRtpSourceEntry& aRhs) const {
     37      return aLhs.mTimestamp == aRhs.mTimestamp;
     38    }
     39  };
     40 
     41  // *sigh* We have to re-sort this by JS timestamp; we can run into cases
     42  // where the libwebrtc timestamps are not in exactly the same order as JS
     43  // timestamps due to clock differences (wibbly-wobbly, timey-wimey stuff)
     44  outSources.Sort(TimestampComparator());
     45 }
     46 
     47 static double rtpToDomAudioLevel(uint8_t aAudioLevel) {
     48  if (aAudioLevel == 127) {
     49    // Spec indicates that a value of 127 should be set to 0
     50    return 0;
     51  }
     52 
     53  // All other values are calculated as 10^(-rfc_level/20)
     54  return std::pow(10, -aAudioLevel / 20.0);
     55 }
     56 
     57 void MediaSessionConduit::UpdateRtpSources(
     58    const std::vector<webrtc::RtpSource>& aSources) const {
     59  MOZ_ASSERT(NS_IsMainThread());
     60  // Empty out the cache; we'll copy things back as needed
     61  auto cache = std::move(mSourcesCache);
     62 
     63  for (const auto& source : aSources) {
     64    SourceKey key(source);
     65    auto it = cache.find(key);
     66    if (it != cache.end()) {
     67      // This source entry was already in the cache, and should continue to be
     68      // present in exactly the same form as before. This means we do _not_
     69      // want to perform the timestamp adjustment again, since it might yield a
     70      // slightly different result. This is why we copy this entry from the old
     71      // cache instead of simply rebuilding it, and is also why we key the
     72      // cache based on timestamp (keying the cache based on timestamp also
     73      // gets us the ordering we want, conveniently).
     74      mSourcesCache[key] = it->second;
     75      continue;
     76    }
     77 
     78    // This is something we did not already have in the cache.
     79    dom::RTCRtpSourceEntry domEntry;
     80    domEntry.mSource = source.source_id();
     81    switch (source.source_type()) {
     82      case webrtc::RtpSourceType::SSRC:
     83        domEntry.mSourceType = dom::RTCRtpSourceEntryType::Synchronization;
     84        break;
     85      case webrtc::RtpSourceType::CSRC:
     86        domEntry.mSourceType = dom::RTCRtpSourceEntryType::Contributing;
     87        break;
     88      default:
     89        MOZ_CRASH("Unexpected RTCRtpSourceEntryType");
     90    }
     91 
     92    if (source.audio_level()) {
     93      domEntry.mAudioLevel.Construct(rtpToDomAudioLevel(*source.audio_level()));
     94    }
     95 
     96    // These timestamps are always **rounded** to milliseconds. That means they
     97    // can jump up to half a millisecond into the future. We compensate for that
     98    // here so that things seem consistent to js.
     99    domEntry.mTimestamp =
    100        dom::RTCStatsTimestamp::FromRealtime(
    101            GetTimestampMaker(),
    102            webrtc::Timestamp::Millis(source.timestamp().ms()) -
    103                webrtc::TimeDelta::Micros(500))
    104            .ToDom();
    105    domEntry.mRtpTimestamp = source.rtp_timestamp();
    106    mSourcesCache[key] = domEntry;
    107  }
    108 }
    109 
    110 void MediaSessionConduit::OnSourcesUpdated() const {
    111  MOZ_ASSERT(NS_IsMainThread());
    112  MOZ_ASSERT(mSourcesUpdateNeeded);
    113  mSourcesUpdateNeeded = false;
    114  // Reset the updateNeeded flag and clear the cache in a direct task, i.e.,
    115  // as soon as the current task has finished.
    116  AbstractThread::GetCurrent()->TailDispatcher().AddDirectTask(
    117      NS_NewRunnableFunction(
    118          __func__, [this, self = RefPtr<const MediaSessionConduit>(this)] {
    119            mSourcesUpdateNeeded = true;
    120            mSourcesCache.clear();
    121          }));
    122 }
    123 
    124 void MediaSessionConduit::InsertAudioLevelForContributingSource(
    125    const uint32_t aCsrcSource, const int64_t aTimestamp,
    126    const uint32_t aRtpTimestamp, const bool aHasAudioLevel,
    127    const uint8_t aAudioLevel) {
    128  MOZ_ASSERT(NS_IsMainThread());
    129 
    130  if (mSourcesUpdateNeeded) {
    131    OnSourcesUpdated();
    132  }
    133 
    134  dom::RTCRtpSourceEntry domEntry;
    135  domEntry.mSource = aCsrcSource;
    136  domEntry.mSourceType = dom::RTCRtpSourceEntryType::Contributing;
    137  domEntry.mTimestamp = aTimestamp;
    138  domEntry.mRtpTimestamp = aRtpTimestamp;
    139  if (aHasAudioLevel) {
    140    domEntry.mAudioLevel.Construct(rtpToDomAudioLevel(aAudioLevel));
    141  }
    142 
    143  auto now = GetTimestampMaker().GetNow();
    144  webrtc::Timestamp convertedTimestamp =
    145      now.ToRealtime() - webrtc::TimeDelta::Millis(now.ToDom() - aTimestamp);
    146 
    147  SourceKey key(convertedTimestamp.ms<uint32_t>(), aCsrcSource);
    148  mSourcesCache[key] = domEntry;
    149 }
    150 
    151 }  // namespace mozilla