tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 3d6bd9cfb30056093a156b4a276603e240a39c15
parent ed534cda355fda623fda7f0eebd82d3a753620bc
Author: Andrew Osmond <aosmond@gmail.com>
Date:   Mon, 20 Oct 2025 15:43:04 +0000

Bug 1993758 - Rework how RDD/utility processes initialize PVideoBridge with the GPU process. r=gfx-reviewers,lsalzman

This avoids calls to GPUProcessManager::EnsureGPUReady as well as making
it more manageable to avoid relaunching the GPU process while in the
background on Android.

Differential Revision: https://phabricator.services.mozilla.com/D269115

Diffstat:
Mdom/ipc/ContentParent.cpp | 11++++++-----
Mdom/media/ipc/RDDChild.cpp | 18+++++++++---------
Mdom/media/ipc/RDDProcessManager.cpp | 51++++++---------------------------------------------
Mdom/media/ipc/RDDProcessManager.h | 1-
Mgfx/ipc/GPUProcessManager.cpp | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mgfx/ipc/GPUProcessManager.h | 24++++++++++++++++++------
Mgfx/thebes/gfxPlatform.cpp | 8+++++---
Mipc/glue/UtilityMediaServiceChild.cpp | 72++++++++++++++++++++++++++++++------------------------------------------
Mipc/glue/UtilityMediaServiceChild.h | 2+-
Mipc/glue/UtilityProcessManager.cpp | 2+-
10 files changed, 158 insertions(+), 124 deletions(-)

diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp @@ -2786,12 +2786,15 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { xpcomInit.userContentSheetURL() = nullptr; } - // 1. Build ContentDeviceData first, as it may affect some gfxVars. + // 1. Ensure the GPU process is ready, as we know we are not yet in shutdown. + GPUProcessManager* gpm = GPUProcessManager::Get(); + gpm->EnsureGPUReady(); + // 2. Build ContentDeviceData first, as it may affect some gfxVars. gfxPlatform::GetPlatform()->BuildContentDeviceData( &xpcomInit.contentDeviceData()); - // 2. Gather non-default gfxVars. + // 3. Gather non-default gfxVars. xpcomInit.gfxNonDefaultVarUpdates() = gfxVars::FetchNonDefaultVars(); - // 3. Start listening for gfxVars updates, to notify content process later on. + // 4. Start listening for gfxVars updates, to notify content process later on. gfxVars::AddReceiver(this); nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service(); @@ -2905,8 +2908,6 @@ bool ContentParent::InitInternal(ProcessPriority aInitialPriority) { // PBrowsers are created, because they rely on the Compositor // already being around. (Creation is async, so can't happen // on demand.) - GPUProcessManager* gpm = GPUProcessManager::Get(); - Endpoint<PCompositorManagerChild> compositor; Endpoint<PImageBridgeChild> imageBridge; Endpoint<PVRManagerChild> vrBridge; diff --git a/dom/media/ipc/RDDChild.cpp b/dom/media/ipc/RDDChild.cpp @@ -72,10 +72,6 @@ bool RDDChild::Init() { Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid())); gfxVars::AddReceiver(this); - auto* gpm = gfx::GPUProcessManager::Get(); - if (gpm) { - gpm->AddListener(this); - } return true; } @@ -110,9 +106,14 @@ bool RDDChild::SendRequestMemoryReport(const uint32_t& aGeneration, } void RDDChild::OnCompositorUnexpectedShutdown() { - auto* rddm = RDDProcessManager::Get(); - if (rddm) { - rddm->CreateVideoBridge(); + if (!CanSend()) { + return; + } + + if (RDDProcessManager* rddpm = RDDProcessManager::Get()) { + if (auto* gpm = GPUProcessManager::Get()) { + gpm->CreateRddVideoBridge(rddpm, this); + } } } @@ -207,8 +208,7 @@ void RDDChild::ActorDestroy(ActorDestroyReason aWhy) { GenerateCrashReport(); } - auto* gpm = gfx::GPUProcessManager::Get(); - if (gpm) { + if (auto* gpm = gfx::GPUProcessManager::Get()) { // Note: the manager could have shutdown already. gpm->RemoveListener(this); } diff --git a/dom/media/ipc/RDDProcessManager.cpp b/dom/media/ipc/RDDProcessManager.cpp @@ -173,12 +173,17 @@ RefPtr<GenericNonExclusivePromise> RDDProcessManager::LaunchRDDProcess() { CrashReporter::RecordAnnotationCString( CrashReporter::Annotation::RDDProcessStatus, "Running"); - if (!CreateVideoBridge()) { + auto* gpm = GPUProcessManager::Get(); + if (NS_WARN_IF(!mRDDChild->CanSend()) || NS_WARN_IF(!gpm) || + NS_WARN_IF(NS_FAILED(gpm->EnsureGPUReady())) || + NS_WARN_IF(NS_FAILED(gpm->CreateRddVideoBridge(this, mRDDChild)))) { mNumProcessAttempts++; DestroyProcess(); return GenericNonExclusivePromise::CreateAndReject( NS_ERROR_NOT_AVAILABLE, __func__); } + + gpm->AddListener(mRDDChild); return GenericNonExclusivePromise::CreateAndResolve(true, __func__); }, [this](nsresult aError) { @@ -304,50 +309,6 @@ bool RDDProcessManager::CreateContentBridge( return true; } -bool RDDProcessManager::CreateVideoBridge() { - MOZ_ASSERT(NS_IsMainThread()); - ipc::Endpoint<PVideoBridgeParent> parentPipe; - ipc::Endpoint<PVideoBridgeChild> childPipe; - - GPUProcessManager* gpuManager = GPUProcessManager::Get(); - ipc::EndpointProcInfo gpuProcessInfo = gpuManager - ? gpuManager->GPUEndpointProcInfo() - : ipc::EndpointProcInfo::Invalid(); - - // Build content device data first; this ensure that the GPU process is fully - // ready. - ContentDeviceData contentDeviceData; - gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData); - - // The child end is the producer of video frames; the parent end is the - // consumer. - ipc::EndpointProcInfo childInfo = RDDEndpointProcInfo(); - ipc::EndpointProcInfo parentInfo = - gpuProcessInfo != ipc::EndpointProcInfo::Invalid() - ? gpuProcessInfo - : ipc::EndpointProcInfo::Current(); - - nsresult rv = PVideoBridge::CreateEndpoints(parentInfo, childInfo, - &parentPipe, &childPipe); - if (NS_FAILED(rv)) { - MOZ_LOG(sPDMLog, LogLevel::Debug, - ("Could not create video bridge: %d", int(rv))); - return false; - } - - mRDDChild->SendInitVideoBridge(std::move(childPipe), - mNumUnexpectedCrashes == 0, contentDeviceData); - if (gpuProcessInfo != ipc::EndpointProcInfo::Invalid()) { - gpuManager->InitVideoBridge(std::move(parentPipe), - VideoBridgeSource::RddProcess); - } else { - VideoBridgeParent::Open(std::move(parentPipe), - VideoBridgeSource::RddProcess); - } - - return true; -} - base::ProcessId RDDProcessManager::RDDProcessPid() { MOZ_ASSERT(NS_IsMainThread()); base::ProcessId rddPid = diff --git a/dom/media/ipc/RDDProcessManager.h b/dom/media/ipc/RDDProcessManager.h @@ -76,7 +76,6 @@ class RDDProcessManager final : public RDDProcessHost::Listener { private: bool IsRDDProcessLaunching(); bool IsRDDProcessDestroyed() const; - bool CreateVideoBridge(); // Called from our xpcom-shutdown observer. void OnXPCOMShutdown(); diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp @@ -13,13 +13,15 @@ #include "mozilla/AppShutdown.h" #include "mozilla/MemoryReportingProcess.h" #include "mozilla/Preferences.h" +#include "mozilla/RDDChild.h" +#include "mozilla/RDDProcessManager.h" +#include "mozilla/RemoteMediaManagerChild.h" +#include "mozilla/RemoteMediaManagerParent.h" #include "mozilla/Sprintf.h" #include "mozilla/StaticPtr.h" #include "mozilla/StaticPrefs_gfx.h" #include "mozilla/StaticPrefs_layers.h" #include "mozilla/StaticPrefs_media.h" -#include "mozilla/RemoteMediaManagerChild.h" -#include "mozilla/RemoteMediaManagerParent.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/GPUChild.h" @@ -39,6 +41,7 @@ #include "mozilla/layers/InProcessCompositorSession.h" #include "mozilla/layers/LayerTreeOwnerTracker.h" #include "mozilla/layers/RemoteCompositorSession.h" +#include "mozilla/layers/VideoBridgeParent.h" #include "mozilla/webrender/RenderThread.h" #include "mozilla/widget/PlatformWidgetTypes.h" #include "nsAppRunner.h" @@ -56,6 +59,10 @@ #include "nsExceptionHandler.h" #include "nsPrintfCString.h" +#ifdef MOZ_WMF_MEDIA_ENGINE +# include "mozilla/ipc/UtilityMediaServiceChild.h" +#endif + #if defined(MOZ_WIDGET_ANDROID) # include "mozilla/java/SurfaceControlManagerWrappers.h" # include "mozilla/widget/AndroidUiThread.h" @@ -435,6 +442,11 @@ nsresult GPUProcessManager::EnsureGPUReady() { break; } + // We already call this in OnProcessLaunchComplete that is called during + // WaitForLaunch, but there could be more gfxVar/gfxConfig updates that need + // to be sent over, if we are calling this well after the process has + // launched. This is because changes can occur due to device resets without + // a process crash. if (mGPUChild->EnsureGPUReady()) { return NS_OK; } @@ -589,7 +601,8 @@ void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) { // By definition, the process failing to launch is an unstable attempt. While // we did not get to the point where we are using the features, we should just // follow the same fallback procedure. - if (!mProcess->IsConnected()) { + auto* gpuChild = mProcess->GetActor(); + if (!mProcess->IsConnected() || !gpuChild || !gpuChild->EnsureGPUReady()) { ++mLaunchProcessAttempts; if (mLaunchProcessAttempts > uint32_t(StaticPrefs::layers_gpu_process_max_launch_attempts())) { @@ -605,7 +618,7 @@ void GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) { } mLaunchProcessAttempts = 0; - mGPUChild = mProcess->GetActor(); + mGPUChild = gpuChild; mProcessToken = mProcess->GetProcessToken(); #if defined(XP_WIN) if (mAppInForeground) { @@ -1511,16 +1524,72 @@ void GPUProcessManager::CreateContentRemoteMediaManager( *aOutEndpoint = std::move(childPipe); } -void GPUProcessManager::InitVideoBridge( - ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge, - layers::VideoBridgeSource aSource) { - if (NS_WARN_IF(NS_FAILED(EnsureGPUReady()))) { - return; +#ifdef MOZ_WMF_MEDIA_ENGINE +nsresult GPUProcessManager::CreateUtilityMFCDMVideoBridge( + mozilla::ipc::UtilityMediaServiceChild* aChild, + mozilla::ipc::EndpointProcInfo aOtherProcess) { + MOZ_ASSERT(aChild); + MOZ_ASSERT(aChild->CanSend()); + + ipc::Endpoint<PVideoBridgeChild> childPipe; + nsresult rv = EnsureVideoBridge(VideoBridgeSource::MFMediaEngineCDMProcess, + aOtherProcess, &childPipe); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + gfx::ContentDeviceData contentDeviceData; + gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData); + aChild->SendInitVideoBridge(std::move(childPipe), contentDeviceData); + return NS_OK; +} +#endif + +nsresult GPUProcessManager::CreateRddVideoBridge(RDDProcessManager* aRDD, + RDDChild* aChild) { + MOZ_ASSERT(aRDD); + MOZ_ASSERT(aChild); + MOZ_ASSERT(aChild->CanSend()); + + ipc::Endpoint<PVideoBridgeChild> childPipe; + nsresult rv = EnsureVideoBridge(VideoBridgeSource::RddProcess, + aChild->OtherEndpointProcInfo(), &childPipe); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + gfx::ContentDeviceData contentDeviceData; + gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData); + aChild->SendInitVideoBridge(std::move(childPipe), + !aRDD->AttemptedRDDProcess(), contentDeviceData); + return NS_OK; +} + +nsresult GPUProcessManager::EnsureVideoBridge( + layers::VideoBridgeSource aSource, + mozilla::ipc::EndpointProcInfo aOtherProcess, + mozilla::ipc::Endpoint<layers::PVideoBridgeChild>* aOutChildPipe) { + MOZ_ASSERT(aOutChildPipe); + MOZ_DIAGNOSTIC_ASSERT(IsGPUReady()); + + ipc::EndpointProcInfo gpuInfo = mGPUChild ? mGPUChild->OtherEndpointProcInfo() + : ipc::EndpointProcInfo::Current(); + + // The child end is the producer of video frames; the parent end is the + // consumer. + ipc::Endpoint<PVideoBridgeParent> parentPipe; + nsresult rv = PVideoBridge::CreateEndpoints(gpuInfo, aOtherProcess, + &parentPipe, aOutChildPipe); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } if (mGPUChild) { - mGPUChild->SendInitVideoBridge(std::move(aVideoBridge), aSource); + mGPUChild->SendInitVideoBridge(std::move(parentPipe), aSource); + } else { + VideoBridgeParent::Open(std::move(parentPipe), aSource); } + return NS_OK; } void GPUProcessManager::MapLayerTreeId(LayersId aLayersId, @@ -1658,7 +1727,9 @@ void GPUProcessManager::UnregisterInProcessSession( } void GPUProcessManager::AddListener(GPUProcessListener* aListener) { - mListeners.AppendElement(aListener); + if (!mListeners.Contains(aListener)) { + mListeners.AppendElement(aListener); + } } void GPUProcessManager::RemoveListener(GPUProcessListener* aListener) { diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h @@ -27,6 +27,8 @@ enum class DeviceResetReason; namespace mozilla { class MemoryReportingProcess; class PRemoteMediaManagerChild; +class RDDProcessManager; +class RDDChild; namespace layers { class IAPZCTreeManager; class CompositorOptions; @@ -50,6 +52,9 @@ class BrowserParent; } // namespace dom namespace ipc { class GeckoChildProcessHost; +#ifdef MOZ_WMF_MEDIA_ENGINE +class UtilityMediaServiceChild; +#endif } // namespace ipc namespace gfx { @@ -105,6 +110,8 @@ class GPUProcessManager final : public GPUProcessHost::Listener { // in shutdown. nsresult EnsureGPUReady(); + bool IsGPUReady() const; + already_AddRefed<CompositorSession> CreateTopLevelCompositor( nsIWidget* aWidget, WebRenderLayerManager* aLayerManager, CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions, @@ -119,10 +126,12 @@ class GPUProcessManager final : public GPUProcessHost::Listener { mozilla::ipc::Endpoint<PRemoteMediaManagerChild>* aOutVideoManager, dom::ContentParentId aChildId, nsTArray<uint32_t>* aNamespaces); - // Initialize GPU process with consuming end of PVideoBridge. - void InitVideoBridge( - mozilla::ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge, - layers::VideoBridgeSource aSource); + nsresult CreateRddVideoBridge(RDDProcessManager* aRDD, RDDChild* aChild); +#ifdef MOZ_WMF_MEDIA_ENGINE + nsresult CreateUtilityMFCDMVideoBridge( + mozilla::ipc::UtilityMediaServiceChild* aChild, + mozilla::ipc::EndpointProcInfo aOtherProcess); +#endif // Maps the layer tree and process together so that aOwningPID is allowed // to access aLayersId across process. @@ -235,8 +244,6 @@ class GPUProcessManager final : public GPUProcessHost::Listener { void OnPreferenceChange(const char16_t* aData); void ScreenInformationChanged(); - bool IsGPUReady() const; - bool CreateContentCompositorManager( mozilla::ipc::EndpointProcInfo aOtherProcess, dom::ContentParentId aChildId, uint32_t aNamespace, @@ -254,6 +261,11 @@ class GPUProcessManager final : public GPUProcessHost::Listener { dom::ContentParentId aChildId, mozilla::ipc::Endpoint<PRemoteMediaManagerChild>* aOutEndPoint); + nsresult EnsureVideoBridge( + layers::VideoBridgeSource aSource, + mozilla::ipc::EndpointProcInfo aOtherProcess, + mozilla::ipc::Endpoint<layers::PVideoBridgeChild>* aOutChildPipe); + // Called from RemoteCompositorSession. We track remote sessions so we can // notify their owning widgets that the session must be restarted. void RegisterRemoteProcessSession(RemoteCompositorSession* aSession); diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp @@ -4163,9 +4163,11 @@ void gfxPlatform::BuildContentDeviceData( mozilla::gfx::ContentDeviceData* aOut) { MOZ_ASSERT(XRE_IsParentProcess()); - // Make sure our settings are synchronized from the GPU process. - DebugOnly<nsresult> rv = GPUProcessManager::Get()->EnsureGPUReady(); - MOZ_ASSERT(NS_SUCCEEDED(rv)); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED + if (auto* gpm = GPUProcessManager::Get()) { + MOZ_DIAGNOSTIC_ASSERT(gpm->IsGPUReady()); + } +#endif aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING); aOut->prefs().oglCompositing() = diff --git a/ipc/glue/UtilityMediaServiceChild.cpp b/ipc/glue/UtilityMediaServiceChild.cpp @@ -88,6 +88,13 @@ nsresult UtilityMediaServiceChild::BindToUtilityProcess( void UtilityMediaServiceChild::ActorDestroy(ActorDestroyReason aReason) { MOZ_ASSERT(NS_IsMainThread()); gfx::gfxVars::RemoveReceiver(this); +#ifdef MOZ_WMF_MEDIA_ENGINE + mHasCreatedVideoBridge = State::None; + if (auto* gpm = gfx::GPUProcessManager::Get()) { + // Note: the manager could have shutdown already. + gpm->RemoveListener(this); + } +#endif Shutdown(mSandbox); } @@ -136,7 +143,11 @@ mozilla::ipc::IPCResult UtilityMediaServiceChild::RecvCompleteCreatedVideoBridge() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM); - mHasCreatedVideoBridge = State::Created; + if (mHasCreatedVideoBridge == State::Creating) { + mHasCreatedVideoBridge = State::Created; + } else { + MOZ_ASSERT_UNREACHABLE("Video bridge created but was not creating?"); + } return IPC_OK(); } @@ -144,60 +155,37 @@ void UtilityMediaServiceChild::OnCompositorUnexpectedShutdown() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM); mHasCreatedVideoBridge = State::None; - CreateVideoBridge(); + + if (auto* gpm = gfx::GPUProcessManager::Get()) { + if (auto utilpm = UtilityProcessManager::GetSingleton()) + if (auto parent = utilpm->GetProcessParent(mSandbox)) { + if (NS_SUCCEEDED(gpm->CreateUtilityMFCDMVideoBridge( + this, parent->OtherEndpointProcInfo()))) { + mHasCreatedVideoBridge = State::Creating; + } + } + } } -bool UtilityMediaServiceChild::CreateVideoBridge() { +bool UtilityMediaServiceChild::CreateVideoBridge( + mozilla::ipc::EndpointProcInfo aOtherProcess) { MOZ_ASSERT(NS_IsMainThread()); - ipc::Endpoint<layers::PVideoBridgeParent> parentPipe; - ipc::Endpoint<layers::PVideoBridgeChild> childPipe; - MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM); // Creating or already created, avoiding reinit a bridge. if (mHasCreatedVideoBridge != State::None) { return true; } - mHasCreatedVideoBridge = State::Creating; - gfx::GPUProcessManager* gpuManager = gfx::GPUProcessManager::Get(); - ipc::EndpointProcInfo gpuProcessInfo = gpuManager - ? gpuManager->GPUEndpointProcInfo() - : ipc::EndpointProcInfo::Invalid(); - - // Build content device data first; this ensure that the GPU process is fully - // ready. - gfx::ContentDeviceData contentDeviceData; - gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData); - - // The child end is the producer of video frames; the parent end is the - // consumer. - EndpointProcInfo childInfo = UtilityProcessManager::GetSingleton() - ->GetProcessParent(mSandbox) - ->OtherEndpointProcInfo(); - EndpointProcInfo parentInfo = - gpuProcessInfo != ipc::EndpointProcInfo::Invalid() - ? gpuProcessInfo - : ipc::EndpointProcInfo::Current(); - - nsresult rv = layers::PVideoBridge::CreateEndpoints(parentInfo, childInfo, - &parentPipe, &childPipe); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to create endpoints for video bridge!"); + auto* gpm = gfx::GPUProcessManager::Get(); + if (NS_WARN_IF(!gpm) || NS_WARN_IF(NS_FAILED(gpm->EnsureGPUReady())) || + NS_WARN_IF( + NS_FAILED(gpm->CreateUtilityMFCDMVideoBridge(this, aOtherProcess)))) { return false; } - if (gpuProcessInfo != ipc::EndpointProcInfo::Invalid()) { - gpuManager->InitVideoBridge( - std::move(parentPipe), - layers::VideoBridgeSource::MFMediaEngineCDMProcess); - } else { - layers::VideoBridgeParent::Open( - std::move(parentPipe), - layers::VideoBridgeSource::MFMediaEngineCDMProcess); - } - - SendInitVideoBridge(std::move(childPipe), contentDeviceData); + gpm->AddListener(this); + mHasCreatedVideoBridge = State::Creating; return true; } #endif diff --git a/ipc/glue/UtilityMediaServiceChild.h b/ipc/glue/UtilityMediaServiceChild.h @@ -77,7 +77,7 @@ class UtilityMediaServiceChild final : public PUtilityMediaServiceChild, // True if creating a video bridge sucessfully. Currently only used for media // engine cdm. - bool CreateVideoBridge(); + bool CreateVideoBridge(mozilla::ipc::EndpointProcInfo aOtherProcess); #endif #ifdef MOZ_WMF_CDM diff --git a/ipc/glue/UtilityProcessManager.cpp b/ipc/glue/UtilityProcessManager.cpp @@ -385,7 +385,7 @@ UtilityProcessManager::StartProcessForRemoteMediaDecoding( #ifdef MOZ_WMF_MEDIA_ENGINE if (aSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM && - !umsc->CreateVideoBridge()) { + !umsc->CreateVideoBridge(process)) { MOZ_ASSERT(false, "Failed to create video bridge"); return RetPromise::CreateAndReject( LaunchError("UMSC::CreateVideoBridge"), __func__);