Bug Summary

File:root/firefox-clang/dom/media/MediaTrackGraph.cpp
Warning:line 480, column 5
Value stored to 'needInputProcessingParamUpdate' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_dom_media3.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D HAVE_UINT64_T -D WEBRTC_MOZILLA_BUILD -D RTC_ENABLE_VP9 -D WEBRTC_POSIX -D WEBRTC_BUILD_LIBEVENT -D WEBRTC_LINUX -D WEBRTC_USE_PIPEWIRE -D WEBRTC_USE_X11 -D MOZILLA_INTERNAL_API -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/media -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/media -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libsoundtouch/src -I /root/firefox-clang/caps -I /root/firefox-clang/docshell/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/media/webrtc -I /root/firefox-clang/layout/generic -I /root/firefox-clang/layout/xul -I /root/firefox-clang/media/libyuv/libyuv/include -I /root/firefox-clang/netwerk/base -I /root/firefox-clang/toolkit/content/tests/browser -I /root/firefox-clang/dom/media/webrtc/common -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/third_party/libwebrtc -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/gfx/skia -I /root/firefox-clang/gfx/skia/skia -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-error=attributes -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-27-100320-3286336-1 -x c++ Unified_cpp_dom_media3.cpp
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2/* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6#include "MediaTrackGraphImpl.h"
7#include "mozilla/MathAlgorithms.h"
8#include "mozilla/Unused.h"
9
10#include "AudioSegment.h"
11#include "CrossGraphPort.h"
12#include "VideoSegment.h"
13#include "nsContentUtils.h"
14#include "nsGlobalWindowInner.h"
15#include "nsPrintfCString.h"
16#include "nsServiceManagerUtils.h"
17#include "prerror.h"
18#include "mozilla/Logging.h"
19#include "mozilla/Attributes.h"
20#include "ForwardedInputTrack.h"
21#include "ImageContainer.h"
22#include "AudioCaptureTrack.h"
23#include "AudioDeviceInfo.h"
24#include "AudioNodeTrack.h"
25#include "AudioNodeExternalInputTrack.h"
26#if defined(MOZ_WEBRTC1)
27# include "MediaEngineWebRTCAudio.h"
28#endif // MOZ_WEBRTC
29#include "MediaTrackListener.h"
30#include "mozilla/dom/BaseAudioContextBinding.h"
31#include "mozilla/dom/Document.h"
32#include "mozilla/dom/WorkletThread.h"
33#include "mozilla/media/MediaUtils.h"
34#include <algorithm>
35#include "GeckoProfiler.h"
36#include "VideoFrameContainer.h"
37#include "mozilla/AbstractThread.h"
38#include "mozilla/StaticPrefs_dom.h"
39#include "mozilla/StaticPrefs_media.h"
40#include "transport/runnable_utils.h"
41#include "VideoUtils.h"
42#include "GraphRunner.h"
43#include "Tracing.h"
44#include "UnderrunHandler.h"
45#include "mozilla/CycleCollectedJSRuntime.h"
46#include "mozilla/Preferences.h"
47
48#include "webaudio/blink/DenormalDisabler.h"
49#include "webaudio/blink/HRTFDatabaseLoader.h"
50
51using namespace mozilla::layers;
52using namespace mozilla::dom;
53using namespace mozilla::gfx;
54using namespace mozilla::media;
55
56namespace mozilla {
57
58using AudioDeviceID = CubebUtils::AudioDeviceID;
59using IsInShutdown = MediaTrack::IsInShutdown;
60
61LazyLogModule gMediaTrackGraphLog("MediaTrackGraph");
62#ifdef LOG
63# undef LOG
64#endif // LOG
65#define LOG(type, msg) MOZ_LOG(gMediaTrackGraphLog, type, msg)do { const ::mozilla::LogModule* moz_real_module = gMediaTrackGraphLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, type)), 0))) { mozilla::detail::log_print(moz_real_module, type
, MOZ_LOG_EXPAND_ARGS msg); } } while (0)
66
67NativeInputTrack* DeviceInputTrackManager::GetNativeInputTrack() {
68 return mNativeInputTrack.get();
69}
70
71DeviceInputTrack* DeviceInputTrackManager::GetDeviceInputTrack(
72 CubebUtils::AudioDeviceID aID) {
73 if (mNativeInputTrack && mNativeInputTrack->mDeviceId == aID) {
74 return mNativeInputTrack.get();
75 }
76 for (const RefPtr<NonNativeInputTrack>& t : mNonNativeInputTracks) {
77 if (t->mDeviceId == aID) {
78 return t.get();
79 }
80 }
81 return nullptr;
82}
83
84NonNativeInputTrack* DeviceInputTrackManager::GetFirstNonNativeInputTrack() {
85 if (mNonNativeInputTracks.IsEmpty()) {
86 return nullptr;
87 }
88 return mNonNativeInputTracks[0].get();
89}
90
91void DeviceInputTrackManager::Add(DeviceInputTrack* aTrack) {
92 if (NativeInputTrack* native = aTrack->AsNativeInputTrack()) {
93 MOZ_ASSERT(!mNativeInputTrack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNativeInputTrack)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNativeInputTrack))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mNativeInputTrack"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 93); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mNativeInputTrack" ")"); do { MOZ_CrashSequence
(__null, 93); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
94 mNativeInputTrack = native;
95 } else {
96 NonNativeInputTrack* nonNative = aTrack->AsNonNativeInputTrack();
97 MOZ_ASSERT(nonNative)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nonNative)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nonNative))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("nonNative", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 97); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonNative" ")"
); do { MOZ_CrashSequence(__null, 97); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
98 struct DeviceTrackComparator {
99 public:
100 bool Equals(const RefPtr<NonNativeInputTrack>& aTrack,
101 CubebUtils::AudioDeviceID aDeviceId) const {
102 return aTrack->mDeviceId == aDeviceId;
103 }
104 };
105 MOZ_ASSERT(!mNonNativeInputTracks.Contains(aTrack->mDeviceId,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNonNativeInputTracks.Contains(aTrack->mDeviceId
, DeviceTrackComparator()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNonNativeInputTracks.Contains
(aTrack->mDeviceId, DeviceTrackComparator())))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mNonNativeInputTracks.Contains(aTrack->mDeviceId, DeviceTrackComparator())"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 106); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mNonNativeInputTracks.Contains(aTrack->mDeviceId, DeviceTrackComparator())"
")"); do { MOZ_CrashSequence(__null, 106); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
106 DeviceTrackComparator()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNonNativeInputTracks.Contains(aTrack->mDeviceId
, DeviceTrackComparator()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNonNativeInputTracks.Contains
(aTrack->mDeviceId, DeviceTrackComparator())))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mNonNativeInputTracks.Contains(aTrack->mDeviceId, DeviceTrackComparator())"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 106); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mNonNativeInputTracks.Contains(aTrack->mDeviceId, DeviceTrackComparator())"
")"); do { MOZ_CrashSequence(__null, 106); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
107 mNonNativeInputTracks.AppendElement(nonNative);
108 }
109}
110
111void DeviceInputTrackManager::Remove(DeviceInputTrack* aTrack) {
112 if (aTrack->AsNativeInputTrack()) {
113 MOZ_ASSERT(mNativeInputTrack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNativeInputTrack)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNativeInputTrack))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mNativeInputTrack"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 113); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mNativeInputTrack" ")"); do { MOZ_CrashSequence
(__null, 113); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
114 MOZ_ASSERT(mNativeInputTrack.get() == aTrack->AsNativeInputTrack())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNativeInputTrack.get() == aTrack->AsNativeInputTrack
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mNativeInputTrack.get() == aTrack->AsNativeInputTrack
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mNativeInputTrack.get() == aTrack->AsNativeInputTrack()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 114); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mNativeInputTrack.get() == aTrack->AsNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 114); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
115 mNativeInputTrack = nullptr;
116 } else {
117 NonNativeInputTrack* nonNative = aTrack->AsNonNativeInputTrack();
118 MOZ_ASSERT(nonNative)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nonNative)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nonNative))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("nonNative", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonNative" ")"
); do { MOZ_CrashSequence(__null, 118); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
119 DebugOnly<bool> removed = mNonNativeInputTracks.RemoveElement(nonNative);
120 MOZ_ASSERT(removed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(removed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(removed))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("removed", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 120); AnnotateMozCrashReason("MOZ_ASSERT" "(" "removed" ")"
); do { MOZ_CrashSequence(__null, 120); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
121 }
122}
123
124/**
125 * A hash table containing the graph instances, one per Window ID,
126 * sample rate, and device ID combination.
127 */
128
129struct MediaTrackGraphImpl::Lookup final {
130 HashNumber Hash() const {
131 return HashGeneric(mWindowID, mSampleRate, mOutputDeviceID);
132 }
133 const uint64_t mWindowID;
134 const TrackRate mSampleRate;
135 const CubebUtils::AudioDeviceID mOutputDeviceID;
136};
137
138// Implicit to support GraphHashSet.lookup(*graph).
139MOZ_IMPLICIT MediaTrackGraphImpl::operator MediaTrackGraphImpl::Lookup() const {
140 return {mWindowID, mSampleRate, PrimaryOutputDeviceID()};
141}
142
143namespace {
144struct GraphHasher { // for HashSet
145 using Lookup = const MediaTrackGraphImpl::Lookup;
146
147 static HashNumber hash(const Lookup& aLookup) { return aLookup.Hash(); }
148
149 static bool match(const MediaTrackGraphImpl* aGraph, const Lookup& aLookup) {
150 return aGraph->mWindowID == aLookup.mWindowID &&
151 aGraph->GraphRate() == aLookup.mSampleRate &&
152 aGraph->PrimaryOutputDeviceID() == aLookup.mOutputDeviceID;
153 }
154};
155
156// The weak reference to the graph is removed when its last track is removed.
157using GraphHashSet =
158 HashSet<MediaTrackGraphImpl*, GraphHasher, InfallibleAllocPolicy>;
159GraphHashSet* Graphs() {
160 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 160); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 160); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
161 static GraphHashSet sGraphs(4); // 4 is minimum HashSet capacity
162 return &sGraphs;
163}
164} // anonymous namespace
165
166static void ApplyTrackDisabling(DisabledTrackMode aDisabledMode,
167 MediaSegment* aSegment,
168 MediaSegment* aRawSegment) {
169 if (aDisabledMode == DisabledTrackMode::ENABLED) {
170 return;
171 }
172 if (aDisabledMode == DisabledTrackMode::SILENCE_BLACK) {
173 aSegment->ReplaceWithDisabled();
174 if (aRawSegment) {
175 aRawSegment->ReplaceWithDisabled();
176 }
177 } else if (aDisabledMode == DisabledTrackMode::SILENCE_FREEZE) {
178 aSegment->ReplaceWithNull();
179 if (aRawSegment) {
180 aRawSegment->ReplaceWithNull();
181 }
182 } else {
183 MOZ_CRASH("Unsupported mode")do { do { } while (false); MOZ_ReportCrash("" "Unsupported mode"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 183); AnnotateMozCrashReason
("MOZ_CRASH(" "Unsupported mode" ")"); do { MOZ_CrashSequence
(__null, 183); __attribute__((nomerge)) ::abort(); } while (false
); } while (false)
;
184 }
185}
186
187MediaTrackGraphImpl::~MediaTrackGraphImpl() {
188 MOZ_ASSERT(mTracks.IsEmpty() && mSuspendedTracks.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTracks.IsEmpty() && mSuspendedTracks.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTracks.IsEmpty() && mSuspendedTracks.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mTracks.IsEmpty() && mSuspendedTracks.IsEmpty()" " ("
"All tracks should have been destroyed by messages from the main "
"thread" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTracks.IsEmpty() && mSuspendedTracks.IsEmpty()"
") (" "All tracks should have been destroyed by messages from the main "
"thread" ")"); do { MOZ_CrashSequence(__null, 190); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
189 "All tracks should have been destroyed by messages from the main "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTracks.IsEmpty() && mSuspendedTracks.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTracks.IsEmpty() && mSuspendedTracks.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mTracks.IsEmpty() && mSuspendedTracks.IsEmpty()" " ("
"All tracks should have been destroyed by messages from the main "
"thread" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTracks.IsEmpty() && mSuspendedTracks.IsEmpty()"
") (" "All tracks should have been destroyed by messages from the main "
"thread" ")"); do { MOZ_CrashSequence(__null, 190); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
190 "thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTracks.IsEmpty() && mSuspendedTracks.IsEmpty
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTracks.IsEmpty() && mSuspendedTracks.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mTracks.IsEmpty() && mSuspendedTracks.IsEmpty()" " ("
"All tracks should have been destroyed by messages from the main "
"thread" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTracks.IsEmpty() && mSuspendedTracks.IsEmpty()"
") (" "All tracks should have been destroyed by messages from the main "
"thread" ")"); do { MOZ_CrashSequence(__null, 190); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
191 LOG(LogLevel::Debug, ("MediaTrackGraph %p destroyed", this));
192 LOG(LogLevel::Debug, ("MediaTrackGraphImpl::~MediaTrackGraphImpl"));
193}
194
195void MediaTrackGraphImpl::AddTrackGraphThread(MediaTrack* aTrack) {
196 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 196); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()" ")"); do { MOZ_CrashSequence
(__null, 196); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
197 aTrack->mStartTime = mProcessedTime;
198
199 if (aTrack->IsSuspended()) {
200 mSuspendedTracks.AppendElement(aTrack);
201 LOG(LogLevel::Debug,
202 ("%p: Adding media track %p, in the suspended track array", this,
203 aTrack));
204 } else {
205 mTracks.AppendElement(aTrack);
206 LOG(LogLevel::Debug, ("%p: Adding media track %p, count %zu", this, aTrack,
207 mTracks.Length()));
208 }
209
210 SetTrackOrderDirty();
211}
212
213void MediaTrackGraphImpl::RemoveTrackGraphThread(MediaTrack* aTrack) {
214 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 214); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()" ")"); do { MOZ_CrashSequence
(__null, 214); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
215 // Remove references in mTrackUpdates before we allow aTrack to die.
216 // Pending updates are not needed (since the main thread has already given
217 // up the track) so we will just drop them.
218 {
219 MonitorAutoLock lock(mMonitor);
220 for (uint32_t i = 0; i < mTrackUpdates.Length(); ++i) {
221 if (mTrackUpdates[i].mTrack == aTrack) {
222 mTrackUpdates[i].mTrack = nullptr;
223 }
224 }
225 }
226
227 // Ensure that mFirstCycleBreaker is updated when necessary.
228 SetTrackOrderDirty();
229
230 UnregisterAllAudioOutputs(aTrack);
231
232 if (aTrack->IsSuspended()) {
233 mSuspendedTracks.RemoveElement(aTrack);
234 } else {
235 mTracks.RemoveElement(aTrack);
236 }
237
238 LOG(LogLevel::Debug, ("%p: Removed media track %p, count %zu", this, aTrack,
239 mTracks.Length()));
240
241 NS_RELEASE(aTrack)do { (aTrack)->Release(); (aTrack) = 0; } while (0); // probably destroying it
242}
243
244TrackTime MediaTrackGraphImpl::GraphTimeToTrackTimeWithBlocking(
245 const MediaTrack* aTrack, GraphTime aTime) const {
246 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTime <= mStateComputedTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTime <= mStateComputedTime
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTime <= mStateComputedTime" " (" "Don't ask about times where we haven't made blocking decisions yet"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 248
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTime <= mStateComputedTime"
") (" "Don't ask about times where we haven't made blocking decisions yet"
")"); do { MOZ_CrashSequence(__null, 248); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
247 aTime <= mStateComputedTime,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTime <= mStateComputedTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTime <= mStateComputedTime
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTime <= mStateComputedTime" " (" "Don't ask about times where we haven't made blocking decisions yet"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 248
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTime <= mStateComputedTime"
") (" "Don't ask about times where we haven't made blocking decisions yet"
")"); do { MOZ_CrashSequence(__null, 248); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
248 "Don't ask about times where we haven't made blocking decisions yet")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTime <= mStateComputedTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTime <= mStateComputedTime
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTime <= mStateComputedTime" " (" "Don't ask about times where we haven't made blocking decisions yet"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 248
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTime <= mStateComputedTime"
") (" "Don't ask about times where we haven't made blocking decisions yet"
")"); do { MOZ_CrashSequence(__null, 248); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
249 return std::max<TrackTime>(
250 0, std::min(aTime, aTrack->mStartBlocking) - aTrack->mStartTime);
251}
252
253void MediaTrackGraphImpl::UpdateCurrentTimeForTracks(
254 GraphTime aPrevCurrentTime) {
255 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 255); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThread()" ")"); do { MOZ_CrashSequence
(__null, 255); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
256 for (MediaTrack* track : AllTracks()) {
257 // Shouldn't have already notified of ended *and* have output!
258 MOZ_ASSERT_IF(track->mStartBlocking > aPrevCurrentTime,do { if (track->mStartBlocking > aPrevCurrentTime) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!track->mNotifiedEnded)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!track->mNotifiedEnded)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!track->mNotifiedEnded"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 259); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!track->mNotifiedEnded" ")"); do { MOZ_CrashSequence
(__null, 259); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); } } while (false)
259 !track->mNotifiedEnded)do { if (track->mStartBlocking > aPrevCurrentTime) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!track->mNotifiedEnded)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!track->mNotifiedEnded)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!track->mNotifiedEnded"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 259); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!track->mNotifiedEnded" ")"); do { MOZ_CrashSequence
(__null, 259); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false); } } while (false)
;
260
261 // Calculate blocked time and fire Blocked/Unblocked events
262 GraphTime blockedTime = mStateComputedTime - track->mStartBlocking;
263 NS_ASSERTION(blockedTime >= 0, "Error in blocking time")do { if (!(blockedTime >= 0)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Error in blocking time", "blockedTime >= 0", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 263); MOZ_PretendNoReturn(); } } while (0)
;
264 track->AdvanceTimeVaryingValuesToCurrentTime(mStateComputedTime,
265 blockedTime);
266 LOG(LogLevel::Verbose,
267 ("%p: MediaTrack %p bufferStartTime=%f blockedTime=%f", this, track,
268 MediaTimeToSeconds(track->mStartTime),
269 MediaTimeToSeconds(blockedTime)));
270 track->mStartBlocking = mStateComputedTime;
271
272 TrackTime trackCurrentTime =
273 track->GraphTimeToTrackTime(mStateComputedTime);
274 if (track->mEnded) {
275 MOZ_ASSERT(track->GetEnd() <= trackCurrentTime)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(track->GetEnd() <= trackCurrentTime)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(track->GetEnd() <= trackCurrentTime))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("track->GetEnd() <= trackCurrentTime"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 275); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "track->GetEnd() <= trackCurrentTime"
")"); do { MOZ_CrashSequence(__null, 275); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
276 if (!track->mNotifiedEnded) {
277 // Playout of this track ended and listeners have not been notified.
278 track->mNotifiedEnded = true;
279 SetTrackOrderDirty();
280 for (const auto& listener : track->mTrackListeners) {
281 listener->NotifyOutput(this, track->GetEnd());
282 listener->NotifyEnded(this);
283 }
284 }
285 } else {
286 for (const auto& listener : track->mTrackListeners) {
287 listener->NotifyOutput(this, trackCurrentTime);
288 }
289 }
290 }
291}
292
293template <typename C, typename Chunk>
294void MediaTrackGraphImpl::ProcessChunkMetadataForInterval(MediaTrack* aTrack,
295 C& aSegment,
296 TrackTime aStart,
297 TrackTime aEnd) {
298 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 298); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()" ")"); do { MOZ_CrashSequence
(__null, 298); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
299 MOZ_ASSERT(aTrack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrack)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aTrack))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTrack", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 299); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrack" ")")
; do { MOZ_CrashSequence(__null, 299); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
300
301 TrackTime offset = 0;
302 for (typename C::ConstChunkIterator chunk(aSegment); !chunk.IsEnded();
303 chunk.Next()) {
304 if (offset >= aEnd) {
305 break;
306 }
307 offset += chunk->GetDuration();
308 if (chunk->IsNull() || offset < aStart) {
309 continue;
310 }
311 const PrincipalHandle& principalHandle = chunk->GetPrincipalHandle();
312 if (principalHandle != aSegment.GetLastPrincipalHandle()) {
313 aSegment.SetLastPrincipalHandle(principalHandle);
314 LOG(LogLevel::Debug,
315 ("%p: MediaTrack %p, principalHandle "
316 "changed in %sChunk with duration %lld",
317 this, aTrack,
318 aSegment.GetType() == MediaSegment::AUDIO ? "Audio" : "Video",
319 (long long)chunk->GetDuration()));
320 for (const auto& listener : aTrack->mTrackListeners) {
321 listener->NotifyPrincipalHandleChanged(this, principalHandle);
322 }
323 }
324 }
325}
326
327void MediaTrackGraphImpl::ProcessChunkMetadata(GraphTime aPrevCurrentTime) {
328 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 328); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()" ")"); do { MOZ_CrashSequence
(__null, 328); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
329 for (MediaTrack* track : AllTracks()) {
330 TrackTime iterationStart = track->GraphTimeToTrackTime(aPrevCurrentTime);
331 TrackTime iterationEnd = track->GraphTimeToTrackTime(mProcessedTime);
332 if (!track->mSegment) {
333 continue;
334 }
335 if (track->mType == MediaSegment::AUDIO) {
336 ProcessChunkMetadataForInterval<AudioSegment, AudioChunk>(
337 track, *track->GetData<AudioSegment>(), iterationStart, iterationEnd);
338 } else if (track->mType == MediaSegment::VIDEO) {
339 ProcessChunkMetadataForInterval<VideoSegment, VideoChunk>(
340 track, *track->GetData<VideoSegment>(), iterationStart, iterationEnd);
341 } else {
342 MOZ_CRASH("Unknown track type")do { do { } while (false); MOZ_ReportCrash("" "Unknown track type"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 342); AnnotateMozCrashReason
("MOZ_CRASH(" "Unknown track type" ")"); do { MOZ_CrashSequence
(__null, 342); __attribute__((nomerge)) ::abort(); } while (false
); } while (false)
;
343 }
344 }
345}
346
347GraphTime MediaTrackGraphImpl::WillUnderrun(MediaTrack* aTrack,
348 GraphTime aEndBlockingDecisions) {
349 // Ended tracks can't underrun. ProcessedMediaTracks also can't cause
350 // underrun currently, since we'll always be able to produce data for them
351 // unless they block on some other track.
352 if (aTrack->mEnded || aTrack->AsProcessedTrack()) {
353 return aEndBlockingDecisions;
354 }
355 // This track isn't ended or suspended. We don't need to call
356 // TrackTimeToGraphTime since an underrun is the only thing that can block
357 // it.
358 GraphTime bufferEnd = aTrack->GetEnd() + aTrack->mStartTime;
359#ifdef DEBUG1
360 if (bufferEnd < mProcessedTime) {
361 LOG(LogLevel::Error, ("%p: MediaTrack %p underrun, "
362 "bufferEnd %f < mProcessedTime %f (%" PRId64"l" "d"
363 " < %" PRId64"l" "d" "), TrackTime %" PRId64"l" "d",
364 this, aTrack, MediaTimeToSeconds(bufferEnd),
365 MediaTimeToSeconds(mProcessedTime), bufferEnd,
366 mProcessedTime, aTrack->GetEnd()));
367 NS_ASSERTION(bufferEnd >= mProcessedTime, "Buffer underran")do { if (!(bufferEnd >= mProcessedTime)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Buffer underran", "bufferEnd >= mProcessedTime", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 367); MOZ_PretendNoReturn(); } } while (0)
;
368 }
369#endif
370 return std::min(bufferEnd, aEndBlockingDecisions);
371}
372
373namespace {
374// Value of mCycleMarker for unvisited tracks in cycle detection.
375const uint32_t NOT_VISITED = UINT32_MAX(4294967295U);
376// Value of mCycleMarker for ordered tracks in muted cycles.
377const uint32_t IN_MUTED_CYCLE = 1;
378} // namespace
379
380bool MediaTrackGraphImpl::AudioTrackPresent() {
381 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 381); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()" ")"); do { MOZ_CrashSequence
(__null, 381); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
382
383 bool audioTrackPresent = false;
384 for (MediaTrack* track : mTracks) {
385 if (track->AsAudioNodeTrack()) {
386 audioTrackPresent = true;
387 break;
388 }
389
390 if (track->mType == MediaSegment::AUDIO && !track->mNotifiedEnded) {
391 audioTrackPresent = true;
392 break;
393 }
394 }
395
396 // We may not have audio input device when we only have AudioNodeTracks. But
397 // if audioTrackPresent is false, we must have no input device.
398 MOZ_DIAGNOSTIC_ASSERT_IF(do { if (!audioTrackPresent) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(!mDeviceInputTrackManagerGraphThread
.GetNativeInputTrack())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDeviceInputTrackManagerGraphThread
.GetNativeInputTrack()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mDeviceInputTrackManagerGraphThread.GetNativeInputTrack()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 400); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "!mDeviceInputTrackManagerGraphThread.GetNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
399 !audioTrackPresent,do { if (!audioTrackPresent) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(!mDeviceInputTrackManagerGraphThread
.GetNativeInputTrack())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDeviceInputTrackManagerGraphThread
.GetNativeInputTrack()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mDeviceInputTrackManagerGraphThread.GetNativeInputTrack()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 400); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "!mDeviceInputTrackManagerGraphThread.GetNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
400 !mDeviceInputTrackManagerGraphThread.GetNativeInputTrack())do { if (!audioTrackPresent) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(!mDeviceInputTrackManagerGraphThread
.GetNativeInputTrack())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDeviceInputTrackManagerGraphThread
.GetNativeInputTrack()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mDeviceInputTrackManagerGraphThread.GetNativeInputTrack()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 400); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "!mDeviceInputTrackManagerGraphThread.GetNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 400); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
401
402 return audioTrackPresent;
403}
404
405void MediaTrackGraphImpl::CheckDriver() {
406 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 406); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThread()" ")"); do { MOZ_CrashSequence
(__null, 406); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
407 // An offline graph has only one driver.
408 // Otherwise, if a switch is already pending, let that happen.
409 if (!mRealtime || Switching()) {
410 return;
411 }
412
413 AudioCallbackDriver* audioCallbackDriver =
414 CurrentDriver()->AsAudioCallbackDriver();
415 if (audioCallbackDriver && !audioCallbackDriver->OnFallback()) {
416 for (PendingResumeOperation& op : mPendingResumeOperations) {
417 op.Apply(this);
418 }
419 mPendingResumeOperations.Clear();
420 }
421
422 // Note that this looks for any audio tracks, input or output, and switches
423 // to a SystemClockDriver if there are none active or no resume operations
424 // to make any active.
425 bool needAudioCallbackDriver =
426 !mPendingResumeOperations.IsEmpty() || AudioTrackPresent();
427 if (!needAudioCallbackDriver) {
428 if (audioCallbackDriver && audioCallbackDriver->IsStarted()) {
429 SwitchAtNextIteration(
430 new SystemClockDriver(this, CurrentDriver(), mSampleRate));
431 }
432 return;
433 }
434
435 NativeInputTrack* native =
436 mDeviceInputTrackManagerGraphThread.GetNativeInputTrack();
437 CubebUtils::AudioDeviceID inputDevice = native ? native->mDeviceId : nullptr;
438 uint32_t inputChannelCount = AudioInputChannelCount(inputDevice);
439 AudioInputType inputPreference = AudioInputDevicePreference(inputDevice);
440 Maybe<AudioInputProcessingParamsRequest> processingRequest =
441 ToMaybeRef(native).map([](auto& native) {
442 return native.UpdateRequestedProcessingParams();
443 });
444
445 uint32_t primaryOutputChannelCount = PrimaryOutputChannelCount();
446 if (!audioCallbackDriver) {
447 if (primaryOutputChannelCount > 0) {
448 AudioCallbackDriver* driver = new AudioCallbackDriver(
449 this, CurrentDriver(), mSampleRate, primaryOutputChannelCount,
450 inputChannelCount, PrimaryOutputDeviceID(), inputDevice,
451 inputPreference, processingRequest);
452 SwitchAtNextIteration(driver);
453 }
454 return;
455 }
456
457 bool needInputProcessingParamUpdate =
458 processingRequest &&
459 processingRequest->mGeneration !=
460 audioCallbackDriver->RequestedInputProcessingParams().mGeneration;
461
462 // Check if this graph should switch to a different number of output channels.
463 // Generally, a driver switch is explicitly made by an event (e.g., setting
464 // the AudioDestinationNode channelCount), but if an HTMLMediaElement is
465 // directly playing back via another HTMLMediaElement, the number of channels
466 // of the media determines how many channels to output, and it can change
467 // dynamically.
468 if (primaryOutputChannelCount != audioCallbackDriver->OutputChannelCount()) {
469 if (needInputProcessingParamUpdate) {
470 needInputProcessingParamUpdate = false;
471 }
472 AudioCallbackDriver* driver = new AudioCallbackDriver(
473 this, CurrentDriver(), mSampleRate, primaryOutputChannelCount,
474 inputChannelCount, PrimaryOutputDeviceID(), inputDevice,
475 inputPreference, processingRequest);
476 SwitchAtNextIteration(driver);
477 }
478
479 if (needInputProcessingParamUpdate) {
480 needInputProcessingParamUpdate = false;
Value stored to 'needInputProcessingParamUpdate' is never read
481 LOG(LogLevel::Debug,
482 ("%p: Setting on the fly requested processing params %s (Gen %d)", this,
483 CubebUtils::ProcessingParamsToString(processingRequest->mParams).get(),
484 processingRequest->mGeneration));
485 audioCallbackDriver->RequestInputProcessingParams(*processingRequest);
486 }
487}
488
489void MediaTrackGraphImpl::UpdateTrackOrder() {
490 if (!mTrackOrderDirty) {
491 return;
492 }
493
494 mTrackOrderDirty = false;
495
496 // The algorithm for finding cycles is based on Tim Leslie's iterative
497 // implementation [1][2] of Pearce's variant [3] of Tarjan's strongly
498 // connected components (SCC) algorithm. There are variations (a) to
499 // distinguish whether tracks in SCCs of size 1 are in a cycle and (b) to
500 // re-run the algorithm over SCCs with breaks at DelayNodes.
501 //
502 // [1] http://www.timl.id.au/?p=327
503 // [2]
504 // https://github.com/scipy/scipy/blob/e2c502fca/scipy/sparse/csgraph/_traversal.pyx#L582
505 // [3] http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.102.1707
506 //
507 // There are two stacks. One for the depth-first search (DFS),
508 mozilla::LinkedList<MediaTrack> dfsStack;
509 // and another for tracks popped from the DFS stack, but still being
510 // considered as part of SCCs involving tracks on the stack.
511 mozilla::LinkedList<MediaTrack> sccStack;
512
513 // An index into mTracks for the next track found with no unsatisfied
514 // upstream dependencies.
515 uint32_t orderedTrackCount = 0;
516
517 for (uint32_t i = 0; i < mTracks.Length(); ++i) {
518 MediaTrack* t = mTracks[i];
519 ProcessedMediaTrack* pt = t->AsProcessedTrack();
520 if (pt) {
521 // The dfsStack initially contains a list of all processed tracks in
522 // unchanged order.
523 dfsStack.insertBack(t);
524 pt->mCycleMarker = NOT_VISITED;
525 } else {
526 // SourceMediaTracks have no inputs and so can be ordered now.
527 mTracks[orderedTrackCount] = t;
528 ++orderedTrackCount;
529 }
530 }
531
532 // mNextStackMarker corresponds to "index" in Tarjan's algorithm. It is a
533 // counter to label mCycleMarker on the next visited track in the DFS
534 // uniquely in the set of visited tracks that are still being considered.
535 //
536 // In this implementation, the counter descends so that the values are
537 // strictly greater than the values that mCycleMarker takes when the track
538 // has been ordered (0 or IN_MUTED_CYCLE).
539 //
540 // Each new track labelled, as the DFS searches upstream, receives a value
541 // less than those used for all other tracks being considered.
542 uint32_t nextStackMarker = NOT_VISITED - 1;
543 // Reset list of DelayNodes in cycles stored at the tail of mTracks.
544 mFirstCycleBreaker = mTracks.Length();
545
546 // Rearrange dfsStack order as required to DFS upstream and pop tracks
547 // in processing order to place in mTracks.
548 while (auto pt = static_cast<ProcessedMediaTrack*>(dfsStack.getFirst())) {
549 const auto& inputs = pt->mInputs;
550 MOZ_ASSERT(pt->AsProcessedTrack())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pt->AsProcessedTrack())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pt->AsProcessedTrack())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("pt->AsProcessedTrack()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 550); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "pt->AsProcessedTrack()" ")"); do { MOZ_CrashSequence
(__null, 550); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
551 if (pt->mCycleMarker == NOT_VISITED) {
552 // Record the position on the visited stack, so that any searches
553 // finding this track again know how much of the stack is in the cycle.
554 pt->mCycleMarker = nextStackMarker;
555 --nextStackMarker;
556 // Not-visited input tracks should be processed first.
557 // SourceMediaTracks have already been ordered.
558 for (uint32_t i = inputs.Length(); i--;) {
559 if (inputs[i]->GetSource()->IsSuspended()) {
560 continue;
561 }
562 auto input = inputs[i]->GetSource()->AsProcessedTrack();
563 if (input && input->mCycleMarker == NOT_VISITED) {
564 // It can be that this track has an input which is from a suspended
565 // AudioContext.
566 if (input->isInList()) {
567 input->remove();
568 dfsStack.insertFront(input);
569 }
570 }
571 }
572 continue;
573 }
574
575 // Returning from DFS. Pop from dfsStack.
576 pt->remove();
577
578 // cycleStackMarker keeps track of the highest marker value on any
579 // upstream track, if any, found receiving input, directly or indirectly,
580 // from the visited stack (and so from |ps|, making a cycle). In a
581 // variation from Tarjan's SCC algorithm, this does not include |ps|
582 // unless it is part of the cycle.
583 uint32_t cycleStackMarker = 0;
584 for (uint32_t i = inputs.Length(); i--;) {
585 if (inputs[i]->GetSource()->IsSuspended()) {
586 continue;
587 }
588 auto input = inputs[i]->GetSource()->AsProcessedTrack();
589 if (input) {
590 cycleStackMarker = std::max(cycleStackMarker, input->mCycleMarker);
591 }
592 }
593
594 if (cycleStackMarker <= IN_MUTED_CYCLE) {
595 // All inputs have been ordered and their stack markers have been removed.
596 // This track is not part of a cycle. It can be processed next.
597 pt->mCycleMarker = 0;
598 mTracks[orderedTrackCount] = pt;
599 ++orderedTrackCount;
600 continue;
601 }
602
603 // A cycle has been found. Record this track for ordering when all
604 // tracks in this SCC have been popped from the DFS stack.
605 sccStack.insertFront(pt);
606
607 if (cycleStackMarker > pt->mCycleMarker) {
608 // Cycles have been found that involve tracks that remain on the stack.
609 // Leave mCycleMarker indicating the most downstream (last) track on
610 // the stack known to be part of this SCC. In this way, any searches on
611 // other paths that find |ps| will know (without having to traverse from
612 // this track again) that they are part of this SCC (i.e. part of an
613 // intersecting cycle).
614 pt->mCycleMarker = cycleStackMarker;
615 continue;
616 }
617
618 // |pit| is the root of an SCC involving no other tracks on dfsStack, the
619 // complete SCC has been recorded, and tracks in this SCC are part of at
620 // least one cycle.
621 MOZ_ASSERT(cycleStackMarker == pt->mCycleMarker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(cycleStackMarker == pt->mCycleMarker)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(cycleStackMarker == pt->mCycleMarker))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("cycleStackMarker == pt->mCycleMarker"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 621); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "cycleStackMarker == pt->mCycleMarker" ")"
); do { MOZ_CrashSequence(__null, 621); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
622 // If there are DelayNodes in this SCC, then they may break the cycles.
623 bool haveDelayNode = false;
624 auto next = sccStack.getFirst();
625 // Tracks in this SCC are identified by mCycleMarker <= cycleStackMarker.
626 // (There may be other tracks later in sccStack from other incompletely
627 // searched SCCs, involving tracks still on dfsStack.)
628 //
629 // DelayNodes in cycles must behave differently from those not in cycles,
630 // so all DelayNodes in the SCC must be identified.
631 while (next && static_cast<ProcessedMediaTrack*>(next)->mCycleMarker <=
632 cycleStackMarker) {
633 auto nt = next->AsAudioNodeTrack();
634 // Get next before perhaps removing from list below.
635 next = next->getNext();
636 if (nt && nt->Engine()->AsDelayNodeEngine()) {
637 haveDelayNode = true;
638 // DelayNodes break cycles by producing their output in a
639 // preprocessing phase; they do not need to be ordered before their
640 // consumers. Order them at the tail of mTracks so that they can be
641 // handled specially. Do so now, so that DFS ignores them.
642 nt->remove();
643 nt->mCycleMarker = 0;
644 --mFirstCycleBreaker;
645 mTracks[mFirstCycleBreaker] = nt;
646 }
647 }
648 auto after_scc = next;
649 while ((next = sccStack.getFirst()) != after_scc) {
650 next->remove();
651 auto removed = static_cast<ProcessedMediaTrack*>(next);
652 if (haveDelayNode) {
653 // Return tracks to the DFS stack again (to order and detect cycles
654 // without delayNodes). Any of these tracks that are still inputs
655 // for tracks on the visited stack must be returned to the front of
656 // the stack to be ordered before their dependents. We know that none
657 // of these tracks need input from tracks on the visited stack, so
658 // they can all be searched and ordered before the current stack head
659 // is popped.
660 removed->mCycleMarker = NOT_VISITED;
661 dfsStack.insertFront(removed);
662 } else {
663 // Tracks in cycles without any DelayNodes must be muted, and so do
664 // not need input and can be ordered now. They must be ordered before
665 // their consumers so that their muted output is available.
666 removed->mCycleMarker = IN_MUTED_CYCLE;
667 mTracks[orderedTrackCount] = removed;
668 ++orderedTrackCount;
669 }
670 }
671 }
672
673 MOZ_ASSERT(orderedTrackCount == mFirstCycleBreaker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(orderedTrackCount == mFirstCycleBreaker)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(orderedTrackCount == mFirstCycleBreaker))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("orderedTrackCount == mFirstCycleBreaker"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 673); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "orderedTrackCount == mFirstCycleBreaker" ")"
); do { MOZ_CrashSequence(__null, 673); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
674}
675
676TrackTime MediaTrackGraphImpl::PlayAudio(const TrackAndVolume& aOutput,
677 GraphTime aPlayedTime,
678 uint32_t aOutputChannelCount) {
679 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 679); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThread()" ")"); do { MOZ_CrashSequence
(__null, 679); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
680 MOZ_ASSERT(mRealtime, "Should only attempt to play audio in realtime mode")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRealtime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRealtime))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mRealtime" " (" "Should only attempt to play audio in realtime mode"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 680
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRealtime" ") (" "Should only attempt to play audio in realtime mode"
")"); do { MOZ_CrashSequence(__null, 680); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
681
682 TrackTime ticksWritten = 0;
683
684 ticksWritten = 0;
685 MediaTrack* track = aOutput.mTrack;
686 AudioSegment* audio = track->GetData<AudioSegment>();
687 AudioSegment output;
688
689 TrackTime offset = track->GraphTimeToTrackTime(aPlayedTime);
690
691 // We don't update Track->mTracksStartTime here to account for time spent
692 // blocked. Instead, we'll update it in UpdateCurrentTimeForTracks after
693 // the blocked period has completed. But we do need to make sure we play
694 // from the right offsets in the track buffer, even if we've already
695 // written silence for some amount of blocked time after the current time.
696 GraphTime t = aPlayedTime;
697 while (t < mStateComputedTime) {
698 bool blocked = t >= track->mStartBlocking;
699 GraphTime end = blocked ? mStateComputedTime : track->mStartBlocking;
700 NS_ASSERTION(end <= mStateComputedTime, "mStartBlocking is wrong!")do { if (!(end <= mStateComputedTime)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mStartBlocking is wrong!", "end <= mStateComputedTime",
"/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 700); MOZ_PretendNoReturn
(); } } while (0)
;
701
702 // Check how many ticks of sound we can provide if we are blocked some
703 // time in the middle of this cycle.
704 TrackTime toWrite = end - t;
705
706 if (blocked) {
707 output.InsertNullDataAtStart(toWrite);
708 ticksWritten += toWrite;
709 LOG(LogLevel::Verbose,
710 ("%p: MediaTrack %p writing %" PRId64"l" "d" " blocking-silence samples for "
711 "%f to %f (%" PRId64"l" "d" " to %" PRId64"l" "d" ")",
712 this, track, toWrite, MediaTimeToSeconds(t), MediaTimeToSeconds(end),
713 offset, offset + toWrite));
714 } else {
715 TrackTime endTicksNeeded = offset + toWrite;
716 TrackTime endTicksAvailable = audio->GetDuration();
717
718 if (endTicksNeeded <= endTicksAvailable) {
719 LOG(LogLevel::Verbose,
720 ("%p: MediaTrack %p writing %" PRId64"l" "d" " samples for %f to %f "
721 "(samples %" PRId64"l" "d" " to %" PRId64"l" "d" ")",
722 this, track, toWrite, MediaTimeToSeconds(t),
723 MediaTimeToSeconds(end), offset, endTicksNeeded));
724 output.AppendSlice(*audio, offset, endTicksNeeded);
725 ticksWritten += toWrite;
726 offset = endTicksNeeded;
727 } else {
728 // MOZ_ASSERT(track->IsEnded(), "Not enough data, and track not
729 // ended."); If we are at the end of the track, maybe write the
730 // remaining samples, and pad with/output silence.
731 if (endTicksNeeded > endTicksAvailable && offset < endTicksAvailable) {
732 output.AppendSlice(*audio, offset, endTicksAvailable);
733
734 LOG(LogLevel::Verbose,
735 ("%p: MediaTrack %p writing %" PRId64"l" "d" " samples for %f to %f "
736 "(samples %" PRId64"l" "d" " to %" PRId64"l" "d" ")",
737 this, track, toWrite, MediaTimeToSeconds(t),
738 MediaTimeToSeconds(end), offset, endTicksNeeded));
739 uint32_t available = endTicksAvailable - offset;
740 ticksWritten += available;
741 toWrite -= available;
742 offset = endTicksAvailable;
743 }
744 output.AppendNullData(toWrite);
745 LOG(LogLevel::Verbose,
746 ("%p MediaTrack %p writing %" PRId64"l" "d" " padding slsamples for %f to "
747 "%f (samples %" PRId64"l" "d" " to %" PRId64"l" "d" ")",
748 this, track, toWrite, MediaTimeToSeconds(t),
749 MediaTimeToSeconds(end), offset, endTicksNeeded));
750 ticksWritten += toWrite;
751 }
752 output.ApplyVolume(mGlobalVolume * aOutput.mVolume);
753 }
754 t = end;
755
756 output.Mix(mMixer, aOutputChannelCount, mSampleRate);
757 }
758 return ticksWritten;
759}
760
761DeviceInputTrack* MediaTrackGraph::GetDeviceInputTrackMainThread(
762 CubebUtils::AudioDeviceID aID) {
763 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 763); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 763); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
764 auto* impl = static_cast<MediaTrackGraphImpl*>(this);
765 return impl->mDeviceInputTrackManagerMainThread.GetDeviceInputTrack(aID);
766}
767
768NativeInputTrack* MediaTrackGraph::GetNativeInputTrackMainThread() {
769 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 769); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 769); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
770 auto* impl = static_cast<MediaTrackGraphImpl*>(this);
771 return impl->mDeviceInputTrackManagerMainThread.GetNativeInputTrack();
772}
773
774void MediaTrackGraphImpl::OpenAudioInputImpl(DeviceInputTrack* aTrack) {
775 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 775); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThread()" ")"); do { MOZ_CrashSequence
(__null, 775); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
776 LOG(LogLevel::Debug,
777 ("%p OpenAudioInputImpl: device %p", this, aTrack->mDeviceId));
778
779 mDeviceInputTrackManagerGraphThread.Add(aTrack);
780
781 if (aTrack->AsNativeInputTrack()) {
782 // Switch Drivers since we're adding input (to input-only or full-duplex)
783 AudioCallbackDriver* driver = new AudioCallbackDriver(
784 this, CurrentDriver(), mSampleRate, PrimaryOutputChannelCount(),
785 AudioInputChannelCount(aTrack->mDeviceId), PrimaryOutputDeviceID(),
786 aTrack->mDeviceId, AudioInputDevicePreference(aTrack->mDeviceId),
787 Some(aTrack->UpdateRequestedProcessingParams()));
788 LOG(LogLevel::Debug,
789 ("%p OpenAudioInputImpl: starting new AudioCallbackDriver(input) %p",
790 this, driver));
791 SwitchAtNextIteration(driver);
792 } else {
793 NonNativeInputTrack* nonNative = aTrack->AsNonNativeInputTrack();
794 MOZ_ASSERT(nonNative)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nonNative)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nonNative))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("nonNative", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nonNative" ")"
); do { MOZ_CrashSequence(__null, 794); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
795 // Start non-native input right away.
796 nonNative->StartAudio(MakeRefPtr<AudioInputSource>(
797 MakeRefPtr<AudioInputSourceListener>(nonNative),
798 nonNative->GenerateSourceId(), nonNative->mDeviceId,
799 AudioInputChannelCount(nonNative->mDeviceId),
800 AudioInputDevicePreference(nonNative->mDeviceId) ==
801 AudioInputType::Voice,
802 nonNative->mPrincipalHandle, nonNative->mSampleRate, GraphRate()));
803 }
804}
805
806void MediaTrackGraphImpl::OpenAudioInput(DeviceInputTrack* aTrack) {
807 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 807); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 807); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
808 MOZ_ASSERT(aTrack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrack)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aTrack))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTrack", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 808); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrack" ")")
; do { MOZ_CrashSequence(__null, 808); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
809
810 LOG(LogLevel::Debug, ("%p OpenInput: DeviceInputTrack %p for device %p", this,
811 aTrack, aTrack->mDeviceId));
812
813 class Message : public ControlMessage {
814 public:
815 Message(MediaTrackGraphImpl* aGraph, DeviceInputTrack* aInputTrack)
816 : ControlMessage(nullptr), mGraph(aGraph), mInputTrack(aInputTrack) {}
817 void Run() override {
818 TRACE("MTG::OpenAudioInputImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::OpenAudioInputImpl ControlMessage"
);
;
819 mGraph->OpenAudioInputImpl(mInputTrack);
820 }
821 MediaTrackGraphImpl* mGraph;
822 DeviceInputTrack* mInputTrack;
823 };
824
825 mDeviceInputTrackManagerMainThread.Add(aTrack);
826
827 this->AppendMessage(MakeUnique<Message>(this, aTrack));
828}
829
830void MediaTrackGraphImpl::CloseAudioInputImpl(DeviceInputTrack* aTrack) {
831 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 831); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThread()" ")"); do { MOZ_CrashSequence
(__null, 831); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
832
833 LOG(LogLevel::Debug,
834 ("%p CloseAudioInputImpl: device %p", this, aTrack->mDeviceId));
835
836 if (NonNativeInputTrack* nonNative = aTrack->AsNonNativeInputTrack()) {
837 nonNative->StopAudio();
838 mDeviceInputTrackManagerGraphThread.Remove(aTrack);
839 return;
840 }
841
842 MOZ_ASSERT(aTrack->AsNativeInputTrack())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrack->AsNativeInputTrack())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTrack->AsNativeInputTrack
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aTrack->AsNativeInputTrack()", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrack->AsNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 842); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
843
844 mDeviceInputTrackManagerGraphThread.Remove(aTrack);
845
846 // Switch Drivers since we're adding or removing an input (to nothing/system
847 // or output only)
848 bool audioTrackPresent = AudioTrackPresent();
849
850 GraphDriver* driver;
851 if (audioTrackPresent) {
852 // We still have audio output
853 LOG(LogLevel::Debug,
854 ("%p: CloseInput: output present (AudioCallback)", this));
855
856 driver = new AudioCallbackDriver(
857 this, CurrentDriver(), mSampleRate, PrimaryOutputChannelCount(),
858 AudioInputChannelCount(aTrack->mDeviceId), PrimaryOutputDeviceID(),
859 nullptr, AudioInputDevicePreference(aTrack->mDeviceId),
860 Some(aTrack->UpdateRequestedProcessingParams()));
861 SwitchAtNextIteration(driver);
862 } else if (CurrentDriver()->AsAudioCallbackDriver()) {
863 LOG(LogLevel::Debug,
864 ("%p: CloseInput: no output present (SystemClockCallback)", this));
865
866 driver = new SystemClockDriver(this, CurrentDriver(), mSampleRate);
867 SwitchAtNextIteration(driver);
868 } // else SystemClockDriver->SystemClockDriver, no switch
869}
870
871void MediaTrackGraphImpl::UnregisterAllAudioOutputs(MediaTrack* aTrack) {
872 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 872); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()" ")"); do { MOZ_CrashSequence
(__null, 872); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
873 mOutputDevices.RemoveElementsBy([&](OutputDeviceEntry& aDeviceRef) {
874 aDeviceRef.mTrackOutputs.RemoveElement(aTrack);
875 // mReceiver is null for the primary output device, which is retained for
876 // AudioCallbackDriver output even when no tracks have audio outputs.
877 return aDeviceRef.mTrackOutputs.IsEmpty() && aDeviceRef.mReceiver;
878 });
879}
880
881void MediaTrackGraphImpl::CloseAudioInput(DeviceInputTrack* aTrack) {
882 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 882); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 882); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
883 MOZ_ASSERT(aTrack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrack)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aTrack))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTrack", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 883); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrack" ")")
; do { MOZ_CrashSequence(__null, 883); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
884
885 LOG(LogLevel::Debug, ("%p CloseInput: DeviceInputTrack %p for device %p",
886 this, aTrack, aTrack->mDeviceId));
887
888 class Message : public ControlMessage {
889 public:
890 Message(MediaTrackGraphImpl* aGraph, DeviceInputTrack* aInputTrack)
891 : ControlMessage(nullptr), mGraph(aGraph), mInputTrack(aInputTrack) {}
892 void Run() override {
893 TRACE("MTG::CloseAudioInputImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::CloseAudioInputImpl ControlMessage"
);
;
894 mGraph->CloseAudioInputImpl(mInputTrack);
895 }
896 MediaTrackGraphImpl* mGraph;
897 DeviceInputTrack* mInputTrack;
898 };
899
900 // DeviceInputTrack is still alive (in mTracks) even we remove it here, since
901 // aTrack->Destroy() is called after this. See DeviceInputTrack::CloseAudio
902 // for more details.
903 mDeviceInputTrackManagerMainThread.Remove(aTrack);
904
905 this->AppendMessage(MakeUnique<Message>(this, aTrack));
906
907 if (aTrack->AsNativeInputTrack()) {
908 LOG(LogLevel::Debug,
909 ("%p Native input device %p is closed!", this, aTrack->mDeviceId));
910 SetNewNativeInput();
911 }
912}
913
914// All AudioInput listeners get the same speaker data (at least for now).
915void MediaTrackGraphImpl::NotifyOutputData(const AudioChunk& aChunk) {
916 if (!mDeviceInputTrackManagerGraphThread.GetNativeInputTrack()) {
917 return;
918 }
919
920#if defined(MOZ_WEBRTC1)
921 for (const auto& track : mTracks) {
922 if (const auto& t = track->AsAudioProcessingTrack()) {
923 t->NotifyOutputData(this, aChunk);
924 }
925 }
926#endif
927}
928
929void MediaTrackGraphImpl::NotifyInputStopped() {
930 NativeInputTrack* native =
931 mDeviceInputTrackManagerGraphThread.GetNativeInputTrack();
932 if (!native) {
933 return;
934 }
935 native->NotifyInputStopped(this);
936}
937
938void MediaTrackGraphImpl::NotifyInputData(const AudioDataValue* aBuffer,
939 size_t aFrames, TrackRate aRate,
940 uint32_t aChannels,
941 uint32_t aAlreadyBuffered) {
942 // Either we have an audio input device, or we just removed the audio input
943 // this iteration, and we're switching back to an output-only driver next
944 // iteration.
945 NativeInputTrack* native =
946 mDeviceInputTrackManagerGraphThread.GetNativeInputTrack();
947 MOZ_ASSERT(native || Switching())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(native || Switching())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(native || Switching()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("native || Switching()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 947); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "native || Switching()" ")"); do { MOZ_CrashSequence
(__null, 947); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
948 if (!native) {
949 return;
950 }
951 native->NotifyInputData(this, aBuffer, aFrames, aRate, aChannels,
952 aAlreadyBuffered);
953}
954
955void MediaTrackGraphImpl::NotifySetRequestedInputProcessingParamsResult(
956 AudioCallbackDriver* aDriver, int aGeneration,
957 Result<cubeb_input_processing_params, int>&& aResult) {
958 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 958); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 958); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
959 NativeInputTrack* native =
960 mDeviceInputTrackManagerMainThread.GetNativeInputTrack();
961 if (!native) {
962 return;
963 }
964 QueueControlMessageWithNoShutdown([this, self = RefPtr(this),
965 driver = RefPtr(aDriver), aGeneration,
966 result = std::move(aResult)]() mutable {
967 NativeInputTrack* native =
968 mDeviceInputTrackManagerGraphThread.GetNativeInputTrack();
969 if (!native) {
970 return;
971 }
972 if (driver != mDriver) {
973 return;
974 }
975 native->NotifySetRequestedProcessingParamsResult(this, aGeneration, result);
976 });
977}
978
979void MediaTrackGraphImpl::DeviceChangedImpl() {
980 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 980); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThread()" ")"); do { MOZ_CrashSequence
(__null, 980); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
981 NativeInputTrack* native =
982 mDeviceInputTrackManagerGraphThread.GetNativeInputTrack();
983 if (!native) {
984 return;
985 }
986 native->DeviceChanged(this);
987}
988
989void MediaTrackGraphImpl::SetMaxOutputChannelCount(uint32_t aMaxChannelCount) {
990 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 990); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "OnGraphThread()" ")"); do { MOZ_CrashSequence
(__null, 990); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
991 mMaxOutputChannelCount = aMaxChannelCount;
992}
993
994void MediaTrackGraphImpl::DeviceChanged() {
995 // This is safe to be called from any thread: this message comes from an
996 // underlying platform API, and we don't have much guarantees. If it is not
997 // called from the main thread (and it probably will rarely be), it will post
998 // itself to the main thread, and the actual device change message will be ran
999 // and acted upon on the graph thread.
1000 if (!NS_IsMainThread()) {
1001 RefPtr<nsIRunnable> runnable = WrapRunnable(
1002 RefPtr<MediaTrackGraphImpl>(this), &MediaTrackGraphImpl::DeviceChanged);
1003 mMainThread->Dispatch(runnable.forget());
1004 return;
1005 }
1006
1007 class Message : public ControlMessage {
1008 public:
1009 explicit Message(MediaTrackGraph* aGraph)
1010 : ControlMessage(nullptr),
1011 mGraphImpl(static_cast<MediaTrackGraphImpl*>(aGraph)) {}
1012 void Run() override {
1013 TRACE("MTG::DeviceChangeImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::DeviceChangeImpl ControlMessage"
);
;
1014 mGraphImpl->DeviceChangedImpl();
1015 }
1016 // We know that this is valid, because the graph can't shutdown if it has
1017 // messages.
1018 MediaTrackGraphImpl* mGraphImpl;
1019 };
1020
1021 if (mMainThreadTrackCount == 0 && mMainThreadPortCount == 0) {
1022 // This is a special case where the origin of this event cannot control the
1023 // lifetime of the graph, because the graph is controling the lifetime of
1024 // the AudioCallbackDriver where the event originated.
1025 // We know the graph is soon going away, so there's no need to notify about
1026 // this device change.
1027 return;
1028 }
1029
1030 // Reset the latency, it will get fetched again next time it's queried.
1031 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1031);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1031); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1032 mAudioOutputLatency = 0.0;
1033
1034 // Dispatch to the bg thread to do the (potentially expensive) query of the
1035 // maximum channel count, and then dispatch back to the main thread, then to
1036 // the graph, with the new info. The "special case" above is to be handled
1037 // back on the main thread as well for the same reasons.
1038 RefPtr<MediaTrackGraphImpl> self = this;
1039 NS_DispatchBackgroundTask(NS_NewRunnableFunction(
1040 "MaxChannelCountUpdateOnBgThread", [self{std::move(self)}]() {
1041 uint32_t maxChannelCount = CubebUtils::MaxNumberOfChannels();
1042 self->Dispatch(NS_NewRunnableFunction(
1043 "MaxChannelCountUpdateToMainThread",
1044 [self{self}, maxChannelCount]() {
1045 class MessageToGraph : public ControlMessage {
1046 public:
1047 explicit MessageToGraph(MediaTrackGraph* aGraph,
1048 uint32_t aMaxChannelCount)
1049 : ControlMessage(nullptr),
1050 mGraphImpl(static_cast<MediaTrackGraphImpl*>(aGraph)),
1051 mMaxChannelCount(aMaxChannelCount) {}
1052 void Run() override {
1053 TRACE("MTG::SetMaxOutputChannelCount ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::SetMaxOutputChannelCount ControlMessage"
);
1054 mGraphImpl->SetMaxOutputChannelCount(mMaxChannelCount);
1055 }
1056 MediaTrackGraphImpl* mGraphImpl;
1057 uint32_t mMaxChannelCount;
1058 };
1059
1060 if (self->mMainThreadTrackCount == 0 &&
1061 self->mMainThreadPortCount == 0) {
1062 // See comments above.
1063 return;
1064 }
1065
1066 self->AppendMessage(
1067 MakeUnique<MessageToGraph>(self, maxChannelCount));
1068 }));
1069 }));
1070
1071 AppendMessage(MakeUnique<Message>(this));
1072}
1073
1074static const char* GetAudioInputTypeString(const AudioInputType& aType) {
1075 return aType == AudioInputType::Voice ? "Voice" : "Unknown";
1076}
1077
1078void MediaTrackGraph::ReevaluateInputDevice(CubebUtils::AudioDeviceID aID) {
1079 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1079);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1079); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1080 auto* impl = static_cast<MediaTrackGraphImpl*>(this);
1081 impl->ReevaluateInputDevice(aID);
1082}
1083
1084void MediaTrackGraphImpl::ReevaluateInputDevice(CubebUtils::AudioDeviceID aID) {
1085 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1085);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1085); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1086 LOG(LogLevel::Debug, ("%p: ReevaluateInputDevice: device %p", this, aID));
1087
1088 DeviceInputTrack* track =
1089 mDeviceInputTrackManagerGraphThread.GetDeviceInputTrack(aID);
1090 if (!track) {
1091 LOG(LogLevel::Debug,
1092 ("%p: No DeviceInputTrack for this device. Ignore", this));
1093 return;
1094 }
1095
1096 bool needToSwitch = false;
1097
1098 if (NonNativeInputTrack* nonNative = track->AsNonNativeInputTrack()) {
1099 if (nonNative->NumberOfChannels() != AudioInputChannelCount(aID)) {
1100 LOG(LogLevel::Debug,
1101 ("%p: %u-channel non-native input device %p (track %p) is "
1102 "re-configured to %d-channel",
1103 this, nonNative->NumberOfChannels(), aID, track,
1104 AudioInputChannelCount(aID)));
1105 needToSwitch = true;
1106 }
1107 if (nonNative->DevicePreference() != AudioInputDevicePreference(aID)) {
1108 LOG(LogLevel::Debug,
1109 ("%p: %s-type non-native input device %p (track %p) is re-configured "
1110 "to %s-type",
1111 this, GetAudioInputTypeString(nonNative->DevicePreference()), aID,
1112 track, GetAudioInputTypeString(AudioInputDevicePreference(aID))));
1113 needToSwitch = true;
1114 }
1115
1116 if (needToSwitch) {
1117 nonNative->StopAudio();
1118 nonNative->StartAudio(MakeRefPtr<AudioInputSource>(
1119 MakeRefPtr<AudioInputSourceListener>(nonNative),
1120 nonNative->GenerateSourceId(), aID, AudioInputChannelCount(aID),
1121 AudioInputDevicePreference(aID) == AudioInputType::Voice,
1122 nonNative->mPrincipalHandle, nonNative->mSampleRate, GraphRate()));
1123 }
1124
1125 return;
1126 }
1127
1128 MOZ_ASSERT(track->AsNativeInputTrack())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(track->AsNativeInputTrack())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(track->AsNativeInputTrack
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("track->AsNativeInputTrack()", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1128); AnnotateMozCrashReason("MOZ_ASSERT" "(" "track->AsNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 1128); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1129
1130 if (AudioCallbackDriver* audioCallbackDriver =
1131 CurrentDriver()->AsAudioCallbackDriver()) {
1132 if (audioCallbackDriver->InputChannelCount() !=
1133 AudioInputChannelCount(aID)) {
1134 LOG(LogLevel::Debug,
1135 ("%p: ReevaluateInputDevice: %u-channel AudioCallbackDriver %p is "
1136 "re-configured to %d-channel",
1137 this, audioCallbackDriver->InputChannelCount(), audioCallbackDriver,
1138 AudioInputChannelCount(aID)));
1139 needToSwitch = true;
1140 }
1141 if (audioCallbackDriver->InputDevicePreference() !=
1142 AudioInputDevicePreference(aID)) {
1143 LOG(LogLevel::Debug,
1144 ("%p: ReevaluateInputDevice: %s-type AudioCallbackDriver %p is "
1145 "re-configured to %s-type",
1146 this,
1147 GetAudioInputTypeString(
1148 audioCallbackDriver->InputDevicePreference()),
1149 audioCallbackDriver,
1150 GetAudioInputTypeString(AudioInputDevicePreference(aID))));
1151 needToSwitch = true;
1152 }
1153 } else if (Switching() && NextDriver()->AsAudioCallbackDriver()) {
1154 // We're already in the process of switching to a audio callback driver,
1155 // which will happen at the next iteration.
1156 // However, maybe it's not the correct number of channels. Re-query the
1157 // correct channel amount at this time.
1158 needToSwitch = true;
1159 }
1160
1161 if (needToSwitch) {
1162 AudioCallbackDriver* newDriver = new AudioCallbackDriver(
1163 this, CurrentDriver(), mSampleRate, PrimaryOutputChannelCount(),
1164 AudioInputChannelCount(aID), PrimaryOutputDeviceID(), aID,
1165 AudioInputDevicePreference(aID),
1166 Some(track->UpdateRequestedProcessingParams()));
1167 SwitchAtNextIteration(newDriver);
1168 }
1169}
1170
1171bool MediaTrackGraphImpl::OnGraphThreadOrNotRunning() const {
1172 // either we're on the right thread (and calling CurrentDriver() is safe),
1173 // or we're going to fail the assert anyway, so don't cross-check
1174 // via CurrentDriver().
1175 return mGraphDriverRunning ? OnGraphThread() : NS_IsMainThread();
1176}
1177
1178bool MediaTrackGraphImpl::OnGraphThread() const {
1179 // we're on the right thread (and calling mDriver is safe),
1180 MOZ_ASSERT(mDriver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDriver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDriver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mDriver", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1180); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDriver" ")"
); do { MOZ_CrashSequence(__null, 1180); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1181 if (mGraphRunner && mGraphRunner->OnThread()) {
1182 return true;
1183 }
1184 return mDriver->OnThread();
1185}
1186
1187bool MediaTrackGraphImpl::Destroyed() const {
1188 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1188);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1188); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1189 return !mSelfRef;
1190}
1191
1192bool MediaTrackGraphImpl::ShouldUpdateMainThread() {
1193 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1193);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()"
")"); do { MOZ_CrashSequence(__null, 1193); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1194 if (mRealtime) {
1195 return true;
1196 }
1197
1198 TimeStamp now = TimeStamp::Now();
1199 // For offline graphs, update now if it has been long enough since the last
1200 // update, or if it has reached the end.
1201 if ((now - mLastMainThreadUpdate).ToMilliseconds() >
1202 CurrentDriver()->IterationDuration() ||
1203 mStateComputedTime >= mEndTime) {
1204 mLastMainThreadUpdate = now;
1205 return true;
1206 }
1207 return false;
1208}
1209
1210void MediaTrackGraphImpl::PrepareUpdatesToMainThreadState(bool aFinalUpdate) {
1211 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1211);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()"
")"); do { MOZ_CrashSequence(__null, 1211); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1212 mMonitor.AssertCurrentThreadOwns();
1213
1214 // We don't want to frequently update the main thread about timing update
1215 // when we are not running in realtime.
1216 if (aFinalUpdate || ShouldUpdateMainThread()) {
1217 // Strip updates that will be obsoleted below, so as to keep the length of
1218 // mTrackUpdates sane.
1219 size_t keptUpdateCount = 0;
1220 for (size_t i = 0; i < mTrackUpdates.Length(); ++i) {
1221 MediaTrack* track = mTrackUpdates[i].mTrack;
1222 // RemoveTrackGraphThread() clears mTrack in updates for
1223 // tracks that are removed from the graph.
1224 MOZ_ASSERT(!track || track->GraphImpl() == this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!track || track->GraphImpl() == this)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!track || track->GraphImpl() == this))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!track || track->GraphImpl() == this"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1224);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!track || track->GraphImpl() == this"
")"); do { MOZ_CrashSequence(__null, 1224); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1225 if (!track || track->MainThreadNeedsUpdates()) {
1226 // Discard this update as it has either been cleared when the track
1227 // was destroyed or there will be a newer update below.
1228 continue;
1229 }
1230 if (keptUpdateCount != i) {
1231 mTrackUpdates[keptUpdateCount] = std::move(mTrackUpdates[i]);
1232 MOZ_ASSERT(!mTrackUpdates[i].mTrack)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mTrackUpdates[i].mTrack)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mTrackUpdates[i].mTrack))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("!mTrackUpdates[i].mTrack"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1232);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mTrackUpdates[i].mTrack"
")"); do { MOZ_CrashSequence(__null, 1232); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1233 }
1234 ++keptUpdateCount;
1235 }
1236 mTrackUpdates.TruncateLength(keptUpdateCount);
1237
1238 mTrackUpdates.SetCapacity(mTrackUpdates.Length() + mTracks.Length() +
1239 mSuspendedTracks.Length());
1240 for (MediaTrack* track : AllTracks()) {
1241 if (!track->MainThreadNeedsUpdates()) {
1242 continue;
1243 }
1244 TrackUpdate* update = mTrackUpdates.AppendElement();
1245 update->mTrack = track;
1246 // No blocking to worry about here, since we've passed
1247 // UpdateCurrentTimeForTracks.
1248 update->mNextMainThreadCurrentTime =
1249 track->GraphTimeToTrackTime(mProcessedTime);
1250 update->mNextMainThreadEnded = track->mNotifiedEnded;
1251 }
1252 mNextMainThreadGraphTime = mProcessedTime;
1253 if (!mPendingUpdateRunnables.IsEmpty()) {
1254 mUpdateRunnables.AppendElements(std::move(mPendingUpdateRunnables));
1255 }
1256 }
1257
1258 // If this is the final update, then a stable state event will soon be
1259 // posted just before this thread finishes, and so there is no need to also
1260 // post here.
1261 if (!aFinalUpdate &&
1262 // Don't send the message to the main thread if it's not going to have
1263 // any work to do.
1264 !(mUpdateRunnables.IsEmpty() && mTrackUpdates.IsEmpty())) {
1265 EnsureStableStateEventPosted();
1266 }
1267}
1268
1269GraphTime MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(GraphTime aTime) {
1270 if (aTime % WEBAUDIO_BLOCK_SIZE == 0) {
1271 return aTime;
1272 }
1273 return RoundUpToNextAudioBlock(aTime);
1274}
1275
1276GraphTime MediaTrackGraphImpl::RoundUpToNextAudioBlock(GraphTime aTime) {
1277 uint64_t block = aTime >> WEBAUDIO_BLOCK_SIZE_BITS;
1278 uint64_t nextBlock = block + 1;
1279 GraphTime nextTime = nextBlock << WEBAUDIO_BLOCK_SIZE_BITS;
1280 return nextTime;
1281}
1282
1283void MediaTrackGraphImpl::ProduceDataForTracksBlockByBlock(
1284 uint32_t aTrackIndex, TrackRate aSampleRate) {
1285 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1285);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1285); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1286 MOZ_ASSERT(aTrackIndex <= mFirstCycleBreaker,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrackIndex <= mFirstCycleBreaker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTrackIndex <= mFirstCycleBreaker
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTrackIndex <= mFirstCycleBreaker" " (" "Cycle breaker is not AudioNodeTrack?"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1287
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrackIndex <= mFirstCycleBreaker"
") (" "Cycle breaker is not AudioNodeTrack?" ")"); do { MOZ_CrashSequence
(__null, 1287); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1287 "Cycle breaker is not AudioNodeTrack?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrackIndex <= mFirstCycleBreaker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTrackIndex <= mFirstCycleBreaker
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTrackIndex <= mFirstCycleBreaker" " (" "Cycle breaker is not AudioNodeTrack?"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1287
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrackIndex <= mFirstCycleBreaker"
") (" "Cycle breaker is not AudioNodeTrack?" ")"); do { MOZ_CrashSequence
(__null, 1287); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1288
1289 while (mProcessedTime < mStateComputedTime) {
1290 // Microtask checkpoints are in between render quanta.
1291 nsAutoMicroTask mt;
1292
1293 GraphTime next = RoundUpToNextAudioBlock(mProcessedTime);
1294 for (uint32_t i = mFirstCycleBreaker; i < mTracks.Length(); ++i) {
1295 auto nt = static_cast<AudioNodeTrack*>(mTracks[i]);
1296 MOZ_ASSERT(nt->AsAudioNodeTrack())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nt->AsAudioNodeTrack())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nt->AsAudioNodeTrack())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("nt->AsAudioNodeTrack()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1296);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "nt->AsAudioNodeTrack()"
")"); do { MOZ_CrashSequence(__null, 1296); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1297 nt->ProduceOutputBeforeInput(mProcessedTime);
1298 }
1299 for (uint32_t i = aTrackIndex; i < mTracks.Length(); ++i) {
1300 ProcessedMediaTrack* pt = mTracks[i]->AsProcessedTrack();
1301 if (pt) {
1302 pt->ProcessInput(
1303 mProcessedTime, next,
1304 (next == mStateComputedTime) ? ProcessedMediaTrack::ALLOW_END : 0);
1305 }
1306 }
1307 mProcessedTime = next;
1308 }
1309 NS_ASSERTION(mProcessedTime == mStateComputedTime,do { if (!(mProcessedTime == mStateComputedTime)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Something went wrong with rounding to block boundaries"
, "mProcessedTime == mStateComputedTime", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1310); MOZ_PretendNoReturn(); } } while (0)
1310 "Something went wrong with rounding to block boundaries")do { if (!(mProcessedTime == mStateComputedTime)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Something went wrong with rounding to block boundaries"
, "mProcessedTime == mStateComputedTime", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1310); MOZ_PretendNoReturn(); } } while (0)
;
1311}
1312
1313void MediaTrackGraphImpl::RunMessageAfterProcessing(
1314 UniquePtr<ControlMessageInterface> aMessage) {
1315 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1315);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1315); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1316
1317 if (mFrontMessageQueue.IsEmpty()) {
1318 mFrontMessageQueue.AppendElement();
1319 }
1320
1321 // Only one block is used for messages from the graph thread.
1322 MOZ_ASSERT(mFrontMessageQueue.Length() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFrontMessageQueue.Length() == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFrontMessageQueue.Length() ==
1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFrontMessageQueue.Length() == 1", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1322); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFrontMessageQueue.Length() == 1"
")"); do { MOZ_CrashSequence(__null, 1322); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1323 mFrontMessageQueue[0].mMessages.AppendElement(std::move(aMessage));
1324}
1325
1326void MediaTrackGraphImpl::RunMessagesInQueue() {
1327 TRACE("MTG::RunMessagesInQueue")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::RunMessagesInQueue"
);
;
1328 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1328);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1328); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1329 // Calculate independent action times for each batch of messages (each
1330 // batch corresponding to an event loop task). This isolates the performance
1331 // of different scripts to some extent.
1332 for (uint32_t i = 0; i < mFrontMessageQueue.Length(); ++i) {
1333 nsTArray<UniquePtr<ControlMessageInterface>>& messages =
1334 mFrontMessageQueue[i].mMessages;
1335
1336 for (uint32_t j = 0; j < messages.Length(); ++j) {
1337 TRACE("ControlMessage::Run")AutoTracer trace(gAudioCallbackTraceLogger, "ControlMessage::Run"
);
;
1338 messages[j]->Run();
1339 }
1340 }
1341 mFrontMessageQueue.Clear();
1342}
1343
1344void MediaTrackGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions) {
1345 TRACE("MTG::UpdateGraph")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::UpdateGraph"
);
;
1346 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1346);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1346); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1347 MOZ_ASSERT(aEndBlockingDecisions >= mProcessedTime)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEndBlockingDecisions >= mProcessedTime)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEndBlockingDecisions >= mProcessedTime))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aEndBlockingDecisions >= mProcessedTime"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1347);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEndBlockingDecisions >= mProcessedTime"
")"); do { MOZ_CrashSequence(__null, 1347); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1348 // The next state computed time can be the same as the previous: it
1349 // means the driver would have been blocking indefinitly, but the graph has
1350 // been woken up right after having been to sleep.
1351 MOZ_ASSERT(aEndBlockingDecisions >= mStateComputedTime)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEndBlockingDecisions >= mStateComputedTime)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEndBlockingDecisions >= mStateComputedTime))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEndBlockingDecisions >= mStateComputedTime"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1351);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEndBlockingDecisions >= mStateComputedTime"
")"); do { MOZ_CrashSequence(__null, 1351); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1352
1353 CheckDriver();
1354 UpdateTrackOrder();
1355
1356 // Always do another iteration if there are tracks waiting to resume.
1357 bool ensureNextIteration = !mPendingResumeOperations.IsEmpty();
1358
1359 for (MediaTrack* track : mTracks) {
1360 if (SourceMediaTrack* is = track->AsSourceTrack()) {
1361 ensureNextIteration |= is->PullNewData(aEndBlockingDecisions);
1362 is->ExtractPendingInput(mStateComputedTime, aEndBlockingDecisions);
1363 }
1364 if (track->mEnded) {
1365 // The track's not suspended, and since it's ended, underruns won't
1366 // stop it playing out. So there's no blocking other than what we impose
1367 // here.
1368 GraphTime endTime = track->GetEnd() + track->mStartTime;
1369 if (endTime <= mStateComputedTime) {
1370 LOG(LogLevel::Verbose,
1371 ("%p: MediaTrack %p is blocked due to being ended", this, track));
1372 track->mStartBlocking = mStateComputedTime;
1373 } else {
1374 LOG(LogLevel::Verbose,
1375 ("%p: MediaTrack %p has ended, but is not blocked yet (current "
1376 "time %f, end at %f)",
1377 this, track, MediaTimeToSeconds(mStateComputedTime),
1378 MediaTimeToSeconds(endTime)));
1379 // Data can't be added to a ended track, so underruns are irrelevant.
1380 MOZ_ASSERT(endTime <= aEndBlockingDecisions)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(endTime <= aEndBlockingDecisions)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(endTime <= aEndBlockingDecisions
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"endTime <= aEndBlockingDecisions", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1380); AnnotateMozCrashReason("MOZ_ASSERT" "(" "endTime <= aEndBlockingDecisions"
")"); do { MOZ_CrashSequence(__null, 1380); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1381 track->mStartBlocking = endTime;
1382 }
1383 } else {
1384 track->mStartBlocking = WillUnderrun(track, aEndBlockingDecisions);
1385
1386#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
1387 if (SourceMediaTrack* s = track->AsSourceTrack()) {
1388 if (s->Ended()) {
1389 continue;
1390 }
1391 {
1392 MutexAutoLock lock(s->mMutex);
1393 if (!s->mUpdateTrack->mPullingEnabled) {
1394 // The invariant that data must be provided is only enforced when
1395 // pulling.
1396 continue;
1397 }
1398 }
1399 if (track->GetEnd() <
1400 track->GraphTimeToTrackTime(aEndBlockingDecisions)) {
1401 LOG(LogLevel::Error,
1402 ("%p: SourceMediaTrack %p (%s) is live and pulled, "
1403 "but wasn't fed "
1404 "enough data. TrackListeners=%zu. Track-end=%f, "
1405 "Iteration-end=%f",
1406 this, track,
1407 (track->mType == MediaSegment::AUDIO ? "audio" : "video"),
1408 track->mTrackListeners.Length(),
1409 MediaTimeToSeconds(track->GetEnd()),
1410 MediaTimeToSeconds(
1411 track->GraphTimeToTrackTime(aEndBlockingDecisions))));
1412 MOZ_DIAGNOSTIC_CRASH(do { do { } while (false); MOZ_ReportCrash("" "A non-ended SourceMediaTrack wasn't fed "
"enough data by NotifyPull", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1414); AnnotateMozCrashReason("MOZ_CRASH(" "A non-ended SourceMediaTrack wasn't fed "
"enough data by NotifyPull" ")"); do { MOZ_CrashSequence(__null
, 1414); __attribute__((nomerge)) ::abort(); } while (false);
} while (false)
1413 "A non-ended SourceMediaTrack wasn't fed "do { do { } while (false); MOZ_ReportCrash("" "A non-ended SourceMediaTrack wasn't fed "
"enough data by NotifyPull", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1414); AnnotateMozCrashReason("MOZ_CRASH(" "A non-ended SourceMediaTrack wasn't fed "
"enough data by NotifyPull" ")"); do { MOZ_CrashSequence(__null
, 1414); __attribute__((nomerge)) ::abort(); } while (false);
} while (false)
1414 "enough data by NotifyPull")do { do { } while (false); MOZ_ReportCrash("" "A non-ended SourceMediaTrack wasn't fed "
"enough data by NotifyPull", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1414); AnnotateMozCrashReason("MOZ_CRASH(" "A non-ended SourceMediaTrack wasn't fed "
"enough data by NotifyPull" ")"); do { MOZ_CrashSequence(__null
, 1414); __attribute__((nomerge)) ::abort(); } while (false);
} while (false)
;
1415 }
1416 }
1417#endif /* MOZ_DIAGNOSTIC_ASSERT_ENABLED */
1418 }
1419 }
1420
1421 for (MediaTrack* track : mSuspendedTracks) {
1422 track->mStartBlocking = mStateComputedTime;
1423 }
1424
1425 // If the loop is woken up so soon that IterationEnd() barely advances or
1426 // if an offline graph is not currently rendering, we end up having
1427 // aEndBlockingDecisions == mStateComputedTime.
1428 // Since the process interval [mStateComputedTime, aEndBlockingDecision) is
1429 // empty, Process() will not find any unblocked track and so will not
1430 // ensure another iteration. If the graph should be rendering, then ensure
1431 // another iteration to render.
1432 if (ensureNextIteration || (aEndBlockingDecisions == mStateComputedTime &&
1433 mStateComputedTime < mEndTime)) {
1434 EnsureNextIteration();
1435 }
1436}
1437
1438void MediaTrackGraphImpl::SelectOutputDeviceForAEC() {
1439 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1439);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1439); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1440 size_t currentDeviceIndex = mOutputDevices.IndexOf(mOutputDeviceForAEC);
1441 if (currentDeviceIndex == mOutputDevices.NoIndex) {
1442 // Outputs for this device have been removed.
1443 // Fall back to the primary output device.
1444 LOG(LogLevel::Info, ("%p: No remaining outputs to device %p. "
1445 "Switch to primary output device %p for AEC",
1446 this, mOutputDeviceForAEC, PrimaryOutputDeviceID()));
1447 mOutputDeviceForAEC = PrimaryOutputDeviceID();
1448 currentDeviceIndex = 0;
1449 MOZ_ASSERT(mOutputDevices[0].mDeviceID == mOutputDeviceForAEC)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mOutputDevices[0].mDeviceID == mOutputDeviceForAEC)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mOutputDevices[0].mDeviceID == mOutputDeviceForAEC))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOutputDevices[0].mDeviceID == mOutputDeviceForAEC"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1449);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOutputDevices[0].mDeviceID == mOutputDeviceForAEC"
")"); do { MOZ_CrashSequence(__null, 1449); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1450 }
1451 if (mOutputDevices.Length() == 1) {
1452 // No other output devices so there is no choice.
1453 return;
1454 }
1455
1456 // The output is considered silent intentionally only if the whole duration
1457 // (often more than just this processing interval) of audio data in the
1458 // MediaSegment is null so as to reduce switching between output devices
1459 // should there be short durations of silence.
1460 auto HasNonNullAudio = [](const TrackAndVolume& aTV) {
1461 return aTV.mVolume != 0 && !aTV.mTrack->IsSuspended() &&
1462 !aTV.mTrack->GetData()->IsNull();
1463 };
1464 // Keep using the same output device stream if it has non-null data,
1465 // so as to stay with a stream having ongoing audio. If the output stream
1466 // is switched, the echo cancellation algorithm can take some time to adjust
1467 // to the change in delay, so there is less value in switching back and
1468 // forth between output devices for very short sounds.
1469 for (const auto& output : mOutputDevices[currentDeviceIndex].mTrackOutputs) {
1470 if (HasNonNullAudio(output)) {
1471 return;
1472 }
1473 }
1474 // The current output device is silent. Use another if it has non-null data.
1475 for (const auto& outputDeviceEntry : mOutputDevices) {
1476 for (const auto& output : outputDeviceEntry.mTrackOutputs) {
1477 if (HasNonNullAudio(output)) {
1478 // Switch to this device.
1479 LOG(LogLevel::Info,
1480 ("%p: Switch output device for AEC from silent %p to non-null %p",
1481 this, mOutputDeviceForAEC, outputDeviceEntry.mDeviceID));
1482 mOutputDeviceForAEC = outputDeviceEntry.mDeviceID;
1483 return;
1484 }
1485 }
1486 }
1487 // Null data for all outputs. Keep using the same device.
1488}
1489
1490void MediaTrackGraphImpl::Process(MixerCallbackReceiver* aMixerReceiver) {
1491 TRACE("MTG::Process")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::Process");;
1492 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1492);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1492); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1493 if (mStateComputedTime == mProcessedTime) { // No frames to render.
1494 return;
1495 }
1496
1497 // Play track contents.
1498 bool allBlockedForever = true;
1499 // True when we've done ProcessInput for all processed tracks.
1500 bool doneAllProducing = false;
1501 const GraphTime oldProcessedTime = mProcessedTime;
1502
1503 // Figure out what each track wants to do
1504 for (uint32_t i = 0; i < mTracks.Length(); ++i) {
1505 MediaTrack* track = mTracks[i];
1506 if (!doneAllProducing) {
1507 ProcessedMediaTrack* pt = track->AsProcessedTrack();
1508 if (pt) {
1509 AudioNodeTrack* n = track->AsAudioNodeTrack();
1510 if (n) {
1511#ifdef DEBUG1
1512 // Verify that the sampling rate for all of the following tracks is
1513 // the same
1514 for (uint32_t j = i + 1; j < mTracks.Length(); ++j) {
1515 AudioNodeTrack* nextTrack = mTracks[j]->AsAudioNodeTrack();
1516 if (nextTrack) {
1517 MOZ_ASSERT(n->mSampleRate == nextTrack->mSampleRate,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(n->mSampleRate == nextTrack->mSampleRate)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(n->mSampleRate == nextTrack->mSampleRate))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("n->mSampleRate == nextTrack->mSampleRate"
" (" "All AudioNodeTracks in the graph must have the same " "sampling rate"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1519
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "n->mSampleRate == nextTrack->mSampleRate"
") (" "All AudioNodeTracks in the graph must have the same "
"sampling rate" ")"); do { MOZ_CrashSequence(__null, 1519); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
1518 "All AudioNodeTracks in the graph must have the same "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(n->mSampleRate == nextTrack->mSampleRate)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(n->mSampleRate == nextTrack->mSampleRate))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("n->mSampleRate == nextTrack->mSampleRate"
" (" "All AudioNodeTracks in the graph must have the same " "sampling rate"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1519
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "n->mSampleRate == nextTrack->mSampleRate"
") (" "All AudioNodeTracks in the graph must have the same "
"sampling rate" ")"); do { MOZ_CrashSequence(__null, 1519); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
1519 "sampling rate")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(n->mSampleRate == nextTrack->mSampleRate)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(n->mSampleRate == nextTrack->mSampleRate))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("n->mSampleRate == nextTrack->mSampleRate"
" (" "All AudioNodeTracks in the graph must have the same " "sampling rate"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1519
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "n->mSampleRate == nextTrack->mSampleRate"
") (" "All AudioNodeTracks in the graph must have the same "
"sampling rate" ")"); do { MOZ_CrashSequence(__null, 1519); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
1520 }
1521 }
1522#endif
1523 // Since an AudioNodeTrack is present, go ahead and
1524 // produce audio block by block for all the rest of the tracks.
1525 ProduceDataForTracksBlockByBlock(i, n->mSampleRate);
1526 doneAllProducing = true;
1527 } else {
1528 pt->ProcessInput(mProcessedTime, mStateComputedTime,
1529 ProcessedMediaTrack::ALLOW_END);
1530 // Assert that a live track produced enough data
1531 MOZ_ASSERT_IF(!track->mEnded,do { if (!track->mEnded) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(track->GetEnd() >=
GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(track->GetEnd() >= GraphTimeToTrackTimeWithBlocking
( track, mStateComputedTime)))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("track->GetEnd() >= GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1533);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "track->GetEnd() >= GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)"
")"); do { MOZ_CrashSequence(__null, 1533); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1532 track->GetEnd() >= GraphTimeToTrackTimeWithBlocking(do { if (!track->mEnded) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(track->GetEnd() >=
GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(track->GetEnd() >= GraphTimeToTrackTimeWithBlocking
( track, mStateComputedTime)))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("track->GetEnd() >= GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1533);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "track->GetEnd() >= GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)"
")"); do { MOZ_CrashSequence(__null, 1533); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1533 track, mStateComputedTime))do { if (!track->mEnded) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(track->GetEnd() >=
GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(track->GetEnd() >= GraphTimeToTrackTimeWithBlocking
( track, mStateComputedTime)))), 0))) { do { } while (false);
MOZ_ReportAssertionFailure("track->GetEnd() >= GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1533);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "track->GetEnd() >= GraphTimeToTrackTimeWithBlocking( track, mStateComputedTime)"
")"); do { MOZ_CrashSequence(__null, 1533); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1534 }
1535 }
1536 }
1537 if (track->mStartBlocking > oldProcessedTime) {
1538 allBlockedForever = false;
1539 }
1540 }
1541 mProcessedTime = mStateComputedTime;
1542
1543 SelectOutputDeviceForAEC();
1544 for (const auto& outputDeviceEntry : mOutputDevices) {
1545 uint32_t outputChannelCount;
1546 if (!outputDeviceEntry.mReceiver) { // primary output
1547 if (!aMixerReceiver) {
1548 // Running off a system clock driver. No need to mix output.
1549 continue;
1550 }
1551 MOZ_ASSERT(CurrentDriver()->AsAudioCallbackDriver(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CurrentDriver()->AsAudioCallbackDriver())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(CurrentDriver()->AsAudioCallbackDriver()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("CurrentDriver()->AsAudioCallbackDriver()"
" (" "Driver must be AudioCallbackDriver if aMixerReceiver" ")"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1552);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "CurrentDriver()->AsAudioCallbackDriver()"
") (" "Driver must be AudioCallbackDriver if aMixerReceiver"
")"); do { MOZ_CrashSequence(__null, 1552); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1552 "Driver must be AudioCallbackDriver if aMixerReceiver")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(CurrentDriver()->AsAudioCallbackDriver())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(CurrentDriver()->AsAudioCallbackDriver()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("CurrentDriver()->AsAudioCallbackDriver()"
" (" "Driver must be AudioCallbackDriver if aMixerReceiver" ")"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1552);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "CurrentDriver()->AsAudioCallbackDriver()"
") (" "Driver must be AudioCallbackDriver if aMixerReceiver"
")"); do { MOZ_CrashSequence(__null, 1552); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1553 // Use the number of channel the driver expects: this is the number of
1554 // channel that can be output by the underlying system level audio stream.
1555 outputChannelCount =
1556 CurrentDriver()->AsAudioCallbackDriver()->OutputChannelCount();
1557 } else {
1558 outputChannelCount = AudioOutputChannelCount(outputDeviceEntry);
1559 }
1560 MOZ_ASSERT(mRealtime,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRealtime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRealtime))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mRealtime" " (" "If there's an output device, this graph must be realtime"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1561
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRealtime" ") (" "If there's an output device, this graph must be realtime"
")"); do { MOZ_CrashSequence(__null, 1561); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1561 "If there's an output device, this graph must be realtime")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRealtime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRealtime))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mRealtime" " (" "If there's an output device, this graph must be realtime"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1561
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRealtime" ") (" "If there's an output device, this graph must be realtime"
")"); do { MOZ_CrashSequence(__null, 1561); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1562 mMixer.StartMixing();
1563 // This is the number of frames that are written to the output buffer, for
1564 // this iteration.
1565 TrackTime ticksPlayed = 0;
1566 for (const auto& t : outputDeviceEntry.mTrackOutputs) {
1567 TrackTime ticksPlayedForThisTrack =
1568 PlayAudio(t, oldProcessedTime, outputChannelCount);
1569 if (ticksPlayed == 0) {
1570 ticksPlayed = ticksPlayedForThisTrack;
1571 } else {
1572 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ticksPlayedForThisTrack || ticksPlayedForThisTrack ==
ticksPlayed)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!ticksPlayedForThisTrack || ticksPlayedForThisTrack
== ticksPlayed))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ticksPlayedForThisTrack || ticksPlayedForThisTrack == ticksPlayed"
" (" "Each track should have the same number of frames." ")"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1574);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ticksPlayedForThisTrack || ticksPlayedForThisTrack == ticksPlayed"
") (" "Each track should have the same number of frames." ")"
); do { MOZ_CrashSequence(__null, 1574); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1573 !ticksPlayedForThisTrack || ticksPlayedForThisTrack == ticksPlayed,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ticksPlayedForThisTrack || ticksPlayedForThisTrack ==
ticksPlayed)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!ticksPlayedForThisTrack || ticksPlayedForThisTrack
== ticksPlayed))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ticksPlayedForThisTrack || ticksPlayedForThisTrack == ticksPlayed"
" (" "Each track should have the same number of frames." ")"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1574);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ticksPlayedForThisTrack || ticksPlayedForThisTrack == ticksPlayed"
") (" "Each track should have the same number of frames." ")"
); do { MOZ_CrashSequence(__null, 1574); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1574 "Each track should have the same number of frames.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ticksPlayedForThisTrack || ticksPlayedForThisTrack ==
ticksPlayed)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!ticksPlayedForThisTrack || ticksPlayedForThisTrack
== ticksPlayed))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ticksPlayedForThisTrack || ticksPlayedForThisTrack == ticksPlayed"
" (" "Each track should have the same number of frames." ")"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1574);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ticksPlayedForThisTrack || ticksPlayedForThisTrack == ticksPlayed"
") (" "Each track should have the same number of frames." ")"
); do { MOZ_CrashSequence(__null, 1574); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1575 }
1576 }
1577
1578 if (ticksPlayed == 0) {
1579 // Nothing was played, so the mixer doesn't know how many frames were
1580 // processed. We still tell it so AudioCallbackDriver knows how much has
1581 // been processed. (bug 1406027)
1582 mMixer.Mix(nullptr, outputChannelCount,
1583 mStateComputedTime - oldProcessedTime, mSampleRate);
1584 }
1585 AudioChunk* outputChunk = mMixer.MixedChunk();
1586 if (outputDeviceEntry.mDeviceID == mOutputDeviceForAEC) {
1587 // Callback any observers for the AEC speaker data. Note that one
1588 // (maybe) of these will be full-duplex, the others will get their input
1589 // data off separate cubeb callbacks.
1590 NotifyOutputData(*outputChunk);
1591 }
1592 if (!outputDeviceEntry.mReceiver) { // primary output
1593 aMixerReceiver->MixerCallback(outputChunk, mSampleRate);
1594 } else {
1595 outputDeviceEntry.mReceiver->EnqueueAudio(*outputChunk);
1596 }
1597 }
1598
1599 if (!allBlockedForever) {
1600 EnsureNextIteration();
1601 }
1602}
1603
1604bool MediaTrackGraphImpl::UpdateMainThreadState() {
1605 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1605);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1605); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1606 if (mForceShutDownReceived) {
1607 for (MediaTrack* track : AllTracks()) {
1608 track->OnGraphThreadDone();
1609 }
1610 }
1611 {
1612 MonitorAutoLock lock(mMonitor);
1613 bool finalUpdate =
1614 mForceShutDownReceived || (IsEmpty() && mBackMessageQueue.IsEmpty());
1615 PrepareUpdatesToMainThreadState(finalUpdate);
1616 if (!finalUpdate) {
1617 SwapMessageQueues();
1618 return true;
1619 }
1620 // The JSContext will not be used again.
1621 // Clear main thread access while under monitor.
1622 mJSContext = nullptr;
1623 }
1624 dom::WorkletThread::DeleteCycleCollectedJSContext();
1625 // Enter shutdown mode when this iteration is completed.
1626 // No need to Destroy tracks here. The main-thread owner of each
1627 // track is responsible for calling Destroy on them.
1628 return false;
1629}
1630
1631auto MediaTrackGraphImpl::OneIteration(GraphTime aStateTime,
1632 GraphTime aIterationEnd,
1633 MixerCallbackReceiver* aMixerReceiver)
1634 -> IterationResult {
1635 if (mGraphRunner) {
1636 return mGraphRunner->OneIteration(aStateTime, aIterationEnd,
1637 aMixerReceiver);
1638 }
1639
1640 return OneIterationImpl(aStateTime, aIterationEnd, aMixerReceiver);
1641}
1642
1643auto MediaTrackGraphImpl::OneIterationImpl(
1644 GraphTime aStateTime, GraphTime aIterationEnd,
1645 MixerCallbackReceiver* aMixerReceiver) -> IterationResult {
1646 TRACE("MTG::OneIterationImpl")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::OneIterationImpl"
);
;
1647
1648 if (SoftRealTimeLimitReached()) {
1649 TRACE("MTG::Demoting real-time thread!")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::Demoting real-time thread!"
);
;
1650 DemoteThreadFromRealTime();
1651 }
1652
1653 // Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
1654 // thread, and so the monitor need not be held to check mLifecycleState.
1655 // LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
1656 // graphs that have not started.
1657
1658 // While changes occur on mainthread, this assert confirms that
1659 // this code shouldn't run if mainthread might be changing the state (to
1660 // > LIFECYCLE_RUNNING)
1661
1662 // Ignore mutex warning: static during execution of the graph
1663 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
1664 MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLifecycleState <= LIFECYCLE_RUNNING)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mLifecycleState <= LIFECYCLE_RUNNING))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mLifecycleState <= LIFECYCLE_RUNNING"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1664);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mLifecycleState <= LIFECYCLE_RUNNING"
")"); do { MOZ_CrashSequence(__null, 1664); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1665 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
1666
1667 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1667);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 1667); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1668
1669 WebCore::DenormalDisabler disabler;
1670
1671 // Process graph message from the main thread for this iteration.
1672 RunMessagesInQueue();
1673
1674 // Process MessagePort events.
1675 // These require a single thread, which has an nsThread with an event queue.
1676 if (mGraphRunner || !mRealtime) {
1677 TRACE("MTG::MessagePort events")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::MessagePort events"
);
;
1678 NS_ProcessPendingEvents(nullptr);
1679 }
1680
1681 GraphTime stateTime = std::min(aStateTime, GraphTime(mEndTime));
1682 UpdateGraph(stateTime);
1683
1684 mStateComputedTime = stateTime;
1685
1686 GraphTime oldProcessedTime = mProcessedTime;
1687 Process(aMixerReceiver);
1688 MOZ_ASSERT(mProcessedTime == stateTime)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mProcessedTime == stateTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mProcessedTime == stateTime)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mProcessedTime == stateTime"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1688);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mProcessedTime == stateTime"
")"); do { MOZ_CrashSequence(__null, 1688); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1689
1690 UpdateCurrentTimeForTracks(oldProcessedTime);
1691
1692 ProcessChunkMetadata(oldProcessedTime);
1693
1694 // Process graph messages queued from RunMessageAfterProcessing() on this
1695 // thread during the iteration.
1696 RunMessagesInQueue();
1697
1698 if (!UpdateMainThreadState()) {
1699 if (Switching()) {
1700 // We'll never get to do this switch. Clear mNextDriver to break the
1701 // ref-cycle graph->nextDriver->currentDriver->graph.
1702 SwitchAtNextIteration(nullptr);
1703 }
1704 return IterationResult::CreateStop(
1705 NewRunnableMethod("MediaTrackGraphImpl::SignalMainThreadCleanup", this,
1706 &MediaTrackGraphImpl::SignalMainThreadCleanup));
1707 }
1708
1709 if (Switching()) {
1710 RefPtr<GraphDriver> nextDriver = std::move(mNextDriver);
1711 return IterationResult::CreateSwitchDriver(
1712 nextDriver, NewRunnableMethod<StoreRefPtrPassByPtr<GraphDriver>>(
1713 "MediaTrackGraphImpl::SetCurrentDriver", this,
1714 &MediaTrackGraphImpl::SetCurrentDriver, nextDriver));
1715 }
1716
1717 return IterationResult::CreateStillProcessing();
1718}
1719
1720void MediaTrackGraphImpl::ApplyTrackUpdate(TrackUpdate* aUpdate) {
1721 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1721);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1721); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1722 mMonitor.AssertCurrentThreadOwns();
1723
1724 MediaTrack* track = aUpdate->mTrack;
1725 if (!track) return;
1726 track->mMainThreadCurrentTime = aUpdate->mNextMainThreadCurrentTime;
1727 track->mMainThreadEnded = aUpdate->mNextMainThreadEnded;
1728
1729 if (track->ShouldNotifyTrackEnded()) {
1730 track->NotifyMainThreadListeners();
1731 }
1732}
1733
1734void MediaTrackGraphImpl::ForceShutDown() {
1735 MOZ_ASSERT(NS_IsMainThread(), "Must be called on main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Must be called on main thread" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1735); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Must be called on main thread" ")"); do { MOZ_CrashSequence
(__null, 1735); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1736 LOG(LogLevel::Debug, ("%p: MediaTrackGraph::ForceShutdown", this));
1737
1738 if (mShutdownBlocker) {
1739 // Avoid waiting forever for a graph to shut down
1740 // synchronously. Reports are that some 3rd-party audio drivers
1741 // occasionally hang in shutdown (both for us and Chrome).
1742 NS_NewTimerWithCallback(
1743 getter_AddRefs(mShutdownTimer), this,
1744 MediaTrackGraph::AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT,
1745 nsITimer::TYPE_ONE_SHOT);
1746 }
1747
1748 class Message final : public ControlMessage {
1749 public:
1750 explicit Message(MediaTrackGraphImpl* aGraph)
1751 : ControlMessage(nullptr), mGraph(aGraph) {}
1752 void Run() override {
1753 TRACE("MTG::ForceShutdown ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::ForceShutdown ControlMessage"
);
;
1754 mGraph->mForceShutDownReceived = true;
1755 }
1756 // The graph owns this message.
1757 MediaTrackGraphImpl* MOZ_NON_OWNING_REF mGraph;
1758 };
1759
1760 if (mMainThreadTrackCount > 0 || mMainThreadPortCount > 0) {
1761 // If both the track and port counts are zero, the regular shutdown
1762 // sequence will progress shortly to shutdown threads and destroy the graph.
1763 AppendMessage(MakeUnique<Message>(this));
1764 InterruptJS();
1765 }
1766}
1767
1768NS_IMETHODIMPnsresult
1769MediaTrackGraphImpl::Notify(nsITimer* aTimer) {
1770 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1770);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1770); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1771 MOZ_ASSERT(!mShutdownBlocker, "MediaTrackGraph took too long to shut down!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mShutdownBlocker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mShutdownBlocker))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mShutdownBlocker"
" (" "MediaTrackGraph took too long to shut down!" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mShutdownBlocker"
") (" "MediaTrackGraph took too long to shut down!" ")"); do
{ MOZ_CrashSequence(__null, 1771); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1772 // Sigh, graph took too long to shut down. Stop blocking system
1773 // shutdown and hope all is well.
1774 RemoveShutdownBlocker();
1775 return NS_OK;
1776}
1777
1778static nsCString GetDocumentTitle(uint64_t aWindowID) {
1779 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1779);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1779); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1780 nsCString title;
1781 auto* win = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
1782 if (!win) {
1783 return title;
1784 }
1785 Document* doc = win->GetExtantDoc();
1786 if (!doc) {
1787 return title;
1788 }
1789 nsAutoString titleUTF16;
1790 doc->GetTitle(titleUTF16);
1791 CopyUTF16toUTF8(titleUTF16, title);
1792 return title;
1793}
1794
1795NS_IMETHODIMPnsresult
1796MediaTrackGraphImpl::Observe(nsISupports* aSubject, const char* aTopic,
1797 const char16_t* aData) {
1798 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1798);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1798); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1799 MOZ_ASSERT(strcmp(aTopic, "document-title-changed") == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(strcmp(aTopic, "document-title-changed") == 0)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(strcmp(aTopic, "document-title-changed") == 0))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("strcmp(aTopic, \"document-title-changed\") == 0"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1799);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(aTopic, \"document-title-changed\") == 0"
")"); do { MOZ_CrashSequence(__null, 1799); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1800 nsCString streamName = GetDocumentTitle(mWindowID);
1801 LOG(LogLevel::Debug, ("%p: document title: %s", this, streamName.get()));
1802 if (streamName.IsEmpty()) {
1803 return NS_OK;
1804 }
1805 QueueControlMessageWithNoShutdown(
1806 [self = RefPtr{this}, this, streamName = std::move(streamName)] {
1807 CurrentDriver()->SetStreamName(streamName);
1808 });
1809 return NS_OK;
1810}
1811
1812bool MediaTrackGraphImpl::AddShutdownBlocker() {
1813 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1813);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1813); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1814 MOZ_ASSERT(!mShutdownBlocker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mShutdownBlocker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mShutdownBlocker))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mShutdownBlocker"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1814);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mShutdownBlocker" ")"
); do { MOZ_CrashSequence(__null, 1814); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1815
1816 class Blocker : public media::ShutdownBlocker {
1817 const RefPtr<MediaTrackGraphImpl> mGraph;
1818
1819 public:
1820 Blocker(MediaTrackGraphImpl* aGraph, const nsString& aName)
1821 : media::ShutdownBlocker(aName), mGraph(aGraph) {}
1822
1823 NS_IMETHODvirtual nsresult
1824 BlockShutdown(nsIAsyncShutdownClient* aProfileBeforeChange) override {
1825 mGraph->ForceShutDown();
1826 return NS_OK;
1827 }
1828 };
1829
1830 nsCOMPtr<nsIAsyncShutdownClient> barrier = media::GetShutdownBarrier();
1831 if (!barrier) {
1832 // We're already shutting down, we won't be able to add a blocker, bail.
1833 LOG(LogLevel::Error,
1834 ("%p: Couldn't get shutdown barrier, won't add shutdown blocker",
1835 this));
1836 return false;
1837 }
1838
1839 // Blocker names must be distinct.
1840 nsString blockerName;
1841 blockerName.AppendPrintf("MediaTrackGraph %p shutdown", this);
1842 mShutdownBlocker = MakeAndAddRef<Blocker>(this, blockerName);
1843 nsresult rv = barrier->AddBlocker(mShutdownBlocker,
1844 NS_LITERAL_STRING_FROM_CSTRING(__FILE__)static_cast<const nsLiteralString&>( nsLiteralString
(u"" "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"))
,
1845 __LINE__1845, u"MediaTrackGraph shutdown"_ns);
1846 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1846); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 1846); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1847 return true;
1848}
1849
1850void MediaTrackGraphImpl::RemoveShutdownBlocker() {
1851 if (!mShutdownBlocker) {
1852 return;
1853 }
1854 media::MustGetShutdownBarrier()->RemoveBlocker(mShutdownBlocker);
1855 mShutdownBlocker = nullptr;
1856}
1857
1858NS_IMETHODIMPnsresult
1859MediaTrackGraphImpl::GetName(nsACString& aName) {
1860 aName.AssignLiteral("MediaTrackGraphImpl");
1861 return NS_OK;
1862}
1863
1864namespace {
1865
1866class MediaTrackGraphShutDownRunnable : public Runnable {
1867 public:
1868 explicit MediaTrackGraphShutDownRunnable(MediaTrackGraphImpl* aGraph)
1869 : Runnable("MediaTrackGraphShutDownRunnable"), mGraph(aGraph) {}
1870 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
1871 // See bug 1535398.
1872 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
1873 TRACE("MTG::MediaTrackGraphShutDownRunnable runnable")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::MediaTrackGraphShutDownRunnable runnable"
);
;
1874 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1874);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 1874); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1875 MOZ_ASSERT(!mGraph->mGraphDriverRunning && mGraph->mDriver,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGraph->mGraphDriverRunning && mGraph->
mDriver)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mGraph->mGraphDriverRunning && mGraph->
mDriver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mGraph->mGraphDriverRunning && mGraph->mDriver"
" (" "We should know the graph thread control loop isn't running!"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1876
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGraph->mGraphDriverRunning && mGraph->mDriver"
") (" "We should know the graph thread control loop isn't running!"
")"); do { MOZ_CrashSequence(__null, 1876); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1876 "We should know the graph thread control loop isn't running!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGraph->mGraphDriverRunning && mGraph->
mDriver)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mGraph->mGraphDriverRunning && mGraph->
mDriver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mGraph->mGraphDriverRunning && mGraph->mDriver"
" (" "We should know the graph thread control loop isn't running!"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1876
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGraph->mGraphDriverRunning && mGraph->mDriver"
") (" "We should know the graph thread control loop isn't running!"
")"); do { MOZ_CrashSequence(__null, 1876); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1877
1878 LOG(LogLevel::Debug, ("%p: Shutting down graph", mGraph.get()));
1879
1880 // We've asserted the graph isn't running. Use mDriver instead of
1881 // CurrentDriver to avoid thread-safety checks
1882#if 0 // AudioCallbackDrivers are released asynchronously anyways
1883 // XXX a better test would be have setting mGraphDriverRunning make sure
1884 // any current callback has finished and block future ones -- or just
1885 // handle it all in Shutdown()!
1886 if (mGraph->mDriver->AsAudioCallbackDriver()) {
1887 MOZ_ASSERT(!mGraph->mDriver->AsAudioCallbackDriver()->InCallback())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGraph->mDriver->AsAudioCallbackDriver()->
InCallback())>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!mGraph->mDriver->AsAudioCallbackDriver
()->InCallback()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mGraph->mDriver->AsAudioCallbackDriver()->InCallback()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1887);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGraph->mDriver->AsAudioCallbackDriver()->InCallback()"
")"); do { MOZ_CrashSequence(__null, 1887); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1888 }
1889#endif
1890
1891 for (MediaTrackGraphImpl::PendingResumeOperation& op :
1892 mGraph->mPendingResumeOperations) {
1893 op.Abort();
1894 }
1895
1896 if (mGraph->mGraphRunner) {
1897 RefPtr<GraphRunner>(mGraph->mGraphRunner)->Shutdown();
1898 }
1899
1900 RefPtr<GraphDriver>(mGraph->mDriver)->Shutdown();
1901
1902 // Release the driver now so that an AudioCallbackDriver will release its
1903 // SharedThreadPool reference. Each SharedThreadPool reference must be
1904 // released before SharedThreadPool::SpinUntilEmpty() runs on
1905 // xpcom-shutdown-threads. Don't wait for GC/CC to release references to
1906 // objects owning tracks, or for expiration of mGraph->mShutdownTimer,
1907 // which won't otherwise release its reference on the graph until
1908 // nsTimerImpl::Shutdown(), which runs after xpcom-shutdown-threads.
1909 mGraph->SetCurrentDriver(nullptr);
1910
1911 // Safe to access these without the monitor since the graph isn't running.
1912 // We may be one of several graphs. Drop ticket to eventually unblock
1913 // shutdown.
1914 if (mGraph->mShutdownTimer && !mGraph->mShutdownBlocker) {
1915 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")"); do { MOZ_CrashSequence
(__null, 1918); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1916 false,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")"); do { MOZ_CrashSequence
(__null, 1918); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1917 "AudioCallbackDriver took too long to shut down and we let shutdown"do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")"); do { MOZ_CrashSequence
(__null, 1918); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1918 " continue - freezing and leaking")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"AudioCallbackDriver took too long to shut down and we let shutdown"
" continue - freezing and leaking" ")"); do { MOZ_CrashSequence
(__null, 1918); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1919
1920 // The timer fired, so we may be deeper in shutdown now. Block any
1921 // further teardown and just leak, for safety.
1922 return NS_OK;
1923 }
1924
1925 // mGraph's thread is not running so it's OK to do whatever here
1926 for (MediaTrack* track : mGraph->AllTracks()) {
1927 // Clean up all MediaSegments since we cannot release Images too
1928 // late during shutdown. Also notify listeners that they were removed
1929 // so they can clean up any gfx resources.
1930 track->RemoveAllResourcesAndListenersImpl();
1931 }
1932
1933#ifdef DEBUG1
1934 {
1935 MonitorAutoLock lock(mGraph->mMonitor);
1936 MOZ_ASSERT(mGraph->mUpdateRunnables.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGraph->mUpdateRunnables.IsEmpty())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(mGraph->mUpdateRunnables.IsEmpty()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mGraph->mUpdateRunnables.IsEmpty()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1936);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGraph->mUpdateRunnables.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 1936); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1937 }
1938#endif
1939 mGraph->mPendingUpdateRunnables.Clear();
1940
1941 mGraph->RemoveShutdownBlocker();
1942
1943 // We can't block past the final LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION
1944 // stage, since completion of that stage requires all tracks to be freed,
1945 // which requires shutdown to proceed.
1946
1947 if (mGraph->IsEmpty()) {
1948 // mGraph is no longer needed, so delete it.
1949 mGraph->Destroy();
1950 } else {
1951 // The graph is not empty. We must be in a forced shutdown.
1952 // Some later AppendMessage will detect that the graph has
1953 // been emptied, and delete it.
1954 NS_ASSERTION(mGraph->mForceShutDownReceived, "Not in forced shutdown?")do { if (!(mGraph->mForceShutDownReceived)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Not in forced shutdown?", "mGraph->mForceShutDownReceived"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 1954);
MOZ_PretendNoReturn(); } } while (0)
;
1955 mGraph->LifecycleStateRef() =
1956 MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION;
1957 }
1958 return NS_OK;
1959 }
1960
1961 private:
1962 RefPtr<MediaTrackGraphImpl> mGraph;
1963};
1964
1965class MediaTrackGraphStableStateRunnable : public Runnable {
1966 public:
1967 explicit MediaTrackGraphStableStateRunnable(MediaTrackGraphImpl* aGraph,
1968 bool aSourceIsMTG)
1969 : Runnable("MediaTrackGraphStableStateRunnable"),
1970 mGraph(aGraph),
1971 mSourceIsMTG(aSourceIsMTG) {}
1972 NS_IMETHODvirtual nsresult Run() override {
1973 TRACE("MTG::MediaTrackGraphStableStateRunnable ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::MediaTrackGraphStableStateRunnable ControlMessage"
);
;
1974 if (mGraph) {
1975 mGraph->RunInStableState(mSourceIsMTG);
1976 }
1977 return NS_OK;
1978 }
1979
1980 private:
1981 RefPtr<MediaTrackGraphImpl> mGraph;
1982 bool mSourceIsMTG;
1983};
1984
1985/*
1986 * Control messages forwarded from main thread to graph manager thread
1987 */
1988class CreateMessage : public ControlMessage {
1989 public:
1990 explicit CreateMessage(MediaTrack* aTrack) : ControlMessage(aTrack) {}
1991 void Run() override {
1992 TRACE("MTG::AddTrackGraphThread ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::AddTrackGraphThread ControlMessage"
);
;
1993 mTrack->GraphImpl()->AddTrackGraphThread(mTrack);
1994 }
1995 void RunDuringShutdown() override {
1996 // Make sure to run this message during shutdown too, to make sure
1997 // that we balance the number of tracks registered with the graph
1998 // as they're destroyed during shutdown.
1999 Run();
2000 }
2001};
2002
2003} // namespace
2004
2005void MediaTrackGraphImpl::RunInStableState(bool aSourceIsMTG) {
2006 MOZ_ASSERT(NS_IsMainThread(), "Must be called on main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Must be called on main thread" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2006); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Must be called on main thread" ")"); do { MOZ_CrashSequence
(__null, 2006); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2007
2008 nsTArray<nsCOMPtr<nsIRunnable>> runnables;
2009 // When we're doing a forced shutdown, pending control messages may be
2010 // run on the main thread via RunDuringShutdown. Those messages must
2011 // run without the graph monitor being held. So, we collect them here.
2012 nsTArray<UniquePtr<ControlMessageInterface>>
2013 controlMessagesToRunDuringShutdown;
2014
2015 {
2016 MonitorAutoLock lock(mMonitor);
2017 if (aSourceIsMTG) {
2018 MOZ_ASSERT(mPostedRunInStableStateEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPostedRunInStableStateEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPostedRunInStableStateEvent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mPostedRunInStableStateEvent", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2018); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPostedRunInStableStateEvent"
")"); do { MOZ_CrashSequence(__null, 2018); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2019 mPostedRunInStableStateEvent = false;
2020 }
2021
2022 // This should be kept in sync with the LifecycleState enum in
2023 // MediaTrackGraphImpl.h
2024 const char* LifecycleState_str[] = {
2025 "LIFECYCLE_THREAD_NOT_STARTED", "LIFECYCLE_RUNNING",
2026 "LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP",
2027 "LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN",
2028 "LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION"};
2029
2030 if (LifecycleStateRef() != LIFECYCLE_RUNNING) {
2031 LOG(LogLevel::Debug,
2032 ("%p: Running stable state callback. Current state: %s", this,
2033 LifecycleState_str[LifecycleStateRef()]));
2034 }
2035
2036 runnables = std::move(mUpdateRunnables);
2037 for (uint32_t i = 0; i < mTrackUpdates.Length(); ++i) {
2038 TrackUpdate* update = &mTrackUpdates[i];
2039 if (update->mTrack) {
2040 ApplyTrackUpdate(update);
2041 }
2042 }
2043 mTrackUpdates.Clear();
2044
2045 mMainThreadGraphTime = mNextMainThreadGraphTime;
2046
2047 if (mCurrentTaskMessageQueue.IsEmpty()) {
2048 if (LifecycleStateRef() == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP &&
2049 IsEmpty()) {
2050 // Complete shutdown. First, ensure that this graph is no longer used.
2051 // A new graph graph will be created if one is needed.
2052 // Asynchronously clean up old graph. We don't want to do this
2053 // synchronously because it spins the event loop waiting for threads
2054 // to shut down, and we don't want to do that in a stable state handler.
2055 LifecycleStateRef() = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN;
2056 LOG(LogLevel::Debug,
2057 ("%p: Sending MediaTrackGraphShutDownRunnable", this));
2058 nsCOMPtr<nsIRunnable> event = new MediaTrackGraphShutDownRunnable(this);
2059 mMainThread->Dispatch(event.forget());
2060 }
2061 } else {
2062 if (LifecycleStateRef() <= LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
2063 MessageBlock* block = mBackMessageQueue.AppendElement();
2064 block->mMessages = std::move(mCurrentTaskMessageQueue);
2065 EnsureNextIteration();
2066 }
2067
2068 // If this MediaTrackGraph has entered regular (non-forced) shutdown it
2069 // is not able to process any more messages. Those messages being added to
2070 // the graph in the first place is an error.
2071 MOZ_DIAGNOSTIC_ASSERT(LifecycleStateRef() <do { static_assert( mozilla::detail::AssertionConditionType<
decltype(LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP
|| mForceShutDownReceived)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP
|| mForceShutDownReceived))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP || mForceShutDownReceived"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2073);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP || mForceShutDownReceived"
")"); do { MOZ_CrashSequence(__null, 2073); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2072 LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP
|| mForceShutDownReceived)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP
|| mForceShutDownReceived))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP || mForceShutDownReceived"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2073);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP || mForceShutDownReceived"
")"); do { MOZ_CrashSequence(__null, 2073); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2073 mForceShutDownReceived)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP
|| mForceShutDownReceived)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP
|| mForceShutDownReceived))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP || mForceShutDownReceived"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2073);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "LifecycleStateRef() < LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP || mForceShutDownReceived"
")"); do { MOZ_CrashSequence(__null, 2073); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2074 }
2075
2076 if (LifecycleStateRef() == LIFECYCLE_THREAD_NOT_STARTED) {
2077 // Start the driver now. We couldn't start it earlier because the graph
2078 // might exit immediately on finding it has no tracks. The first message
2079 // for a new graph must create a track. Ensure that his message runs on
2080 // the first iteration.
2081 MOZ_ASSERT(MessagesQueued())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(MessagesQueued())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(MessagesQueued()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("MessagesQueued()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2081);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "MessagesQueued()" ")"
); do { MOZ_CrashSequence(__null, 2081); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2082 SwapMessageQueues();
2083
2084 LOG(LogLevel::Debug,
2085 ("%p: Starting a graph with a %s", this,
2086 CurrentDriver()->AsAudioCallbackDriver() ? "AudioCallbackDriver"
2087 : "SystemClockDriver"));
2088 LifecycleStateRef() = LIFECYCLE_RUNNING;
2089 mGraphDriverRunning = true;
2090 RefPtr<GraphDriver> driver = CurrentDriver();
2091 driver->Start();
2092 // It's not safe to Shutdown() a thread from StableState, and
2093 // releasing this may shutdown a SystemClockDriver thread.
2094 // Proxy the release to outside of StableState.
2095 NS_ReleaseOnMainThread("MediaTrackGraphImpl::CurrentDriver",
2096 driver.forget(),
2097 true); // always proxy
2098 }
2099
2100 if (LifecycleStateRef() == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP &&
2101 mForceShutDownReceived) {
2102 // Defer calls to RunDuringShutdown() to happen while mMonitor is not
2103 // held.
2104 for (uint32_t i = 0; i < mBackMessageQueue.Length(); ++i) {
2105 MessageBlock& mb = mBackMessageQueue[i];
2106 controlMessagesToRunDuringShutdown.AppendElements(
2107 std::move(mb.mMessages));
2108 }
2109 mBackMessageQueue.Clear();
2110 MOZ_ASSERT(mCurrentTaskMessageQueue.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCurrentTaskMessageQueue.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCurrentTaskMessageQueue.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mCurrentTaskMessageQueue.IsEmpty()", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentTaskMessageQueue.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 2110); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2111 // Stop MediaTrackGraph threads.
2112 LifecycleStateRef() = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN;
2113 nsCOMPtr<nsIRunnable> event = new MediaTrackGraphShutDownRunnable(this);
2114 mMainThread->Dispatch(event.forget());
2115 }
2116
2117 mGraphDriverRunning = LifecycleStateRef() == LIFECYCLE_RUNNING;
2118 }
2119
2120 // Make sure we get a new current time in the next event loop task
2121 if (!aSourceIsMTG) {
2122 MOZ_ASSERT(mPostedRunInStableState)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPostedRunInStableState)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPostedRunInStableState))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mPostedRunInStableState"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2122);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPostedRunInStableState"
")"); do { MOZ_CrashSequence(__null, 2122); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2123 mPostedRunInStableState = false;
2124 }
2125
2126 for (uint32_t i = 0; i < controlMessagesToRunDuringShutdown.Length(); ++i) {
2127 controlMessagesToRunDuringShutdown[i]->RunDuringShutdown();
2128 }
2129
2130#ifdef DEBUG1
2131 mCanRunMessagesSynchronously =
2132 !mGraphDriverRunning &&
2133 LifecycleStateRef() >= LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN;
2134#endif
2135
2136 for (uint32_t i = 0; i < runnables.Length(); ++i) {
2137 runnables[i]->Run();
2138 }
2139}
2140
2141void MediaTrackGraphImpl::EnsureRunInStableState() {
2142 MOZ_ASSERT(NS_IsMainThread(), "main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "main thread only" ")"); do { MOZ_CrashSequence(__null
, 2142); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2143
2144 if (mPostedRunInStableState) return;
2145 mPostedRunInStableState = true;
2146 nsCOMPtr<nsIRunnable> event =
2147 new MediaTrackGraphStableStateRunnable(this, false);
2148 nsContentUtils::RunInStableState(event.forget());
2149}
2150
2151void MediaTrackGraphImpl::EnsureStableStateEventPosted() {
2152 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2152);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 2152); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2153 mMonitor.AssertCurrentThreadOwns();
2154
2155 if (mPostedRunInStableStateEvent) return;
2156 mPostedRunInStableStateEvent = true;
2157 nsCOMPtr<nsIRunnable> event =
2158 new MediaTrackGraphStableStateRunnable(this, true);
2159 mMainThread->Dispatch(event.forget());
2160}
2161
2162void MediaTrackGraphImpl::SignalMainThreadCleanup() {
2163 MOZ_ASSERT(mDriver->OnThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDriver->OnThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDriver->OnThread()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mDriver->OnThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2163);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDriver->OnThread()"
")"); do { MOZ_CrashSequence(__null, 2163); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2164
2165 MonitorAutoLock lock(mMonitor);
2166 // LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
2167 // graphs that have not started.
2168 MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLifecycleState <= LIFECYCLE_RUNNING)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mLifecycleState <= LIFECYCLE_RUNNING))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mLifecycleState <= LIFECYCLE_RUNNING"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2168);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mLifecycleState <= LIFECYCLE_RUNNING"
")"); do { MOZ_CrashSequence(__null, 2168); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2169 LOG(LogLevel::Debug,
2170 ("%p: MediaTrackGraph waiting for main thread cleanup", this));
2171 LifecycleStateRef() =
2172 MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP;
2173 EnsureStableStateEventPosted();
2174}
2175
2176void MediaTrackGraphImpl::AppendMessage(
2177 UniquePtr<ControlMessageInterface> aMessage) {
2178 MOZ_ASSERT(NS_IsMainThread(), "main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "main thread only" ")"); do { MOZ_CrashSequence(__null
, 2178); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2179 MOZ_DIAGNOSTIC_ASSERT(mMainThreadTrackCount > 0 || mMainThreadPortCount > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMainThreadTrackCount > 0 || mMainThreadPortCount
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mMainThreadTrackCount > 0 || mMainThreadPortCount
> 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mMainThreadTrackCount > 0 || mMainThreadPortCount > 0"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2179);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mMainThreadTrackCount > 0 || mMainThreadPortCount > 0"
")"); do { MOZ_CrashSequence(__null, 2179); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2180
2181 if (!mGraphDriverRunning &&
2182 LifecycleStateRef() > LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
2183 // The graph control loop is not running and main thread cleanup has
2184 // happened. From now on we can't append messages to
2185 // mCurrentTaskMessageQueue, because that will never be processed again, so
2186 // just RunDuringShutdown this message. This should only happen during
2187 // forced shutdown, or after a non-realtime graph has finished processing.
2188#ifdef DEBUG1
2189 MOZ_ASSERT(mCanRunMessagesSynchronously)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCanRunMessagesSynchronously)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCanRunMessagesSynchronously
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mCanRunMessagesSynchronously", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCanRunMessagesSynchronously"
")"); do { MOZ_CrashSequence(__null, 2189); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2190 mCanRunMessagesSynchronously = false;
2191#endif
2192 aMessage->RunDuringShutdown();
2193#ifdef DEBUG1
2194 mCanRunMessagesSynchronously = true;
2195#endif
2196 if (IsEmpty() &&
2197 LifecycleStateRef() >= LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION) {
2198 Destroy();
2199 }
2200 return;
2201 }
2202
2203 mCurrentTaskMessageQueue.AppendElement(std::move(aMessage));
2204 EnsureRunInStableState();
2205}
2206
2207void MediaTrackGraphImpl::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable) {
2208 mMainThread->Dispatch(std::move(aRunnable));
2209}
2210
2211MediaTrack::MediaTrack(TrackRate aSampleRate, MediaSegment::Type aType,
2212 MediaSegment* aSegment)
2213 : mSampleRate(aSampleRate),
2214 mType(aType),
2215 mSegment(aSegment),
2216 mStartTime(0),
2217 mForgottenTime(0),
2218 mEnded(false),
2219 mNotifiedEnded(false),
2220 mDisabledMode(DisabledTrackMode::ENABLED),
2221 mStartBlocking(GRAPH_TIME_MAX),
2222 mSuspendedCount(0),
2223 mMainThreadCurrentTime(0),
2224 mMainThreadEnded(false),
2225 mEndedNotificationSent(false),
2226 mMainThreadDestroyed(false),
2227 mGraph(nullptr) {
2228 MOZ_COUNT_CTOR(MediaTrack)do { static_assert(std::is_class_v<MediaTrack>, "Token '"
"MediaTrack" "' is not a class type."); static_assert(!std::
is_base_of<nsISupports, MediaTrack>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "MediaTrack", sizeof
(*this)); } while (0)
;
2229 MOZ_ASSERT_IF(mSegment, mSegment->GetType() == aType)do { if (mSegment) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mSegment->GetType() == aType)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSegment->GetType() == aType
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mSegment->GetType() == aType", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2229); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSegment->GetType() == aType"
")"); do { MOZ_CrashSequence(__null, 2229); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2230}
2231
2232MediaTrack::~MediaTrack() {
2233 MOZ_COUNT_DTOR(MediaTrack)do { static_assert(std::is_class_v<MediaTrack>, "Token '"
"MediaTrack" "' is not a class type."); static_assert(!std::
is_base_of<nsISupports, MediaTrack>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "MediaTrack", sizeof
(*this)); } while (0)
;
2234 NS_ASSERTION(mMainThreadDestroyed, "Should have been destroyed already")do { if (!(mMainThreadDestroyed)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Should have been destroyed already", "mMainThreadDestroyed"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2234);
MOZ_PretendNoReturn(); } } while (0)
;
2235 NS_ASSERTION(mMainThreadListeners.IsEmpty(),do { if (!(mMainThreadListeners.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "All main thread listeners should have been removed", "mMainThreadListeners.IsEmpty()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2236);
MOZ_PretendNoReturn(); } } while (0)
2236 "All main thread listeners should have been removed")do { if (!(mMainThreadListeners.IsEmpty())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "All main thread listeners should have been removed", "mMainThreadListeners.IsEmpty()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2236);
MOZ_PretendNoReturn(); } } while (0)
;
2237}
2238
2239size_t MediaTrack::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
2240 size_t amount = 0;
2241
2242 // Not owned:
2243 // - mGraph - Not reported here
2244 // - mConsumers - elements
2245 // Future:
2246 // - mLastPlayedVideoFrame
2247 // - mTrackListeners - elements
2248
2249 amount += mTrackListeners.ShallowSizeOfExcludingThis(aMallocSizeOf);
2250 amount += mMainThreadListeners.ShallowSizeOfExcludingThis(aMallocSizeOf);
2251 amount += mConsumers.ShallowSizeOfExcludingThis(aMallocSizeOf);
2252
2253 return amount;
2254}
2255
2256size_t MediaTrack::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
2257 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
2258}
2259
2260void MediaTrack::IncrementSuspendCount() {
2261 ++mSuspendedCount;
2262 if (mSuspendedCount != 1 || !mGraph) {
2263 MOZ_ASSERT(mGraph || mConsumers.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGraph || mConsumers.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGraph || mConsumers.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGraph || mConsumers.IsEmpty()", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGraph || mConsumers.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 2263); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2264 return;
2265 }
2266 AssertOnGraphThreadOrNotRunning();
2267 auto* graph = GraphImpl();
2268 for (uint32_t i = 0; i < mConsumers.Length(); ++i) {
2269 mConsumers[i]->Suspended();
2270 }
2271 MOZ_ASSERT(graph->mTracks.Contains(this))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(graph->mTracks.Contains(this))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(graph->mTracks.Contains(this
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("graph->mTracks.Contains(this)", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2271); AnnotateMozCrashReason("MOZ_ASSERT" "(" "graph->mTracks.Contains(this)"
")"); do { MOZ_CrashSequence(__null, 2271); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2272 graph->mTracks.RemoveElement(this);
2273 graph->mSuspendedTracks.AppendElement(this);
2274 graph->SetTrackOrderDirty();
2275}
2276
2277void MediaTrack::DecrementSuspendCount() {
2278 MOZ_ASSERT(mSuspendedCount > 0, "Suspend count underrun")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSuspendedCount > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSuspendedCount > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mSuspendedCount > 0"
" (" "Suspend count underrun" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2278); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSuspendedCount > 0"
") (" "Suspend count underrun" ")"); do { MOZ_CrashSequence(
__null, 2278); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
2279 --mSuspendedCount;
2280 if (mSuspendedCount != 0 || !mGraph) {
2281 MOZ_ASSERT(mGraph || mConsumers.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGraph || mConsumers.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGraph || mConsumers.IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mGraph || mConsumers.IsEmpty()", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGraph || mConsumers.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 2281); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2282 return;
2283 }
2284 AssertOnGraphThreadOrNotRunning();
2285 auto* graph = GraphImpl();
2286 for (uint32_t i = 0; i < mConsumers.Length(); ++i) {
2287 mConsumers[i]->Resumed();
2288 }
2289 MOZ_ASSERT(graph->mSuspendedTracks.Contains(this))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(graph->mSuspendedTracks.Contains(this))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(graph->mSuspendedTracks.Contains(this)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("graph->mSuspendedTracks.Contains(this)"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2289);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "graph->mSuspendedTracks.Contains(this)"
")"); do { MOZ_CrashSequence(__null, 2289); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2290 graph->mSuspendedTracks.RemoveElement(this);
2291 graph->mTracks.AppendElement(this);
2292 graph->SetTrackOrderDirty();
2293}
2294
2295void ProcessedMediaTrack::DecrementSuspendCount() {
2296 mCycleMarker = NOT_VISITED;
2297 MediaTrack::DecrementSuspendCount();
2298}
2299
2300MediaTrackGraphImpl* MediaTrack::GraphImpl() {
2301 return static_cast<MediaTrackGraphImpl*>(mGraph);
2302}
2303
2304const MediaTrackGraphImpl* MediaTrack::GraphImpl() const {
2305 return static_cast<MediaTrackGraphImpl*>(mGraph);
2306}
2307
2308void MediaTrack::SetGraphImpl(MediaTrackGraphImpl* aGraph) {
2309 MOZ_ASSERT(!mGraph, "Should only be called once")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGraph)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mGraph))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mGraph" " (" "Should only be called once"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2309
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGraph" ") (" "Should only be called once"
")"); do { MOZ_CrashSequence(__null, 2309); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2310 MOZ_ASSERT(mSampleRate == aGraph->GraphRate())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSampleRate == aGraph->GraphRate())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(mSampleRate == aGraph->GraphRate()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mSampleRate == aGraph->GraphRate()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2310);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSampleRate == aGraph->GraphRate()"
")"); do { MOZ_CrashSequence(__null, 2310); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2311 mGraph = aGraph;
2312}
2313
2314void MediaTrack::SetGraphImpl(MediaTrackGraph* aGraph) {
2315 MediaTrackGraphImpl* graph = static_cast<MediaTrackGraphImpl*>(aGraph);
2316 SetGraphImpl(graph);
2317}
2318
2319TrackTime MediaTrack::GraphTimeToTrackTime(GraphTime aTime) const {
2320 NS_ASSERTION(mStartBlocking == GraphImpl()->mStateComputedTime ||do { if (!(mStartBlocking == GraphImpl()->mStateComputedTime
|| aTime <= mStartBlocking)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Incorrectly ignoring blocking!", "mStartBlocking == GraphImpl()->mStateComputedTime || aTime <= mStartBlocking"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2322);
MOZ_PretendNoReturn(); } } while (0)
2321 aTime <= mStartBlocking,do { if (!(mStartBlocking == GraphImpl()->mStateComputedTime
|| aTime <= mStartBlocking)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Incorrectly ignoring blocking!", "mStartBlocking == GraphImpl()->mStateComputedTime || aTime <= mStartBlocking"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2322);
MOZ_PretendNoReturn(); } } while (0)
2322 "Incorrectly ignoring blocking!")do { if (!(mStartBlocking == GraphImpl()->mStateComputedTime
|| aTime <= mStartBlocking)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Incorrectly ignoring blocking!", "mStartBlocking == GraphImpl()->mStateComputedTime || aTime <= mStartBlocking"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2322);
MOZ_PretendNoReturn(); } } while (0)
;
2323 return aTime - mStartTime;
2324}
2325
2326GraphTime MediaTrack::TrackTimeToGraphTime(TrackTime aTime) const {
2327 NS_ASSERTION(mStartBlocking == GraphImpl()->mStateComputedTime ||do { if (!(mStartBlocking == GraphImpl()->mStateComputedTime
|| aTime + mStartTime <= mStartBlocking)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Incorrectly ignoring blocking!", "mStartBlocking == GraphImpl()->mStateComputedTime || aTime + mStartTime <= mStartBlocking"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2329);
MOZ_PretendNoReturn(); } } while (0)
2328 aTime + mStartTime <= mStartBlocking,do { if (!(mStartBlocking == GraphImpl()->mStateComputedTime
|| aTime + mStartTime <= mStartBlocking)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Incorrectly ignoring blocking!", "mStartBlocking == GraphImpl()->mStateComputedTime || aTime + mStartTime <= mStartBlocking"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2329);
MOZ_PretendNoReturn(); } } while (0)
2329 "Incorrectly ignoring blocking!")do { if (!(mStartBlocking == GraphImpl()->mStateComputedTime
|| aTime + mStartTime <= mStartBlocking)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Incorrectly ignoring blocking!", "mStartBlocking == GraphImpl()->mStateComputedTime || aTime + mStartTime <= mStartBlocking"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2329);
MOZ_PretendNoReturn(); } } while (0)
;
2330 return aTime + mStartTime;
2331}
2332
2333TrackTime MediaTrack::GraphTimeToTrackTimeWithBlocking(GraphTime aTime) const {
2334 return GraphImpl()->GraphTimeToTrackTimeWithBlocking(this, aTime);
2335}
2336
2337void MediaTrack::RemoveAllResourcesAndListenersImpl() {
2338 GraphImpl()->AssertOnGraphThreadOrNotRunning();
2339
2340 for (auto& l : mTrackListeners.Clone()) {
2341 l->NotifyRemoved(Graph());
2342 }
2343 mTrackListeners.Clear();
2344
2345 RemoveAllDirectListenersImpl();
2346
2347 if (mSegment) {
2348 mSegment->Clear();
2349 }
2350}
2351
2352void MediaTrack::DestroyImpl() {
2353 for (int32_t i = mConsumers.Length() - 1; i >= 0; --i) {
2354 mConsumers[i]->Disconnect();
2355 }
2356 if (mSegment) {
2357 mSegment->Clear();
2358 }
2359 mGraph = nullptr;
2360}
2361
2362void MediaTrack::Destroy() {
2363 // Keep this track alive until we leave this method
2364 RefPtr<MediaTrack> kungFuDeathGrip = this;
2365 // Keep a reference to the graph, since Message might RunDuringShutdown()
2366 // synchronously and make GraphImpl() invalid.
2367 RefPtr<MediaTrackGraphImpl> graph = GraphImpl();
2368
2369 QueueControlOrShutdownMessage(
2370 [self = RefPtr{this}, this](IsInShutdown aInShutdown) {
2371 if (aInShutdown == IsInShutdown::No) {
2372 OnGraphThreadDone();
2373 }
2374 TRACE("MediaTrack::Destroy ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::Destroy ControlMessage"
);
;
2375 RemoveAllResourcesAndListenersImpl();
2376 auto* graph = GraphImpl();
2377 DestroyImpl();
2378 graph->RemoveTrackGraphThread(this);
2379 });
2380 graph->RemoveTrack(this);
2381 // Message::RunDuringShutdown may have removed this track from the graph,
2382 // but our kungFuDeathGrip above will have kept this track alive if
2383 // necessary.
2384 mMainThreadDestroyed = true;
2385}
2386
2387uint64_t MediaTrack::GetWindowId() const { return GraphImpl()->mWindowID; }
2388
2389TrackTime MediaTrack::GetEnd() const {
2390 return mSegment ? mSegment->GetDuration() : 0;
2391}
2392
2393void MediaTrack::AddAudioOutput(void* aKey, const AudioDeviceInfo* aSink) {
2394 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2394);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2394); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2395 AudioDeviceID deviceID = nullptr;
2396 TrackRate preferredSampleRate = 0;
2397 if (aSink) {
2398 deviceID = aSink->DeviceID();
2399 preferredSampleRate = static_cast<TrackRate>(aSink->DefaultRate());
2400 }
2401 AddAudioOutput(aKey, deviceID, preferredSampleRate);
2402}
2403
2404void MediaTrack::AddAudioOutput(void* aKey, CubebUtils::AudioDeviceID aDeviceID,
2405 TrackRate aPreferredSampleRate) {
2406 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2406);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2406); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2407 if (mMainThreadDestroyed) {
2408 return;
2409 }
2410 LOG(LogLevel::Info, ("MediaTrack %p adding AudioOutput", this));
2411 GraphImpl()->RegisterAudioOutput(this, aKey, aDeviceID, aPreferredSampleRate);
2412}
2413
2414void MediaTrackGraphImpl::SetAudioOutputVolume(MediaTrack* aTrack, void* aKey,
2415 float aVolume) {
2416 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2416);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2416); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2417 for (auto& params : mAudioOutputParams) {
2418 if (params.mKey == aKey && aTrack == params.mTrack) {
2419 params.mVolume = aVolume;
2420 UpdateAudioOutput(aTrack, params.mDeviceID);
2421 return;
2422 }
2423 }
2424 MOZ_CRASH("Audio output key not found when setting the volume.")do { do { } while (false); MOZ_ReportCrash("" "Audio output key not found when setting the volume."
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2424);
AnnotateMozCrashReason("MOZ_CRASH(" "Audio output key not found when setting the volume."
")"); do { MOZ_CrashSequence(__null, 2424); __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2425}
2426
2427void MediaTrack::SetAudioOutputVolume(void* aKey, float aVolume) {
2428 if (mMainThreadDestroyed) {
2429 return;
2430 }
2431 GraphImpl()->SetAudioOutputVolume(this, aKey, aVolume);
2432}
2433
2434void MediaTrack::RemoveAudioOutput(void* aKey) {
2435 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2435);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2435); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2436 if (mMainThreadDestroyed) {
2437 return;
2438 }
2439 LOG(LogLevel::Info, ("MediaTrack %p removing AudioOutput", this));
2440 GraphImpl()->UnregisterAudioOutput(this, aKey);
2441}
2442
2443void MediaTrackGraphImpl::RegisterAudioOutput(
2444 MediaTrack* aTrack, void* aKey, CubebUtils::AudioDeviceID aDeviceID,
2445 TrackRate aPreferredSampleRate) {
2446 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2446);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2446); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2447 MOZ_ASSERT(!mAudioOutputParams.Contains(TrackAndKey{aTrack, aKey}))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mAudioOutputParams.Contains(TrackAndKey{aTrack, aKey
}))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mAudioOutputParams.Contains(TrackAndKey{aTrack, aKey
})))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mAudioOutputParams.Contains(TrackAndKey{aTrack, aKey})", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2447); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mAudioOutputParams.Contains(TrackAndKey{aTrack, aKey})"
")"); do { MOZ_CrashSequence(__null, 2447); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2448
2449 IncrementOutputDeviceRefCnt(aDeviceID, aPreferredSampleRate);
2450
2451 mAudioOutputParams.EmplaceBack(
2452 TrackKeyDeviceAndVolume{aTrack, aKey, aDeviceID, 1.f});
2453
2454 UpdateAudioOutput(aTrack, aDeviceID);
2455}
2456
2457void MediaTrackGraphImpl::UnregisterAudioOutput(MediaTrack* aTrack,
2458 void* aKey) {
2459 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2459);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2459); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2460
2461 size_t index = mAudioOutputParams.IndexOf(TrackAndKey{aTrack, aKey});
2462 MOZ_ASSERT(index != mAudioOutputParams.NoIndex)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(index != mAudioOutputParams.NoIndex)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(index != mAudioOutputParams.
NoIndex))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("index != mAudioOutputParams.NoIndex", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2462); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index != mAudioOutputParams.NoIndex"
")"); do { MOZ_CrashSequence(__null, 2462); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2463 AudioDeviceID deviceID = mAudioOutputParams[index].mDeviceID;
2464 mAudioOutputParams.UnorderedRemoveElementAt(index);
2465
2466 UpdateAudioOutput(aTrack, deviceID);
2467
2468 DecrementOutputDeviceRefCnt(deviceID);
2469}
2470
2471void MediaTrackGraphImpl::UpdateAudioOutput(MediaTrack* aTrack,
2472 AudioDeviceID aDeviceID) {
2473 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2473);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2473); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2474 MOZ_ASSERT(!aTrack->IsDestroyed())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aTrack->IsDestroyed())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aTrack->IsDestroyed())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aTrack->IsDestroyed()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2474);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aTrack->IsDestroyed()"
")"); do { MOZ_CrashSequence(__null, 2474); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2475
2476 float volume = 0.f;
2477 bool found = false;
2478 for (const auto& params : mAudioOutputParams) {
2479 if (params.mTrack == aTrack && params.mDeviceID == aDeviceID) {
2480 volume += params.mVolume;
2481 found = true;
2482 }
2483 }
2484
2485 QueueControlMessageWithNoShutdown(
2486 // track has a strong reference to this.
2487 [track = RefPtr{aTrack}, aDeviceID, volume, found] {
2488 TRACE("MediaTrack::UpdateAudioOutput ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::UpdateAudioOutput ControlMessage"
);
;
2489 MediaTrackGraphImpl* graph = track->GraphImpl();
2490 auto& outputDevicesRef = graph->mOutputDevices;
2491 size_t deviceIndex = outputDevicesRef.IndexOf(aDeviceID);
2492 MOZ_ASSERT(deviceIndex != outputDevicesRef.NoIndex)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(deviceIndex != outputDevicesRef.NoIndex)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(deviceIndex != outputDevicesRef.NoIndex))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("deviceIndex != outputDevicesRef.NoIndex"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2492);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "deviceIndex != outputDevicesRef.NoIndex"
")"); do { MOZ_CrashSequence(__null, 2492); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2493 auto& deviceOutputsRef = outputDevicesRef[deviceIndex].mTrackOutputs;
2494 if (found) {
2495 for (auto& outputRef : deviceOutputsRef) {
2496 if (outputRef.mTrack == track) {
2497 outputRef.mVolume = volume;
2498 return;
2499 }
2500 }
2501 deviceOutputsRef.EmplaceBack(TrackAndVolume{track, volume});
2502 } else {
2503 DebugOnly<bool> removed = deviceOutputsRef.RemoveElement(track);
2504 MOZ_ASSERT(removed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(removed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(removed))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("removed", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "removed" ")"
); do { MOZ_CrashSequence(__null, 2504); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2505 // mOutputDevices[0] is retained for AudioCallbackDriver output even
2506 // when no tracks have audio outputs.
2507 if (deviceIndex != 0 && deviceOutputsRef.IsEmpty()) {
2508 // The device is no longer in use.
2509 outputDevicesRef.UnorderedRemoveElementAt(deviceIndex);
2510 }
2511 }
2512 });
2513}
2514
2515void MediaTrackGraphImpl::IncrementOutputDeviceRefCnt(
2516 AudioDeviceID aDeviceID, TrackRate aPreferredSampleRate) {
2517 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2517);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2517); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2518
2519 for (auto& elementRef : mOutputDeviceRefCnts) {
2520 if (elementRef.mDeviceID == aDeviceID) {
2521 ++elementRef.mRefCnt;
2522 return;
2523 }
2524 }
2525 MOZ_ASSERT(aDeviceID != mPrimaryOutputDeviceID,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDeviceID != mPrimaryOutputDeviceID)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDeviceID != mPrimaryOutputDeviceID
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aDeviceID != mPrimaryOutputDeviceID" " (" "mOutputDeviceRefCnts should always have the primary device"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2526
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDeviceID != mPrimaryOutputDeviceID"
") (" "mOutputDeviceRefCnts should always have the primary device"
")"); do { MOZ_CrashSequence(__null, 2526); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2526 "mOutputDeviceRefCnts should always have the primary device")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDeviceID != mPrimaryOutputDeviceID)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDeviceID != mPrimaryOutputDeviceID
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aDeviceID != mPrimaryOutputDeviceID" " (" "mOutputDeviceRefCnts should always have the primary device"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2526
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDeviceID != mPrimaryOutputDeviceID"
") (" "mOutputDeviceRefCnts should always have the primary device"
")"); do { MOZ_CrashSequence(__null, 2526); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2527 // Need to add an output device.
2528 // Output via another graph for this device.
2529 // This sample rate is not exposed to content.
2530 TrackRate sampleRate =
2531 aPreferredSampleRate != 0
2532 ? aPreferredSampleRate
2533 : static_cast<TrackRate>(CubebUtils::PreferredSampleRate(
2534 /*aShouldResistFingerprinting*/ false));
2535 MediaTrackGraph* newGraph = MediaTrackGraphImpl::GetInstance(
2536 MediaTrackGraph::AUDIO_THREAD_DRIVER, mWindowID, sampleRate, aDeviceID,
2537 GetMainThreadSerialEventTarget());
2538 // CreateCrossGraphReceiver wants the sample rate of this graph.
2539 RefPtr receiver = newGraph->CreateCrossGraphReceiver(mSampleRate);
2540 receiver->AddAudioOutput(nullptr, aDeviceID, sampleRate);
2541 mOutputDeviceRefCnts.EmplaceBack(
2542 DeviceReceiverAndCount{aDeviceID, receiver, 1});
2543
2544 QueueControlMessageWithNoShutdown([self = RefPtr{this}, this, aDeviceID,
2545 receiver = std::move(receiver)]() mutable {
2546 TRACE("MediaTrackGraph add output device ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrackGraph add output device ControlMessage"
);
;
2547 MOZ_ASSERT(!mOutputDevices.Contains(aDeviceID))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOutputDevices.Contains(aDeviceID))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOutputDevices.Contains(aDeviceID
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mOutputDevices.Contains(aDeviceID)", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2547); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mOutputDevices.Contains(aDeviceID)"
")"); do { MOZ_CrashSequence(__null, 2547); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2548 mOutputDevices.EmplaceBack(
2549 OutputDeviceEntry{aDeviceID, std::move(receiver)});
2550 });
2551}
2552
2553void MediaTrackGraphImpl::DecrementOutputDeviceRefCnt(AudioDeviceID aDeviceID) {
2554 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2554);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2554); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2555
2556 size_t index = mOutputDeviceRefCnts.IndexOf(aDeviceID);
2557 MOZ_ASSERT(index != mOutputDeviceRefCnts.NoIndex)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(index != mOutputDeviceRefCnts.NoIndex)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(index != mOutputDeviceRefCnts.NoIndex))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("index != mOutputDeviceRefCnts.NoIndex"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2557);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "index != mOutputDeviceRefCnts.NoIndex"
")"); do { MOZ_CrashSequence(__null, 2557); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2558 // mOutputDeviceRefCnts[0] is retained for consistency with
2559 // mOutputDevices[0], which is retained for AudioCallbackDriver output even
2560 // when no tracks have audio outputs.
2561 if (--mOutputDeviceRefCnts[index].mRefCnt == 0 && index != 0) {
2562 mOutputDeviceRefCnts[index].mReceiver->Destroy();
2563 mOutputDeviceRefCnts.UnorderedRemoveElementAt(index);
2564 }
2565}
2566
2567void MediaTrack::Suspend() {
2568 // This can happen if this method has been called asynchronously, and the
2569 // track has been destroyed since then.
2570 if (mMainThreadDestroyed) {
2571 return;
2572 }
2573 QueueControlMessageWithNoShutdown([self = RefPtr{this}, this] {
2574 TRACE("MediaTrack::IncrementSuspendCount ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::IncrementSuspendCount ControlMessage"
);
;
2575 IncrementSuspendCount();
2576 });
2577}
2578
2579void MediaTrack::Resume() {
2580 // This can happen if this method has been called asynchronously, and the
2581 // track has been destroyed since then.
2582 if (mMainThreadDestroyed) {
2583 return;
2584 }
2585 QueueControlMessageWithNoShutdown([self = RefPtr{this}, this] {
2586 TRACE("MediaTrack::DecrementSuspendCount ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::DecrementSuspendCount ControlMessage"
);
;
2587 DecrementSuspendCount();
2588 });
2589}
2590
2591void MediaTrack::AddListenerImpl(
2592 already_AddRefed<MediaTrackListener> aListener) {
2593 RefPtr<MediaTrackListener> l(aListener);
2594 mTrackListeners.AppendElement(std::move(l));
2595
2596 PrincipalHandle lastPrincipalHandle = mSegment->GetLastPrincipalHandle();
2597 mTrackListeners.LastElement()->NotifyPrincipalHandleChanged(
2598 Graph(), lastPrincipalHandle);
2599 if (mNotifiedEnded) {
2600 mTrackListeners.LastElement()->NotifyEnded(Graph());
2601 }
2602 if (CombinedDisabledMode() == DisabledTrackMode::SILENCE_BLACK) {
2603 mTrackListeners.LastElement()->NotifyEnabledStateChanged(Graph(), false);
2604 }
2605}
2606
2607void MediaTrack::AddListener(MediaTrackListener* aListener) {
2608 MOZ_ASSERT(mSegment, "Segment-less tracks do not support listeners")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSegment)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSegment))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mSegment" " (" "Segment-less tracks do not support listeners"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2608
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSegment" ") (" "Segment-less tracks do not support listeners"
")"); do { MOZ_CrashSequence(__null, 2608); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2609 if (mMainThreadDestroyed) {
2610 return;
2611 }
2612 QueueControlMessageWithNoShutdown(
2613 [self = RefPtr{this}, this, listener = RefPtr{aListener}]() mutable {
2614 TRACE("MediaTrack::AddListenerImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::AddListenerImpl ControlMessage"
);
;
2615 AddListenerImpl(listener.forget());
2616 });
2617}
2618
2619void MediaTrack::RemoveListenerImpl(MediaTrackListener* aListener) {
2620 for (size_t i = 0; i < mTrackListeners.Length(); ++i) {
2621 if (mTrackListeners[i] == aListener) {
2622 mTrackListeners[i]->NotifyRemoved(Graph());
2623 mTrackListeners.RemoveElementAt(i);
2624 return;
2625 }
2626 }
2627}
2628
2629RefPtr<GenericPromise> MediaTrack::RemoveListener(
2630 MediaTrackListener* aListener) {
2631 MozPromiseHolder<GenericPromise> promiseHolder;
2632 RefPtr<GenericPromise> p = promiseHolder.Ensure(__func__);
2633 if (mMainThreadDestroyed) {
2634 promiseHolder.Reject(NS_ERROR_FAILURE, __func__);
2635 return p;
2636 }
2637 QueueControlOrShutdownMessage(
2638 [self = RefPtr{this}, this, listener = RefPtr{aListener},
2639 promiseHolder = std::move(promiseHolder)](IsInShutdown) mutable {
2640 TRACE("MediaTrack::RemoveListenerImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::RemoveListenerImpl ControlMessage"
);
;
2641 // During shutdown we still want the listener's NotifyRemoved to be
2642 // called, since not doing that might block shutdown of other modules.
2643 RemoveListenerImpl(listener);
2644 promiseHolder.Resolve(true, __func__);
2645 });
2646 return p;
2647}
2648
2649void MediaTrack::AddDirectListenerImpl(
2650 already_AddRefed<DirectMediaTrackListener> aListener) {
2651 AssertOnGraphThread();
2652 // Base implementation, for tracks that don't support direct track listeners.
2653 RefPtr<DirectMediaTrackListener> listener = aListener;
2654 listener->NotifyDirectListenerInstalled(
2655 DirectMediaTrackListener::InstallationResult::TRACK_NOT_SUPPORTED);
2656}
2657
2658void MediaTrack::AddDirectListener(DirectMediaTrackListener* aListener) {
2659 if (mMainThreadDestroyed) {
2660 return;
2661 }
2662 QueueControlMessageWithNoShutdown(
2663 [self = RefPtr{this}, this, listener = RefPtr{aListener}]() mutable {
2664 TRACE("MediaTrack::AddDirectListenerImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::AddDirectListenerImpl ControlMessage"
);
;
2665 AddDirectListenerImpl(listener.forget());
2666 });
2667}
2668
2669void MediaTrack::RemoveDirectListenerImpl(DirectMediaTrackListener* aListener) {
2670 // Base implementation, the listener was never added so nothing to do.
2671}
2672
2673void MediaTrack::RemoveDirectListener(DirectMediaTrackListener* aListener) {
2674 if (mMainThreadDestroyed) {
2675 return;
2676 }
2677 QueueControlOrShutdownMessage(
2678 [self = RefPtr{this}, this, listener = RefPtr{aListener}](IsInShutdown) {
2679 TRACE("MediaTrack::RemoveDirectListenerImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::RemoveDirectListenerImpl ControlMessage"
);
;
2680 // During shutdown we still want the listener's
2681 // NotifyDirectListenerUninstalled to be called, since not doing that
2682 // might block shutdown of other modules.
2683 RemoveDirectListenerImpl(listener);
2684 });
2685}
2686
2687void MediaTrack::RunAfterPendingUpdates(
2688 already_AddRefed<nsIRunnable> aRunnable) {
2689 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2689);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2689); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2690 if (mMainThreadDestroyed) {
2691 return;
2692 }
2693 QueueControlOrShutdownMessage(
2694 [self = RefPtr{this}, this,
2695 runnable = nsCOMPtr{aRunnable}](IsInShutdown aInShutdown) mutable {
2696 TRACE("MediaTrack::DispatchToMainThreadStableState ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::DispatchToMainThreadStableState ControlMessage"
);
;
2697 if (aInShutdown == IsInShutdown::No) {
2698 Graph()->DispatchToMainThreadStableState(runnable.forget());
2699 } else {
2700 // Don't run mRunnable now as it may call AppendMessage() which would
2701 // assume that there are no remaining
2702 // controlMessagesToRunDuringShutdown.
2703 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2703);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2703); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2704 GraphImpl()->Dispatch(runnable.forget());
2705 }
2706 });
2707}
2708
2709void MediaTrack::SetDisabledTrackModeImpl(DisabledTrackMode aMode) {
2710 AssertOnGraphThread();
2711 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMode == DisabledTrackMode::ENABLED || mDisabledMode
== DisabledTrackMode::ENABLED)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMode == DisabledTrackMode::
ENABLED || mDisabledMode == DisabledTrackMode::ENABLED))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
" (" "Changing disabled track mode for a track is not allowed"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2714
); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
") (" "Changing disabled track mode for a track is not allowed"
")"); do { MOZ_CrashSequence(__null, 2714); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2712 aMode == DisabledTrackMode::ENABLED ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMode == DisabledTrackMode::ENABLED || mDisabledMode
== DisabledTrackMode::ENABLED)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMode == DisabledTrackMode::
ENABLED || mDisabledMode == DisabledTrackMode::ENABLED))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
" (" "Changing disabled track mode for a track is not allowed"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2714
); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
") (" "Changing disabled track mode for a track is not allowed"
")"); do { MOZ_CrashSequence(__null, 2714); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2713 mDisabledMode == DisabledTrackMode::ENABLED,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMode == DisabledTrackMode::ENABLED || mDisabledMode
== DisabledTrackMode::ENABLED)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMode == DisabledTrackMode::
ENABLED || mDisabledMode == DisabledTrackMode::ENABLED))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
" (" "Changing disabled track mode for a track is not allowed"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2714
); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
") (" "Changing disabled track mode for a track is not allowed"
")"); do { MOZ_CrashSequence(__null, 2714); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2714 "Changing disabled track mode for a track is not allowed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMode == DisabledTrackMode::ENABLED || mDisabledMode
== DisabledTrackMode::ENABLED)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMode == DisabledTrackMode::
ENABLED || mDisabledMode == DisabledTrackMode::ENABLED))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
" (" "Changing disabled track mode for a track is not allowed"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2714
); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aMode == DisabledTrackMode::ENABLED || mDisabledMode == DisabledTrackMode::ENABLED"
") (" "Changing disabled track mode for a track is not allowed"
")"); do { MOZ_CrashSequence(__null, 2714); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2715 DisabledTrackMode oldMode = CombinedDisabledMode();
2716 mDisabledMode = aMode;
2717 NotifyIfDisabledModeChangedFrom(oldMode);
2718}
2719
2720void MediaTrack::SetDisabledTrackMode(DisabledTrackMode aMode) {
2721 if (mMainThreadDestroyed) {
2722 return;
2723 }
2724 QueueControlMessageWithNoShutdown([self = RefPtr{this}, this, aMode]() {
2725 TRACE("MediaTrack::SetDisabledTrackModeImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::SetDisabledTrackModeImpl ControlMessage"
);
;
2726 SetDisabledTrackModeImpl(aMode);
2727 });
2728}
2729
2730void MediaTrack::ApplyTrackDisabling(MediaSegment* aSegment,
2731 MediaSegment* aRawSegment) {
2732 AssertOnGraphThread();
2733 mozilla::ApplyTrackDisabling(mDisabledMode, aSegment, aRawSegment);
2734}
2735
2736void MediaTrack::AddMainThreadListener(
2737 MainThreadMediaTrackListener* aListener) {
2738 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2738);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2738); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2739 MOZ_ASSERT(aListener)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aListener)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aListener))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aListener", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2739); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aListener" ")"
); do { MOZ_CrashSequence(__null, 2739); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2740 MOZ_ASSERT(!mMainThreadListeners.Contains(aListener))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mMainThreadListeners.Contains(aListener))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mMainThreadListeners.Contains(aListener)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mMainThreadListeners.Contains(aListener)"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2740);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mMainThreadListeners.Contains(aListener)"
")"); do { MOZ_CrashSequence(__null, 2740); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2741
2742 mMainThreadListeners.AppendElement(aListener);
2743
2744 // If it is not yet time to send the notification, then exit here.
2745 if (!mEndedNotificationSent) {
2746 return;
2747 }
2748
2749 class NotifyRunnable final : public Runnable {
2750 public:
2751 explicit NotifyRunnable(MediaTrack* aTrack)
2752 : Runnable("MediaTrack::NotifyRunnable"), mTrack(aTrack) {}
2753
2754 NS_IMETHODvirtual nsresult Run() override {
2755 TRACE("MediaTrack::NotifyMainThreadListeners Runnable")AutoTracer trace(gAudioCallbackTraceLogger, "MediaTrack::NotifyMainThreadListeners Runnable"
);
;
2756 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2756);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 2756); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2757 mTrack->NotifyMainThreadListeners();
2758 return NS_OK;
2759 }
2760
2761 private:
2762 ~NotifyRunnable() = default;
2763
2764 RefPtr<MediaTrack> mTrack;
2765 };
2766
2767 nsCOMPtr<nsIRunnable> runnable = new NotifyRunnable(this);
2768 GraphImpl()->Dispatch(runnable.forget());
2769}
2770
2771void MediaTrack::AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime,
2772 GraphTime aBlockedTime) {
2773 mStartTime += aBlockedTime;
2774
2775 if (!mSegment) {
2776 // No data to be forgotten.
2777 return;
2778 }
2779
2780 TrackTime time = aCurrentTime - mStartTime;
2781 // Only prune if there is a reasonable chunk (50ms) to forget, so we don't
2782 // spend too much time pruning segments.
2783 const TrackTime minChunkSize = mSampleRate * 50 / 1000;
2784 if (time < mForgottenTime + minChunkSize) {
2785 return;
2786 }
2787
2788 mForgottenTime = std::min(GetEnd() - 1, time);
2789 mSegment->ForgetUpTo(mForgottenTime);
2790}
2791
2792void MediaTrack::NotifyIfDisabledModeChangedFrom(DisabledTrackMode aOldMode) {
2793 DisabledTrackMode mode = CombinedDisabledMode();
2794 if (aOldMode == mode) {
2795 return;
2796 }
2797
2798 for (const auto& listener : mTrackListeners) {
2799 listener->NotifyEnabledStateChanged(
2800 Graph(), mode != DisabledTrackMode::SILENCE_BLACK);
2801 }
2802
2803 for (const auto& c : mConsumers) {
2804 if (c->GetDestination()) {
2805 c->GetDestination()->OnInputDisabledModeChanged(mode);
2806 }
2807 }
2808}
2809
2810void MediaTrack::QueueMessage(UniquePtr<ControlMessageInterface> aMessage) {
2811 MOZ_ASSERT(NS_IsMainThread(), "Main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2811); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Main thread only" ")"); do { MOZ_CrashSequence(__null
, 2811); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2812 MOZ_RELEASE_ASSERT(!IsDestroyed())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsDestroyed())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsDestroyed()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!IsDestroyed()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2812);
AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!IsDestroyed()"
")"); do { MOZ_CrashSequence(__null, 2812); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2813 GraphImpl()->AppendMessage(std::move(aMessage));
2814}
2815
2816void MediaTrack::RunMessageAfterProcessing(
2817 UniquePtr<ControlMessageInterface> aMessage) {
2818 AssertOnGraphThread();
2819 GraphImpl()->RunMessageAfterProcessing(std::move(aMessage));
2820}
2821
2822SourceMediaTrack::SourceMediaTrack(MediaSegment::Type aType,
2823 TrackRate aSampleRate)
2824 : MediaTrack(aSampleRate, aType,
2825 aType == MediaSegment::AUDIO
2826 ? static_cast<MediaSegment*>(new AudioSegment())
2827 : static_cast<MediaSegment*>(new VideoSegment())),
2828 mMutex("mozilla::media::SourceMediaTrack") {
2829 mUpdateTrack = MakeUnique<TrackData>();
2830 mUpdateTrack->mInputRate = aSampleRate;
2831 mUpdateTrack->mResamplerChannelCount = 0;
2832 mUpdateTrack->mData = UniquePtr<MediaSegment>(mSegment->CreateEmptyClone());
2833 mUpdateTrack->mEnded = false;
2834 mUpdateTrack->mPullingEnabled = false;
2835 mUpdateTrack->mGraphThreadDone = false;
2836}
2837
2838void SourceMediaTrack::DestroyImpl() {
2839 GraphImpl()->AssertOnGraphThreadOrNotRunning();
2840 for (int32_t i = mConsumers.Length() - 1; i >= 0; --i) {
2841 // Disconnect before we come under mMutex's lock since it can call back
2842 // through RemoveDirectListenerImpl() and deadlock.
2843 mConsumers[i]->Disconnect();
2844 }
2845
2846 // Hold mMutex while mGraph is reset so that other threads holding mMutex
2847 // can null-check know that the graph will not destroyed.
2848 MutexAutoLock lock(mMutex);
2849 mUpdateTrack = nullptr;
2850 MediaTrack::DestroyImpl();
2851}
2852
2853void SourceMediaTrack::SetPullingEnabled(bool aEnabled) {
2854 class Message : public ControlMessage {
2855 public:
2856 Message(SourceMediaTrack* aTrack, bool aEnabled)
2857 : ControlMessage(nullptr), mTrack(aTrack), mEnabled(aEnabled) {}
2858 void Run() override {
2859 TRACE("SourceMediaTrack::SetPullingEnabled ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "SourceMediaTrack::SetPullingEnabled ControlMessage"
);
;
2860 MutexAutoLock lock(mTrack->mMutex);
2861 if (!mTrack->mUpdateTrack) {
2862 // We can't enable pulling for a track that has ended. We ignore
2863 // this if we're disabling pulling, since shutdown sequences are
2864 // complex. If there's truly an issue we'll have issues enabling anyway.
2865 MOZ_ASSERT_IF(mEnabled, mTrack->mEnded)do { if (mEnabled) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(mTrack->mEnded)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTrack->mEnded))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mTrack->mEnded"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2865);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTrack->mEnded" ")"
); do { MOZ_CrashSequence(__null, 2865); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2866 return;
2867 }
2868 MOZ_ASSERT(mTrack->mType == MediaSegment::AUDIO,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTrack->mType == MediaSegment::AUDIO)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mTrack->mType == MediaSegment::AUDIO))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTrack->mType == MediaSegment::AUDIO"
" (" "Pulling is not allowed for video" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2869); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTrack->mType == MediaSegment::AUDIO"
") (" "Pulling is not allowed for video" ")"); do { MOZ_CrashSequence
(__null, 2869); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
2869 "Pulling is not allowed for video")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTrack->mType == MediaSegment::AUDIO)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mTrack->mType == MediaSegment::AUDIO))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mTrack->mType == MediaSegment::AUDIO"
" (" "Pulling is not allowed for video" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2869); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTrack->mType == MediaSegment::AUDIO"
") (" "Pulling is not allowed for video" ")"); do { MOZ_CrashSequence
(__null, 2869); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2870 mTrack->mUpdateTrack->mPullingEnabled = mEnabled;
2871 }
2872 SourceMediaTrack* mTrack;
2873 bool mEnabled;
2874 };
2875 GraphImpl()->AppendMessage(MakeUnique<Message>(this, aEnabled));
2876}
2877
2878bool SourceMediaTrack::PullNewData(GraphTime aDesiredUpToTime) {
2879 TRACE_COMMENT("SourceMediaTrack::PullNewData", "%p", this)AutoTracer trace(gAudioCallbackTraceLogger, "SourceMediaTrack::PullNewData"
, AutoTracer::DurationType::ELAPSED_TIME, "%p", this);
;
2880 TrackTime t;
2881 TrackTime current;
2882 {
2883 if (mEnded) {
2884 return false;
2885 }
2886 MutexAutoLock lock(mMutex);
2887 if (mUpdateTrack->mEnded) {
2888 return false;
2889 }
2890 if (!mUpdateTrack->mPullingEnabled) {
2891 return false;
2892 }
2893 // Compute how much track time we'll need assuming we don't block
2894 // the track at all.
2895 t = GraphTimeToTrackTime(aDesiredUpToTime);
2896 current = GetEnd() + mUpdateTrack->mData->GetDuration();
2897 }
2898 if (t <= current) {
2899 return false;
2900 }
2901 LOG(LogLevel::Verbose, ("%p: Calling NotifyPull track=%p t=%f current end=%f",
2902 GraphImpl(), this, GraphImpl()->MediaTimeToSeconds(t),
2903 GraphImpl()->MediaTimeToSeconds(current)));
2904 for (auto& l : mTrackListeners) {
2905 l->NotifyPull(Graph(), current, t);
2906 }
2907 return true;
2908}
2909
2910/**
2911 * This moves chunks from aIn to aOut. For audio this is simple. For video
2912 * we carry durations over if present, or extend up to aDesiredUpToTime if not.
2913 *
2914 * We also handle "resetters" from captured media elements. This type of source
2915 * pushes future frames into the track, and should it need to remove some, e.g.,
2916 * because of a seek or pause, it tells us by letting time go backwards. Without
2917 * this, tracks would be live for too long after a seek or pause.
2918 */
2919static void MoveToSegment(SourceMediaTrack* aTrack, MediaSegment* aIn,
2920 MediaSegment* aOut, TrackTime aCurrentTime,
2921 TrackTime aDesiredUpToTime)
2922 MOZ_REQUIRES(aTrack->GetMutex())__attribute__((exclusive_locks_required(aTrack->GetMutex()
)))
{
2923 MOZ_ASSERT(aIn->GetType() == aOut->GetType())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIn->GetType() == aOut->GetType())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aIn->GetType() == aOut->GetType()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aIn->GetType() == aOut->GetType()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2923);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIn->GetType() == aOut->GetType()"
")"); do { MOZ_CrashSequence(__null, 2923); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2924 MOZ_ASSERT(aOut->GetDuration() >= aCurrentTime)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOut->GetDuration() >= aCurrentTime)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aOut->GetDuration() >= aCurrentTime))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aOut->GetDuration() >= aCurrentTime"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2924);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOut->GetDuration() >= aCurrentTime"
")"); do { MOZ_CrashSequence(__null, 2924); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2925 MOZ_ASSERT(aDesiredUpToTime >= aCurrentTime)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDesiredUpToTime >= aCurrentTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDesiredUpToTime >= aCurrentTime
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aDesiredUpToTime >= aCurrentTime", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDesiredUpToTime >= aCurrentTime"
")"); do { MOZ_CrashSequence(__null, 2925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2926 if (aIn->GetType() == MediaSegment::AUDIO) {
2927 AudioSegment* in = static_cast<AudioSegment*>(aIn);
2928 AudioSegment* out = static_cast<AudioSegment*>(aOut);
2929 TrackTime desiredDurationToMove = aDesiredUpToTime - aCurrentTime;
2930 TrackTime end = std::min(in->GetDuration(), desiredDurationToMove);
2931
2932 out->AppendSlice(*in, 0, end);
2933 in->RemoveLeading(end);
2934
2935 aTrack->GetMutex().AssertCurrentThreadOwns();
2936 out->ApplyVolume(aTrack->GetVolumeLocked());
2937 } else {
2938 VideoSegment* in = static_cast<VideoSegment*>(aIn);
2939 VideoSegment* out = static_cast<VideoSegment*>(aOut);
2940 for (VideoSegment::ConstChunkIterator c(*in); !c.IsEnded(); c.Next()) {
2941 MOZ_ASSERT(!c->mTimeStamp.IsNull())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!c->mTimeStamp.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!c->mTimeStamp.IsNull()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!c->mTimeStamp.IsNull()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 2941);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!c->mTimeStamp.IsNull()"
")"); do { MOZ_CrashSequence(__null, 2941); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2942 VideoChunk* last = out->GetLastChunk();
2943 if (!last || last->mTimeStamp.IsNull()) {
2944 // This is the first frame, or the last frame pushed to `out` has been
2945 // all consumed. Just append and we deal with its duration later.
2946 out->AppendFrame(*c);
2947 if (c->GetDuration() > 0) {
2948 out->ExtendLastFrameBy(c->GetDuration());
2949 }
2950 continue;
2951 }
2952
2953 // We now know when this frame starts, aka when the last frame ends.
2954
2955 if (c->mTimeStamp < last->mTimeStamp) {
2956 // Time is going backwards. This is a resetting frame from
2957 // DecodedStream. Clear everything up to currentTime.
2958 out->Clear();
2959 out->AppendNullData(aCurrentTime);
2960 }
2961
2962 // Append the current frame (will have duration 0).
2963 out->AppendFrame(*c);
2964 if (c->GetDuration() > 0) {
2965 out->ExtendLastFrameBy(c->GetDuration());
2966 }
2967 }
2968 if (out->GetDuration() < aDesiredUpToTime) {
2969 out->ExtendLastFrameBy(aDesiredUpToTime - out->GetDuration());
2970 }
2971 in->Clear();
2972 MOZ_ASSERT(aIn->GetDuration() == 0, "aIn must be consumed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aIn->GetDuration() == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aIn->GetDuration() == 0))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aIn->GetDuration() == 0"
" (" "aIn must be consumed" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2972); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIn->GetDuration() == 0"
") (" "aIn must be consumed" ")"); do { MOZ_CrashSequence(__null
, 2972); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2973 }
2974}
2975
2976void SourceMediaTrack::ExtractPendingInput(GraphTime aCurrentTime,
2977 GraphTime aDesiredUpToTime) {
2978 MutexAutoLock lock(mMutex);
2979
2980 if (!mUpdateTrack) {
2981 MOZ_ASSERT(mEnded)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mEnded)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(mEnded))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mEnded", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 2981); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mEnded" ")"
); do { MOZ_CrashSequence(__null, 2981); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2982 return;
2983 }
2984
2985 TrackTime trackCurrentTime = GraphTimeToTrackTime(aCurrentTime);
2986
2987 ApplyTrackDisabling(mUpdateTrack->mData.get());
2988
2989 if (!mUpdateTrack->mData->IsEmpty()) {
2990 for (const auto& l : mTrackListeners) {
2991 l->NotifyQueuedChanges(GraphImpl(), GetEnd(), *mUpdateTrack->mData);
2992 }
2993 }
2994 TrackTime trackDesiredUpToTime = GraphTimeToTrackTime(aDesiredUpToTime);
2995 TrackTime endTime = trackDesiredUpToTime;
2996 if (mUpdateTrack->mEnded) {
2997 endTime = std::min(trackDesiredUpToTime,
2998 GetEnd() + mUpdateTrack->mData->GetDuration());
2999 }
3000 LOG(LogLevel::Verbose,
3001 ("%p: SourceMediaTrack %p advancing end from %" PRId64"l" "d" " to %" PRId64"l" "d",
3002 GraphImpl(), this, int64_t(trackCurrentTime), int64_t(endTime)));
3003 MoveToSegment(this, mUpdateTrack->mData.get(), mSegment.get(),
3004 trackCurrentTime, endTime);
3005 if (mUpdateTrack->mEnded && GetEnd() < trackDesiredUpToTime) {
3006 mEnded = true;
3007 mUpdateTrack = nullptr;
3008 }
3009}
3010
3011void SourceMediaTrack::ResampleAudioToGraphSampleRate(MediaSegment* aSegment) {
3012 mMutex.AssertCurrentThreadOwns();
3013 if (aSegment->GetType() != MediaSegment::AUDIO ||
3014 mUpdateTrack->mInputRate == GraphImpl()->GraphRate()) {
3015 return;
3016 }
3017 AudioSegment* segment = static_cast<AudioSegment*>(aSegment);
3018 segment->ResampleChunks(mUpdateTrack->mResampler,
3019 &mUpdateTrack->mResamplerChannelCount,
3020 mUpdateTrack->mInputRate, GraphImpl()->GraphRate());
3021}
3022
3023void SourceMediaTrack::AdvanceTimeVaryingValuesToCurrentTime(
3024 GraphTime aCurrentTime, GraphTime aBlockedTime) {
3025 MutexAutoLock lock(mMutex);
3026 MediaTrack::AdvanceTimeVaryingValuesToCurrentTime(aCurrentTime, aBlockedTime);
3027}
3028
3029void SourceMediaTrack::SetAppendDataSourceRate(TrackRate aRate) {
3030 MutexAutoLock lock(mMutex);
3031 if (!mUpdateTrack) {
3032 return;
3033 }
3034 MOZ_DIAGNOSTIC_ASSERT(mSegment->GetType() == MediaSegment::AUDIO)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSegment->GetType() == MediaSegment::AUDIO)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mSegment->GetType() == MediaSegment::AUDIO))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("mSegment->GetType() == MediaSegment::AUDIO"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3034);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mSegment->GetType() == MediaSegment::AUDIO"
")"); do { MOZ_CrashSequence(__null, 3034); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3035 // Set the new input rate and reset the resampler.
3036 mUpdateTrack->mInputRate = aRate;
3037 mUpdateTrack->mResampler.own(nullptr);
3038 mUpdateTrack->mResamplerChannelCount = 0;
3039}
3040
3041TrackTime SourceMediaTrack::AppendData(MediaSegment* aSegment,
3042 MediaSegment* aRawSegment) {
3043 MutexAutoLock lock(mMutex);
3044 MOZ_DIAGNOSTIC_ASSERT(aSegment->GetType() == mType)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSegment->GetType() == mType)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSegment->GetType() == mType
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aSegment->GetType() == mType", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3044); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aSegment->GetType() == mType"
")"); do { MOZ_CrashSequence(__null, 3044); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3045 TrackTime appended = 0;
3046 if (!mUpdateTrack || mUpdateTrack->mEnded || mUpdateTrack->mGraphThreadDone) {
3047 aSegment->Clear();
3048 return appended;
3049 }
3050
3051 // Data goes into mData, and on the next iteration of the MTG moves
3052 // into the track's segment after NotifyQueuedTrackChanges(). This adds
3053 // 0-10ms of delay before data gets to direct listeners.
3054 // Indirect listeners (via subsequent TrackUnion nodes) are synced to
3055 // playout time, and so can be delayed by buffering.
3056
3057 // Apply track disabling before notifying any consumers directly
3058 // or inserting into the graph
3059 mozilla::ApplyTrackDisabling(mDirectDisabledMode, aSegment, aRawSegment);
3060
3061 ResampleAudioToGraphSampleRate(aSegment);
3062
3063 // Must notify first, since AppendFrom() will empty out aSegment
3064 NotifyDirectConsumers(aRawSegment ? aRawSegment : aSegment);
3065 appended = aSegment->GetDuration();
3066 mUpdateTrack->mData->AppendFrom(aSegment); // note: aSegment is now dead
3067 {
3068 auto graph = GraphImpl();
3069 MonitorAutoLock lock(graph->GetMonitor());
3070 if (graph->CurrentDriver()) { // graph has not completed forced shutdown
3071 graph->EnsureNextIteration();
3072 }
3073 }
3074
3075 return appended;
3076}
3077
3078TrackTime SourceMediaTrack::ClearFutureData() {
3079 MutexAutoLock lock(mMutex);
3080 auto graph = GraphImpl();
3081 if (!mUpdateTrack || !graph) {
3082 return 0;
3083 }
3084
3085 TrackTime duration = mUpdateTrack->mData->GetDuration();
3086 mUpdateTrack->mData->Clear();
3087 return duration;
3088}
3089
3090void SourceMediaTrack::NotifyDirectConsumers(MediaSegment* aSegment) {
3091 mMutex.AssertCurrentThreadOwns();
3092
3093 for (const auto& l : mDirectTrackListeners) {
3094 TrackTime offset = 0; // FIX! need a separate TrackTime.... or the end of
3095 // the internal buffer
3096 l->NotifyRealtimeTrackDataAndApplyTrackDisabling(Graph(), offset,
3097 *aSegment);
3098 }
3099}
3100
3101void SourceMediaTrack::AddDirectListenerImpl(
3102 already_AddRefed<DirectMediaTrackListener> aListener) {
3103 AssertOnGraphThread();
3104 MutexAutoLock lock(mMutex);
3105
3106 RefPtr<DirectMediaTrackListener> listener = aListener;
3107 LOG(LogLevel::Debug,
3108 ("%p: Adding direct track listener %p to source track %p", GraphImpl(),
3109 listener.get(), this));
3110
3111 MOZ_ASSERT(mType == MediaSegment::VIDEO)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mType == MediaSegment::VIDEO)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mType == MediaSegment::VIDEO
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mType == MediaSegment::VIDEO", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mType == MediaSegment::VIDEO"
")"); do { MOZ_CrashSequence(__null, 3111); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3112 for (const auto& l : mDirectTrackListeners) {
3113 if (l == listener) {
3114 listener->NotifyDirectListenerInstalled(
3115 DirectMediaTrackListener::InstallationResult::ALREADY_EXISTS);
3116 return;
3117 }
3118 }
3119
3120 mDirectTrackListeners.AppendElement(listener);
3121
3122 LOG(LogLevel::Debug,
3123 ("%p: Added direct track listener %p", GraphImpl(), listener.get()));
3124 listener->NotifyDirectListenerInstalled(
3125 DirectMediaTrackListener::InstallationResult::SUCCESS);
3126
3127 if (mDisabledMode != DisabledTrackMode::ENABLED) {
3128 listener->IncreaseDisabled(mDisabledMode);
3129 }
3130
3131 if (mEnded) {
3132 return;
3133 }
3134
3135 // Pass buffered data to the listener
3136 VideoSegment bufferedData;
3137 size_t videoFrames = 0;
3138 VideoSegment& segment = *GetData<VideoSegment>();
3139 for (VideoSegment::ConstChunkIterator iter(segment); !iter.IsEnded();
3140 iter.Next()) {
3141 if (iter->mTimeStamp.IsNull()) {
3142 // No timestamp means this is only for the graph's internal book-keeping,
3143 // denoting a late start of the track.
3144 continue;
3145 }
3146 ++videoFrames;
3147 bufferedData.AppendFrame(*iter);
3148 }
3149
3150 VideoSegment& video = static_cast<VideoSegment&>(*mUpdateTrack->mData);
3151 for (VideoSegment::ConstChunkIterator iter(video); !iter.IsEnded();
3152 iter.Next()) {
3153 ++videoFrames;
3154 MOZ_ASSERT(!iter->mTimeStamp.IsNull())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!iter->mTimeStamp.IsNull())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!iter->mTimeStamp.IsNull(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!iter->mTimeStamp.IsNull()", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!iter->mTimeStamp.IsNull()"
")"); do { MOZ_CrashSequence(__null, 3154); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3155 bufferedData.AppendFrame(*iter);
3156 }
3157
3158 LOG(LogLevel::Info,
3159 ("%p: Notifying direct listener %p of %zu video frames and duration "
3160 "%" PRId64"l" "d",
3161 GraphImpl(), listener.get(), videoFrames, bufferedData.GetDuration()));
3162 listener->NotifyRealtimeTrackData(Graph(), 0, bufferedData);
3163}
3164
3165void SourceMediaTrack::RemoveDirectListenerImpl(
3166 DirectMediaTrackListener* aListener) {
3167 mGraph->AssertOnGraphThreadOrNotRunning();
3168 MutexAutoLock lock(mMutex);
3169 for (int32_t i = mDirectTrackListeners.Length() - 1; i >= 0; --i) {
3170 const RefPtr<DirectMediaTrackListener>& l = mDirectTrackListeners[i];
3171 if (l == aListener) {
3172 if (mDisabledMode != DisabledTrackMode::ENABLED) {
3173 aListener->DecreaseDisabled(mDisabledMode);
3174 }
3175 aListener->NotifyDirectListenerUninstalled();
3176 mDirectTrackListeners.RemoveElementAt(i);
3177 }
3178 }
3179}
3180
3181void SourceMediaTrack::End() {
3182 MutexAutoLock lock(mMutex);
3183 if (!mUpdateTrack) {
3184 // Already ended
3185 return;
3186 }
3187 mUpdateTrack->mEnded = true;
3188 if (auto graph = GraphImpl()) {
3189 MonitorAutoLock lock(graph->GetMonitor());
3190 if (graph->CurrentDriver()) { // graph has not completed forced shutdown
3191 graph->EnsureNextIteration();
3192 }
3193 }
3194}
3195
3196void SourceMediaTrack::SetDisabledTrackModeImpl(DisabledTrackMode aMode) {
3197 AssertOnGraphThread();
3198 {
3199 MutexAutoLock lock(mMutex);
3200 const DisabledTrackMode oldMode = mDirectDisabledMode;
3201 const bool oldEnabled = oldMode == DisabledTrackMode::ENABLED;
3202 const bool enabled = aMode == DisabledTrackMode::ENABLED;
3203 mDirectDisabledMode = aMode;
3204 for (const auto& l : mDirectTrackListeners) {
3205 if (!oldEnabled && enabled) {
3206 LOG(LogLevel::Debug, ("%p: SourceMediaTrack %p setting "
3207 "direct listener enabled",
3208 GraphImpl(), this));
3209 l->DecreaseDisabled(oldMode);
3210 } else if (oldEnabled && !enabled) {
3211 LOG(LogLevel::Debug, ("%p: SourceMediaTrack %p setting "
3212 "direct listener disabled",
3213 GraphImpl(), this));
3214 l->IncreaseDisabled(aMode);
3215 }
3216 }
3217 }
3218 MediaTrack::SetDisabledTrackModeImpl(aMode);
3219}
3220
3221uint32_t SourceMediaTrack::NumberOfChannels() const {
3222 AudioSegment* audio = GetData<AudioSegment>();
3223 MOZ_DIAGNOSTIC_ASSERT(audio)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(audio)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(audio))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("audio", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3223); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "audio"
")"); do { MOZ_CrashSequence(__null, 3223); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3224 if (!audio) {
3225 return 0;
3226 }
3227 return audio->MaxChannelCount();
3228}
3229
3230void SourceMediaTrack::RemoveAllDirectListenersImpl() {
3231 GraphImpl()->AssertOnGraphThreadOrNotRunning();
3232 MutexAutoLock lock(mMutex);
3233
3234 for (auto& l : mDirectTrackListeners.Clone()) {
3235 l->NotifyDirectListenerUninstalled();
3236 }
3237 mDirectTrackListeners.Clear();
3238}
3239
3240void SourceMediaTrack::SetVolume(float aVolume) {
3241 MutexAutoLock lock(mMutex);
3242 mVolume = aVolume;
3243}
3244
3245float SourceMediaTrack::GetVolumeLocked() {
3246 mMutex.AssertCurrentThreadOwns();
3247 return mVolume;
3248}
3249
3250SourceMediaTrack::~SourceMediaTrack() = default;
3251
3252void MediaInputPort::Init() {
3253 mGraph->AssertOnGraphThreadOrNotRunning();
3254 LOG(LogLevel::Debug, ("%p: Adding MediaInputPort %p (from %p to %p)", mGraph,
3255 this, mSource, mDest));
3256 // Only connect the port if it wasn't disconnected on allocation.
3257 if (mSource) {
3258 mSource->AddConsumer(this);
3259 mDest->AddInput(this);
3260 }
3261 // mPortCount decremented via MediaInputPort::Destroy's message
3262 ++mGraph->mPortCount;
3263}
3264
3265void MediaInputPort::Disconnect() {
3266 mGraph->AssertOnGraphThreadOrNotRunning();
3267 NS_ASSERTION(!mSource == !mDest,do { if (!(!mSource == !mDest)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mSource and mDest must either both be null or both non-null"
, "!mSource == !mDest", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3268); MOZ_PretendNoReturn(); } } while (0)
3268 "mSource and mDest must either both be null or both non-null")do { if (!(!mSource == !mDest)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "mSource and mDest must either both be null or both non-null"
, "!mSource == !mDest", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3268); MOZ_PretendNoReturn(); } } while (0)
;
3269
3270 if (!mSource) {
3271 return;
3272 }
3273
3274 mSource->RemoveConsumer(this);
3275 mDest->RemoveInput(this);
3276 mSource = nullptr;
3277 mDest = nullptr;
3278
3279 mGraph->SetTrackOrderDirty();
3280}
3281
3282MediaTrack* MediaInputPort::GetSource() const {
3283 mGraph->AssertOnGraphThreadOrNotRunning();
3284 return mSource;
3285}
3286
3287ProcessedMediaTrack* MediaInputPort::GetDestination() const {
3288 mGraph->AssertOnGraphThreadOrNotRunning();
3289 return mDest;
3290}
3291
3292MediaInputPort::InputInterval MediaInputPort::GetNextInputInterval(
3293 MediaInputPort const* aPort, GraphTime aTime) {
3294 InputInterval result = {GRAPH_TIME_MAX, GRAPH_TIME_MAX, false};
3295 if (!aPort) {
3296 result.mStart = aTime;
3297 result.mInputIsBlocked = true;
3298 return result;
3299 }
3300 aPort->mGraph->AssertOnGraphThreadOrNotRunning();
3301 if (aTime >= aPort->mDest->mStartBlocking) {
3302 return result;
3303 }
3304 result.mStart = aTime;
3305 result.mEnd = aPort->mDest->mStartBlocking;
3306 result.mInputIsBlocked = aTime >= aPort->mSource->mStartBlocking;
3307 if (!result.mInputIsBlocked) {
3308 result.mEnd = std::min(result.mEnd, aPort->mSource->mStartBlocking);
3309 }
3310 return result;
3311}
3312
3313void MediaInputPort::Suspended() {
3314 mGraph->AssertOnGraphThreadOrNotRunning();
3315 mDest->InputSuspended(this);
3316}
3317
3318void MediaInputPort::Resumed() {
3319 mGraph->AssertOnGraphThreadOrNotRunning();
3320 mDest->InputResumed(this);
3321}
3322
3323void MediaInputPort::Destroy() {
3324 class Message : public ControlMessage {
3325 public:
3326 explicit Message(MediaInputPort* aPort)
3327 : ControlMessage(nullptr), mPort(aPort) {}
3328 void Run() override {
3329 TRACE("MediaInputPort::Destroy ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MediaInputPort::Destroy ControlMessage"
);
;
3330 mPort->Disconnect();
3331 --mPort->GraphImpl()->mPortCount;
3332 mPort->SetGraphImpl(nullptr);
3333 NS_RELEASE(mPort)do { (mPort)->Release(); (mPort) = 0; } while (0);
3334 }
3335 void RunDuringShutdown() override { Run(); }
3336 MediaInputPort* mPort;
3337 };
3338 // Keep a reference to the graph, since Message might RunDuringShutdown()
3339 // synchronously and make GraphImpl() invalid.
3340 RefPtr<MediaTrackGraphImpl> graph = mGraph;
3341 graph->AppendMessage(MakeUnique<Message>(this));
3342 --graph->mMainThreadPortCount;
3343}
3344
3345MediaTrackGraphImpl* MediaInputPort::GraphImpl() const {
3346 mGraph->AssertOnGraphThreadOrNotRunning();
3347 return mGraph;
3348}
3349
3350MediaTrackGraph* MediaInputPort::Graph() const {
3351 mGraph->AssertOnGraphThreadOrNotRunning();
3352 return mGraph;
3353}
3354
3355void MediaInputPort::SetGraphImpl(MediaTrackGraphImpl* aGraph) {
3356 MOZ_ASSERT(!mGraph || !aGraph, "Should only be set once")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGraph || !aGraph)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mGraph || !aGraph))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mGraph || !aGraph"
" (" "Should only be set once" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3356); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGraph || !aGraph"
") (" "Should only be set once" ")"); do { MOZ_CrashSequence
(__null, 3356); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3357 DebugOnly<MediaTrackGraphImpl*> graph = mGraph ? mGraph : aGraph;
3358 MOZ_ASSERT(graph->OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(graph->OnGraphThreadOrNotRunning())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(graph->OnGraphThreadOrNotRunning()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("graph->OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3358);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "graph->OnGraphThreadOrNotRunning()"
")"); do { MOZ_CrashSequence(__null, 3358); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3359 mGraph = aGraph;
3360}
3361
3362already_AddRefed<MediaInputPort> ProcessedMediaTrack::AllocateInputPort(
3363 MediaTrack* aTrack, uint16_t aInputNumber, uint16_t aOutputNumber) {
3364 // This method creates two references to the MediaInputPort: one for
3365 // the main thread, and one for the MediaTrackGraph.
3366 class Message : public ControlMessage {
3367 public:
3368 explicit Message(MediaInputPort* aPort)
3369 : ControlMessage(aPort->mDest), mPort(aPort) {}
3370 void Run() override {
3371 TRACE("ProcessedMediaTrack::AllocateInputPort ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "ProcessedMediaTrack::AllocateInputPort ControlMessage"
);
;
3372 mPort->Init();
3373 // The graph holds its reference implicitly
3374 mPort->GraphImpl()->SetTrackOrderDirty();
3375 Unused << mPort.forget();
3376 }
3377 void RunDuringShutdown() override { Run(); }
3378 RefPtr<MediaInputPort> mPort;
3379 };
3380
3381 MOZ_DIAGNOSTIC_ASSERT(aTrack->mType == mType)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrack->mType == mType)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTrack->mType == mType)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aTrack->mType == mType"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3381);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aTrack->mType == mType"
")"); do { MOZ_CrashSequence(__null, 3381); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3382 RefPtr<MediaInputPort> port;
3383 if (aTrack->IsDestroyed()) {
3384 // Create a port that's disconnected, which is what it'd be after its source
3385 // track is Destroy()ed normally. Disconnect() is idempotent so destroying
3386 // this later is fine.
3387 port = new MediaInputPort(GraphImpl(), nullptr, nullptr, aInputNumber,
3388 aOutputNumber);
3389 } else {
3390 MOZ_ASSERT(aTrack->GraphImpl() == GraphImpl())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTrack->GraphImpl() == GraphImpl())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(aTrack->GraphImpl() == GraphImpl()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTrack->GraphImpl() == GraphImpl()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3390);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTrack->GraphImpl() == GraphImpl()"
")"); do { MOZ_CrashSequence(__null, 3390); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3391 port = new MediaInputPort(GraphImpl(), aTrack, this, aInputNumber,
3392 aOutputNumber);
3393 }
3394 ++GraphImpl()->mMainThreadPortCount;
3395 GraphImpl()->AppendMessage(MakeUnique<Message>(port));
3396 return port.forget();
3397}
3398
3399void ProcessedMediaTrack::QueueSetAutoend(bool aAutoend) {
3400 class Message : public ControlMessage {
3401 public:
3402 Message(ProcessedMediaTrack* aTrack, bool aAutoend)
3403 : ControlMessage(aTrack), mAutoend(aAutoend) {}
3404 void Run() override {
3405 TRACE("ProcessedMediaTrack::SetAutoendImpl ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "ProcessedMediaTrack::SetAutoendImpl ControlMessage"
);
;
3406 static_cast<ProcessedMediaTrack*>(mTrack)->SetAutoendImpl(mAutoend);
3407 }
3408 bool mAutoend;
3409 };
3410 if (mMainThreadDestroyed) {
3411 return;
3412 }
3413 GraphImpl()->AppendMessage(MakeUnique<Message>(this, aAutoend));
3414}
3415
3416void ProcessedMediaTrack::DestroyImpl() {
3417 for (int32_t i = mInputs.Length() - 1; i >= 0; --i) {
3418 mInputs[i]->Disconnect();
3419 }
3420
3421 for (int32_t i = mSuspendedInputs.Length() - 1; i >= 0; --i) {
3422 mSuspendedInputs[i]->Disconnect();
3423 }
3424
3425 MediaTrack::DestroyImpl();
3426 // The track order is only important if there are connections, in which
3427 // case MediaInputPort::Disconnect() called SetTrackOrderDirty().
3428 // MediaTrackGraphImpl::RemoveTrackGraphThread() will also call
3429 // SetTrackOrderDirty(), for other reasons.
3430}
3431
3432MediaTrackGraphImpl::MediaTrackGraphImpl(uint64_t aWindowID,
3433 TrackRate aSampleRate,
3434 AudioDeviceID aPrimaryOutputDeviceID,
3435 nsISerialEventTarget* aMainThread)
3436 : MediaTrackGraph(aSampleRate, aPrimaryOutputDeviceID),
3437 mWindowID(aWindowID),
3438 mFirstCycleBreaker(0)
3439 // An offline graph is not initially processing.
3440 ,
3441 mPortCount(0),
3442 mMonitor("MediaTrackGraphImpl"),
3443 mLifecycleState(LIFECYCLE_THREAD_NOT_STARTED),
3444 mPostedRunInStableStateEvent(false),
3445 mGraphDriverRunning(false),
3446 mPostedRunInStableState(false),
3447 mTrackOrderDirty(false),
3448 mMainThread(aMainThread),
3449 mGlobalVolume(CubebUtils::GetVolumeScale())
3450#ifdef DEBUG1
3451 ,
3452 mCanRunMessagesSynchronously(false)
3453#endif
3454 ,
3455 mMainThreadGraphTime(0, "MediaTrackGraphImpl::mMainThreadGraphTime"),
3456 mAudioOutputLatency(0.0),
3457 mMaxOutputChannelCount(CubebUtils::MaxNumberOfChannels()) {
3458}
3459
3460void MediaTrackGraphImpl::Init(GraphDriverType aDriverRequested,
3461 GraphRunType aRunTypeRequested,
3462 uint32_t aChannelCount) {
3463 mSelfRef = this;
3464 mEndTime = aDriverRequested == OFFLINE_THREAD_DRIVER ? 0 : GRAPH_TIME_MAX;
3465 mRealtime = aDriverRequested != OFFLINE_THREAD_DRIVER;
3466 // The primary output device always exists because an AudioCallbackDriver
3467 // may exist, and want to be fed data, even when no tracks have audio
3468 // outputs.
3469 mOutputDeviceRefCnts.EmplaceBack(
3470 DeviceReceiverAndCount{mPrimaryOutputDeviceID, nullptr, 0});
3471 mOutputDevices.EmplaceBack(OutputDeviceEntry{mPrimaryOutputDeviceID});
3472
3473 bool failedToGetShutdownBlocker = false;
3474 if (!IsNonRealtime()) {
3475 failedToGetShutdownBlocker = !AddShutdownBlocker();
3476 }
3477
3478 mGraphRunner = aRunTypeRequested == SINGLE_THREAD
3479 ? GraphRunner::Create(this)
3480 : already_AddRefed<GraphRunner>(nullptr);
3481
3482 if ((aRunTypeRequested == SINGLE_THREAD && !mGraphRunner) ||
3483 failedToGetShutdownBlocker) {
3484 MonitorAutoLock lock(mMonitor);
3485 // At least one of the following happened
3486 // - Failed to create thread.
3487 // - Failed to install a shutdown blocker when one is needed.
3488 // Because we have a fail state, jump to last phase of the lifecycle.
3489 mLifecycleState = LIFECYCLE_WAITING_FOR_TRACK_DESTRUCTION;
3490 RemoveShutdownBlocker(); // No-op if blocker wasn't added.
3491#ifdef DEBUG1
3492 mCanRunMessagesSynchronously = true;
3493#endif
3494 return;
3495 }
3496 if (mRealtime) {
3497 if (aDriverRequested == AUDIO_THREAD_DRIVER) {
3498 // Always start with zero input channels, and no particular preferences
3499 // for the input channel.
3500 mDriver = new AudioCallbackDriver(
3501 this, nullptr, mSampleRate, aChannelCount, 0, PrimaryOutputDeviceID(),
3502 nullptr, AudioInputType::Unknown, Nothing());
3503 } else {
3504 mDriver = new SystemClockDriver(this, nullptr, mSampleRate);
3505 }
3506 nsCString streamName = GetDocumentTitle(mWindowID);
3507 LOG(LogLevel::Debug, ("%p: document title: %s", this, streamName.get()));
3508 mDriver->SetStreamName(streamName);
3509 } else {
3510 mDriver =
3511 new OfflineClockDriver(this, mSampleRate, MEDIA_GRAPH_TARGET_PERIOD_MS);
3512 }
3513
3514 mLastMainThreadUpdate = TimeStamp::Now();
3515
3516 RegisterWeakAsyncMemoryReporter(this);
3517}
3518
3519#ifdef DEBUG1
3520bool MediaTrackGraphImpl::InDriverIteration(const GraphDriver* aDriver) const {
3521 return aDriver->OnThread() ||
3522 (mGraphRunner && mGraphRunner->InDriverIteration(aDriver));
3523}
3524#endif
3525
3526void MediaTrackGraphImpl::Destroy() {
3527 // First unregister from memory reporting.
3528 UnregisterWeakMemoryReporter(this);
3529
3530 // Clear the self reference which will destroy this instance if all
3531 // associated GraphDrivers are destroyed.
3532 mSelfRef = nullptr;
3533}
3534
3535// Internal method has a Window ID parameter so that TestAudioTrackGraph
3536// GTests can create a graph without a window.
3537/* static */
3538MediaTrackGraphImpl* MediaTrackGraphImpl::GetInstanceIfExists(
3539 uint64_t aWindowID, TrackRate aSampleRate,
3540 AudioDeviceID aPrimaryOutputDeviceID) {
3541 MOZ_ASSERT(NS_IsMainThread(), "Main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3541); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Main thread only" ")"); do { MOZ_CrashSequence(__null
, 3541); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3542 MOZ_ASSERT(aSampleRate > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSampleRate > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSampleRate > 0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aSampleRate > 0"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3542);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSampleRate > 0"
")"); do { MOZ_CrashSequence(__null, 3542); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3543
3544 GraphHashSet::Ptr p =
3545 Graphs()->lookup({aWindowID, aSampleRate, aPrimaryOutputDeviceID});
3546 return p ? *p : nullptr;
3547}
3548
3549// Public method has an nsPIDOMWindowInner* parameter to ensure that the
3550// window is a real inner Window, not a WindowProxy.
3551/* static */
3552MediaTrackGraph* MediaTrackGraph::GetInstanceIfExists(
3553 nsPIDOMWindowInner* aWindow, TrackRate aSampleRate,
3554 AudioDeviceID aPrimaryOutputDeviceID) {
3555 TrackRate sampleRate =
3556 aSampleRate ? aSampleRate
3557 : CubebUtils::PreferredSampleRate(
3558 aWindow->AsGlobal()->ShouldResistFingerprinting(
3559 RFPTarget::AudioSampleRate));
3560 return MediaTrackGraphImpl::GetInstanceIfExists(
3561 aWindow->WindowID(), sampleRate, aPrimaryOutputDeviceID);
3562}
3563
3564/* static */
3565MediaTrackGraphImpl* MediaTrackGraphImpl::GetInstance(
3566 GraphDriverType aGraphDriverRequested, uint64_t aWindowID,
3567 TrackRate aSampleRate, AudioDeviceID aPrimaryOutputDeviceID,
3568 nsISerialEventTarget* aMainThread) {
3569 MOZ_ASSERT(NS_IsMainThread(), "Main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3569); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Main thread only" ")"); do { MOZ_CrashSequence(__null
, 3569); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3570 MOZ_ASSERT(aSampleRate > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSampleRate > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSampleRate > 0))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aSampleRate > 0"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3570);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSampleRate > 0"
")"); do { MOZ_CrashSequence(__null, 3570); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3571 MOZ_ASSERT(aGraphDriverRequested != OFFLINE_THREAD_DRIVER,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGraphDriverRequested != OFFLINE_THREAD_DRIVER)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aGraphDriverRequested != OFFLINE_THREAD_DRIVER))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aGraphDriverRequested != OFFLINE_THREAD_DRIVER"
" (" "Use CreateNonRealtimeInstance() for offline graphs" ")"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3572);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGraphDriverRequested != OFFLINE_THREAD_DRIVER"
") (" "Use CreateNonRealtimeInstance() for offline graphs" ")"
); do { MOZ_CrashSequence(__null, 3572); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3572 "Use CreateNonRealtimeInstance() for offline graphs")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGraphDriverRequested != OFFLINE_THREAD_DRIVER)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aGraphDriverRequested != OFFLINE_THREAD_DRIVER))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aGraphDriverRequested != OFFLINE_THREAD_DRIVER"
" (" "Use CreateNonRealtimeInstance() for offline graphs" ")"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3572);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGraphDriverRequested != OFFLINE_THREAD_DRIVER"
") (" "Use CreateNonRealtimeInstance() for offline graphs" ")"
); do { MOZ_CrashSequence(__null, 3572); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3573
3574 GraphHashSet* graphs = Graphs();
3575 GraphHashSet::AddPtr addPtr =
3576 graphs->lookupForAdd({aWindowID, aSampleRate, aPrimaryOutputDeviceID});
3577 if (addPtr) { // graph already exists
3578 return *addPtr;
3579 }
3580
3581 GraphRunType runType = DIRECT_DRIVER;
3582 if (Preferences::GetBool("media.audiograph.single_thread.enabled", true)) {
3583 runType = SINGLE_THREAD;
3584 }
3585
3586 // In a real time graph, the number of output channels is determined by
3587 // the underlying number of channel of the default audio output device.
3588 uint32_t channelCount = CubebUtils::MaxNumberOfChannels();
3589 MediaTrackGraphImpl* graph = new MediaTrackGraphImpl(
3590 aWindowID, aSampleRate, aPrimaryOutputDeviceID, aMainThread);
3591 graph->Init(aGraphDriverRequested, runType, channelCount);
3592 MOZ_ALWAYS_TRUE(graphs->add(addPtr, graph))do { if ((__builtin_expect(!!(graphs->add(addPtr, graph)),
1))) { } else { do { do { } while (false); MOZ_ReportCrash(""
"graphs->add(addPtr, graph)", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3592); AnnotateMozCrashReason("MOZ_CRASH(" "graphs->add(addPtr, graph)"
")"); do { MOZ_CrashSequence(__null, 3592); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
3593
3594 LOG(LogLevel::Debug, ("Starting up MediaTrackGraph %p for window 0x%" PRIx64"l" "x",
3595 graph, aWindowID));
3596
3597 return graph;
3598}
3599
3600/* static */
3601MediaTrackGraph* MediaTrackGraph::GetInstance(
3602 GraphDriverType aGraphDriverRequested, nsPIDOMWindowInner* aWindow,
3603 TrackRate aSampleRate, AudioDeviceID aPrimaryOutputDeviceID) {
3604 TrackRate sampleRate =
3605 aSampleRate ? aSampleRate
3606 : CubebUtils::PreferredSampleRate(
3607 aWindow->AsGlobal()->ShouldResistFingerprinting(
3608 RFPTarget::AudioSampleRate));
3609 return MediaTrackGraphImpl::GetInstance(
3610 aGraphDriverRequested, aWindow->WindowID(), sampleRate,
3611 aPrimaryOutputDeviceID, GetMainThreadSerialEventTarget());
3612}
3613
3614MediaTrackGraph* MediaTrackGraphImpl::CreateNonRealtimeInstance(
3615 TrackRate aSampleRate) {
3616 MOZ_ASSERT(NS_IsMainThread(), "Main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3616); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Main thread only" ")"); do { MOZ_CrashSequence(__null
, 3616); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3617
3618 nsISerialEventTarget* mainThread = GetMainThreadSerialEventTarget();
3619 // Offline graphs have 0 output channel count: they write the output to a
3620 // buffer, not an audio output track.
3621 MediaTrackGraphImpl* graph = new MediaTrackGraphImpl(
3622 0, aSampleRate, DEFAULT_OUTPUT_DEVICE, mainThread);
3623 graph->Init(OFFLINE_THREAD_DRIVER, DIRECT_DRIVER, 0);
3624
3625 LOG(LogLevel::Debug, ("Starting up Offline MediaTrackGraph %p", graph));
3626
3627 return graph;
3628}
3629
3630MediaTrackGraph* MediaTrackGraph::CreateNonRealtimeInstance(
3631 TrackRate aSampleRate) {
3632 return MediaTrackGraphImpl::CreateNonRealtimeInstance(aSampleRate);
3633}
3634
3635void MediaTrackGraph::ForceShutDown() {
3636 MOZ_ASSERT(NS_IsMainThread(), "Main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3636); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Main thread only" ")"); do { MOZ_CrashSequence(__null
, 3636); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3637
3638 MediaTrackGraphImpl* graph = static_cast<MediaTrackGraphImpl*>(this);
3639
3640 graph->ForceShutDown();
3641}
3642
3643NS_IMPL_ISUPPORTS(MediaTrackGraphImpl, nsIMemoryReporter, nsIObserver,MozExternalRefCountType MediaTrackGraphImpl::AddRef(void) { static_assert
(!std::is_destructible_v<MediaTrackGraphImpl>, "Reference-counted class "
"MediaTrackGraphImpl" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 3644
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("MediaTrackGraphImpl" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("MediaTrackGraphImpl" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"MediaTrackGraphImpl\" != nullptr" " (" "Must specify a name"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3644
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MediaTrackGraphImpl\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 3644); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("MediaTrackGraphImpl" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("MediaTrackGraphImpl"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
MediaTrackGraphImpl::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3644
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 3644
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("MediaTrackGraphImpl" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("MediaTrackGraphImpl" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"MediaTrackGraphImpl\" != nullptr" " (" "Must specify a name"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3644
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MediaTrackGraphImpl\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 3644); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("MediaTrackGraphImpl" " not thread-safe"); const
char* const nametmp = "MediaTrackGraphImpl"; nsrefcnt count =
--mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult MediaTrackGraphImpl::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3644); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<MediaTrackGraphImpl, nsIMemoryReporter>
, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((MediaTrackGraphImpl*)0x1000)) - reinterpret_cast<char
*>((MediaTrackGraphImpl*)0x1000))}, {&mozilla::detail::
kImplementedIID<MediaTrackGraphImpl, nsIObserver>, int32_t
( reinterpret_cast<char*>(static_cast<nsIObserver*>
((MediaTrackGraphImpl*)0x1000)) - reinterpret_cast<char*>
((MediaTrackGraphImpl*)0x1000))}, {&mozilla::detail::kImplementedIID
<MediaTrackGraphImpl, nsIThreadObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadObserver*>((MediaTrackGraphImpl
*)0x1000)) - reinterpret_cast<char*>((MediaTrackGraphImpl
*)0x1000))}, {&mozilla::detail::kImplementedIID<MediaTrackGraphImpl
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((MediaTrackGraphImpl*)0x1000
)) - reinterpret_cast<char*>((MediaTrackGraphImpl*)0x1000
))}, {&mozilla::detail::kImplementedIID<MediaTrackGraphImpl
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((MediaTrackGraphImpl*)0x1000)) - reinterpret_cast
<char*>((MediaTrackGraphImpl*)0x1000))}, {&mozilla::
detail::kImplementedIID<MediaTrackGraphImpl, nsISupports>
, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIMemoryReporter*>((MediaTrackGraphImpl
*)0x1000))) - reinterpret_cast<char*>((MediaTrackGraphImpl
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
3644 nsIThreadObserver, nsITimerCallback, nsINamed)MozExternalRefCountType MediaTrackGraphImpl::AddRef(void) { static_assert
(!std::is_destructible_v<MediaTrackGraphImpl>, "Reference-counted class "
"MediaTrackGraphImpl" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 3644
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("MediaTrackGraphImpl" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("MediaTrackGraphImpl" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"MediaTrackGraphImpl\" != nullptr" " (" "Must specify a name"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3644
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MediaTrackGraphImpl\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 3644); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("MediaTrackGraphImpl" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("MediaTrackGraphImpl"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
MediaTrackGraphImpl::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3644
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 3644
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("MediaTrackGraphImpl" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("MediaTrackGraphImpl" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"MediaTrackGraphImpl\" != nullptr" " (" "Must specify a name"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3644
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"MediaTrackGraphImpl\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 3644); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("MediaTrackGraphImpl" " not thread-safe"); const
char* const nametmp = "MediaTrackGraphImpl"; nsrefcnt count =
--mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult MediaTrackGraphImpl::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3644); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(5 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<MediaTrackGraphImpl, nsIMemoryReporter>
, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((MediaTrackGraphImpl*)0x1000)) - reinterpret_cast<char
*>((MediaTrackGraphImpl*)0x1000))}, {&mozilla::detail::
kImplementedIID<MediaTrackGraphImpl, nsIObserver>, int32_t
( reinterpret_cast<char*>(static_cast<nsIObserver*>
((MediaTrackGraphImpl*)0x1000)) - reinterpret_cast<char*>
((MediaTrackGraphImpl*)0x1000))}, {&mozilla::detail::kImplementedIID
<MediaTrackGraphImpl, nsIThreadObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadObserver*>((MediaTrackGraphImpl
*)0x1000)) - reinterpret_cast<char*>((MediaTrackGraphImpl
*)0x1000))}, {&mozilla::detail::kImplementedIID<MediaTrackGraphImpl
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((MediaTrackGraphImpl*)0x1000
)) - reinterpret_cast<char*>((MediaTrackGraphImpl*)0x1000
))}, {&mozilla::detail::kImplementedIID<MediaTrackGraphImpl
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((MediaTrackGraphImpl*)0x1000)) - reinterpret_cast
<char*>((MediaTrackGraphImpl*)0x1000))}, {&mozilla::
detail::kImplementedIID<MediaTrackGraphImpl, nsISupports>
, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIMemoryReporter*>((MediaTrackGraphImpl
*)0x1000))) - reinterpret_cast<char*>((MediaTrackGraphImpl
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
3645
3646NS_IMETHODIMPnsresult
3647MediaTrackGraphImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
3648 nsISupports* aData, bool aAnonymize) {
3649 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3649);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 3649); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3650 if (mMainThreadTrackCount == 0) {
3651 // No tracks to report.
3652 FinishCollectReports(aHandleReport, aData, nsTArray<AudioNodeSizes>());
3653 return NS_OK;
3654 }
3655
3656 class Message final : public ControlMessage {
3657 public:
3658 Message(MediaTrackGraphImpl* aGraph, nsIHandleReportCallback* aHandleReport,
3659 nsISupports* aHandlerData)
3660 : ControlMessage(nullptr),
3661 mGraph(aGraph),
3662 mHandleReport(aHandleReport),
3663 mHandlerData(aHandlerData) {}
3664 void Run() override {
3665 TRACE("MTG::CollectSizesForMemoryReport ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::CollectSizesForMemoryReport ControlMessage"
);
;
3666 mGraph->CollectSizesForMemoryReport(mHandleReport.forget(),
3667 mHandlerData.forget());
3668 }
3669 void RunDuringShutdown() override {
3670 // Run this message during shutdown too, so that endReports is called.
3671 Run();
3672 }
3673 MediaTrackGraphImpl* mGraph;
3674 // nsMemoryReporterManager keeps the callback and data alive only if it
3675 // does not time out.
3676 nsCOMPtr<nsIHandleReportCallback> mHandleReport;
3677 nsCOMPtr<nsISupports> mHandlerData;
3678 };
3679
3680 AppendMessage(MakeUnique<Message>(this, aHandleReport, aData));
3681
3682 return NS_OK;
3683}
3684
3685void MediaTrackGraphImpl::CollectSizesForMemoryReport(
3686 already_AddRefed<nsIHandleReportCallback> aHandleReport,
3687 already_AddRefed<nsISupports> aHandlerData) {
3688 class FinishCollectRunnable final : public Runnable {
3689 public:
3690 explicit FinishCollectRunnable(
3691 already_AddRefed<nsIHandleReportCallback> aHandleReport,
3692 already_AddRefed<nsISupports> aHandlerData)
3693 : mozilla::Runnable("FinishCollectRunnable"),
3694 mHandleReport(aHandleReport),
3695 mHandlerData(aHandlerData) {}
3696
3697 NS_IMETHODvirtual nsresult Run() override {
3698 TRACE("MTG::FinishCollectReports ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::FinishCollectReports ControlMessage"
);
;
3699 MediaTrackGraphImpl::FinishCollectReports(mHandleReport, mHandlerData,
3700 std::move(mAudioTrackSizes));
3701 return NS_OK;
3702 }
3703
3704 nsTArray<AudioNodeSizes> mAudioTrackSizes;
3705
3706 private:
3707 ~FinishCollectRunnable() = default;
3708
3709 // Avoiding nsCOMPtr because NSCAP_ASSERT_NO_QUERY_NEEDED in its
3710 // constructor modifies the ref-count, which cannot be done off main
3711 // thread.
3712 RefPtr<nsIHandleReportCallback> mHandleReport;
3713 RefPtr<nsISupports> mHandlerData;
3714 };
3715
3716 RefPtr<FinishCollectRunnable> runnable = new FinishCollectRunnable(
3717 std::move(aHandleReport), std::move(aHandlerData));
3718
3719 auto audioTrackSizes = &runnable->mAudioTrackSizes;
3720
3721 for (MediaTrack* t : AllTracks()) {
3722 AudioNodeTrack* track = t->AsAudioNodeTrack();
3723 if (track) {
3724 AudioNodeSizes* usage = audioTrackSizes->AppendElement();
3725 track->SizeOfAudioNodesIncludingThis(MallocSizeOf, *usage);
3726 }
3727 }
3728
3729 mMainThread->Dispatch(runnable.forget());
3730}
3731
3732void MediaTrackGraphImpl::FinishCollectReports(
3733 nsIHandleReportCallback* aHandleReport, nsISupports* aData,
3734 const nsTArray<AudioNodeSizes>& aAudioTrackSizes) {
3735 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3735);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 3735); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3736
3737 nsCOMPtr<nsIMemoryReporterManager> manager =
3738 do_GetService("@mozilla.org/memory-reporter-manager;1");
3739
3740 if (!manager) return;
3741
3742#define REPORT(_path, _amount, _desc) \
3743 aHandleReport->Callback(""_ns, _path, KIND_HEAP, UNITS_BYTES, _amount, \
3744 nsLiteralCString(_desc), aData);
3745
3746 for (size_t i = 0; i < aAudioTrackSizes.Length(); i++) {
3747 const AudioNodeSizes& usage = aAudioTrackSizes[i];
3748 const char* const nodeType =
3749 usage.mNodeType ? usage.mNodeType : "<unknown>";
3750
3751 nsPrintfCString enginePath("explicit/webaudio/audio-node/%s/engine-objects",
3752 nodeType);
3753 REPORT(enginePath, usage.mEngine,
3754 "Memory used by AudioNode engine objects (Web Audio).");
3755
3756 nsPrintfCString trackPath("explicit/webaudio/audio-node/%s/track-objects",
3757 nodeType);
3758 REPORT(trackPath, usage.mTrack,
3759 "Memory used by AudioNode track objects (Web Audio).");
3760 }
3761
3762 size_t hrtfLoaders = WebCore::HRTFDatabaseLoader::sizeOfLoaders(MallocSizeOf);
3763 if (hrtfLoaders) {
3764 REPORT(nsLiteralCString(
3765 "explicit/webaudio/audio-node/PannerNode/hrtf-databases"),
3766 hrtfLoaders, "Memory used by PannerNode databases (Web Audio).");
3767 }
3768
3769#undef REPORT
3770
3771 manager->EndReport();
3772}
3773
3774SourceMediaTrack* MediaTrackGraph::CreateSourceTrack(MediaSegment::Type aType) {
3775 SourceMediaTrack* track = new SourceMediaTrack(aType, GraphRate());
3776 AddTrack(track);
3777 return track;
3778}
3779
3780ProcessedMediaTrack* MediaTrackGraph::CreateForwardedInputTrack(
3781 MediaSegment::Type aType) {
3782 ForwardedInputTrack* track = new ForwardedInputTrack(GraphRate(), aType);
3783 AddTrack(track);
3784 return track;
3785}
3786
3787AudioCaptureTrack* MediaTrackGraph::CreateAudioCaptureTrack() {
3788 AudioCaptureTrack* track = new AudioCaptureTrack(GraphRate());
3789 AddTrack(track);
3790 return track;
3791}
3792
3793CrossGraphTransmitter* MediaTrackGraph::CreateCrossGraphTransmitter(
3794 CrossGraphReceiver* aReceiver) {
3795 CrossGraphTransmitter* track =
3796 new CrossGraphTransmitter(GraphRate(), aReceiver);
3797 AddTrack(track);
3798 return track;
3799}
3800
3801CrossGraphReceiver* MediaTrackGraph::CreateCrossGraphReceiver(
3802 TrackRate aTransmitterRate) {
3803 CrossGraphReceiver* track =
3804 new CrossGraphReceiver(GraphRate(), aTransmitterRate);
3805 AddTrack(track);
3806 return track;
3807}
3808
3809void MediaTrackGraph::AddTrack(MediaTrack* aTrack) {
3810 MediaTrackGraphImpl* graph = static_cast<MediaTrackGraphImpl*>(this);
3811 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3811);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 3811); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3812#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
3813 if (graph->mRealtime) {
3814 GraphHashSet::Ptr p = Graphs()->lookup(*graph);
3815 MOZ_DIAGNOSTIC_ASSERT(p, "Graph must not be shutting down")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(p)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(p))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("p" " (" "Graph must not be shutting down" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3815); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "p"
") (" "Graph must not be shutting down" ")"); do { MOZ_CrashSequence
(__null, 3815); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3816 }
3817#endif
3818 if (graph->mMainThreadTrackCount == 0) {
3819 nsCOMPtr<nsIObserverService> observerService =
3820 mozilla::services::GetObserverService();
3821 if (observerService) {
3822 observerService->AddObserver(graph, "document-title-changed", false);
3823 }
3824 }
3825
3826 NS_ADDREF(aTrack)(aTrack)->AddRef();
3827 aTrack->SetGraphImpl(graph);
3828 ++graph->mMainThreadTrackCount;
3829 graph->AppendMessage(MakeUnique<CreateMessage>(aTrack));
3830}
3831
3832void MediaTrackGraphImpl::RemoveTrack(MediaTrack* aTrack) {
3833 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3833);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 3833); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3834 MOZ_DIAGNOSTIC_ASSERT(mMainThreadTrackCount > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMainThreadTrackCount > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMainThreadTrackCount > 0
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mMainThreadTrackCount > 0", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3834); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mMainThreadTrackCount > 0"
")"); do { MOZ_CrashSequence(__null, 3834); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3835
3836 mAudioOutputParams.RemoveElementsBy(
3837 [&](const TrackKeyDeviceAndVolume& aElement) {
3838 if (aElement.mTrack != aTrack) {
3839 return false;
3840 };
3841 DecrementOutputDeviceRefCnt(aElement.mDeviceID);
3842 return true;
3843 });
3844
3845 if (--mMainThreadTrackCount == 0) {
3846 LOG(LogLevel::Info, ("MediaTrackGraph %p, last track %p removed from "
3847 "main thread. Graph will shut down.",
3848 this, aTrack));
3849 if (mRealtime) {
3850 // Find the graph in the hash table and remove it.
3851 GraphHashSet* graphs = Graphs();
3852 GraphHashSet::Ptr p = graphs->lookup(*this);
3853 MOZ_ASSERT(*p == this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*p == this)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*p == this))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("*p == this", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3853); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == this"
")"); do { MOZ_CrashSequence(__null, 3853); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3854 graphs->remove(p);
3855
3856 nsCOMPtr<nsIObserverService> observerService =
3857 mozilla::services::GetObserverService();
3858 if (observerService) {
3859 observerService->RemoveObserver(this, "document-title-changed");
3860 }
3861 }
3862 // The graph thread will shut itself down soon, but won't be able to do
3863 // that if JS continues to run.
3864 InterruptJS();
3865 }
3866}
3867
3868auto MediaTrackGraphImpl::NotifyWhenDeviceStarted(AudioDeviceID aDeviceID)
3869 -> RefPtr<GraphStartedPromise> {
3870 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3870);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 3870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3871
3872 size_t index = mOutputDeviceRefCnts.IndexOf(aDeviceID);
3873 if (index == decltype(mOutputDeviceRefCnts)::NoIndex) {
3874 return GraphStartedPromise::CreateAndReject(NS_ERROR_INVALID_ARG, __func__);
3875 }
3876
3877 MozPromiseHolder<GraphStartedPromise> h;
3878 RefPtr<GraphStartedPromise> p = h.Ensure(__func__);
3879
3880 if (CrossGraphReceiver* receiver = mOutputDeviceRefCnts[index].mReceiver) {
3881 receiver->GraphImpl()->NotifyWhenPrimaryDeviceStarted(std::move(h));
3882 return p;
3883 }
3884
3885 // aSink corresponds to the primary audio output device of this graph.
3886 NotifyWhenPrimaryDeviceStarted(std::move(h));
3887 return p;
3888}
3889
3890void MediaTrackGraphImpl::NotifyWhenPrimaryDeviceStarted(
3891 MozPromiseHolder<GraphStartedPromise>&& aHolder) {
3892 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3892);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 3892); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3893 if (mOutputDeviceRefCnts[0].mRefCnt == 0) {
3894 // There are no track outputs that require the device, so the creator of
3895 // this promise no longer needs to know when the graph is running. Don't
3896 // keep the graph alive with another message.
3897 aHolder.Reject(NS_ERROR_NOT_AVAILABLE, __func__);
3898 return;
3899 }
3900
3901 QueueControlOrShutdownMessage(
3902 [self = RefPtr{this}, this,
3903 holder = std::move(aHolder)](IsInShutdown aInShutdown) mutable {
3904 if (aInShutdown == IsInShutdown::Yes) {
3905 holder.Reject(NS_ERROR_ILLEGAL_DURING_SHUTDOWN, __func__);
3906 return;
3907 }
3908
3909 TRACE("MTG::NotifyWhenPrimaryDeviceStarted ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::NotifyWhenPrimaryDeviceStarted ControlMessage"
);
;
3910 // This runs on the graph thread, so when this runs, and the current
3911 // driver is an AudioCallbackDriver, we know the audio hardware is
3912 // started. If not, we are going to switch soon, keep reposting this
3913 // ControlMessage.
3914 if (CurrentDriver()->AsAudioCallbackDriver() &&
3915 CurrentDriver()->ThreadRunning() &&
3916 !CurrentDriver()->AsAudioCallbackDriver()->OnFallback()) {
3917 // Avoid Resolve's locking on the graph thread by doing it on main.
3918 Dispatch(NS_NewRunnableFunction(
3919 "MediaTrackGraphImpl::NotifyWhenPrimaryDeviceStarted::Resolver",
3920 [holder = std::move(holder)]() mutable {
3921 holder.Resolve(true, __func__);
3922 }));
3923 } else {
3924 DispatchToMainThreadStableState(
3925 NewRunnableMethod<
3926 StoreCopyPassByRRef<MozPromiseHolder<GraphStartedPromise>>>(
3927 "MediaTrackGraphImpl::NotifyWhenPrimaryDeviceStarted", this,
3928 &MediaTrackGraphImpl::NotifyWhenPrimaryDeviceStarted,
3929 std::move(holder)));
3930 }
3931 });
3932}
3933
3934class AudioContextOperationControlMessage : public ControlMessage {
3935 using AudioContextOperationPromise =
3936 MediaTrackGraph::AudioContextOperationPromise;
3937
3938 public:
3939 AudioContextOperationControlMessage(
3940 MediaTrack* aDestinationTrack, nsTArray<RefPtr<MediaTrack>> aTracks,
3941 AudioContextOperation aOperation,
3942 MozPromiseHolder<AudioContextOperationPromise>&& aHolder)
3943 : ControlMessage(aDestinationTrack),
3944 mTracks(std::move(aTracks)),
3945 mAudioContextOperation(aOperation),
3946 mHolder(std::move(aHolder)) {}
3947 void Run() override {
3948 TRACE_COMMENT("MTG::ApplyAudioContextOperationImpl ControlMessage",AutoTracer trace(gAudioCallbackTraceLogger, "MTG::ApplyAudioContextOperationImpl ControlMessage"
, AutoTracer::DurationType::ELAPSED_TIME, kAudioContextOptionsStrings
[static_cast<uint8_t>( mAudioContextOperation)]);
3949 kAudioContextOptionsStrings[static_cast<uint8_t>(AutoTracer trace(gAudioCallbackTraceLogger, "MTG::ApplyAudioContextOperationImpl ControlMessage"
, AutoTracer::DurationType::ELAPSED_TIME, kAudioContextOptionsStrings
[static_cast<uint8_t>( mAudioContextOperation)]);
3950 mAudioContextOperation)])AutoTracer trace(gAudioCallbackTraceLogger, "MTG::ApplyAudioContextOperationImpl ControlMessage"
, AutoTracer::DurationType::ELAPSED_TIME, kAudioContextOptionsStrings
[static_cast<uint8_t>( mAudioContextOperation)]);
;
3951 mTrack->GraphImpl()->ApplyAudioContextOperationImpl(this);
3952 }
3953 void RunDuringShutdown() override {
3954 MOZ_ASSERT(mAudioContextOperation == AudioContextOperation::Close,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAudioContextOperation == AudioContextOperation::Close
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mAudioContextOperation == AudioContextOperation::Close
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mAudioContextOperation == AudioContextOperation::Close" " ("
"We should be reviving the graph?" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAudioContextOperation == AudioContextOperation::Close"
") (" "We should be reviving the graph?" ")"); do { MOZ_CrashSequence
(__null, 3955); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3955 "We should be reviving the graph?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mAudioContextOperation == AudioContextOperation::Close
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mAudioContextOperation == AudioContextOperation::Close
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mAudioContextOperation == AudioContextOperation::Close" " ("
"We should be reviving the graph?" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 3955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mAudioContextOperation == AudioContextOperation::Close"
") (" "We should be reviving the graph?" ")"); do { MOZ_CrashSequence
(__null, 3955); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3956 mHolder.Reject(false, __func__);
3957 }
3958
3959 nsTArray<RefPtr<MediaTrack>> mTracks;
3960 AudioContextOperation mAudioContextOperation;
3961 MozPromiseHolder<AudioContextOperationPromise> mHolder;
3962};
3963
3964void MediaTrackGraphImpl::ApplyAudioContextOperationImpl(
3965 AudioContextOperationControlMessage* aMessage) {
3966 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 3966);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 3966); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3967 // Initialize state to zero. This silences a GCC warning about uninitialized
3968 // values, because although the switch below initializes state for all valid
3969 // enum values, the actual value could be any integer that fits in the enum.
3970 AudioContextState state{0};
3971 switch (aMessage->mAudioContextOperation) {
3972 // Suspend and Close operations may be performed immediately because no
3973 // specific kind of GraphDriver is required. CheckDriver() will schedule
3974 // a change to a SystemCallbackDriver if all tracks are suspended.
3975 case AudioContextOperation::Suspend:
3976 state = AudioContextState::Suspended;
3977 break;
3978 case AudioContextOperation::Close:
3979 state = AudioContextState::Closed;
3980 break;
3981 case AudioContextOperation::Resume:
3982 // Resume operations require an AudioCallbackDriver. CheckDriver() will
3983 // schedule an AudioCallbackDriver if necessary and process pending
3984 // operations if and when an AudioCallbackDriver is running.
3985 mPendingResumeOperations.EmplaceBack(aMessage);
3986 return;
3987 }
3988 // First resolve any pending Resume promises for the same AudioContext so as
3989 // to resolve its associated promises in the same order as they were
3990 // created. These Resume operations are considered complete and immediately
3991 // canceled by the Suspend or Close.
3992 MediaTrack* destinationTrack = aMessage->GetTrack();
3993 bool shrinking = false;
3994 auto moveDest = mPendingResumeOperations.begin();
3995 for (PendingResumeOperation& op : mPendingResumeOperations) {
3996 if (op.DestinationTrack() == destinationTrack) {
3997 op.Apply(this);
3998 shrinking = true;
3999 continue;
4000 }
4001 if (shrinking) { // Fill-in gaps in the array.
4002 *moveDest = std::move(op);
4003 }
4004 ++moveDest;
4005 }
4006 mPendingResumeOperations.TruncateLength(moveDest -
4007 mPendingResumeOperations.begin());
4008
4009 for (MediaTrack* track : aMessage->mTracks) {
4010 track->IncrementSuspendCount();
4011 }
4012 // Resolve after main thread state is up to date with completed processing.
4013 DispatchToMainThreadStableState(NS_NewRunnableFunction(
4014 "MediaTrackGraphImpl::ApplyAudioContextOperationImpl",
4015 [holder = std::move(aMessage->mHolder), state]() mutable {
4016 holder.Resolve(state, __func__);
4017 }));
4018}
4019
4020MediaTrackGraphImpl::PendingResumeOperation::PendingResumeOperation(
4021 AudioContextOperationControlMessage* aMessage)
4022 : mDestinationTrack(aMessage->GetTrack()),
4023 mTracks(std::move(aMessage->mTracks)),
4024 mHolder(std::move(aMessage->mHolder)) {
4025 MOZ_ASSERT(aMessage->mAudioContextOperation == AudioContextOperation::Resume)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage->mAudioContextOperation == AudioContextOperation
::Resume)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aMessage->mAudioContextOperation ==
AudioContextOperation::Resume))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aMessage->mAudioContextOperation == AudioContextOperation::Resume"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4025);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage->mAudioContextOperation == AudioContextOperation::Resume"
")"); do { MOZ_CrashSequence(__null, 4025); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4026}
4027
4028void MediaTrackGraphImpl::PendingResumeOperation::Apply(
4029 MediaTrackGraphImpl* aGraph) {
4030 MOZ_ASSERT(aGraph->OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGraph->OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGraph->OnGraphThread()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aGraph->OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4030);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGraph->OnGraphThread()"
")"); do { MOZ_CrashSequence(__null, 4030); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4031 for (MediaTrack* track : mTracks) {
4032 track->DecrementSuspendCount();
4033 }
4034 // The graph is provided through the parameter so that it is available even
4035 // when the track is destroyed.
4036 aGraph->DispatchToMainThreadStableState(NS_NewRunnableFunction(
4037 "PendingResumeOperation::Apply", [holder = std::move(mHolder)]() mutable {
4038 holder.Resolve(AudioContextState::Running, __func__);
4039 }));
4040}
4041
4042void MediaTrackGraphImpl::PendingResumeOperation::Abort() {
4043 // The graph is shutting down before the operation completed.
4044 MOZ_ASSERT(!mDestinationTrack->GraphImpl() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDestinationTrack->GraphImpl() || mDestinationTrack
->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl
::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDestinationTrack->GraphImpl
() || mDestinationTrack->GraphImpl()->LifecycleStateRef
() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mDestinationTrack->GraphImpl() || mDestinationTrack->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4046);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDestinationTrack->GraphImpl() || mDestinationTrack->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN"
")"); do { MOZ_CrashSequence(__null, 4046); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4045 mDestinationTrack->GraphImpl()->LifecycleStateRef() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDestinationTrack->GraphImpl() || mDestinationTrack
->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl
::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDestinationTrack->GraphImpl
() || mDestinationTrack->GraphImpl()->LifecycleStateRef
() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mDestinationTrack->GraphImpl() || mDestinationTrack->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4046);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDestinationTrack->GraphImpl() || mDestinationTrack->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN"
")"); do { MOZ_CrashSequence(__null, 4046); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4046 MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDestinationTrack->GraphImpl() || mDestinationTrack
->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl
::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDestinationTrack->GraphImpl
() || mDestinationTrack->GraphImpl()->LifecycleStateRef
() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mDestinationTrack->GraphImpl() || mDestinationTrack->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4046);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDestinationTrack->GraphImpl() || mDestinationTrack->GraphImpl()->LifecycleStateRef() == MediaTrackGraphImpl::LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN"
")"); do { MOZ_CrashSequence(__null, 4046); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4047 mHolder.Reject(false, __func__);
4048}
4049
4050auto MediaTrackGraph::ApplyAudioContextOperation(
4051 MediaTrack* aDestinationTrack, nsTArray<RefPtr<MediaTrack>> aTracks,
4052 AudioContextOperation aOperation) -> RefPtr<AudioContextOperationPromise> {
4053 MozPromiseHolder<AudioContextOperationPromise> holder;
4054 RefPtr<AudioContextOperationPromise> p = holder.Ensure(__func__);
4055 MediaTrackGraphImpl* graphImpl = static_cast<MediaTrackGraphImpl*>(this);
4056 graphImpl->AppendMessage(MakeUnique<AudioContextOperationControlMessage>(
4057 aDestinationTrack, std::move(aTracks), aOperation, std::move(holder)));
4058 return p;
4059}
4060
4061uint32_t MediaTrackGraphImpl::PrimaryOutputChannelCount() const {
4062 MOZ_ASSERT(!mOutputDevices[0].mReceiver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mOutputDevices[0].mReceiver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mOutputDevices[0].mReceiver
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mOutputDevices[0].mReceiver", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 4062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mOutputDevices[0].mReceiver"
")"); do { MOZ_CrashSequence(__null, 4062); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4063 return AudioOutputChannelCount(mOutputDevices[0]);
4064}
4065
4066uint32_t MediaTrackGraphImpl::AudioOutputChannelCount(
4067 const OutputDeviceEntry& aDevice) const {
4068 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4068);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 4068); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4069 // The audio output channel count for a graph is the maximum of the output
4070 // channel count of all the tracks with outputs to this device, or the max
4071 // audio output channel count the machine can do, whichever is smaller.
4072 uint32_t channelCount = 0;
4073 for (const auto& output : aDevice.mTrackOutputs) {
4074 channelCount = std::max(channelCount, output.mTrack->NumberOfChannels());
4075 }
4076 channelCount = std::min(channelCount, mMaxOutputChannelCount);
4077 if (channelCount) {
4078 return channelCount;
4079 } else {
4080 // null aDevice.mReceiver indicates the primary graph output device.
4081 if (!aDevice.mReceiver && CurrentDriver()->AsAudioCallbackDriver()) {
4082 return CurrentDriver()->AsAudioCallbackDriver()->OutputChannelCount();
4083 }
4084 return 2;
4085 }
4086}
4087
4088double MediaTrackGraph::AudioOutputLatency() {
4089 return static_cast<MediaTrackGraphImpl*>(this)->AudioOutputLatency();
4090}
4091
4092double MediaTrackGraphImpl::AudioOutputLatency() {
4093 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4093);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4093); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4094 if (mAudioOutputLatency != 0.0) {
4095 return mAudioOutputLatency;
4096 }
4097 MonitorAutoLock lock(mMonitor);
4098 if (CurrentDriver()->AsAudioCallbackDriver()) {
4099 mAudioOutputLatency = CurrentDriver()
4100 ->AsAudioCallbackDriver()
4101 ->AudioOutputLatency()
4102 .ToSeconds();
4103 } else {
4104 // Failure mode: return 0.0 if running on a normal thread.
4105 mAudioOutputLatency = 0.0;
4106 }
4107
4108 return mAudioOutputLatency;
4109}
4110
4111bool MediaTrackGraph::OutputForAECMightDrift() {
4112 return static_cast<MediaTrackGraphImpl*>(this)->OutputForAECMightDrift();
4113}
4114bool MediaTrackGraph::IsNonRealtime() const {
4115 return !static_cast<const MediaTrackGraphImpl*>(this)->mRealtime;
4116}
4117
4118void MediaTrackGraph::StartNonRealtimeProcessing(uint32_t aTicksToProcess) {
4119 MOZ_ASSERT(NS_IsMainThread(), "main thread only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "main thread only" ")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 4119); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "main thread only" ")"); do { MOZ_CrashSequence(__null
, 4119); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4120
4121 MediaTrackGraphImpl* graph = static_cast<MediaTrackGraphImpl*>(this);
4122 NS_ASSERTION(!graph->mRealtime, "non-realtime only")do { if (!(!graph->mRealtime)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "non-realtime only", "!graph->mRealtime", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 4122); MOZ_PretendNoReturn(); } } while (0)
;
4123
4124 class Message : public ControlMessage {
4125 public:
4126 explicit Message(MediaTrackGraphImpl* aGraph, uint32_t aTicksToProcess)
4127 : ControlMessage(nullptr),
4128 mGraph(aGraph),
4129 mTicksToProcess(aTicksToProcess) {}
4130 void Run() override {
4131 TRACE("MTG::StartNonRealtimeProcessing ControlMessage")AutoTracer trace(gAudioCallbackTraceLogger, "MTG::StartNonRealtimeProcessing ControlMessage"
);
;
4132 MOZ_ASSERT(mGraph->mEndTime == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGraph->mEndTime == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGraph->mEndTime == 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mGraph->mEndTime == 0"
" (" "StartNonRealtimeProcessing should be called only once"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4133
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGraph->mEndTime == 0"
") (" "StartNonRealtimeProcessing should be called only once"
")"); do { MOZ_CrashSequence(__null, 4133); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4133 "StartNonRealtimeProcessing should be called only once")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGraph->mEndTime == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGraph->mEndTime == 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mGraph->mEndTime == 0"
" (" "StartNonRealtimeProcessing should be called only once"
")", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4133
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGraph->mEndTime == 0"
") (" "StartNonRealtimeProcessing should be called only once"
")"); do { MOZ_CrashSequence(__null, 4133); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4134 mGraph->mEndTime = mGraph->RoundUpToEndOfAudioBlock(
4135 mGraph->mStateComputedTime + mTicksToProcess);
4136 }
4137 // The graph owns this message.
4138 MediaTrackGraphImpl* MOZ_NON_OWNING_REF mGraph;
4139 uint32_t mTicksToProcess;
4140 };
4141
4142 graph->AppendMessage(MakeUnique<Message>(graph, aTicksToProcess));
4143}
4144
4145void MediaTrackGraphImpl::InterruptJS() {
4146 MonitorAutoLock lock(mMonitor);
4147 mInterruptJSCalled = true;
4148 if (mJSContext) {
4149 JS_RequestInterruptCallback(mJSContext);
4150 }
4151}
4152
4153static bool InterruptCallback(JSContext* aCx) {
4154 // Interrupt future calls also.
4155 JS_RequestInterruptCallback(aCx);
4156 // Stop execution.
4157 return false;
4158}
4159
4160void MediaTrackGraph::NotifyJSContext(JSContext* aCx) {
4161 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4161);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 4161); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4162 MOZ_ASSERT(aCx)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCx)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aCx))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aCx", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 4162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCx" ")"); do
{ MOZ_CrashSequence(__null, 4162); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4163
4164 auto* impl = static_cast<MediaTrackGraphImpl*>(this);
4165 MonitorAutoLock lock(impl->mMonitor);
4166 if (impl->mJSContext) {
4167 MOZ_ASSERT(impl->mJSContext == aCx)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(impl->mJSContext == aCx)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(impl->mJSContext == aCx))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("impl->mJSContext == aCx"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4167);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "impl->mJSContext == aCx"
")"); do { MOZ_CrashSequence(__null, 4167); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4168 return;
4169 }
4170 JS_AddInterruptCallback(aCx, InterruptCallback);
4171 impl->mJSContext = aCx;
4172 if (impl->mInterruptJSCalled) {
4173 JS_RequestInterruptCallback(aCx);
4174 }
4175}
4176
4177void ProcessedMediaTrack::AddInput(MediaInputPort* aPort) {
4178 MediaTrack* t = aPort->GetSource();
4179 if (!t->IsSuspended()) {
4180 mInputs.AppendElement(aPort);
4181 } else {
4182 mSuspendedInputs.AppendElement(aPort);
4183 }
4184 GraphImpl()->SetTrackOrderDirty();
4185}
4186
4187void ProcessedMediaTrack::InputSuspended(MediaInputPort* aPort) {
4188 GraphImpl()->AssertOnGraphThreadOrNotRunning();
4189 mInputs.RemoveElement(aPort);
4190 mSuspendedInputs.AppendElement(aPort);
4191 GraphImpl()->SetTrackOrderDirty();
4192}
4193
4194void ProcessedMediaTrack::InputResumed(MediaInputPort* aPort) {
4195 GraphImpl()->AssertOnGraphThreadOrNotRunning();
4196 mSuspendedInputs.RemoveElement(aPort);
4197 mInputs.AppendElement(aPort);
4198 GraphImpl()->SetTrackOrderDirty();
4199}
4200
4201void MediaTrackGraphImpl::SwitchAtNextIteration(GraphDriver* aNextDriver) {
4202 MOZ_ASSERT(OnGraphThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnGraphThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4202);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThread()" ")"
); do { MOZ_CrashSequence(__null, 4202); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4203 LOG(LogLevel::Debug, ("%p: Switching to new driver: %p", this, aNextDriver));
4204 if (GraphDriver* nextDriver = NextDriver()) {
4205 if (nextDriver != CurrentDriver()) {
4206 LOG(LogLevel::Debug,
4207 ("%p: Discarding previous next driver: %p", this, nextDriver));
4208 }
4209 }
4210 mNextDriver = aNextDriver;
4211}
4212
4213void MediaTrackGraph::RegisterCaptureTrackForWindow(
4214 uint64_t aWindowId, ProcessedMediaTrack* aCaptureTrack) {
4215 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4215);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4215); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4216 MediaTrackGraphImpl* graphImpl = static_cast<MediaTrackGraphImpl*>(this);
4217 graphImpl->RegisterCaptureTrackForWindow(aWindowId, aCaptureTrack);
4218}
4219
4220void MediaTrackGraphImpl::RegisterCaptureTrackForWindow(
4221 uint64_t aWindowId, ProcessedMediaTrack* aCaptureTrack) {
4222 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4222);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4222); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4223 WindowAndTrack winAndTrack;
4224 winAndTrack.mWindowId = aWindowId;
4225 winAndTrack.mCaptureTrackSink = aCaptureTrack;
4226 mWindowCaptureTracks.AppendElement(winAndTrack);
4227}
4228
4229void MediaTrackGraph::UnregisterCaptureTrackForWindow(uint64_t aWindowId) {
4230 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4230);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4230); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4231 MediaTrackGraphImpl* graphImpl = static_cast<MediaTrackGraphImpl*>(this);
4232 graphImpl->UnregisterCaptureTrackForWindow(aWindowId);
4233}
4234
4235void MediaTrackGraphImpl::UnregisterCaptureTrackForWindow(uint64_t aWindowId) {
4236 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4236);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4236); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4237 mWindowCaptureTracks.RemoveElementsBy(
4238 [aWindowId](const auto& track) { return track.mWindowId == aWindowId; });
4239}
4240
4241already_AddRefed<MediaInputPort> MediaTrackGraph::ConnectToCaptureTrack(
4242 uint64_t aWindowId, MediaTrack* aMediaTrack) {
4243 return aMediaTrack->GraphImpl()->ConnectToCaptureTrack(aWindowId,
4244 aMediaTrack);
4245}
4246
4247already_AddRefed<MediaInputPort> MediaTrackGraphImpl::ConnectToCaptureTrack(
4248 uint64_t aWindowId, MediaTrack* aMediaTrack) {
4249 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4249);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4249); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4250 for (uint32_t i = 0; i < mWindowCaptureTracks.Length(); i++) {
4251 if (mWindowCaptureTracks[i].mWindowId == aWindowId) {
4252 ProcessedMediaTrack* sink = mWindowCaptureTracks[i].mCaptureTrackSink;
4253 return sink->AllocateInputPort(aMediaTrack);
4254 }
4255 }
4256 return nullptr;
4257}
4258
4259void MediaTrackGraph::DispatchToMainThreadStableState(
4260 already_AddRefed<nsIRunnable> aRunnable) {
4261 AssertOnGraphThreadOrNotRunning();
4262 static_cast<MediaTrackGraphImpl*>(this)
4263 ->mPendingUpdateRunnables.AppendElement(std::move(aRunnable));
4264}
4265
4266Watchable<mozilla::GraphTime>& MediaTrackGraphImpl::CurrentTime() {
4267 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4267);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4267); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4268 return mMainThreadGraphTime;
4269}
4270
4271GraphTime MediaTrackGraph::ProcessedTime() const {
4272 AssertOnGraphThreadOrNotRunning();
4273 return static_cast<const MediaTrackGraphImpl*>(this)->mProcessedTime;
4274}
4275
4276void* MediaTrackGraph::CurrentDriver() const {
4277 AssertOnGraphThreadOrNotRunning();
4278 return static_cast<const MediaTrackGraphImpl*>(this)->mDriver;
4279}
4280
4281uint32_t MediaTrackGraphImpl::AudioInputChannelCount(
4282 CubebUtils::AudioDeviceID aID) {
4283 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4283);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()"
")"); do { MOZ_CrashSequence(__null, 4283); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4284 DeviceInputTrack* t =
4285 mDeviceInputTrackManagerGraphThread.GetDeviceInputTrack(aID);
4286 return t ? t->MaxRequestedInputChannels() : 0;
4287}
4288
4289AudioInputType MediaTrackGraphImpl::AudioInputDevicePreference(
4290 CubebUtils::AudioDeviceID aID) {
4291 MOZ_ASSERT(OnGraphThreadOrNotRunning())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnGraphThreadOrNotRunning())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnGraphThreadOrNotRunning())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnGraphThreadOrNotRunning()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4291);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnGraphThreadOrNotRunning()"
")"); do { MOZ_CrashSequence(__null, 4291); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4292 DeviceInputTrack* t =
4293 mDeviceInputTrackManagerGraphThread.GetDeviceInputTrack(aID);
4294 return t && t->HasVoiceInput() ? AudioInputType::Voice
4295 : AudioInputType::Unknown;
4296}
4297
4298void MediaTrackGraphImpl::SetNewNativeInput() {
4299 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4299);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 4299); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4300 MOZ_ASSERT(!mDeviceInputTrackManagerMainThread.GetNativeInputTrack())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDeviceInputTrackManagerMainThread.GetNativeInputTrack
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mDeviceInputTrackManagerMainThread.GetNativeInputTrack
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mDeviceInputTrackManagerMainThread.GetNativeInputTrack()",
"/root/firefox-clang/dom/media/MediaTrackGraph.cpp", 4300); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!mDeviceInputTrackManagerMainThread.GetNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 4300); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4301
4302 LOG(LogLevel::Debug, ("%p SetNewNativeInput", this));
4303
4304 NonNativeInputTrack* track =
4305 mDeviceInputTrackManagerMainThread.GetFirstNonNativeInputTrack();
4306 if (!track) {
4307 LOG(LogLevel::Debug, ("%p No other devices opened. Do nothing", this));
4308 return;
4309 }
4310
4311 const CubebUtils::AudioDeviceID deviceId = track->mDeviceId;
4312 const PrincipalHandle principal = track->mPrincipalHandle;
4313
4314 LOG(LogLevel::Debug,
4315 ("%p Select device %p as the new native input device", this, deviceId));
4316
4317 struct TrackListener {
4318 DeviceInputConsumerTrack* track;
4319 // Keep its reference so it won't be dropped when after
4320 // DisconnectDeviceInput().
4321 RefPtr<AudioDataListener> listener;
4322 };
4323 nsTArray<TrackListener> pairs;
4324
4325 for (const auto& t : track->GetConsumerTracks()) {
4326 pairs.AppendElement(
4327 TrackListener{t.get(), t->GetAudioDataListener().get()});
4328 }
4329
4330 for (TrackListener& pair : pairs) {
4331 pair.track->DisconnectDeviceInput();
4332 }
4333
4334 for (TrackListener& pair : pairs) {
4335 pair.track->ConnectDeviceInput(deviceId, pair.listener.get(), principal);
4336 LOG(LogLevel::Debug,
4337 ("%p: Reinitialize AudioProcessingTrack %p for device %p", this,
4338 pair.track, deviceId));
4339 }
4340
4341 LOG(LogLevel::Debug,
4342 ("%p Native input device is set to device %p now", this, deviceId));
4343
4344 MOZ_ASSERT(mDeviceInputTrackManagerMainThread.GetNativeInputTrack())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeviceInputTrackManagerMainThread.GetNativeInputTrack
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mDeviceInputTrackManagerMainThread.GetNativeInputTrack
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeviceInputTrackManagerMainThread.GetNativeInputTrack()", "/root/firefox-clang/dom/media/MediaTrackGraph.cpp"
, 4344); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeviceInputTrackManagerMainThread.GetNativeInputTrack()"
")"); do { MOZ_CrashSequence(__null, 4344); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4345}
4346
4347// nsIThreadObserver methods
4348
4349NS_IMETHODIMPnsresult
4350MediaTrackGraphImpl::OnDispatchedEvent() {
4351 MonitorAutoLock lock(mMonitor);
4352 GraphDriver* driver = CurrentDriver();
4353 if (!driver) {
4354 // The ipc::BackgroundChild started by `UniqueMessagePortId()` destruction
4355 // can queue messages on the thread used for the graph after graph
4356 // shutdown. See bug 1955768.
4357 //
4358 // Other threads may have already taken a reference to this graph as the
4359 // observer, so clearing the thread's observer (on the graph thread) would
4360 // not be effective to prevent this callback from being invoked.
4361 // https://searchfox.org/mozilla-central/rev/8b52ebe3cddf0e63bb42e8b51618bc3ab8dcb12d/xpcom/threads/ThreadEventQueue.cpp#113,135,139
4362 return NS_OK;
4363 }
4364 driver->EnsureNextIteration();
4365 return NS_OK;
4366}
4367
4368NS_IMETHODIMPnsresult
4369MediaTrackGraphImpl::OnProcessNextEvent(nsIThreadInternal*, bool) {
4370 return NS_OK;
4371}
4372
4373NS_IMETHODIMPnsresult
4374MediaTrackGraphImpl::AfterProcessNextEvent(nsIThreadInternal*, bool) {
4375 return NS_OK;
4376}
4377} // namespace mozilla