ForwardedInputTrack.cpp (10245B)
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 "ForwardedInputTrack.h" 6 7 #include <algorithm> 8 9 #include "AudioChannelService.h" 10 #include "AudioNodeEngine.h" 11 #include "AudioNodeExternalInputTrack.h" 12 #include "AudioNodeTrack.h" 13 #include "AudioSegment.h" 14 #include "DOMMediaStream.h" 15 #include "GeckoProfiler.h" 16 #include "ImageContainer.h" 17 #include "MediaTrackGraph.h" 18 #include "Tracing.h" 19 #include "VideoSegment.h" 20 #include "mozilla/Logging.h" 21 #include "nsContentUtils.h" 22 #include "nsPrintfCString.h" 23 #include "nsServiceManagerUtils.h" 24 #include "nsWidgetsCID.h" 25 #include "prerror.h" 26 #include "webaudio/MediaStreamAudioDestinationNode.h" 27 28 using namespace mozilla::layers; 29 using namespace mozilla::dom; 30 using namespace mozilla::gfx; 31 32 namespace mozilla { 33 34 #ifdef TRACK_LOG 35 # undef TRACK_LOG 36 #endif 37 38 LazyLogModule gForwardedInputTrackLog("ForwardedInputTrack"); 39 #define TRACK_LOG(type, msg) MOZ_LOG(gForwardedInputTrackLog, type, msg) 40 41 ForwardedInputTrack::ForwardedInputTrack(TrackRate aSampleRate, 42 MediaSegment::Type aType) 43 : ProcessedMediaTrack( 44 aSampleRate, aType, 45 aType == MediaSegment::AUDIO 46 ? static_cast<MediaSegment*>(new AudioSegment()) 47 : static_cast<MediaSegment*>(new VideoSegment())) {} 48 49 void ForwardedInputTrack::AddInput(MediaInputPort* aPort) { 50 SetInput(aPort); 51 ProcessedMediaTrack::AddInput(aPort); 52 } 53 54 void ForwardedInputTrack::RemoveInput(MediaInputPort* aPort) { 55 TRACK_LOG(LogLevel::Debug, 56 ("ForwardedInputTrack %p removing input %p", this, aPort)); 57 MOZ_ASSERT(aPort == mInputPort); 58 59 for (const auto& listener : mOwnedDirectListeners) { 60 MediaTrack* source = mInputPort->GetSource(); 61 TRACK_LOG(LogLevel::Debug, 62 ("ForwardedInputTrack %p removing direct listener " 63 "%p. Forwarding to input track %p.", 64 this, listener.get(), aPort->GetSource())); 65 source->RemoveDirectListenerImpl(listener); 66 } 67 68 DisabledTrackMode oldMode = CombinedDisabledMode(); 69 mInputDisabledMode = DisabledTrackMode::ENABLED; 70 NotifyIfDisabledModeChangedFrom(oldMode); 71 72 mInputPort = nullptr; 73 ProcessedMediaTrack::RemoveInput(aPort); 74 } 75 76 void ForwardedInputTrack::SetInput(MediaInputPort* aPort) { 77 MOZ_ASSERT(aPort); 78 MOZ_ASSERT(aPort->GetSource()); 79 MOZ_ASSERT(aPort->GetSource()->GetData()); 80 MOZ_ASSERT(!mInputPort); 81 MOZ_ASSERT(mInputDisabledMode == DisabledTrackMode::ENABLED); 82 83 mInputPort = aPort; 84 85 for (const auto& listener : mOwnedDirectListeners) { 86 MediaTrack* source = mInputPort->GetSource(); 87 TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p adding direct listener " 88 "%p. Forwarding to input track %p.", 89 this, listener.get(), aPort->GetSource())); 90 source->AddDirectListenerImpl(do_AddRef(listener)); 91 } 92 93 DisabledTrackMode oldMode = CombinedDisabledMode(); 94 mInputDisabledMode = mInputPort->GetSource()->CombinedDisabledMode(); 95 NotifyIfDisabledModeChangedFrom(oldMode); 96 } 97 98 void ForwardedInputTrack::ProcessInputImpl(MediaTrack* aSource, 99 MediaSegment* aSegment, 100 GraphTime aFrom, GraphTime aTo, 101 uint32_t aFlags) { 102 GraphTime next; 103 for (GraphTime t = aFrom; t < aTo; t = next) { 104 MediaInputPort::InputInterval interval = 105 MediaInputPort::GetNextInputInterval(mInputPort, t); 106 interval.mEnd = std::min(interval.mEnd, aTo); 107 108 const bool inputEnded = 109 !aSource || 110 (aSource->Ended() && 111 aSource->GetEnd() <= 112 aSource->GraphTimeToTrackTimeWithBlocking(interval.mEnd)); 113 114 TrackTime ticks = interval.mEnd - interval.mStart; 115 next = interval.mEnd; 116 117 if (interval.mStart >= interval.mEnd) { 118 break; 119 } 120 121 if (inputEnded) { 122 if (mAutoend && (aFlags & ALLOW_END)) { 123 mEnded = true; 124 break; 125 } 126 aSegment->AppendNullData(ticks); 127 TRACK_LOG(LogLevel::Verbose, 128 ("ForwardedInputTrack %p appending %lld ticks " 129 "of null data (ended input)", 130 this, (long long)ticks)); 131 } else if (interval.mInputIsBlocked) { 132 aSegment->AppendNullData(ticks); 133 TRACK_LOG(LogLevel::Verbose, 134 ("ForwardedInputTrack %p appending %lld ticks " 135 "of null data (blocked input)", 136 this, (long long)ticks)); 137 } else if (InMutedCycle()) { 138 aSegment->AppendNullData(ticks); 139 } else if (aSource->IsSuspended()) { 140 aSegment->AppendNullData(ticks); 141 } else { 142 MOZ_ASSERT(GetEnd() == GraphTimeToTrackTimeWithBlocking(interval.mStart), 143 "Samples missing"); 144 TrackTime inputStart = 145 aSource->GraphTimeToTrackTimeWithBlocking(interval.mStart); 146 TrackTime inputEnd = 147 aSource->GraphTimeToTrackTimeWithBlocking(interval.mEnd); 148 aSegment->AppendSlice(*aSource->GetData(), inputStart, inputEnd); 149 } 150 ApplyTrackDisabling(aSegment); 151 for (const auto& listener : mTrackListeners) { 152 listener->NotifyQueuedChanges(Graph(), GetEnd(), *aSegment); 153 } 154 mSegment->AppendFrom(aSegment); 155 } 156 } 157 158 void ForwardedInputTrack::ProcessInput(GraphTime aFrom, GraphTime aTo, 159 uint32_t aFlags) { 160 TRACE_COMMENT("ForwardedInputTrack::ProcessInput", "ForwardedInputTrack %p", 161 this); 162 if (mEnded) { 163 return; 164 } 165 166 MediaInputPort* input = mInputPort; 167 MediaTrack* source = input ? input->GetSource() : nullptr; 168 if (mType == MediaSegment::AUDIO) { 169 AudioSegment audio; 170 ProcessInputImpl(source, &audio, aFrom, aTo, aFlags); 171 } else if (mType == MediaSegment::VIDEO) { 172 VideoSegment video; 173 ProcessInputImpl(source, &video, aFrom, aTo, aFlags); 174 } else { 175 MOZ_CRASH("Unknown segment type"); 176 } 177 178 if (mEnded) { 179 RemoveAllDirectListenersImpl(); 180 } 181 } 182 183 DisabledTrackMode ForwardedInputTrack::CombinedDisabledMode() const { 184 if (mDisabledMode == DisabledTrackMode::SILENCE_BLACK || 185 mInputDisabledMode == DisabledTrackMode::SILENCE_BLACK) { 186 return DisabledTrackMode::SILENCE_BLACK; 187 } 188 if (mDisabledMode == DisabledTrackMode::SILENCE_FREEZE || 189 mInputDisabledMode == DisabledTrackMode::SILENCE_FREEZE) { 190 return DisabledTrackMode::SILENCE_FREEZE; 191 } 192 return DisabledTrackMode::ENABLED; 193 } 194 195 void ForwardedInputTrack::SetDisabledTrackModeImpl(DisabledTrackMode aMode) { 196 bool enabled = aMode == DisabledTrackMode::ENABLED; 197 TRACK_LOG(LogLevel::Info, ("ForwardedInputTrack %p was explicitly %s", this, 198 enabled ? "enabled" : "disabled")); 199 for (DirectMediaTrackListener* listener : mOwnedDirectListeners) { 200 DisabledTrackMode oldMode = mDisabledMode; 201 bool oldEnabled = oldMode == DisabledTrackMode::ENABLED; 202 if (!oldEnabled && enabled) { 203 TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p setting " 204 "direct listener enabled", 205 this)); 206 listener->DecreaseDisabled(oldMode); 207 } else if (oldEnabled && !enabled) { 208 TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p setting " 209 "direct listener disabled", 210 this)); 211 listener->IncreaseDisabled(aMode); 212 } 213 } 214 MediaTrack::SetDisabledTrackModeImpl(aMode); 215 } 216 217 void ForwardedInputTrack::OnInputDisabledModeChanged( 218 DisabledTrackMode aInputMode) { 219 MOZ_ASSERT(mInputs.Length() == 1); 220 MOZ_ASSERT(mInputs[0]->GetSource()); 221 DisabledTrackMode oldMode = CombinedDisabledMode(); 222 if (mInputDisabledMode == DisabledTrackMode::SILENCE_BLACK && 223 aInputMode == DisabledTrackMode::SILENCE_FREEZE) { 224 // Don't allow demoting from SILENCE_BLACK to SILENCE_FREEZE. Frames will 225 // remain black so we shouldn't notify that the track got enabled. 226 aInputMode = DisabledTrackMode::SILENCE_BLACK; 227 } 228 mInputDisabledMode = aInputMode; 229 NotifyIfDisabledModeChangedFrom(oldMode); 230 } 231 232 uint32_t ForwardedInputTrack::NumberOfChannels() const { 233 MOZ_DIAGNOSTIC_ASSERT(mSegment->GetType() == MediaSegment::AUDIO); 234 if (!mInputPort || !mInputPort->GetSource()) { 235 return GetData<AudioSegment>()->MaxChannelCount(); 236 } 237 return mInputPort->GetSource()->NumberOfChannels(); 238 } 239 240 void ForwardedInputTrack::AddDirectListenerImpl( 241 already_AddRefed<DirectMediaTrackListener> aListener) { 242 RefPtr<DirectMediaTrackListener> listener = aListener; 243 mOwnedDirectListeners.AppendElement(listener); 244 245 DisabledTrackMode currentMode = mDisabledMode; 246 if (currentMode != DisabledTrackMode::ENABLED) { 247 listener->IncreaseDisabled(currentMode); 248 } 249 250 if (mInputPort) { 251 MediaTrack* source = mInputPort->GetSource(); 252 TRACK_LOG(LogLevel::Debug, ("ForwardedInputTrack %p adding direct listener " 253 "%p. Forwarding to input track %p.", 254 this, listener.get(), source)); 255 source->AddDirectListenerImpl(listener.forget()); 256 } 257 } 258 259 void ForwardedInputTrack::RemoveDirectListenerImpl( 260 DirectMediaTrackListener* aListener) { 261 for (size_t i = 0; i < mOwnedDirectListeners.Length(); ++i) { 262 if (mOwnedDirectListeners[i] == aListener) { 263 TRACK_LOG(LogLevel::Debug, 264 ("ForwardedInputTrack %p removing direct listener %p", this, 265 aListener)); 266 DisabledTrackMode currentMode = mDisabledMode; 267 if (currentMode != DisabledTrackMode::ENABLED) { 268 // Reset the listener's state. 269 aListener->DecreaseDisabled(currentMode); 270 } 271 mOwnedDirectListeners.RemoveElementAt(i); 272 break; 273 } 274 } 275 if (mInputPort) { 276 // Forward to the input 277 MediaTrack* source = mInputPort->GetSource(); 278 source->RemoveDirectListenerImpl(aListener); 279 } 280 } 281 282 void ForwardedInputTrack::RemoveAllDirectListenersImpl() { 283 for (const auto& listener : mOwnedDirectListeners.Clone()) { 284 RemoveDirectListenerImpl(listener); 285 } 286 MOZ_DIAGNOSTIC_ASSERT(mOwnedDirectListeners.IsEmpty()); 287 } 288 289 } // namespace mozilla