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"
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"
27 #include "VideoSegment.h"
28 #include "webaudio/MediaStreamAudioDestinationNode.h"
30 using namespace mozilla::layers
;
31 using namespace mozilla::dom
;
32 using namespace mozilla::gfx
;
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(
47 aType
== MediaSegment::AUDIO
48 ? static_cast<MediaSegment
*>(new AudioSegment())
49 : static_cast<MediaSegment
*>(new VideoSegment())) {}
51 void ForwardedInputTrack::AddInput(MediaInputPort
* 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
);
75 ProcessedMediaTrack::RemoveInput(aPort
);
78 void ForwardedInputTrack::SetInput(MediaInputPort
* aPort
) {
80 MOZ_ASSERT(aPort
->GetSource());
81 MOZ_ASSERT(aPort
->GetSource()->GetData());
82 MOZ_ASSERT(!mInputPort
);
83 MOZ_ASSERT(mInputDisabledMode
== DisabledTrackMode::ENABLED
);
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
,
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
=
114 aSource
->GraphTimeToTrackTimeWithBlocking(interval
.mEnd
));
116 TrackTime ticks
= interval
.mEnd
- interval
.mStart
;
117 next
= interval
.mEnd
;
119 if (interval
.mStart
>= interval
.mEnd
) {
124 if (mAutoend
&& (aFlags
& ALLOW_END
)) {
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
);
144 MOZ_ASSERT(GetEnd() == GraphTimeToTrackTimeWithBlocking(interval
.mStart
),
146 TrackTime inputStart
=
147 aSource
->GraphTimeToTrackTimeWithBlocking(interval
.mStart
);
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
,
162 TRACE_COMMENT("ForwardedInputTrack::ProcessInput", "ForwardedInputTrack %p",
168 MediaInputPort
* input
= mInputPort
;
169 MediaTrack
* source
= input
? input
->GetSource() : nullptr;
170 if (mType
== MediaSegment::AUDIO
) {
172 ProcessInputImpl(source
, &audio
, aFrom
, aTo
, aFlags
);
173 } else if (mType
== MediaSegment::VIDEO
) {
175 ProcessInputImpl(source
, &video
, aFrom
, aTo
, aFlags
);
177 MOZ_CRASH("Unknown segment type");
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",
208 listener
->DecreaseDisabled(oldMode
);
209 } else if (oldEnabled
&& !enabled
) {
210 TRACK_LOG(LogLevel::Debug
, ("ForwardedInputTrack %p setting "
211 "direct listener disabled",
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
);
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,
268 DisabledTrackMode currentMode
= mDisabledMode
;
269 if (currentMode
!= DisabledTrackMode::ENABLED
) {
270 // Reset the listener's state.
271 aListener
->DecreaseDisabled(currentMode
);
273 mOwnedDirectListeners
.RemoveElementAt(i
);
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