Bug 1842773 - Part 5: Add ArrayBuffer.prototype.{maxByteLength,resizable} getters...
[gecko.git] / dom / media / gmp / GMPContentParent.cpp
blob4483dfe78434d28ad5266b683f24d75df0039195
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"
7 #include "GMPLog.h"
8 #include "GMPParent.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,
27 aParent);
28 if (mParent) {
29 SetDisplayName(mParent->GetDisplayName());
30 SetPluginId(mParent->GetPluginId());
31 SetPluginType(mParent->GetPluginType());
35 GMPContentParent::~GMPContentParent() {
36 GMP_LOG_DEBUG(
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)",
58 this, aCDM);
59 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
61 MOZ_ALWAYS_TRUE(mChromiumCDMs.RemoveElement(aCDM));
62 CloseIfUnused();
65 void GMPContentParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder) {
66 GMP_LOG_DEBUG("GMPContentParent::VideoDecoderDestroyed(this=%p, aDecoder=%p)",
67 this, aDecoder);
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));
72 CloseIfUnused();
75 void GMPContentParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder) {
76 GMP_LOG_DEBUG("GMPContentParent::VideoEncoderDestroyed(this=%p, aEncoder=%p)",
77 this, aEncoder);
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));
82 CloseIfUnused();
85 void GMPContentParent::AddCloseBlocker() {
86 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
87 ++mCloseBlockerCount;
88 GMP_LOG_DEBUG(
89 "GMPContentParent::AddCloseBlocker(this=%p) mCloseBlockerCount=%" PRIu32,
90 this, mCloseBlockerCount);
93 void GMPContentParent::RemoveCloseBlocker() {
94 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
95 --mCloseBlockerCount;
96 GMP_LOG_DEBUG(
97 "GMPContentParent::RemoveCloseBlocker(this=%p) "
98 "mCloseBlockerCount=%" PRIu32,
99 this, mCloseBlockerCount);
100 CloseIfUnused();
103 void GMPContentParent::CloseIfUnused() {
104 MOZ_ASSERT(GMPEventTarget()->IsOnCurrentThread());
105 GMP_LOG_DEBUG(
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;
115 if (mParent) {
116 toClose = mParent->ForgetGMPContentParent();
117 } else {
118 toClose = this;
119 RefPtr<GeckoMediaPluginServiceChild> gmp(
120 GeckoMediaPluginServiceChild::GetSingleton());
121 if (gmp) {
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");
135 MOZ_ASSERT(mps);
136 if (!mps) {
137 return nullptr;
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,
157 aKeySystem.get());
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));
165 return nullptr;
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.
181 vdp.get()->AddRef();
182 *aGMPVD = vdp;
183 mVideoDecoders.AppendElement(vdp);
185 return NS_OK;
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.
198 vep.get()->AddRef();
199 *aGMPVE = vep;
200 mVideoEncoders.AppendElement(vep);
202 return NS_OK;
205 void GMPContentParentCloseBlocker::Destroy() {
206 MOZ_ASSERT(mParent);
207 MOZ_ASSERT(mEventTarget);
209 if (!mEventTarget->IsOnCurrentThread()) {
210 mEventTarget->Dispatch(NS_NewRunnableFunction(
211 __func__, [parent = std::move(mParent), eventTarget = mEventTarget]() {
212 parent->RemoveCloseBlocker();
213 }));
214 mEventTarget = nullptr;
215 return;
218 mParent->RemoveCloseBlocker();
219 mParent = nullptr;
220 mEventTarget = nullptr;
223 } // namespace mozilla::gmp