tor-browser

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

CrossGraphPort.cpp (5888B)


      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 "CrossGraphPort.h"
      6 
      7 #include "AudioDeviceInfo.h"
      8 #include "AudioStreamTrack.h"
      9 #include "MediaTrackGraph.h"
     10 #include "mozilla/Logging.h"
     11 #include "mozilla/Preferences.h"
     12 
     13 namespace mozilla {
     14 
     15 extern LazyLogModule gMediaTrackGraphLog;
     16 #define LOG(type, msg) MOZ_LOG(gMediaTrackGraphLog, type, msg)
     17 #define LOG_TEST(type) MOZ_LOG_TEST(gMediaTrackGraphLog, type)
     18 
     19 UniquePtr<CrossGraphPort> CrossGraphPort::Connect(
     20    const RefPtr<dom::AudioStreamTrack>& aStreamTrack,
     21    MediaTrackGraph* aPartnerGraph) {
     22  MOZ_ASSERT(aStreamTrack);
     23  MOZ_ASSERT(aPartnerGraph);
     24  if (aStreamTrack->Graph() == aPartnerGraph) {
     25    // Primary graph the same as partner graph, just remove the existing cross
     26    // graph connection
     27    return nullptr;
     28  }
     29 
     30  RefPtr<CrossGraphReceiver> receiver = aPartnerGraph->CreateCrossGraphReceiver(
     31      aStreamTrack->Graph()->GraphRate());
     32 
     33  RefPtr<CrossGraphTransmitter> transmitter =
     34      aStreamTrack->Graph()->CreateCrossGraphTransmitter(receiver);
     35 
     36  RefPtr<MediaInputPort> port =
     37      aStreamTrack->ForwardTrackContentsTo(transmitter);
     38 
     39  LOG(LogLevel::Verbose,
     40      ("Created CrossGraphPort transmitter %p (rate %u, from AudioStreamTrack "
     41       "%p) and receiver %p (rate %u) between graphs %p and %p",
     42       transmitter.get(), transmitter->mSampleRate, aStreamTrack.get(),
     43       receiver.get(), receiver->mSampleRate, aStreamTrack->Graph(),
     44       aPartnerGraph));
     45 
     46  return WrapUnique(new CrossGraphPort(std::move(port), std::move(transmitter),
     47                                       std::move(receiver)));
     48 }
     49 
     50 CrossGraphPort::~CrossGraphPort() {
     51  LOG(LogLevel::Verbose,
     52      ("Destroying CrossGraphPort transmitter %p (rate %u) and receiver %p "
     53       "(rate %u) between graphs %p and %p",
     54       mTransmitter.get(), mTransmitter->mSampleRate, mReceiver.get(),
     55       mReceiver->mSampleRate, mTransmitter->Graph(), mReceiver->Graph()));
     56  mTransmitter->Destroy();
     57  mReceiver->Destroy();
     58  mTransmitterPort->Destroy();
     59 }
     60 
     61 /** CrossGraphTransmitter **/
     62 
     63 CrossGraphTransmitter::CrossGraphTransmitter(
     64    TrackRate aSampleRate, RefPtr<CrossGraphReceiver> aReceiver)
     65    : ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO,
     66                          nullptr /* aSegment */),
     67      mReceiver(std::move(aReceiver)) {}
     68 
     69 void CrossGraphTransmitter::ProcessInput(GraphTime aFrom, GraphTime aTo,
     70                                         uint32_t aFlags) {
     71  MOZ_ASSERT(!mInputs.IsEmpty());
     72  MOZ_ASSERT(mDisabledMode == DisabledTrackMode::ENABLED);
     73 
     74  MediaTrack* input = mInputs[0]->GetSource();
     75 
     76  if (input->Ended() &&
     77      (input->GetEnd() <= input->GraphTimeToTrackTimeWithBlocking(aFrom))) {
     78    mEnded = true;
     79    return;
     80  }
     81 
     82  LOG(LogLevel::Verbose,
     83      ("Transmitter (%p) from %" PRId64 ", to %" PRId64 ", ticks %" PRId64 "",
     84       this, aFrom, aTo, aTo - aFrom));
     85 
     86  AudioSegment audio;
     87  GraphTime next;
     88  for (GraphTime t = aFrom; t < aTo; t = next) {
     89    MediaInputPort::InputInterval interval =
     90        MediaInputPort::GetNextInputInterval(mInputs[0], t);
     91    interval.mEnd = std::min(interval.mEnd, aTo);
     92 
     93    TrackTime ticks = interval.mEnd - interval.mStart;
     94    next = interval.mEnd;
     95 
     96    if (interval.mStart >= interval.mEnd) {
     97      break;
     98    }
     99 
    100    if (interval.mInputIsBlocked) {
    101      audio.AppendNullData(ticks);
    102    } else if (input->IsSuspended()) {
    103      audio.AppendNullData(ticks);
    104    } else {
    105      MOZ_ASSERT(GetEnd() == GraphTimeToTrackTimeWithBlocking(interval.mStart),
    106                 "Samples missing");
    107      TrackTime inputStart =
    108          input->GraphTimeToTrackTimeWithBlocking(interval.mStart);
    109      TrackTime inputEnd =
    110          input->GraphTimeToTrackTimeWithBlocking(interval.mEnd);
    111      audio.AppendSlice(*input->GetData(), inputStart, inputEnd);
    112    }
    113  }
    114 
    115  mStartTime = aTo;
    116 
    117  for (AudioSegment::ChunkIterator iter(audio); !iter.IsEnded(); iter.Next()) {
    118    (void)mReceiver->EnqueueAudio(*iter);
    119  }
    120 }
    121 
    122 /** CrossGraphReceiver **/
    123 
    124 CrossGraphReceiver::CrossGraphReceiver(TrackRate aSampleRate,
    125                                       TrackRate aTransmitterRate)
    126    : ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO,
    127                          static_cast<MediaSegment*>(new AudioSegment())),
    128      mDriftCorrection(aTransmitterRate, aSampleRate, PRINCIPAL_HANDLE_NONE) {}
    129 
    130 uint32_t CrossGraphReceiver::NumberOfChannels() const {
    131  return GetData<AudioSegment>()->MaxChannelCount();
    132 }
    133 
    134 void CrossGraphReceiver::ProcessInput(GraphTime aFrom, GraphTime aTo,
    135                                      uint32_t aFlags) {
    136  LOG(LogLevel::Verbose,
    137      ("Receiver (%p) mSegment: duration: %" PRId64 ", from %" PRId64
    138       ", to %" PRId64 ", ticks %" PRId64 "",
    139       this, mSegment->GetDuration(), aFrom, aTo, aTo - aFrom));
    140 
    141  AudioSegment transmittedAudio;
    142  while (mCrossThreadFIFO.AvailableRead()) {
    143    AudioChunk chunk;
    144    (void)mCrossThreadFIFO.Dequeue(&chunk, 1);
    145    transmittedAudio.AppendAndConsumeChunk(std::move(chunk));
    146    mTransmitterHasStarted = true;
    147  }
    148 
    149  if (mTransmitterHasStarted) {
    150    // If it does not have enough frames the result will be silence.
    151    AudioSegment audioCorrected =
    152        mDriftCorrection.RequestFrames(transmittedAudio, aTo - aFrom);
    153    if (LOG_TEST(LogLevel::Verbose) && audioCorrected.IsNull()) {
    154      LOG(LogLevel::Verbose,
    155          ("Receiver(%p): Silence has been added, not enough input", this));
    156    }
    157    mSegment->AppendFrom(&audioCorrected);
    158  } else {
    159    mSegment->AppendNullData(aTo - aFrom);
    160  }
    161 }
    162 
    163 int CrossGraphReceiver::EnqueueAudio(AudioChunk& aChunk) {
    164  // This will take place on transmitter graph thread only.
    165  return mCrossThreadFIFO.Enqueue(aChunk);
    166 }
    167 
    168 }  // namespace mozilla
    169 
    170 #undef LOG
    171 #undef LOG_TEST