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