1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 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/. */
7 #include "UtilityAudioDecoderChild.h"
9 #include "base/basictypes.h"
10 #include "mozilla/AppShutdown.h"
11 #include "mozilla/dom/ContentParent.h"
13 #ifdef MOZ_WMF_MEDIA_ENGINE
14 # include "mozilla/StaticPrefs_media.h"
15 # include "mozilla/gfx/GPUProcessManager.h"
16 # include "mozilla/gfx/gfxVars.h"
17 # include "mozilla/ipc/UtilityProcessManager.h"
18 # include "mozilla/layers/PVideoBridge.h"
19 # include "mozilla/layers/VideoBridgeUtils.h"
23 # include "mozilla/dom/Promise.h"
24 # include "mozilla/EMEUtils.h"
25 # include "mozilla/PMFCDM.h"
28 namespace mozilla::ipc
{
30 NS_IMETHODIMP
UtilityAudioDecoderChildShutdownObserver::Observe(
31 nsISupports
* aSubject
, const char* aTopic
, const char16_t
* aData
) {
32 MOZ_ASSERT(strcmp(aTopic
, "ipc:utility-shutdown") == 0);
34 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
35 if (observerService
) {
36 observerService
->RemoveObserver(this, "ipc:utility-shutdown");
39 UtilityAudioDecoderChild::Shutdown(mSandbox
);
43 NS_IMPL_ISUPPORTS(UtilityAudioDecoderChildShutdownObserver
, nsIObserver
);
45 static EnumeratedArray
<SandboxingKind
, StaticRefPtr
<UtilityAudioDecoderChild
>,
46 size_t(SandboxingKind::COUNT
)>
49 UtilityAudioDecoderChild::UtilityAudioDecoderChild(SandboxingKind aKind
)
50 : mSandbox(aKind
), mAudioDecoderChildStart(TimeStamp::Now()) {
51 MOZ_ASSERT(NS_IsMainThread());
52 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
53 if (observerService
) {
54 auto* obs
= new UtilityAudioDecoderChildShutdownObserver(aKind
);
55 observerService
->AddObserver(obs
, "ipc:utility-shutdown", false);
59 nsresult
UtilityAudioDecoderChild::BindToUtilityProcess(
60 RefPtr
<UtilityProcessParent
> aUtilityParent
) {
61 Endpoint
<PUtilityAudioDecoderChild
> utilityAudioDecoderChildEnd
;
62 Endpoint
<PUtilityAudioDecoderParent
> utilityAudioDecoderParentEnd
;
63 nsresult rv
= PUtilityAudioDecoder::CreateEndpoints(
64 aUtilityParent
->OtherEndpointProcInfo(), EndpointProcInfo::Current(),
65 &utilityAudioDecoderParentEnd
, &utilityAudioDecoderChildEnd
);
68 MOZ_ASSERT(false, "Protocol endpoints failure");
69 return NS_ERROR_FAILURE
;
72 nsTArray
<gfx::GfxVarUpdate
> updates
;
73 #ifdef MOZ_WMF_MEDIA_ENGINE
74 // Only MFCDM process needs gfxVars
75 if (mSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
) {
76 updates
= gfx::gfxVars::FetchNonDefaultVars();
79 if (!aUtilityParent
->SendStartUtilityAudioDecoderService(
80 std::move(utilityAudioDecoderParentEnd
), std::move(updates
))) {
81 MOZ_ASSERT(false, "StartUtilityAudioDecoder service failure");
82 return NS_ERROR_FAILURE
;
85 Bind(std::move(utilityAudioDecoderChildEnd
));
87 PROFILER_MARKER_UNTYPED("UtilityAudioDecoderChild::BindToUtilityProcess", IPC
,
88 MarkerOptions(MarkerTiming::IntervalUntilNowFrom(
89 mAudioDecoderChildStart
)));
93 void UtilityAudioDecoderChild::ActorDestroy(ActorDestroyReason aReason
) {
94 MOZ_ASSERT(NS_IsMainThread());
95 #ifdef MOZ_WMF_MEDIA_ENGINE
96 if (mSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
) {
97 gfx::gfxVars::RemoveReceiver(this);
103 void UtilityAudioDecoderChild::Bind(
104 Endpoint
<PUtilityAudioDecoderChild
>&& aEndpoint
) {
105 MOZ_ASSERT(NS_IsMainThread());
106 if (NS_WARN_IF(!aEndpoint
.Bind(this))) {
107 MOZ_ASSERT_UNREACHABLE("Failed to bind UtilityAudioDecoderChild!");
110 #ifdef MOZ_WMF_MEDIA_ENGINE
111 if (mSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
) {
112 gfx::gfxVars::AddReceiver(this);
118 void UtilityAudioDecoderChild::Shutdown(SandboxingKind aKind
) {
119 sAudioDecoderChilds
[aKind
] = nullptr;
123 RefPtr
<UtilityAudioDecoderChild
> UtilityAudioDecoderChild::GetSingleton(
124 SandboxingKind aKind
) {
125 MOZ_ASSERT(NS_IsMainThread());
126 bool shutdown
= AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown
);
127 if (!sAudioDecoderChilds
[aKind
] && !shutdown
) {
128 sAudioDecoderChilds
[aKind
] = new UtilityAudioDecoderChild(aKind
);
130 return sAudioDecoderChilds
[aKind
];
133 mozilla::ipc::IPCResult
134 UtilityAudioDecoderChild::RecvUpdateMediaCodecsSupported(
135 const RemoteDecodeIn
& aLocation
,
136 const media::MediaCodecsSupported
& aSupported
) {
137 dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(aLocation
,
142 #ifdef MOZ_WMF_MEDIA_ENGINE
143 mozilla::ipc::IPCResult
144 UtilityAudioDecoderChild::RecvCompleteCreatedVideoBridge() {
145 MOZ_ASSERT(NS_IsMainThread());
146 MOZ_ASSERT(mSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
);
147 mHasCreatedVideoBridge
= State::Created
;
151 void UtilityAudioDecoderChild::OnVarChanged(const gfx::GfxVarUpdate
& aVar
) {
152 MOZ_ASSERT(mSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
);
156 void UtilityAudioDecoderChild::OnCompositorUnexpectedShutdown() {
157 MOZ_ASSERT(NS_IsMainThread());
158 MOZ_ASSERT(mSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
);
159 mHasCreatedVideoBridge
= State::None
;
163 bool UtilityAudioDecoderChild::CreateVideoBridge() {
164 MOZ_ASSERT(NS_IsMainThread());
165 MOZ_ASSERT(mSandbox
== SandboxingKind::MF_MEDIA_ENGINE_CDM
);
167 // Creating or already created, avoiding reinit a bridge.
168 if (mHasCreatedVideoBridge
!= State::None
) {
171 mHasCreatedVideoBridge
= State::Creating
;
173 // Build content device data first; this ensure that the GPU process is fully
175 gfx::ContentDeviceData contentDeviceData
;
176 gfxPlatform::GetPlatform()->BuildContentDeviceData(&contentDeviceData
);
178 gfx::GPUProcessManager
* gpuManager
= gfx::GPUProcessManager::Get();
180 NS_WARNING("Failed to get a gpu mananger!");
184 // The child end is the producer of video frames; the parent end is the
186 EndpointProcInfo childInfo
= UtilityProcessManager::GetSingleton()
187 ->GetProcessParent(mSandbox
)
188 ->OtherEndpointProcInfo();
189 EndpointProcInfo parentInfo
= gpuManager
->GPUEndpointProcInfo();
190 if (parentInfo
== EndpointProcInfo::Invalid()) {
191 NS_WARNING("GPU process Id is invald!");
195 ipc::Endpoint
<layers::PVideoBridgeParent
> parentPipe
;
196 ipc::Endpoint
<layers::PVideoBridgeChild
> childPipe
;
197 nsresult rv
= layers::PVideoBridge::CreateEndpoints(parentInfo
, childInfo
,
198 &parentPipe
, &childPipe
);
200 NS_WARNING("Failed to create endpoints for video bridge!");
204 gpuManager
->InitVideoBridge(
205 std::move(parentPipe
),
206 layers::VideoBridgeSource::MFMediaEngineCDMProcess
);
207 SendInitVideoBridge(std::move(childPipe
), contentDeviceData
);
213 void UtilityAudioDecoderChild::GetKeySystemCapabilities(
214 dom::Promise
* aPromise
) {
215 EME_LOG("Ask capabilities for all supported CDMs");
216 SendGetKeySystemCapabilities()->Then(
217 NS_GetCurrentThread(), __func__
,
218 [promise
= RefPtr
<dom::Promise
>(aPromise
)](
219 CopyableTArray
<MFCDMCapabilitiesIPDL
>&& result
) {
220 FallibleTArray
<dom::CDMInformation
> cdmInfo
;
221 for (const auto& capabilities
: result
) {
222 EME_LOG("Received capabilities for %s",
223 NS_ConvertUTF16toUTF8(capabilities
.keySystem()).get());
224 for (const auto& v
: capabilities
.videoCapabilities()) {
225 for (const auto& scheme
: v
.encryptionSchemes()) {
226 EME_LOG(" capabilities: video=%s, scheme=%s",
227 NS_ConvertUTF16toUTF8(v
.contentType()).get(),
228 EnumValueToString(scheme
));
231 for (const auto& a
: capabilities
.audioCapabilities()) {
232 for (const auto& scheme
: a
.encryptionSchemes()) {
233 EME_LOG(" capabilities: audio=%s, scheme=%s",
234 NS_ConvertUTF16toUTF8(a
.contentType()).get(),
235 EnumValueToString(scheme
));
238 auto* info
= cdmInfo
.AppendElement(fallible
);
240 promise
->MaybeReject(NS_ERROR_OUT_OF_MEMORY
);
243 info
->mKeySystemName
= capabilities
.keySystem();
245 KeySystemConfig config
;
246 MFCDMCapabilitiesIPDLToKeySystemConfig(capabilities
, config
);
247 info
->mCapabilities
= config
.GetDebugInfo();
249 DoesKeySystemSupportClearLead(info
->mKeySystemName
);
250 if (capabilities
.isHDCP22Compatible()) {
251 info
->mIsHDCP22Compatible
= *capabilities
.isHDCP22Compatible();
254 promise
->MaybeResolve(cdmInfo
);
256 [promise
= RefPtr
<dom::Promise
>(aPromise
)](
257 const mozilla::ipc::ResponseRejectReason
& aReason
) {
258 EME_LOG("IPC failure for GetKeySystemCapabilities!");
259 promise
->MaybeReject(NS_ERROR_DOM_MEDIA_CDM_ERR
);
264 } // namespace mozilla::ipc