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
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "GMPContentParent.h"
9 #include "GMPServiceChild.h"
10 #include "GMPVideoDecoderParent.h"
11 #include "GMPVideoEncoderParent.h"
12 #include "ChromiumCDMParent.h"
13 #include "mozIGeckoMediaPluginService.h"
14 #include "mozilla/Logging.h"
15 #include "mozilla/Unused.h"
16 #include "base/task.h"
18 namespace mozilla::gmp
{
20 static const char* GetBoolString(bool aBool
) {
21 return aBool
? "true" : "false";
24 GMPContentParent::GMPContentParent(GMPParent
* aParent
)
25 : mParent(aParent
), mPluginId(0) {
26 GMP_LOG_DEBUG("GMPContentParent::GMPContentParent(this=%p), aParent=%p", this,
29 SetDisplayName(mParent
->GetDisplayName());
30 SetPluginId(mParent
->GetPluginId());
31 SetPluginType(mParent
->GetPluginType());
35 GMPContentParent::~GMPContentParent() {
37 "GMPContentParent::~GMPContentParent(this=%p) mVideoDecoders.IsEmpty=%s, "
38 "mVideoEncoders.IsEmpty=%s, mChromiumCDMs.IsEmpty=%s, "
39 "mCloseBlockerCount=%" PRIu32
,
40 this, GetBoolString(mVideoDecoders
.IsEmpty()),
41 GetBoolString(mVideoEncoders
.IsEmpty()),
42 GetBoolString(mChromiumCDMs
.IsEmpty()), mCloseBlockerCount
);
45 void GMPContentParent::ActorDestroy(ActorDestroyReason aWhy
) {
46 GMP_LOG_DEBUG("GMPContentParent::ActorDestroy(this=%p, aWhy=%d)", this,
47 static_cast<int>(aWhy
));
48 MOZ_ASSERT(mVideoDecoders
.IsEmpty() && mVideoEncoders
.IsEmpty() &&
49 mChromiumCDMs
.IsEmpty());
52 void GMPContentParent::CheckThread() {
53 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
56 void GMPContentParent::ChromiumCDMDestroyed(ChromiumCDMParent
* aCDM
) {
57 GMP_LOG_DEBUG("GMPContentParent::ChromiumCDMDestroyed(this=%p, aCDM=%p)",
59 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
61 MOZ_ALWAYS_TRUE(mChromiumCDMs
.RemoveElement(aCDM
));
65 void GMPContentParent::VideoDecoderDestroyed(GMPVideoDecoderParent
* aDecoder
) {
66 GMP_LOG_DEBUG("GMPContentParent::VideoDecoderDestroyed(this=%p, aDecoder=%p)",
68 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
70 // If the constructor fails, we'll get called before it's added
71 Unused
<< NS_WARN_IF(!mVideoDecoders
.RemoveElement(aDecoder
));
75 void GMPContentParent::VideoEncoderDestroyed(GMPVideoEncoderParent
* aEncoder
) {
76 GMP_LOG_DEBUG("GMPContentParent::VideoEncoderDestroyed(this=%p, aEncoder=%p)",
78 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
80 // If the constructor fails, we'll get called before it's added
81 Unused
<< NS_WARN_IF(!mVideoEncoders
.RemoveElement(aEncoder
));
85 void GMPContentParent::AddCloseBlocker() {
86 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
89 "GMPContentParent::AddCloseBlocker(this=%p) mCloseBlockerCount=%" PRIu32
,
90 this, mCloseBlockerCount
);
93 void GMPContentParent::RemoveCloseBlocker() {
94 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
97 "GMPContentParent::RemoveCloseBlocker(this=%p) "
98 "mCloseBlockerCount=%" PRIu32
,
99 this, mCloseBlockerCount
);
103 void GMPContentParent::CloseIfUnused() {
104 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
106 "GMPContentParent::CloseIfUnused(this=%p) mVideoDecoders.IsEmpty=%s, "
107 "mVideoEncoders.IsEmpty=%s, mChromiumCDMs.IsEmpty=%s, "
108 "mCloseBlockerCount=%" PRIu32
,
109 this, GetBoolString(mVideoDecoders
.IsEmpty()),
110 GetBoolString(mVideoEncoders
.IsEmpty()),
111 GetBoolString(mChromiumCDMs
.IsEmpty()), mCloseBlockerCount
);
112 if (mVideoDecoders
.IsEmpty() && mVideoEncoders
.IsEmpty() &&
113 mChromiumCDMs
.IsEmpty() && mCloseBlockerCount
== 0) {
114 RefPtr
<GMPContentParent
> toClose
;
116 toClose
= mParent
->ForgetGMPContentParent();
119 RefPtr
<GeckoMediaPluginServiceChild
> gmp(
120 GeckoMediaPluginServiceChild::GetSingleton());
122 gmp
->RemoveGMPContentParent(toClose
);
125 NS_DispatchToCurrentThread(NewRunnableMethod(
126 "gmp::GMPContentParent::Close", toClose
, &GMPContentParent::Close
));
130 nsCOMPtr
<nsISerialEventTarget
> GMPContentParent::GMPEventTarget() {
131 if (!mGMPEventTarget
) {
132 GMP_LOG_DEBUG("GMPContentParent::GMPEventTarget(this=%p)", this);
133 nsCOMPtr
<mozIGeckoMediaPluginService
> mps
=
134 do_GetService("@mozilla.org/gecko-media-plugin-service;1");
139 // Not really safe if we just grab to the mGMPEventTarget, as we don't know
140 // what thread we're running on and other threads may be trying to
141 // access this without locks! However, debug only, and primary failure
142 // mode outside of compiler-helped TSAN is a leak. But better would be
143 // to use swap() under a lock.
144 nsCOMPtr
<nsIThread
> gmpThread
;
145 mps
->GetThread(getter_AddRefs(gmpThread
));
146 MOZ_ASSERT(gmpThread
);
148 mGMPEventTarget
= gmpThread
;
151 return mGMPEventTarget
;
154 already_AddRefed
<ChromiumCDMParent
> GMPContentParent::GetChromiumCDM(
155 const nsCString
& aKeySystem
) {
156 GMP_LOG_DEBUG("GMPContentParent::GetChromiumCDM(this=%p aKeySystem=%s)", this,
159 RefPtr
<ChromiumCDMParent
> parent
= new ChromiumCDMParent(this, GetPluginId());
160 // TODO: Remove parent from mChromiumCDMs in ChromiumCDMParent::Destroy().
161 mChromiumCDMs
.AppendElement(parent
);
163 if (!SendPChromiumCDMConstructor(parent
, aKeySystem
)) {
164 MOZ_ASSERT(!mChromiumCDMs
.Contains(parent
));
168 return parent
.forget();
171 nsresult
GMPContentParent::GetGMPVideoDecoder(GMPVideoDecoderParent
** aGMPVD
) {
172 GMP_LOG_DEBUG("GMPContentParent::GetGMPVideoDecoder(this=%p)", this);
174 RefPtr
<GMPVideoDecoderParent
> vdp
= new GMPVideoDecoderParent(this);
175 if (!SendPGMPVideoDecoderConstructor(vdp
)) {
176 return NS_ERROR_FAILURE
;
179 // This addref corresponds to the Proxy pointer the consumer is returned.
180 // It's dropped by calling Close() on the interface.
183 mVideoDecoders
.AppendElement(vdp
);
188 nsresult
GMPContentParent::GetGMPVideoEncoder(GMPVideoEncoderParent
** aGMPVE
) {
189 GMP_LOG_DEBUG("GMPContentParent::GetGMPVideoEncoder(this=%p)", this);
191 RefPtr
<GMPVideoEncoderParent
> vep
= new GMPVideoEncoderParent(this);
192 if (!SendPGMPVideoEncoderConstructor(vep
)) {
193 return NS_ERROR_FAILURE
;
196 // This addref corresponds to the Proxy pointer the consumer is returned.
197 // It's dropped by calling Close() on the interface.
200 mVideoEncoders
.AppendElement(vep
);
205 void GMPContentParentCloseBlocker::Destroy() {
207 MOZ_ASSERT(mEventTarget
);
209 if (!mEventTarget
->IsOnCurrentThread()) {
210 mEventTarget
->Dispatch(NS_NewRunnableFunction(
211 __func__
, [parent
= std::move(mParent
), eventTarget
= mEventTarget
]() {
212 parent
->RemoveCloseBlocker();
214 mEventTarget
= nullptr;
218 mParent
->RemoveCloseBlocker();
220 mEventTarget
= nullptr;
223 } // namespace mozilla::gmp