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