RemoteMediaManagerChild.cpp (48697B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 #include "RemoteMediaManagerChild.h" 7 8 #include "EMEDecoderModule.h" 9 #include "ErrorList.h" 10 #include "MP4Decoder.h" 11 #include "PDMFactory.h" 12 #include "PEMFactory.h" 13 #include "PlatformDecoderModule.h" 14 #include "PlatformEncoderModule.h" 15 #include "RemoteAudioDecoder.h" 16 #include "RemoteCDMChild.h" 17 #include "RemoteMediaDataDecoder.h" 18 #include "RemoteMediaDataEncoderChild.h" 19 #include "RemoteVideoDecoder.h" 20 #include "VideoUtils.h" 21 #include "mozilla/DataMutex.h" 22 #include "mozilla/MozPromise.h" 23 #include "mozilla/RemoteDecodeUtils.h" 24 #include "mozilla/StaticPrefs_media.h" 25 #include "mozilla/StaticPtr.h" 26 #include "mozilla/SyncRunnable.h" 27 #include "mozilla/dom/ContentChild.h" // for launching RDD w/ ContentChild 28 #include "mozilla/gfx/2D.h" 29 #include "mozilla/gfx/DataSurfaceHelpers.h" 30 #include "mozilla/ipc/BackgroundChild.h" 31 #include "mozilla/ipc/Endpoint.h" 32 #include "mozilla/ipc/PBackgroundChild.h" 33 #include "mozilla/ipc/UtilityMediaServiceChild.h" 34 #include "mozilla/layers/ISurfaceAllocator.h" 35 #include "nsContentUtils.h" 36 #include "nsIObserver.h" 37 #include "nsPrintfCString.h" 38 39 #ifdef MOZ_WMF_MEDIA_ENGINE 40 # include "MFMediaEngineChild.h" 41 #endif 42 43 #ifdef MOZ_WMF_CDM 44 # include "MFCDMChild.h" 45 #endif 46 47 namespace mozilla { 48 49 #define LOG(msg, ...) \ 50 MOZ_LOG(gRemoteDecodeLog, LogLevel::Debug, (msg, ##__VA_ARGS__)) 51 52 using namespace layers; 53 using namespace gfx; 54 55 using media::EncodeSupport; 56 using media::EncodeSupportSet; 57 58 // Used so that we only ever attempt to check if the RDD/GPU/Utility processes 59 // should be launched serially. Protects sLaunchPromise 60 StaticMutex sLaunchMutex; 61 static EnumeratedArray<RemoteMediaIn, StaticRefPtr<GenericNonExclusivePromise>, 62 size_t(RemoteMediaIn::SENTINEL)> 63 sLaunchPromises MOZ_GUARDED_BY(sLaunchMutex); 64 65 // Only modified on the main-thread, read on any thread. While it could be read 66 // on the main thread directly, for clarity we force access via the DataMutex 67 // wrapper. 68 MOZ_RUNINIT static StaticDataMutex<StaticRefPtr<nsIThread>> 69 sRemoteMediaManagerChildThread("sRemoteMediaManagerChildThread"); 70 71 // Only accessed from sRemoteMediaManagerChildThread 72 static EnumeratedArray<RemoteMediaIn, StaticRefPtr<RemoteMediaManagerChild>, 73 size_t(RemoteMediaIn::SENTINEL)> 74 sRemoteMediaManagerChildForProcesses; 75 76 static StaticAutoPtr<nsTArray<RefPtr<Runnable>>> sRecreateTasks; 77 78 // Used for protecting codec support information collected from different remote 79 // processes. 80 StaticMutex sProcessSupportedMutex; 81 MOZ_GLOBINIT static EnumeratedArray<RemoteMediaIn, 82 Maybe<media::MediaCodecsSupported>, 83 size_t(RemoteMediaIn::SENTINEL)> 84 sProcessSupported MOZ_GUARDED_BY(sProcessSupportedMutex); 85 86 class ShutdownObserver final : public nsIObserver { 87 public: 88 NS_DECL_ISUPPORTS 89 NS_DECL_NSIOBSERVER 90 91 protected: 92 ~ShutdownObserver() = default; 93 }; 94 NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver); 95 96 NS_IMETHODIMP 97 ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic, 98 const char16_t* aData) { 99 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)); 100 RemoteMediaManagerChild::Shutdown(); 101 return NS_OK; 102 } 103 104 StaticRefPtr<ShutdownObserver> sObserver; 105 106 /* static */ 107 void RemoteMediaManagerChild::Init() { 108 LOG("RemoteMediaManagerChild Init"); 109 110 auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock(); 111 if (!*remoteDecoderManagerThread) { 112 LOG("RemoteMediaManagerChild's thread is created"); 113 // We can't use a MediaThreadType::SUPERVISOR as the RemoteDecoderModule 114 // runs on it and dispatch synchronous tasks to the manager thread, should 115 // more than 4 concurrent videos being instantiated at the same time, we 116 // could end up in a deadlock. 117 RefPtr<nsIThread> childThread; 118 nsresult rv = NS_NewNamedThread( 119 "RemVidChild", getter_AddRefs(childThread), 120 NS_NewRunnableFunction( 121 "RemoteMediaManagerChild::InitPBackground", []() { 122 ipc::PBackgroundChild* bgActor = 123 ipc::BackgroundChild::GetOrCreateForCurrentThread(); 124 NS_WARNING_ASSERTION(bgActor, 125 "Failed to start Background channel"); 126 (void)bgActor; 127 })); 128 129 NS_ENSURE_SUCCESS_VOID(rv); 130 *remoteDecoderManagerThread = childThread; 131 sRecreateTasks = new nsTArray<RefPtr<Runnable>>(); 132 sObserver = new ShutdownObserver(); 133 nsContentUtils::RegisterShutdownObserver(sObserver); 134 } 135 } 136 137 /* static */ 138 void RemoteMediaManagerChild::InitForGPUProcess( 139 Endpoint<PRemoteMediaManagerChild>&& aVideoManager) { 140 MOZ_ASSERT(NS_IsMainThread()); 141 142 Init(); 143 144 auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock(); 145 MOZ_ALWAYS_SUCCEEDS( 146 (*remoteDecoderManagerThread) 147 ->Dispatch(NewRunnableFunction( 148 "InitForContentRunnable", &OpenRemoteMediaManagerChildForProcess, 149 std::move(aVideoManager), RemoteMediaIn::GpuProcess))); 150 } 151 152 /* static */ 153 void RemoteMediaManagerChild::Shutdown() { 154 MOZ_ASSERT(NS_IsMainThread()); 155 LOG("RemoteMediaManagerChild Shutdown"); 156 157 if (sObserver) { 158 nsContentUtils::UnregisterShutdownObserver(sObserver); 159 sObserver = nullptr; 160 } 161 162 nsCOMPtr<nsIThread> childThread; 163 { 164 auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock(); 165 childThread = remoteDecoderManagerThread->forget(); 166 LOG("RemoteMediaManagerChild's thread is released"); 167 } 168 if (childThread) { 169 MOZ_ALWAYS_SUCCEEDS(childThread->Dispatch( 170 NS_NewRunnableFunction("dom::RemoteMediaManagerChild::Shutdown", []() { 171 for (auto& p : sRemoteMediaManagerChildForProcesses) { 172 if (p && p->CanSend()) { 173 p->Close(); 174 } 175 p = nullptr; 176 } 177 { 178 StaticMutexAutoLock lock(sLaunchMutex); 179 for (auto& p : sLaunchPromises) { 180 p = nullptr; 181 } 182 } 183 ipc::BackgroundChild::CloseForCurrentThread(); 184 }))); 185 childThread->Shutdown(); 186 sRecreateTasks = nullptr; 187 } 188 } 189 190 /* static */ void RemoteMediaManagerChild::RunWhenGPUProcessRecreated( 191 const RemoteMediaManagerChild* aDyingManager, 192 already_AddRefed<Runnable> aTask) { 193 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 194 if (!managerThread) { 195 // We've been shutdown, bail. 196 return; 197 } 198 MOZ_ASSERT(managerThread->IsOnCurrentThread()); 199 200 // If we've already been recreated, then run the task immediately. 201 auto* manager = GetSingleton(RemoteMediaIn::GpuProcess); 202 if (manager && manager != aDyingManager && manager->CanSend()) { 203 RefPtr<Runnable> task = aTask; 204 task->Run(); 205 } else { 206 sRecreateTasks->AppendElement(aTask); 207 } 208 } 209 210 /* static */ 211 RemoteMediaManagerChild* RemoteMediaManagerChild::GetSingleton( 212 RemoteMediaIn aLocation) { 213 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 214 if (!managerThread) { 215 // We've been shutdown, bail. 216 return nullptr; 217 } 218 MOZ_ASSERT(managerThread->IsOnCurrentThread()); 219 switch (aLocation) { 220 case RemoteMediaIn::GpuProcess: 221 case RemoteMediaIn::RddProcess: 222 case RemoteMediaIn::UtilityProcess_Generic: 223 case RemoteMediaIn::UtilityProcess_AppleMedia: 224 case RemoteMediaIn::UtilityProcess_WMF: 225 case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: 226 return sRemoteMediaManagerChildForProcesses[aLocation]; 227 default: 228 MOZ_CRASH("Unexpected RemoteMediaIn variant"); 229 return nullptr; 230 } 231 } 232 233 /* static */ 234 nsCOMPtr<nsISerialEventTarget> RemoteMediaManagerChild::GetManagerThread() { 235 auto remoteDecoderManagerThread = sRemoteMediaManagerChildThread.Lock(); 236 return nsCOMPtr<nsISerialEventTarget>(*remoteDecoderManagerThread); 237 } 238 239 /* static */ 240 bool RemoteMediaManagerChild::Supports(RemoteMediaIn aLocation, 241 const SupportDecoderParams& aParams, 242 DecoderDoctorDiagnostics* aDiagnostics) { 243 Maybe<media::MediaCodecsSupported> supported; 244 switch (aLocation) { 245 case RemoteMediaIn::GpuProcess: 246 case RemoteMediaIn::RddProcess: 247 case RemoteMediaIn::UtilityProcess_AppleMedia: 248 case RemoteMediaIn::UtilityProcess_Generic: 249 case RemoteMediaIn::UtilityProcess_WMF: 250 case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: { 251 StaticMutexAutoLock lock(sProcessSupportedMutex); 252 supported = sProcessSupported[aLocation]; 253 break; 254 } 255 default: 256 return false; 257 } 258 if (!supported) { 259 // We haven't received the correct information yet from either the GPU or 260 // the RDD process nor the Utility process. 261 if (aLocation == RemoteMediaIn::UtilityProcess_Generic || 262 aLocation == RemoteMediaIn::UtilityProcess_AppleMedia || 263 aLocation == RemoteMediaIn::UtilityProcess_WMF || 264 aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 265 LaunchUtilityProcessIfNeeded(aLocation); 266 } 267 if (aLocation == RemoteMediaIn::RddProcess) { 268 // Ensure the RDD process got started. 269 // TODO: This can be removed once bug 1684991 is fixed. 270 LaunchRDDProcessIfNeeded(); 271 } 272 273 // Assume the format is supported to prevent false negative, if the remote 274 // process supports that specific track type. 275 const bool isVideo = aParams.mConfig.IsVideo(); 276 const bool isAudio = aParams.mConfig.IsAudio(); 277 const auto trackSupport = GetTrackSupport(aLocation); 278 if (isVideo) { 279 // Special condition for HEVC, which can only be supported in specific 280 // process. As HEVC support is still a experimental feature, we don't want 281 // to report support for it arbitrarily. 282 if (MP4Decoder::IsHEVC(aParams.mConfig.mMimeType)) { 283 if (!StaticPrefs::media_hevc_enabled()) { 284 return false; 285 } 286 #if defined(XP_WIN) 287 return aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM || 288 aLocation == RemoteMediaIn::GpuProcess; 289 #else 290 return trackSupport.contains(TrackSupport::DecodeVideo); 291 #endif 292 } 293 return trackSupport.contains(TrackSupport::DecodeVideo); 294 } 295 if (isAudio) { 296 return trackSupport.contains(TrackSupport::DecodeAudio); 297 } 298 MOZ_ASSERT_UNREACHABLE("Not audio and video?!"); 299 return false; 300 } 301 302 // We can ignore the SupportDecoderParams argument for now as creation of the 303 // decoder will actually fail later and fallback PDMs will be tested on later. 304 return !PDMFactory::SupportsMimeType(aParams.MimeType(), *supported, 305 aLocation) 306 .isEmpty(); 307 } 308 309 /* static */ 310 RefPtr<PlatformDecoderModule::CreateDecoderPromise> 311 RemoteMediaManagerChild::CreateAudioDecoder(const CreateDecoderParams& aParams, 312 RemoteMediaIn aLocation) { 313 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 314 if (!managerThread) { 315 // We got shutdown. 316 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 317 NS_ERROR_DOM_MEDIA_CANCELED, __func__); 318 } 319 320 if (!GetTrackSupport(aLocation).contains(TrackSupport::DecodeAudio)) { 321 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 322 MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, 323 nsPrintfCString("%s doesn't support audio decoding", 324 RemoteMediaInToStr(aLocation)) 325 .get()), 326 __func__); 327 } 328 329 if (!aParams.mMediaEngineId && 330 aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 331 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 332 MediaResult(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR, 333 nsPrintfCString("%s only support for media engine playback", 334 RemoteMediaInToStr(aLocation)) 335 .get()), 336 __func__); 337 } 338 339 RefPtr<GenericNonExclusivePromise> launchPromise; 340 if (StaticPrefs::media_utility_process_enabled() && 341 (aLocation == RemoteMediaIn::UtilityProcess_Generic || 342 aLocation == RemoteMediaIn::UtilityProcess_AppleMedia || 343 aLocation == RemoteMediaIn::UtilityProcess_WMF)) { 344 launchPromise = LaunchUtilityProcessIfNeeded(aLocation); 345 } else if (aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 346 launchPromise = LaunchUtilityProcessIfNeeded(aLocation); 347 } else if (StaticPrefs::media_allow_audio_non_utility() || aParams.mCDM) { 348 launchPromise = LaunchRDDProcessIfNeeded(); 349 } else { 350 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 351 MediaResult( 352 NS_ERROR_DOM_MEDIA_DENIED_IN_NON_UTILITY, 353 nsPrintfCString("%s is not allowed to perform audio decoding", 354 RemoteMediaInToStr(aLocation)) 355 .get()), 356 __func__); 357 } 358 LOG("Create audio decoder in %s", RemoteMediaInToStr(aLocation)); 359 360 return launchPromise->Then( 361 managerThread, __func__, 362 [params = CreateDecoderParamsForAsync(aParams), aLocation](bool) mutable { 363 auto child = MakeRefPtr<RemoteAudioDecoderChild>(aLocation); 364 MediaResult result = 365 child->InitIPDL(params.AudioConfig(), params.mOptions, 366 params.mMediaEngineId, params.mCDM); 367 if (NS_FAILED(result)) { 368 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 369 result, __func__); 370 } 371 return Construct(std::move(child), std::move(params), aLocation); 372 }, 373 [aLocation](nsresult aResult) { 374 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 375 MediaResult(aResult, 376 aLocation == RemoteMediaIn::GpuProcess 377 ? "Couldn't start GPU process" 378 : (aLocation == RemoteMediaIn::RddProcess 379 ? "Couldn't start RDD process" 380 : "Couldn't start Utility process")), 381 __func__); 382 }); 383 } 384 385 /* static */ 386 RefPtr<PlatformDecoderModule::CreateDecoderPromise> 387 RemoteMediaManagerChild::CreateVideoDecoder(const CreateDecoderParams& aParams, 388 RemoteMediaIn aLocation) { 389 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 390 if (!managerThread) { 391 // We got shutdown. 392 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 393 NS_ERROR_DOM_MEDIA_CANCELED, __func__); 394 } 395 396 if (!aParams.mKnowsCompositor && aLocation == RemoteMediaIn::GpuProcess) { 397 // We don't have an image bridge; don't attempt to decode in the GPU 398 // process. 399 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 400 NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR, __func__); 401 } 402 403 if (!GetTrackSupport(aLocation).contains(TrackSupport::DecodeVideo)) { 404 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 405 MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, 406 nsPrintfCString("%s doesn't support video decoding", 407 RemoteMediaInToStr(aLocation)) 408 .get()), 409 __func__); 410 } 411 412 if (!aParams.mMediaEngineId && 413 aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 414 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 415 MediaResult(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR, 416 nsPrintfCString("%s only support for media engine playback", 417 RemoteMediaInToStr(aLocation)) 418 .get()), 419 __func__); 420 } 421 422 MOZ_ASSERT(aLocation != RemoteMediaIn::Unspecified); 423 424 RefPtr<GenericNonExclusivePromise> p; 425 if (aLocation == RemoteMediaIn::GpuProcess) { 426 p = GenericNonExclusivePromise::CreateAndResolve(true, __func__); 427 } else if (aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 428 p = LaunchUtilityProcessIfNeeded(aLocation); 429 } else { 430 p = LaunchRDDProcessIfNeeded(); 431 } 432 LOG("Create video decoder in %s", RemoteMediaInToStr(aLocation)); 433 434 return p->Then( 435 managerThread, __func__, 436 [aLocation, params = CreateDecoderParamsForAsync(aParams)](bool) mutable { 437 auto child = MakeRefPtr<RemoteVideoDecoderChild>(aLocation); 438 MediaResult result = child->InitIPDL( 439 params.VideoConfig(), params.mRate.mValue, params.mOptions, 440 params.mKnowsCompositor 441 ? Some(params.mKnowsCompositor->GetTextureFactoryIdentifier()) 442 : Nothing(), 443 params.mMediaEngineId, params.mTrackingId, params.mCDM); 444 if (NS_FAILED(result)) { 445 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 446 result, __func__); 447 } 448 return Construct(std::move(child), std::move(params), aLocation); 449 }, 450 [](nsresult aResult) { 451 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 452 MediaResult(aResult, "Couldn't start RDD process"), __func__); 453 }); 454 } 455 456 /* static */ 457 RefPtr<RemoteCDMChild> RemoteMediaManagerChild::CreateCDM( 458 RemoteMediaIn aLocation, dom::MediaKeys* aKeys, const nsAString& aKeySystem, 459 bool aDistinctiveIdentifierRequired, bool aPersistentStateRequired) { 460 MOZ_ASSERT(NS_IsMainThread()); 461 462 if (NS_WARN_IF(aLocation != RemoteMediaIn::RddProcess)) { 463 MOZ_ASSERT_UNREACHABLE("Cannot use CDM outside RDD process"); 464 return nullptr; 465 } 466 467 if (!StaticPrefs::media_ffvpx_hw_enabled()) { 468 return nullptr; 469 } 470 471 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 472 if (!managerThread) { 473 // We got shutdown. 474 return nullptr; 475 } 476 477 if (!GetTrackSupport(aLocation).contains(TrackSupport::DecodeVideo)) { 478 return nullptr; 479 } 480 481 RefPtr<GenericNonExclusivePromise> p = LaunchRDDProcessIfNeeded(); 482 LOG("Create CDM in %s", RemoteMediaInToStr(aLocation)); 483 484 return MakeRefPtr<RemoteCDMChild>( 485 std::move(managerThread), std::move(p), aLocation, aKeys, aKeySystem, 486 aDistinctiveIdentifierRequired, aPersistentStateRequired); 487 } 488 489 /* static */ 490 RefPtr<PlatformDecoderModule::CreateDecoderPromise> 491 RemoteMediaManagerChild::Construct(RefPtr<RemoteDecoderChild>&& aChild, 492 CreateDecoderParamsForAsync&& aParams, 493 RemoteMediaIn aLocation) { 494 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 495 if (!managerThread) { 496 // We got shutdown. 497 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 498 NS_ERROR_DOM_MEDIA_CANCELED, __func__); 499 } 500 MOZ_ASSERT(managerThread->IsOnCurrentThread()); 501 502 RefPtr<PlatformDecoderModule::CreateDecoderPromise> p = 503 aChild->SendConstruct()->Then( 504 managerThread, __func__, 505 [child = std::move(aChild), 506 params = std::move(aParams)](MediaResult aResult) { 507 if (NS_FAILED(aResult)) { 508 // We will never get to use this remote decoder, tear it down. 509 child->DestroyIPDL(); 510 return PlatformDecoderModule::CreateDecoderPromise:: 511 CreateAndReject(aResult, __func__); 512 } 513 if (params.mCDM) { 514 if (auto* cdmChild = params.mCDM->AsPRemoteCDMChild()) { 515 return PlatformDecoderModule::CreateDecoderPromise:: 516 CreateAndResolve( 517 MakeRefPtr<EMEMediaDataDecoderProxy>( 518 params, 519 MakeAndAddRef<RemoteMediaDataDecoder>(child), 520 static_cast<RemoteCDMChild*>(cdmChild)), 521 __func__); 522 } 523 return PlatformDecoderModule::CreateDecoderPromise:: 524 CreateAndReject( 525 NS_ERROR_DOM_MEDIA_CDM_PROXY_NOT_SUPPORTED_ERR, __func__); 526 } 527 return PlatformDecoderModule::CreateDecoderPromise:: 528 CreateAndResolve(MakeRefPtr<RemoteMediaDataDecoder>(child), 529 __func__); 530 }, 531 [aLocation](const mozilla::ipc::ResponseRejectReason& aReason) { 532 // The parent has died. 533 nsresult err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR; 534 if (aLocation == RemoteMediaIn::GpuProcess || 535 aLocation == RemoteMediaIn::RddProcess) { 536 err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR; 537 } else if (aLocation == 538 RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 539 err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR; 540 } 541 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject( 542 err, __func__); 543 }); 544 return p; 545 } 546 547 /* static */ 548 EncodeSupportSet RemoteMediaManagerChild::Supports(RemoteMediaIn aLocation, 549 CodecType aCodec) { 550 Maybe<media::MediaCodecsSupported> supported; 551 switch (aLocation) { 552 case RemoteMediaIn::GpuProcess: 553 case RemoteMediaIn::RddProcess: 554 case RemoteMediaIn::UtilityProcess_AppleMedia: 555 case RemoteMediaIn::UtilityProcess_Generic: 556 case RemoteMediaIn::UtilityProcess_WMF: 557 case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: { 558 StaticMutexAutoLock lock(sProcessSupportedMutex); 559 supported = sProcessSupported[aLocation]; 560 break; 561 } 562 default: 563 return EncodeSupportSet{}; 564 } 565 if (!supported) { 566 // We haven't received the correct information yet from either the GPU or 567 // the RDD process nor the Utility process. 568 if (aLocation == RemoteMediaIn::UtilityProcess_Generic || 569 aLocation == RemoteMediaIn::UtilityProcess_AppleMedia || 570 aLocation == RemoteMediaIn::UtilityProcess_WMF || 571 aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 572 LaunchUtilityProcessIfNeeded(aLocation); 573 } 574 if (aLocation == RemoteMediaIn::RddProcess) { 575 // Ensure the RDD process got started. 576 // TODO: This can be removed once bug 1684991 is fixed. 577 LaunchRDDProcessIfNeeded(); 578 } 579 580 // Assume the format is supported to prevent false negative, if the remote 581 // process supports that specific track type. 582 const auto trackSupport = GetTrackSupport(aLocation); 583 if (IsVideo(aCodec)) { 584 // Special condition for HEVC, which can only be supported in specific 585 // process. As HEVC support is still a experimental feature, we don't want 586 // to report support for it arbitrarily. 587 bool supported = trackSupport.contains(TrackSupport::EncodeVideo); 588 if (aCodec == CodecType::H265) { 589 if (!StaticPrefs::media_hevc_enabled()) { 590 return EncodeSupportSet{}; 591 } 592 #if defined(XP_WIN) 593 supported = aLocation == RemoteMediaIn::GpuProcess; 594 #endif 595 } 596 return supported ? EncodeSupportSet{EncodeSupport::SoftwareEncode} 597 : EncodeSupportSet{}; 598 } 599 if (IsAudio(aCodec)) { 600 return trackSupport.contains(TrackSupport::EncodeAudio) 601 ? EncodeSupportSet{EncodeSupport::SoftwareEncode} 602 : EncodeSupportSet{}; 603 } 604 MOZ_ASSERT_UNREACHABLE("Not audio and video?!"); 605 return EncodeSupportSet{}; 606 } 607 608 // We can ignore the rest of EncoderConfig for now as creation of the encoder 609 // will actually fail later and fallback PEMs will be tested on later. 610 return PEMFactory::SupportsCodec(aCodec, *supported, aLocation); 611 } 612 613 /* static */ RefPtr<PlatformEncoderModule::CreateEncoderPromise> 614 RemoteMediaManagerChild::InitializeEncoder( 615 RefPtr<RemoteMediaDataEncoderChild>&& aEncoder, 616 const EncoderConfig& aConfig) { 617 RemoteMediaIn location = aEncoder->GetLocation(); 618 619 TrackSupport required; 620 if (aConfig.IsAudio()) { 621 required = TrackSupport::EncodeAudio; 622 } else if (aConfig.IsVideo()) { 623 required = TrackSupport::EncodeVideo; 624 } else { 625 return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject( 626 MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, 627 nsPrintfCString("%s doesn't support encoding", 628 RemoteMediaInToStr(location)) 629 .get()), 630 __func__); 631 } 632 633 if (!GetTrackSupport(location).contains(required)) { 634 return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject( 635 MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, 636 nsPrintfCString("%s doesn't support encoding", 637 RemoteMediaInToStr(location)) 638 .get()), 639 __func__); 640 } 641 642 auto managerThread = aEncoder->GetManagerThread(); 643 if (!managerThread) { 644 return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject( 645 MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, "Thread shutdown"_ns), 646 __func__); 647 } 648 649 MOZ_ASSERT(location != RemoteMediaIn::Unspecified); 650 651 RefPtr<GenericNonExclusivePromise> p; 652 if (location == RemoteMediaIn::UtilityProcess_Generic || 653 location == RemoteMediaIn::UtilityProcess_AppleMedia || 654 location == RemoteMediaIn::UtilityProcess_WMF) { 655 p = LaunchUtilityProcessIfNeeded(location); 656 } else if (location == RemoteMediaIn::GpuProcess) { 657 p = GenericNonExclusivePromise::CreateAndResolve(true, __func__); 658 } else if (location == RemoteMediaIn::RddProcess) { 659 p = LaunchRDDProcessIfNeeded(); 660 } else { 661 p = GenericNonExclusivePromise::CreateAndReject( 662 NS_ERROR_DOM_MEDIA_DENIED_IN_NON_UTILITY, __func__); 663 } 664 LOG("Creating %s encoder type %d in %s", 665 aConfig.IsAudio() ? "audio" : "video", static_cast<int>(aConfig.mCodec), 666 RemoteMediaInToStr(location)); 667 668 return p->Then( 669 managerThread, __func__, 670 [encoder = std::move(aEncoder), aConfig](bool) { 671 auto* manager = GetSingleton(encoder->GetLocation()); 672 if (!manager) { 673 LOG("Create encoder in %s failed, shutdown", 674 RemoteMediaInToStr(encoder->GetLocation())); 675 // We got shutdown. 676 return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject( 677 MediaResult(NS_ERROR_DOM_MEDIA_CANCELED, 678 "Remote manager not available"), 679 __func__); 680 } 681 if (!manager->SendPRemoteEncoderConstructor(encoder, aConfig)) { 682 LOG("Create encoder in %s failed, send failed", 683 RemoteMediaInToStr(encoder->GetLocation())); 684 return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject( 685 MediaResult(NS_ERROR_NOT_AVAILABLE, 686 "Failed to construct encoder actor"), 687 __func__); 688 } 689 return encoder->Construct(); 690 }, 691 [location](nsresult aResult) { 692 LOG("Create encoder in %s failed, cannot start process", 693 RemoteMediaInToStr(location)); 694 return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject( 695 MediaResult(aResult, "Couldn't start encode process"), __func__); 696 }); 697 } 698 699 /* static */ 700 RefPtr<GenericNonExclusivePromise> 701 RemoteMediaManagerChild::LaunchRDDProcessIfNeeded() { 702 MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess(), 703 "Only supported from a content process."); 704 705 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 706 if (!managerThread) { 707 // We got shutdown. 708 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE, 709 __func__); 710 } 711 712 StaticMutexAutoLock lock(sLaunchMutex); 713 auto& rddLaunchPromise = sLaunchPromises[RemoteMediaIn::RddProcess]; 714 if (rddLaunchPromise) { 715 return rddLaunchPromise; 716 } 717 718 // We have a couple possible states here. We are in a content process 719 // and: 720 // 1) the RDD process has never been launched. RDD should be launched 721 // and the IPC connections setup. 722 // 2) the RDD process has been launched, but this particular content 723 // process has not setup (or has lost) its IPC connection. 724 // In the code below, we assume we need to launch the RDD process and 725 // setup the IPC connections. However, if the manager thread for 726 // RemoteMediaManagerChild is available we do a quick check to see 727 // if we can send (meaning the IPC channel is open). If we can send, 728 // then no work is necessary. If we can't send, then we call 729 // LaunchRDDProcess which will launch RDD if necessary, and setup the 730 // IPC connections between *this* content process and the RDD process. 731 732 RefPtr<GenericNonExclusivePromise> p = InvokeAsync( 733 managerThread, __func__, []() -> RefPtr<GenericNonExclusivePromise> { 734 auto* rps = GetSingleton(RemoteMediaIn::RddProcess); 735 if (rps && rps->CanSend()) { 736 return GenericNonExclusivePromise::CreateAndResolve(true, __func__); 737 } 738 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 739 ipc::PBackgroundChild* bgActor = 740 ipc::BackgroundChild::GetForCurrentThread(); 741 if (!managerThread || NS_WARN_IF(!bgActor)) { 742 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE, 743 __func__); 744 } 745 746 return bgActor->SendEnsureRDDProcessAndCreateBridge()->Then( 747 managerThread, __func__, 748 [](ipc::PBackgroundChild::EnsureRDDProcessAndCreateBridgePromise:: 749 ResolveOrRejectValue&& aResult) { 750 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 751 if (!managerThread || aResult.IsReject()) { 752 // The parent process died or we got shutdown 753 return GenericNonExclusivePromise::CreateAndReject( 754 NS_ERROR_FAILURE, __func__); 755 } 756 nsresult rv = std::get<0>(aResult.ResolveValue()); 757 if (NS_FAILED(rv)) { 758 return GenericNonExclusivePromise::CreateAndReject(rv, 759 __func__); 760 } 761 OpenRemoteMediaManagerChildForProcess( 762 std::get<1>(std::move(aResult.ResolveValue())), 763 RemoteMediaIn::RddProcess); 764 return GenericNonExclusivePromise::CreateAndResolve(true, 765 __func__); 766 }); 767 }); 768 769 // This should not be dispatched to a threadpool thread, so use managerThread 770 p = p->Then( 771 managerThread, __func__, 772 [](const GenericNonExclusivePromise::ResolveOrRejectValue& aResult) { 773 StaticMutexAutoLock lock(sLaunchMutex); 774 sLaunchPromises[RemoteMediaIn::RddProcess] = nullptr; 775 return GenericNonExclusivePromise::CreateAndResolveOrReject(aResult, 776 __func__); 777 }); 778 779 rddLaunchPromise = p; 780 return rddLaunchPromise; 781 } 782 783 /* static */ 784 RefPtr<GenericNonExclusivePromise> 785 RemoteMediaManagerChild::LaunchUtilityProcessIfNeeded(RemoteMediaIn aLocation) { 786 MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess(), 787 "Only supported from a content process."); 788 789 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 790 if (!managerThread) { 791 // We got shutdown. 792 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE, 793 __func__); 794 } 795 796 MOZ_ASSERT(aLocation == RemoteMediaIn::UtilityProcess_Generic || 797 aLocation == RemoteMediaIn::UtilityProcess_AppleMedia || 798 aLocation == RemoteMediaIn::UtilityProcess_WMF || 799 aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM); 800 StaticMutexAutoLock lock(sLaunchMutex); 801 auto& utilityLaunchPromise = sLaunchPromises[aLocation]; 802 803 if (utilityLaunchPromise) { 804 return utilityLaunchPromise; 805 } 806 807 // We have a couple possible states here. We are in a content process 808 // and: 809 // 1) the Utility process has never been launched. Utility should be launched 810 // and the IPC connections setup. 811 // 2) the Utility process has been launched, but this particular content 812 // process has not setup (or has lost) its IPC connection. 813 // In the code below, we assume we need to launch the Utility process and 814 // setup the IPC connections. However, if the manager thread for 815 // RemoteMediaManagerChild is available we do a quick check to see 816 // if we can send (meaning the IPC channel is open). If we can send, 817 // then no work is necessary. If we can't send, then we call 818 // LaunchUtilityProcess which will launch Utility if necessary, and setup the 819 // IPC connections between *this* content process and the Utility process. 820 821 RefPtr<GenericNonExclusivePromise> p = InvokeAsync( 822 managerThread, __func__, 823 [aLocation]() -> RefPtr<GenericNonExclusivePromise> { 824 auto* rps = GetSingleton(aLocation); 825 if (rps && rps->CanSend()) { 826 return GenericNonExclusivePromise::CreateAndResolve(true, __func__); 827 } 828 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 829 ipc::PBackgroundChild* bgActor = 830 ipc::BackgroundChild::GetForCurrentThread(); 831 if (!managerThread || NS_WARN_IF(!bgActor)) { 832 return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE, 833 __func__); 834 } 835 836 return bgActor->SendEnsureUtilityProcessAndCreateBridge(aLocation) 837 ->Then(managerThread, __func__, 838 [aLocation](ipc::PBackgroundChild:: 839 EnsureUtilityProcessAndCreateBridgePromise:: 840 ResolveOrRejectValue&& aResult) 841 -> RefPtr<GenericNonExclusivePromise> { 842 nsCOMPtr<nsISerialEventTarget> managerThread = 843 GetManagerThread(); 844 if (!managerThread || aResult.IsReject()) { 845 // The parent process died or we got shutdown 846 return GenericNonExclusivePromise::CreateAndReject( 847 NS_ERROR_FAILURE, __func__); 848 } 849 nsresult rv = std::get<0>(aResult.ResolveValue()); 850 if (NS_FAILED(rv)) { 851 return GenericNonExclusivePromise::CreateAndReject( 852 rv, __func__); 853 } 854 OpenRemoteMediaManagerChildForProcess( 855 std::get<1>(std::move(aResult.ResolveValue())), 856 aLocation); 857 return GenericNonExclusivePromise::CreateAndResolve( 858 true, __func__); 859 }); 860 }); 861 862 // Let's make sure this promise is also run on the managerThread to avoid 863 // situations where it would be run on a threadpool thread. 864 // During bug 1794988 this was happening when enabling Utility for audio on 865 // Android when running the sequence of tests 866 // dom/media/test/test_access_control.html 867 // dom/media/test/test_arraybuffer.html 868 // 869 // We would have a launched utility process but the promises would not have 870 // been cleared, so any subsequent tentative to perform audio decoding would 871 // think the process is not yet ran and it would try to wait on the pending 872 // promises. 873 p = p->Then( 874 managerThread, __func__, 875 [aLocation]( 876 const GenericNonExclusivePromise::ResolveOrRejectValue& aResult) { 877 StaticMutexAutoLock lock(sLaunchMutex); 878 sLaunchPromises[aLocation] = nullptr; 879 return GenericNonExclusivePromise::CreateAndResolveOrReject(aResult, 880 __func__); 881 }); 882 utilityLaunchPromise = p; 883 return utilityLaunchPromise; 884 } 885 886 /* static */ 887 TrackSupportSet RemoteMediaManagerChild::GetTrackSupport( 888 RemoteMediaIn aLocation) { 889 TrackSupportSet s{TrackSupport::None}; 890 switch (aLocation) { 891 case RemoteMediaIn::GpuProcess: 892 s = TrackSupport::DecodeVideo; 893 if (StaticPrefs::media_use_remote_encoder_video()) { 894 s += TrackSupport::EncodeVideo; 895 } 896 break; 897 case RemoteMediaIn::RddProcess: 898 s = TrackSupport::DecodeVideo; 899 if (StaticPrefs::media_use_remote_encoder_video()) { 900 s += TrackSupport::EncodeVideo; 901 } 902 #ifndef ANDROID 903 // Only use RDD for audio coding if we don't have the utility process. If 904 // we have a CDM (which we can't determine here) on Android, then we want 905 // to perform both the video and audio decoding in the RDD so that they 906 // can share the CDM instance. 907 if (!StaticPrefs::media_utility_process_enabled()) 908 #endif 909 { 910 s += TrackSupport::DecodeAudio; 911 if (StaticPrefs::media_use_remote_encoder_audio()) { 912 s += TrackSupport::EncodeAudio; 913 } 914 } 915 break; 916 case RemoteMediaIn::UtilityProcess_Generic: 917 case RemoteMediaIn::UtilityProcess_AppleMedia: 918 case RemoteMediaIn::UtilityProcess_WMF: 919 if (StaticPrefs::media_utility_process_enabled()) { 920 s = TrackSupport::DecodeAudio; 921 if (StaticPrefs::media_use_remote_encoder_audio()) { 922 s += TrackSupport::EncodeAudio; 923 } 924 } 925 break; 926 case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: 927 #ifdef MOZ_WMF_MEDIA_ENGINE 928 // When we enable the media engine, it would need both tracks to 929 // synchronize the a/v playback. 930 if (StaticPrefs::media_wmf_media_engine_enabled()) { 931 s = TrackSupportSet{TrackSupport::DecodeAudio, 932 TrackSupport::DecodeVideo}; 933 } 934 #endif 935 break; 936 default: 937 MOZ_ASSERT_UNREACHABLE("Undefined location!"); 938 break; 939 } 940 return s; 941 } 942 943 PRemoteDecoderChild* RemoteMediaManagerChild::AllocPRemoteDecoderChild( 944 const RemoteDecoderInfoIPDL& /* not used */, 945 const CreateDecoderParams::OptionSet& aOptions, 946 const Maybe<layers::TextureFactoryIdentifier>& aIdentifier, 947 const Maybe<uint64_t>& aMediaEngineId, const Maybe<TrackingId>& aTrackingId, 948 PRemoteCDMChild* aCDM) { 949 // RemoteDecoderModule is responsible for creating RemoteDecoderChild 950 // classes. 951 MOZ_ASSERT(false, 952 "RemoteMediaManagerChild cannot create " 953 "RemoteDecoderChild classes"); 954 return nullptr; 955 } 956 957 bool RemoteMediaManagerChild::DeallocPRemoteDecoderChild( 958 PRemoteDecoderChild* actor) { 959 RemoteDecoderChild* child = static_cast<RemoteDecoderChild*>(actor); 960 child->IPDLActorDestroyed(); 961 return true; 962 } 963 964 PMFMediaEngineChild* RemoteMediaManagerChild::AllocPMFMediaEngineChild() { 965 MOZ_ASSERT_UNREACHABLE( 966 "RemoteMediaManagerChild cannot create MFMediaEngineChild classes"); 967 return nullptr; 968 } 969 970 bool RemoteMediaManagerChild::DeallocPMFMediaEngineChild( 971 PMFMediaEngineChild* actor) { 972 #ifdef MOZ_WMF_MEDIA_ENGINE 973 MFMediaEngineChild* child = static_cast<MFMediaEngineChild*>(actor); 974 child->IPDLActorDestroyed(); 975 #endif 976 return true; 977 } 978 979 PMFCDMChild* RemoteMediaManagerChild::AllocPMFCDMChild(const nsAString&) { 980 MOZ_ASSERT_UNREACHABLE( 981 "RemoteMediaManagerChild cannot create PMFContentDecryptionModuleChild " 982 "classes"); 983 return nullptr; 984 } 985 986 bool RemoteMediaManagerChild::DeallocPMFCDMChild(PMFCDMChild* actor) { 987 #ifdef MOZ_WMF_CDM 988 static_cast<MFCDMChild*>(actor)->IPDLActorDestroyed(); 989 #endif 990 return true; 991 } 992 993 RemoteMediaManagerChild::RemoteMediaManagerChild(RemoteMediaIn aLocation) 994 : mLocation(aLocation) { 995 MOZ_ASSERT(mLocation == RemoteMediaIn::GpuProcess || 996 mLocation == RemoteMediaIn::RddProcess || 997 mLocation == RemoteMediaIn::UtilityProcess_Generic || 998 mLocation == RemoteMediaIn::UtilityProcess_AppleMedia || 999 mLocation == RemoteMediaIn::UtilityProcess_WMF || 1000 mLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM); 1001 } 1002 1003 /* static */ 1004 void RemoteMediaManagerChild::OpenRemoteMediaManagerChildForProcess( 1005 Endpoint<PRemoteMediaManagerChild>&& aEndpoint, RemoteMediaIn aLocation) { 1006 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 1007 if (!managerThread) { 1008 // We've been shutdown, bail. 1009 return; 1010 } 1011 MOZ_ASSERT(managerThread->IsOnCurrentThread()); 1012 1013 // For GPU process, make sure we always dispatch everything in sRecreateTasks, 1014 // even if we fail since this is as close to being recreated as we will ever 1015 // be. 1016 auto runRecreateTasksIfNeeded = MakeScopeExit([aLocation]() { 1017 if (aLocation == RemoteMediaIn::GpuProcess) { 1018 for (Runnable* task : *sRecreateTasks) { 1019 task->Run(); 1020 } 1021 sRecreateTasks->Clear(); 1022 } 1023 }); 1024 1025 // Only create RemoteMediaManagerChild, bind new endpoint and init 1026 // ipdl if: 1027 // 1) haven't init'd sRemoteMediaManagerChildForProcesses[aLocation] 1028 // or 1029 // 2) if ActorDestroy was called meaning the other end of the ipc channel was 1030 // torn down 1031 // But for GPU process, we always recreate a new manager child. 1032 MOZ_ASSERT(aLocation != RemoteMediaIn::SENTINEL); 1033 auto& remoteDecoderManagerChild = 1034 sRemoteMediaManagerChildForProcesses[aLocation]; 1035 if (aLocation != RemoteMediaIn::GpuProcess && remoteDecoderManagerChild && 1036 remoteDecoderManagerChild->CanSend()) { 1037 return; 1038 } 1039 remoteDecoderManagerChild = nullptr; 1040 if (aEndpoint.IsValid()) { 1041 RefPtr<RemoteMediaManagerChild> manager = 1042 new RemoteMediaManagerChild(aLocation); 1043 if (aEndpoint.Bind(manager)) { 1044 remoteDecoderManagerChild = manager; 1045 } 1046 } 1047 } 1048 1049 bool RemoteMediaManagerChild::DeallocShmem(mozilla::ipc::Shmem& aShmem) { 1050 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 1051 if (!managerThread) { 1052 return false; 1053 } 1054 if (!managerThread->IsOnCurrentThread()) { 1055 MOZ_ALWAYS_SUCCEEDS(managerThread->Dispatch(NS_NewRunnableFunction( 1056 "RemoteMediaManagerChild::DeallocShmem", 1057 [self = RefPtr{this}, shmem = aShmem]() mutable { 1058 if (self->CanSend()) { 1059 self->PRemoteMediaManagerChild::DeallocShmem(shmem); 1060 } 1061 }))); 1062 return true; 1063 } 1064 return PRemoteMediaManagerChild::DeallocShmem(aShmem); 1065 } 1066 1067 struct SurfaceDescriptorUserData { 1068 SurfaceDescriptorUserData(RemoteMediaManagerChild* aAllocator, 1069 SurfaceDescriptor& aSD) 1070 : mAllocator(aAllocator), mSD(aSD) {} 1071 ~SurfaceDescriptorUserData() { DestroySurfaceDescriptor(mAllocator, &mSD); } 1072 1073 RefPtr<RemoteMediaManagerChild> mAllocator; 1074 SurfaceDescriptor mSD; 1075 }; 1076 1077 void DeleteSurfaceDescriptorUserData(void* aClosure) { 1078 SurfaceDescriptorUserData* sd = 1079 reinterpret_cast<SurfaceDescriptorUserData*>(aClosure); 1080 delete sd; 1081 } 1082 1083 already_AddRefed<SourceSurface> RemoteMediaManagerChild::Readback( 1084 const SurfaceDescriptorGPUVideo& aSD) { 1085 // We can't use NS_DispatchAndSpinEventLoopUntilComplete here since that will 1086 // spin the event loop while it waits. This function can be called from JS and 1087 // we don't want that to happen. 1088 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 1089 if (!managerThread) { 1090 return nullptr; 1091 } 1092 1093 SurfaceDescriptor sd; 1094 RefPtr<Runnable> task = 1095 NS_NewRunnableFunction("RemoteMediaManagerChild::Readback", [&]() { 1096 if (CanSend()) { 1097 SendReadback(aSD, &sd); 1098 } 1099 }); 1100 SyncRunnable::DispatchToThread(managerThread, task); 1101 1102 if (!IsSurfaceDescriptorValid(sd)) { 1103 return nullptr; 1104 } 1105 1106 RefPtr<DataSourceSurface> source = GetSurfaceForDescriptor(sd); 1107 if (!source) { 1108 DestroySurfaceDescriptor(this, &sd); 1109 NS_WARNING("Failed to map SurfaceDescriptor in Readback"); 1110 return nullptr; 1111 } 1112 1113 static UserDataKey sSurfaceDescriptor; 1114 source->AddUserData(&sSurfaceDescriptor, 1115 new SurfaceDescriptorUserData(this, sd), 1116 DeleteSurfaceDescriptorUserData); 1117 1118 return source.forget(); 1119 } 1120 1121 already_AddRefed<Image> RemoteMediaManagerChild::TransferToImage( 1122 const SurfaceDescriptorGPUVideo& aSD, const IntSize& aSize, 1123 const ColorDepth& aColorDepth, YUVColorSpace aYUVColorSpace, 1124 ColorSpace2 aColorPrimaries, TransferFunction aTransferFunction, 1125 ColorRange aColorRange) { 1126 // The Image here creates a TextureData object that takes ownership 1127 // of the SurfaceDescriptor, and is responsible for making sure that 1128 // it gets deallocated. 1129 SurfaceDescriptorGPUVideo sd(aSD); 1130 sd.get_SurfaceDescriptorRemoteDecoder().source() = 1131 Some(GetVideoBridgeSourceFromRemoteMediaIn(mLocation)); 1132 return MakeAndAddRef<GPUVideoImage>(this, sd, aSize, aColorDepth, 1133 aYUVColorSpace, aColorPrimaries, 1134 aTransferFunction, aColorRange); 1135 } 1136 1137 void RemoteMediaManagerChild::DeallocateSurfaceDescriptor( 1138 const SurfaceDescriptorGPUVideo& aSD) { 1139 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 1140 if (!managerThread) { 1141 return; 1142 } 1143 MOZ_ALWAYS_SUCCEEDS(managerThread->Dispatch(NS_NewRunnableFunction( 1144 "RemoteMediaManagerChild::DeallocateSurfaceDescriptor", 1145 [ref = RefPtr{this}, sd = aSD]() { 1146 if (ref->CanSend()) { 1147 ref->SendDeallocateSurfaceDescriptorGPUVideo(sd); 1148 } 1149 }))); 1150 } 1151 1152 void RemoteMediaManagerChild::OnSetCurrent( 1153 const SurfaceDescriptorGPUVideo& aSD) { 1154 nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread(); 1155 if (!managerThread) { 1156 return; 1157 } 1158 MOZ_ALWAYS_SUCCEEDS(managerThread->Dispatch( 1159 NS_NewRunnableFunction("RemoteMediaManagerChild::OnSetCurrent", 1160 [ref = RefPtr{this}, sd = aSD]() { 1161 if (ref->CanSend()) { 1162 ref->SendOnSetCurrent(sd); 1163 } 1164 }))); 1165 } 1166 1167 /* static */ void RemoteMediaManagerChild::HandleRejectionError( 1168 const RemoteMediaManagerChild* aDyingManager, RemoteMediaIn aLocation, 1169 const ipc::ResponseRejectReason& aReason, 1170 std::function<void(const MediaResult&)>&& aCallback) { 1171 // If the channel goes down and CanSend() returns false, the IPDL promise will 1172 // be rejected with SendError rather than ActorDestroyed. Both means the same 1173 // thing and we can consider that the parent has crashed. The child can no 1174 // longer be used. 1175 1176 if (aLocation == RemoteMediaIn::GpuProcess) { 1177 // The GPU process will get automatically restarted by the parent process. 1178 // Once it has been restarted the ContentChild will receive the message and 1179 // will call GetManager()->InitForGPUProcess. 1180 // We defer reporting an error until we've recreated the RemoteDecoder 1181 // manager so that it'll be safe for MediaFormatReader to recreate decoders 1182 RunWhenGPUProcessRecreated( 1183 aDyingManager, 1184 NS_NewRunnableFunction( 1185 "RemoteMediaManagerChild::HandleRejectionError", 1186 [callback = std::move(aCallback)]() { 1187 MediaResult error( 1188 NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR, __func__); 1189 callback(error); 1190 })); 1191 return; 1192 } 1193 1194 nsresult err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR; 1195 if (aLocation == RemoteMediaIn::RddProcess) { 1196 err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR; 1197 } else if (aLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 1198 err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR; 1199 } 1200 // The RDD/utility process is restarted on demand and asynchronously, we can 1201 // immediately inform the caller that a new en/decoder is needed. The process 1202 // will then be restarted during the new en/decoder creation by 1203 aCallback(MediaResult(err, __func__)); 1204 } 1205 1206 void RemoteMediaManagerChild::HandleFatalError(const char* aMsg) { 1207 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID()); 1208 } 1209 1210 void RemoteMediaManagerChild::SetSupported( 1211 RemoteMediaIn aLocation, const media::MediaCodecsSupported& aSupported) { 1212 switch (aLocation) { 1213 case RemoteMediaIn::GpuProcess: 1214 case RemoteMediaIn::RddProcess: 1215 case RemoteMediaIn::UtilityProcess_AppleMedia: 1216 case RemoteMediaIn::UtilityProcess_Generic: 1217 case RemoteMediaIn::UtilityProcess_WMF: 1218 case RemoteMediaIn::UtilityProcess_MFMediaEngineCDM: { 1219 StaticMutexAutoLock lock(sProcessSupportedMutex); 1220 sProcessSupported[aLocation] = Some(aSupported); 1221 break; 1222 } 1223 default: 1224 MOZ_CRASH("Not to be used for any other process"); 1225 } 1226 } 1227 1228 #undef LOG 1229 1230 } // namespace mozilla