mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
c560dfa1f4
Differential Revision: https://phabricator.services.mozilla.com/D205394
263 lines
9.1 KiB
C++
263 lines
9.1 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "UtilityAudioDecoderChild.h"
|
|
|
|
#include "base/basictypes.h"
|
|
#include "mozilla/AppShutdown.h"
|
|
#include "mozilla/dom/ContentParent.h"
|
|
|
|
#ifdef MOZ_WMF_MEDIA_ENGINE
|
|
# include "mozilla/StaticPrefs_media.h"
|
|
# include "mozilla/gfx/GPUProcessManager.h"
|
|
# include "mozilla/gfx/gfxVars.h"
|
|
# include "mozilla/ipc/UtilityProcessManager.h"
|
|
# include "mozilla/layers/PVideoBridge.h"
|
|
# include "mozilla/layers/VideoBridgeUtils.h"
|
|
#endif
|
|
|
|
#ifdef MOZ_WMF_CDM
|
|
# include "mozilla/dom/Promise.h"
|
|
# include "mozilla/EMEUtils.h"
|
|
# include "mozilla/PMFCDM.h"
|
|
#endif
|
|
|
|
namespace mozilla::ipc {
|
|
|
|
NS_IMETHODIMP UtilityAudioDecoderChildShutdownObserver::Observe(
|
|
nsISupports* aSubject, const char* aTopic, const char16_t* aData) {
|
|
MOZ_ASSERT(strcmp(aTopic, "ipc:utility-shutdown") == 0);
|
|
|
|
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
|
if (observerService) {
|
|
observerService->RemoveObserver(this, "ipc:utility-shutdown");
|
|
}
|
|
|
|
UtilityAudioDecoderChild::Shutdown(mSandbox);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(UtilityAudioDecoderChildShutdownObserver, nsIObserver);
|
|
|
|
static EnumeratedArray<SandboxingKind, StaticRefPtr<UtilityAudioDecoderChild>,
|
|
size_t(SandboxingKind::COUNT)>
|
|
sAudioDecoderChilds;
|
|
|
|
UtilityAudioDecoderChild::UtilityAudioDecoderChild(SandboxingKind aKind)
|
|
: mSandbox(aKind), mAudioDecoderChildStart(TimeStamp::Now()) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
|
if (observerService) {
|
|
auto* obs = new UtilityAudioDecoderChildShutdownObserver(aKind);
|
|
observerService->AddObserver(obs, "ipc:utility-shutdown", false);
|
|
}
|
|
}
|
|
|
|
nsresult UtilityAudioDecoderChild::BindToUtilityProcess(
|
|
RefPtr<UtilityProcessParent> aUtilityParent) {
|
|
Endpoint<PUtilityAudioDecoderChild> utilityAudioDecoderChildEnd;
|
|
Endpoint<PUtilityAudioDecoderParent> utilityAudioDecoderParentEnd;
|
|
nsresult rv = PUtilityAudioDecoder::CreateEndpoints(
|
|
aUtilityParent->OtherPid(), base::GetCurrentProcId(),
|
|
&utilityAudioDecoderParentEnd, &utilityAudioDecoderChildEnd);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
MOZ_ASSERT(false, "Protocol endpoints failure");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsTArray<gfx::GfxVarUpdate> updates;
|
|
#ifdef MOZ_WMF_MEDIA_ENGINE
|
|
// Only MFCDM process needs gfxVars
|
|
if (mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM) {
|
|
updates = gfx::gfxVars::FetchNonDefaultVars();
|
|
}
|
|
#endif
|
|
if (!aUtilityParent->SendStartUtilityAudioDecoderService(
|
|
std::move(utilityAudioDecoderParentEnd), std::move(updates))) {
|
|
MOZ_ASSERT(false, "StartUtilityAudioDecoder service failure");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
Bind(std::move(utilityAudioDecoderChildEnd));
|
|
|
|
PROFILER_MARKER_UNTYPED("UtilityAudioDecoderChild::BindToUtilityProcess", IPC,
|
|
MarkerOptions(MarkerTiming::IntervalUntilNowFrom(
|
|
mAudioDecoderChildStart)));
|
|
return NS_OK;
|
|
}
|
|
|
|
void UtilityAudioDecoderChild::ActorDestroy(ActorDestroyReason aReason) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
#ifdef MOZ_WMF_MEDIA_ENGINE
|
|
if (mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM) {
|
|
gfx::gfxVars::RemoveReceiver(this);
|
|
}
|
|
#endif
|
|
Shutdown(mSandbox);
|
|
}
|
|
|
|
void UtilityAudioDecoderChild::Bind(
|
|
Endpoint<PUtilityAudioDecoderChild>&& aEndpoint) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
if (NS_WARN_IF(!aEndpoint.Bind(this))) {
|
|
MOZ_ASSERT_UNREACHABLE("Failed to bind UtilityAudioDecoderChild!");
|
|
return;
|
|
}
|
|
#ifdef MOZ_WMF_MEDIA_ENGINE
|
|
if (mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM) {
|
|
gfx::gfxVars::AddReceiver(this);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* static */
|
|
void UtilityAudioDecoderChild::Shutdown(SandboxingKind aKind) {
|
|
sAudioDecoderChilds[aKind] = nullptr;
|
|
}
|
|
|
|
/* static */
|
|
RefPtr<UtilityAudioDecoderChild> UtilityAudioDecoderChild::GetSingleton(
|
|
SandboxingKind aKind) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
bool shutdown = AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown);
|
|
if (!sAudioDecoderChilds[aKind] && !shutdown) {
|
|
sAudioDecoderChilds[aKind] = new UtilityAudioDecoderChild(aKind);
|
|
}
|
|
return sAudioDecoderChilds[aKind];
|
|
}
|
|
|
|
mozilla::ipc::IPCResult
|
|
UtilityAudioDecoderChild::RecvUpdateMediaCodecsSupported(
|
|
const RemoteDecodeIn& aLocation,
|
|
const media::MediaCodecsSupported& aSupported) {
|
|
dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(aLocation,
|
|
aSupported);
|
|
return IPC_OK();
|
|
}
|
|
|
|
#ifdef MOZ_WMF_MEDIA_ENGINE
|
|
mozilla::ipc::IPCResult
|
|
UtilityAudioDecoderChild::RecvCompleteCreatedVideoBridge() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
|
|
mHasCreatedVideoBridge = State::Created;
|
|
return IPC_OK();
|
|
}
|
|
|
|
void UtilityAudioDecoderChild::OnVarChanged(const gfx::GfxVarUpdate& aVar) {
|
|
MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
|
|
SendUpdateVar(aVar);
|
|
}
|
|
|
|
void UtilityAudioDecoderChild::OnCompositorUnexpectedShutdown() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mSandbox == SandboxingKind::MF_MEDIA_ENGINE_CDM);
|
|
mHasCreatedVideoBridge = State::None;
|
|
CreateVideoBridge();
|
|
}
|
|
|
|
bool UtilityAudioDecoderChild::CreateVideoBridge() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
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;
|
|
|
|
// Build content device data first; this ensure that the GPU process is fully
|
|
// ready.
|
|
gfx::ContentDeviceData contentDeviceData;
|
|
gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData);
|
|
|
|
gfx::GPUProcessManager* gpuManager = gfx::GPUProcessManager::Get();
|
|
if (!gpuManager) {
|
|
NS_WARNING("Failed to get a gpu mananger!");
|
|
return false;
|
|
}
|
|
|
|
// The child end is the producer of video frames; the parent end is the
|
|
// consumer.
|
|
base::ProcessId childPid = UtilityProcessManager::GetSingleton()
|
|
->GetProcessParent(mSandbox)
|
|
->OtherPid();
|
|
base::ProcessId parentPid = gpuManager->GPUProcessPid();
|
|
if (parentPid == base::kInvalidProcessId) {
|
|
NS_WARNING("GPU process Id is invald!");
|
|
return false;
|
|
}
|
|
|
|
ipc::Endpoint<layers::PVideoBridgeParent> parentPipe;
|
|
ipc::Endpoint<layers::PVideoBridgeChild> childPipe;
|
|
nsresult rv = layers::PVideoBridge::CreateEndpoints(parentPid, childPid,
|
|
&parentPipe, &childPipe);
|
|
if (NS_FAILED(rv)) {
|
|
NS_WARNING("Failed to create endpoints for video bridge!");
|
|
return false;
|
|
}
|
|
|
|
gpuManager->InitVideoBridge(
|
|
std::move(parentPipe),
|
|
layers::VideoBridgeSource::MFMediaEngineCDMProcess);
|
|
SendInitVideoBridge(std::move(childPipe), contentDeviceData);
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WMF_CDM
|
|
void UtilityAudioDecoderChild::GetKeySystemCapabilities(
|
|
dom::Promise* aPromise) {
|
|
EME_LOG("Ask capabilities for all supported CDMs");
|
|
SendGetKeySystemCapabilities()->Then(
|
|
NS_GetCurrentThread(), __func__,
|
|
[promise = RefPtr<dom::Promise>(aPromise)](
|
|
CopyableTArray<MFCDMCapabilitiesIPDL>&& result) {
|
|
FallibleTArray<dom::CDMInformation> cdmInfo;
|
|
for (const auto& capabilities : result) {
|
|
EME_LOG("Received capabilities for %s",
|
|
NS_ConvertUTF16toUTF8(capabilities.keySystem()).get());
|
|
for (const auto& v : capabilities.videoCapabilities()) {
|
|
EME_LOG(" capabilities: video=%s",
|
|
NS_ConvertUTF16toUTF8(v.contentType()).get());
|
|
}
|
|
for (const auto& a : capabilities.audioCapabilities()) {
|
|
EME_LOG(" capabilities: audio=%s",
|
|
NS_ConvertUTF16toUTF8(a.contentType()).get());
|
|
}
|
|
for (const auto& e : capabilities.encryptionSchemes()) {
|
|
EME_LOG(" capabilities: encryptionScheme=%s",
|
|
EncryptionSchemeStr(e));
|
|
}
|
|
auto* info = cdmInfo.AppendElement(fallible);
|
|
if (!info) {
|
|
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
|
return;
|
|
}
|
|
info->mKeySystemName = capabilities.keySystem();
|
|
|
|
KeySystemConfig config;
|
|
MFCDMCapabilitiesIPDLToKeySystemConfig(capabilities, config);
|
|
info->mCapabilities = config.GetDebugInfo();
|
|
info->mClearlead =
|
|
DoesKeySystemSupportClearLead(info->mKeySystemName);
|
|
if (capabilities.isHDCP22Compatible()) {
|
|
info->mIsHDCP22Compatible = *capabilities.isHDCP22Compatible();
|
|
}
|
|
}
|
|
promise->MaybeResolve(cdmInfo);
|
|
},
|
|
[promise = RefPtr<dom::Promise>(aPromise)](
|
|
const mozilla::ipc::ResponseRejectReason& aReason) {
|
|
EME_LOG("IPC failure for GetKeySystemCapabilities!");
|
|
promise->MaybeReject(NS_ERROR_DOM_MEDIA_CDM_ERR);
|
|
});
|
|
}
|
|
#endif
|
|
|
|
} // namespace mozilla::ipc
|