| File: | root/firefox-clang/dom/media/MediaTrackGraph.cpp |
| Warning: | line 480, column 5 Value stored to 'needInputProcessingParamUpdate' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | |
| 51 | using namespace mozilla::layers; |
| 52 | using namespace mozilla::dom; |
| 53 | using namespace mozilla::gfx; |
| 54 | using namespace mozilla::media; |
| 55 | |
| 56 | namespace mozilla { |
| 57 | |
| 58 | using AudioDeviceID = CubebUtils::AudioDeviceID; |
| 59 | using IsInShutdown = MediaTrack::IsInShutdown; |
| 60 | |
| 61 | LazyLogModule 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 | |
| 67 | NativeInputTrack* DeviceInputTrackManager::GetNativeInputTrack() { |
| 68 | return mNativeInputTrack.get(); |
| 69 | } |
| 70 | |
| 71 | DeviceInputTrack* 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 | |
| 84 | NonNativeInputTrack* DeviceInputTrackManager::GetFirstNonNativeInputTrack() { |
| 85 | if (mNonNativeInputTracks.IsEmpty()) { |
| 86 | return nullptr; |
| 87 | } |
| 88 | return mNonNativeInputTracks[0].get(); |
| 89 | } |
| 90 | |
| 91 | void 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 | |
| 111 | void 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 | |
| 129 | struct 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). |
| 139 | MOZ_IMPLICIT MediaTrackGraphImpl::operator MediaTrackGraphImpl::Lookup() const { |
| 140 | return {mWindowID, mSampleRate, PrimaryOutputDeviceID()}; |
| 141 | } |
| 142 | |
| 143 | namespace { |
| 144 | struct 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. |
| 157 | using GraphHashSet = |
| 158 | HashSet<MediaTrackGraphImpl*, GraphHasher, InfallibleAllocPolicy>; |
| 159 | GraphHashSet* 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 | |
| 166 | static 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 | |
| 187 | MediaTrackGraphImpl::~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 | |
| 195 | void 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 | |
| 213 | void 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 | |
| 244 | TrackTime 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 | |
| 253 | void 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 | |
| 293 | template <typename C, typename Chunk> |
| 294 | void 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 | |
| 327 | void 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 | |
| 347 | GraphTime 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 | |
| 373 | namespace { |
| 374 | // Value of mCycleMarker for unvisited tracks in cycle detection. |
| 375 | const uint32_t NOT_VISITED = UINT32_MAX(4294967295U); |
| 376 | // Value of mCycleMarker for ordered tracks in muted cycles. |
| 377 | const uint32_t IN_MUTED_CYCLE = 1; |
| 378 | } // namespace |
| 379 | |
| 380 | bool 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 | |
| 405 | void 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 | |
| 489 | void 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 | |
| 676 | TrackTime 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 | |
| 761 | DeviceInputTrack* 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 | |
| 768 | NativeInputTrack* 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 | |
| 774 | void 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 | |
| 806 | void 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 | |
| 830 | void 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 | |
| 871 | void 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 | |
| 881 | void 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). |
| 915 | void 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 | |
| 929 | void MediaTrackGraphImpl::NotifyInputStopped() { |
| 930 | NativeInputTrack* native = |
| 931 | mDeviceInputTrackManagerGraphThread.GetNativeInputTrack(); |
| 932 | if (!native) { |
| 933 | return; |
| 934 | } |
| 935 | native->NotifyInputStopped(this); |
| 936 | } |
| 937 | |
| 938 | void 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 | |
| 955 | void 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 | |
| 979 | void 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 | |
| 989 | void 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 | |
| 994 | void 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 | |
| 1074 | static const char* GetAudioInputTypeString(const AudioInputType& aType) { |
| 1075 | return aType == AudioInputType::Voice ? "Voice" : "Unknown"; |
| 1076 | } |
| 1077 | |
| 1078 | void 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 | |
| 1084 | void 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 | |
| 1171 | bool 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 | |
| 1178 | bool 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 | |
| 1187 | bool 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 | |
| 1192 | bool 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 | |
| 1210 | void 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 | |
| 1269 | GraphTime MediaTrackGraphImpl::RoundUpToEndOfAudioBlock(GraphTime aTime) { |
| 1270 | if (aTime % WEBAUDIO_BLOCK_SIZE == 0) { |
| 1271 | return aTime; |
| 1272 | } |
| 1273 | return RoundUpToNextAudioBlock(aTime); |
| 1274 | } |
| 1275 | |
| 1276 | GraphTime 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 | |
| 1283 | void 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 | |
| 1313 | void 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 | |
| 1326 | void 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 | |
| 1344 | void 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 | |
| 1438 | void 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 | |
| 1490 | void 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 | |
| 1604 | bool 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 | |
| 1631 | auto 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 | |
| 1643 | auto 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 | |
| 1720 | void 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 | |
| 1734 | void 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 | |
| 1768 | NS_IMETHODIMPnsresult |
| 1769 | MediaTrackGraphImpl::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 | |
| 1778 | static 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 | |
| 1795 | NS_IMETHODIMPnsresult |
| 1796 | MediaTrackGraphImpl::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 | |
| 1812 | bool 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 | |
| 1850 | void MediaTrackGraphImpl::RemoveShutdownBlocker() { |
| 1851 | if (!mShutdownBlocker) { |
| 1852 | return; |
| 1853 | } |
| 1854 | media::MustGetShutdownBarrier()->RemoveBlocker(mShutdownBlocker); |
| 1855 | mShutdownBlocker = nullptr; |
| 1856 | } |
| 1857 | |
| 1858 | NS_IMETHODIMPnsresult |
| 1859 | MediaTrackGraphImpl::GetName(nsACString& aName) { |
| 1860 | aName.AssignLiteral("MediaTrackGraphImpl"); |
| 1861 | return NS_OK; |
| 1862 | } |
| 1863 | |
| 1864 | namespace { |
| 1865 | |
| 1866 | class 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 | |
| 1965 | class 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 | */ |
| 1988 | class 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 | |
| 2005 | void 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 | |
| 2141 | void 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 | |
| 2151 | void 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 | |
| 2162 | void 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 | |
| 2176 | void 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 | |
| 2207 | void MediaTrackGraphImpl::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable) { |
| 2208 | mMainThread->Dispatch(std::move(aRunnable)); |
| 2209 | } |
| 2210 | |
| 2211 | MediaTrack::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 | |
| 2232 | MediaTrack::~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 | |
| 2239 | size_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 | |
| 2256 | size_t MediaTrack::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
| 2257 | return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
| 2258 | } |
| 2259 | |
| 2260 | void 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 | |
| 2277 | void 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 | |
| 2295 | void ProcessedMediaTrack::DecrementSuspendCount() { |
| 2296 | mCycleMarker = NOT_VISITED; |
| 2297 | MediaTrack::DecrementSuspendCount(); |
| 2298 | } |
| 2299 | |
| 2300 | MediaTrackGraphImpl* MediaTrack::GraphImpl() { |
| 2301 | return static_cast<MediaTrackGraphImpl*>(mGraph); |
| 2302 | } |
| 2303 | |
| 2304 | const MediaTrackGraphImpl* MediaTrack::GraphImpl() const { |
| 2305 | return static_cast<MediaTrackGraphImpl*>(mGraph); |
| 2306 | } |
| 2307 | |
| 2308 | void 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 | |
| 2314 | void MediaTrack::SetGraphImpl(MediaTrackGraph* aGraph) { |
| 2315 | MediaTrackGraphImpl* graph = static_cast<MediaTrackGraphImpl*>(aGraph); |
| 2316 | SetGraphImpl(graph); |
| 2317 | } |
| 2318 | |
| 2319 | TrackTime 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 | |
| 2326 | GraphTime 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 | |
| 2333 | TrackTime MediaTrack::GraphTimeToTrackTimeWithBlocking(GraphTime aTime) const { |
| 2334 | return GraphImpl()->GraphTimeToTrackTimeWithBlocking(this, aTime); |
| 2335 | } |
| 2336 | |
| 2337 | void 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 | |
| 2352 | void 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 | |
| 2362 | void 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 | |
| 2387 | uint64_t MediaTrack::GetWindowId() const { return GraphImpl()->mWindowID; } |
| 2388 | |
| 2389 | TrackTime MediaTrack::GetEnd() const { |
| 2390 | return mSegment ? mSegment->GetDuration() : 0; |
| 2391 | } |
| 2392 | |
| 2393 | void 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 | |
| 2404 | void 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 | |
| 2414 | void 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 | |
| 2427 | void MediaTrack::SetAudioOutputVolume(void* aKey, float aVolume) { |
| 2428 | if (mMainThreadDestroyed) { |
| 2429 | return; |
| 2430 | } |
| 2431 | GraphImpl()->SetAudioOutputVolume(this, aKey, aVolume); |
| 2432 | } |
| 2433 | |
| 2434 | void 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 | |
| 2443 | void 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 | |
| 2457 | void 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 | |
| 2471 | void 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 | |
| 2515 | void 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 | |
| 2553 | void 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 | |
| 2567 | void 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 | |
| 2579 | void 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 | |
| 2591 | void 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 | |
| 2607 | void 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 | |
| 2619 | void 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 | |
| 2629 | RefPtr<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 | |
| 2649 | void 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 | |
| 2658 | void 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 | |
| 2669 | void MediaTrack::RemoveDirectListenerImpl(DirectMediaTrackListener* aListener) { |
| 2670 | // Base implementation, the listener was never added so nothing to do. |
| 2671 | } |
| 2672 | |
| 2673 | void 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 | |
| 2687 | void 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 | |
| 2709 | void 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 | |
| 2720 | void 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 | |
| 2730 | void MediaTrack::ApplyTrackDisabling(MediaSegment* aSegment, |
| 2731 | MediaSegment* aRawSegment) { |
| 2732 | AssertOnGraphThread(); |
| 2733 | mozilla::ApplyTrackDisabling(mDisabledMode, aSegment, aRawSegment); |
| 2734 | } |
| 2735 | |
| 2736 | void 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 | |
| 2771 | void 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 | |
| 2792 | void 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 | |
| 2810 | void 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 | |
| 2816 | void MediaTrack::RunMessageAfterProcessing( |
| 2817 | UniquePtr<ControlMessageInterface> aMessage) { |
| 2818 | AssertOnGraphThread(); |
| 2819 | GraphImpl()->RunMessageAfterProcessing(std::move(aMessage)); |
| 2820 | } |
| 2821 | |
| 2822 | SourceMediaTrack::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 | |
| 2838 | void 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 | |
| 2853 | void 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 | |
| 2878 | bool 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 | */ |
| 2919 | static 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 | |
| 2976 | void 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 | |
| 3011 | void 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 | |
| 3023 | void SourceMediaTrack::AdvanceTimeVaryingValuesToCurrentTime( |
| 3024 | GraphTime aCurrentTime, GraphTime aBlockedTime) { |
| 3025 | MutexAutoLock lock(mMutex); |
| 3026 | MediaTrack::AdvanceTimeVaryingValuesToCurrentTime(aCurrentTime, aBlockedTime); |
| 3027 | } |
| 3028 | |
| 3029 | void 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 | |
| 3041 | TrackTime 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 | |
| 3078 | TrackTime 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 | |
| 3090 | void 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 | |
| 3101 | void 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 | |
| 3165 | void 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 | |
| 3181 | void 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 | |
| 3196 | void 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 | |
| 3221 | uint32_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 | |
| 3230 | void 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 | |
| 3240 | void SourceMediaTrack::SetVolume(float aVolume) { |
| 3241 | MutexAutoLock lock(mMutex); |
| 3242 | mVolume = aVolume; |
| 3243 | } |
| 3244 | |
| 3245 | float SourceMediaTrack::GetVolumeLocked() { |
| 3246 | mMutex.AssertCurrentThreadOwns(); |
| 3247 | return mVolume; |
| 3248 | } |
| 3249 | |
| 3250 | SourceMediaTrack::~SourceMediaTrack() = default; |
| 3251 | |
| 3252 | void 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 | |
| 3265 | void 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 | |
| 3282 | MediaTrack* MediaInputPort::GetSource() const { |
| 3283 | mGraph->AssertOnGraphThreadOrNotRunning(); |
| 3284 | return mSource; |
| 3285 | } |
| 3286 | |
| 3287 | ProcessedMediaTrack* MediaInputPort::GetDestination() const { |
| 3288 | mGraph->AssertOnGraphThreadOrNotRunning(); |
| 3289 | return mDest; |
| 3290 | } |
| 3291 | |
| 3292 | MediaInputPort::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 | |
| 3313 | void MediaInputPort::Suspended() { |
| 3314 | mGraph->AssertOnGraphThreadOrNotRunning(); |
| 3315 | mDest->InputSuspended(this); |
| 3316 | } |
| 3317 | |
| 3318 | void MediaInputPort::Resumed() { |
| 3319 | mGraph->AssertOnGraphThreadOrNotRunning(); |
| 3320 | mDest->InputResumed(this); |
| 3321 | } |
| 3322 | |
| 3323 | void 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 | |
| 3345 | MediaTrackGraphImpl* MediaInputPort::GraphImpl() const { |
| 3346 | mGraph->AssertOnGraphThreadOrNotRunning(); |
| 3347 | return mGraph; |
| 3348 | } |
| 3349 | |
| 3350 | MediaTrackGraph* MediaInputPort::Graph() const { |
| 3351 | mGraph->AssertOnGraphThreadOrNotRunning(); |
| 3352 | return mGraph; |
| 3353 | } |
| 3354 | |
| 3355 | void 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 | |
| 3362 | already_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 | |
| 3399 | void 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 | |
| 3416 | void 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 | |
| 3432 | MediaTrackGraphImpl::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 | |
| 3460 | void 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 |
| 3520 | bool MediaTrackGraphImpl::InDriverIteration(const GraphDriver* aDriver) const { |
| 3521 | return aDriver->OnThread() || |
| 3522 | (mGraphRunner && mGraphRunner->InDriverIteration(aDriver)); |
| 3523 | } |
| 3524 | #endif |
| 3525 | |
| 3526 | void 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 */ |
| 3538 | MediaTrackGraphImpl* 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 */ |
| 3552 | MediaTrackGraph* 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 */ |
| 3565 | MediaTrackGraphImpl* 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 */ |
| 3601 | MediaTrackGraph* 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 | |
| 3614 | MediaTrackGraph* 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 | |
| 3630 | MediaTrackGraph* MediaTrackGraph::CreateNonRealtimeInstance( |
| 3631 | TrackRate aSampleRate) { |
| 3632 | return MediaTrackGraphImpl::CreateNonRealtimeInstance(aSampleRate); |
| 3633 | } |
| 3634 | |
| 3635 | void 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 | |
| 3643 | NS_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 | |
| 3646 | NS_IMETHODIMPnsresult |
| 3647 | MediaTrackGraphImpl::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 | |
| 3685 | void 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 | |
| 3732 | void 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 | |
| 3774 | SourceMediaTrack* MediaTrackGraph::CreateSourceTrack(MediaSegment::Type aType) { |
| 3775 | SourceMediaTrack* track = new SourceMediaTrack(aType, GraphRate()); |
| 3776 | AddTrack(track); |
| 3777 | return track; |
| 3778 | } |
| 3779 | |
| 3780 | ProcessedMediaTrack* MediaTrackGraph::CreateForwardedInputTrack( |
| 3781 | MediaSegment::Type aType) { |
| 3782 | ForwardedInputTrack* track = new ForwardedInputTrack(GraphRate(), aType); |
| 3783 | AddTrack(track); |
| 3784 | return track; |
| 3785 | } |
| 3786 | |
| 3787 | AudioCaptureTrack* MediaTrackGraph::CreateAudioCaptureTrack() { |
| 3788 | AudioCaptureTrack* track = new AudioCaptureTrack(GraphRate()); |
| 3789 | AddTrack(track); |
| 3790 | return track; |
| 3791 | } |
| 3792 | |
| 3793 | CrossGraphTransmitter* MediaTrackGraph::CreateCrossGraphTransmitter( |
| 3794 | CrossGraphReceiver* aReceiver) { |
| 3795 | CrossGraphTransmitter* track = |
| 3796 | new CrossGraphTransmitter(GraphRate(), aReceiver); |
| 3797 | AddTrack(track); |
| 3798 | return track; |
| 3799 | } |
| 3800 | |
| 3801 | CrossGraphReceiver* MediaTrackGraph::CreateCrossGraphReceiver( |
| 3802 | TrackRate aTransmitterRate) { |
| 3803 | CrossGraphReceiver* track = |
| 3804 | new CrossGraphReceiver(GraphRate(), aTransmitterRate); |
| 3805 | AddTrack(track); |
| 3806 | return track; |
| 3807 | } |
| 3808 | |
| 3809 | void 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 | |
| 3832 | void 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 | |
| 3868 | auto 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 | |
| 3890 | void 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 | |
| 3934 | class 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 | |
| 3964 | void 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 | |
| 4020 | MediaTrackGraphImpl::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 | |
| 4028 | void 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 | |
| 4042 | void 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 | |
| 4050 | auto 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 | |
| 4061 | uint32_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 | |
| 4066 | uint32_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 | |
| 4088 | double MediaTrackGraph::AudioOutputLatency() { |
| 4089 | return static_cast<MediaTrackGraphImpl*>(this)->AudioOutputLatency(); |
| 4090 | } |
| 4091 | |
| 4092 | double 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 | |
| 4111 | bool MediaTrackGraph::OutputForAECMightDrift() { |
| 4112 | return static_cast<MediaTrackGraphImpl*>(this)->OutputForAECMightDrift(); |
| 4113 | } |
| 4114 | bool MediaTrackGraph::IsNonRealtime() const { |
| 4115 | return !static_cast<const MediaTrackGraphImpl*>(this)->mRealtime; |
| 4116 | } |
| 4117 | |
| 4118 | void 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 | |
| 4145 | void MediaTrackGraphImpl::InterruptJS() { |
| 4146 | MonitorAutoLock lock(mMonitor); |
| 4147 | mInterruptJSCalled = true; |
| 4148 | if (mJSContext) { |
| 4149 | JS_RequestInterruptCallback(mJSContext); |
| 4150 | } |
| 4151 | } |
| 4152 | |
| 4153 | static bool InterruptCallback(JSContext* aCx) { |
| 4154 | // Interrupt future calls also. |
| 4155 | JS_RequestInterruptCallback(aCx); |
| 4156 | // Stop execution. |
| 4157 | return false; |
| 4158 | } |
| 4159 | |
| 4160 | void 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 | |
| 4177 | void 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 | |
| 4187 | void ProcessedMediaTrack::InputSuspended(MediaInputPort* aPort) { |
| 4188 | GraphImpl()->AssertOnGraphThreadOrNotRunning(); |
| 4189 | mInputs.RemoveElement(aPort); |
| 4190 | mSuspendedInputs.AppendElement(aPort); |
| 4191 | GraphImpl()->SetTrackOrderDirty(); |
| 4192 | } |
| 4193 | |
| 4194 | void ProcessedMediaTrack::InputResumed(MediaInputPort* aPort) { |
| 4195 | GraphImpl()->AssertOnGraphThreadOrNotRunning(); |
| 4196 | mSuspendedInputs.RemoveElement(aPort); |
| 4197 | mInputs.AppendElement(aPort); |
| 4198 | GraphImpl()->SetTrackOrderDirty(); |
| 4199 | } |
| 4200 | |
| 4201 | void 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 | |
| 4213 | void 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 | |
| 4220 | void 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 | |
| 4229 | void 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 | |
| 4235 | void 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 | |
| 4241 | already_AddRefed<MediaInputPort> MediaTrackGraph::ConnectToCaptureTrack( |
| 4242 | uint64_t aWindowId, MediaTrack* aMediaTrack) { |
| 4243 | return aMediaTrack->GraphImpl()->ConnectToCaptureTrack(aWindowId, |
| 4244 | aMediaTrack); |
| 4245 | } |
| 4246 | |
| 4247 | already_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 | |
| 4259 | void MediaTrackGraph::DispatchToMainThreadStableState( |
| 4260 | already_AddRefed<nsIRunnable> aRunnable) { |
| 4261 | AssertOnGraphThreadOrNotRunning(); |
| 4262 | static_cast<MediaTrackGraphImpl*>(this) |
| 4263 | ->mPendingUpdateRunnables.AppendElement(std::move(aRunnable)); |
| 4264 | } |
| 4265 | |
| 4266 | Watchable<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 | |
| 4271 | GraphTime MediaTrackGraph::ProcessedTime() const { |
| 4272 | AssertOnGraphThreadOrNotRunning(); |
| 4273 | return static_cast<const MediaTrackGraphImpl*>(this)->mProcessedTime; |
| 4274 | } |
| 4275 | |
| 4276 | void* MediaTrackGraph::CurrentDriver() const { |
| 4277 | AssertOnGraphThreadOrNotRunning(); |
| 4278 | return static_cast<const MediaTrackGraphImpl*>(this)->mDriver; |
| 4279 | } |
| 4280 | |
| 4281 | uint32_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 | |
| 4289 | AudioInputType 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 | |
| 4298 | void 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 | |
| 4349 | NS_IMETHODIMPnsresult |
| 4350 | MediaTrackGraphImpl::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 | |
| 4368 | NS_IMETHODIMPnsresult |
| 4369 | MediaTrackGraphImpl::OnProcessNextEvent(nsIThreadInternal*, bool) { |
| 4370 | return NS_OK; |
| 4371 | } |
| 4372 | |
| 4373 | NS_IMETHODIMPnsresult |
| 4374 | MediaTrackGraphImpl::AfterProcessNextEvent(nsIThreadInternal*, bool) { |
| 4375 | return NS_OK; |
| 4376 | } |
| 4377 | } // namespace mozilla |