Bug 1858921 - Part 6: Remove unused default template arguments r=sfink
[gecko.git] / dom / media / platforms / AllocationPolicy.cpp
blobea7aaa74c8b12d732399e5d5d91238bc0bbee384
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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 "AllocationPolicy.h"
9 #include "ImageContainer.h"
10 #include "MediaInfo.h"
11 #include "PDMFactory.h"
12 #include "mozilla/ClearOnShutdown.h"
13 #include "mozilla/SchedulerGroup.h"
14 #ifdef MOZ_WIDGET_ANDROID
15 # include "mozilla/jni/Utils.h"
16 #endif
18 namespace mozilla {
20 using TrackType = TrackInfo::TrackType;
22 class AllocPolicyImpl::AutoDeallocToken : public Token {
23 public:
24 explicit AutoDeallocToken(const RefPtr<AllocPolicyImpl>& aPolicy)
25 : mPolicy(aPolicy) {}
27 private:
28 ~AutoDeallocToken() { mPolicy->Dealloc(); }
30 RefPtr<AllocPolicyImpl> mPolicy;
33 AllocPolicyImpl::AllocPolicyImpl(int aDecoderLimit)
34 : mMaxDecoderLimit(aDecoderLimit),
35 mMonitor("AllocPolicyImpl"),
36 mDecoderLimit(aDecoderLimit) {}
37 AllocPolicyImpl::~AllocPolicyImpl() { RejectAll(); }
39 auto AllocPolicyImpl::Alloc() -> RefPtr<Promise> {
40 ReentrantMonitorAutoEnter mon(mMonitor);
41 // No decoder limit set.
42 if (mDecoderLimit < 0) {
43 return Promise::CreateAndResolve(new Token(), __func__);
46 RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
47 mPromises.push(p);
48 ResolvePromise(mon);
49 return p;
52 void AllocPolicyImpl::Dealloc() {
53 ReentrantMonitorAutoEnter mon(mMonitor);
54 ++mDecoderLimit;
55 ResolvePromise(mon);
58 void AllocPolicyImpl::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock) {
59 MOZ_ASSERT(mDecoderLimit >= 0);
61 if (mDecoderLimit > 0 && !mPromises.empty()) {
62 --mDecoderLimit;
63 RefPtr<PromisePrivate> p = std::move(mPromises.front());
64 mPromises.pop();
65 p->Resolve(new AutoDeallocToken(this), __func__);
69 void AllocPolicyImpl::RejectAll() {
70 ReentrantMonitorAutoEnter mon(mMonitor);
71 while (!mPromises.empty()) {
72 RefPtr<PromisePrivate> p = std::move(mPromises.front());
73 mPromises.pop();
74 p->Reject(true, __func__);
78 static int32_t MediaDecoderLimitDefault() {
79 #ifdef MOZ_WIDGET_ANDROID
80 if (jni::GetAPIVersion() < 18) {
81 // Older Android versions have broken support for multiple simultaneous
82 // decoders, see bug 1278574.
83 return 1;
85 #endif
86 // Otherwise, set no decoder limit.
87 return -1;
90 StaticMutex GlobalAllocPolicy::sMutex;
92 NotNull<AllocPolicy*> GlobalAllocPolicy::Instance(TrackType aTrack) {
93 StaticMutexAutoLock lock(sMutex);
94 if (aTrack == TrackType::kAudioTrack) {
95 static RefPtr<AllocPolicyImpl> sAudioPolicy = []() {
96 SchedulerGroup::Dispatch(NS_NewRunnableFunction(
97 "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() {
98 ClearOnShutdown(&sAudioPolicy, ShutdownPhase::XPCOMShutdownThreads);
99 }));
100 return new AllocPolicyImpl(MediaDecoderLimitDefault());
101 }();
102 return WrapNotNull(sAudioPolicy.get());
104 static RefPtr<AllocPolicyImpl> sVideoPolicy = []() {
105 SchedulerGroup::Dispatch(NS_NewRunnableFunction(
106 "GlobalAllocPolicy::GlobalAllocPolicy:Audio", []() {
107 ClearOnShutdown(&sVideoPolicy, ShutdownPhase::XPCOMShutdownThreads);
108 }));
109 return new AllocPolicyImpl(MediaDecoderLimitDefault());
110 }();
111 return WrapNotNull(sVideoPolicy.get());
114 class SingleAllocPolicy::AutoDeallocCombinedToken : public Token {
115 public:
116 AutoDeallocCombinedToken(already_AddRefed<Token> aSingleAllocPolicyToken,
117 already_AddRefed<Token> aGlobalAllocPolicyToken)
118 : mSingleToken(aSingleAllocPolicyToken),
119 mGlobalToken(aGlobalAllocPolicyToken) {}
121 private:
122 // Release tokens allocated from GlobalAllocPolicy and LocalAllocPolicy
123 // and process next token request if any.
124 ~AutoDeallocCombinedToken() = default;
125 const RefPtr<Token> mSingleToken;
126 const RefPtr<Token> mGlobalToken;
129 auto SingleAllocPolicy::Alloc() -> RefPtr<Promise> {
130 MOZ_DIAGNOSTIC_ASSERT(MaxDecoderLimit() == 1,
131 "We can only handle at most one token out at a time.");
132 RefPtr<SingleAllocPolicy> self = this;
133 return AllocPolicyImpl::Alloc()->Then(
134 mOwnerThread, __func__,
135 [self](RefPtr<Token> aToken) {
136 RefPtr<Token> localToken = std::move(aToken);
137 RefPtr<Promise> p = self->mPendingPromise.Ensure(__func__);
138 GlobalAllocPolicy::Instance(self->mTrack)
139 ->Alloc()
140 ->Then(
141 self->mOwnerThread, __func__,
142 [self, localToken = std::move(localToken)](
143 RefPtr<Token> aToken) mutable {
144 self->mTokenRequest.Complete();
145 RefPtr<Token> combinedToken = new AutoDeallocCombinedToken(
146 localToken.forget(), aToken.forget());
147 self->mPendingPromise.Resolve(combinedToken, __func__);
149 [self]() {
150 self->mTokenRequest.Complete();
151 self->mPendingPromise.Reject(true, __func__);
153 ->Track(self->mTokenRequest);
154 return p;
156 []() { return Promise::CreateAndReject(true, __func__); });
159 SingleAllocPolicy::~SingleAllocPolicy() {
160 mPendingPromise.RejectIfExists(true, __func__);
161 mTokenRequest.DisconnectIfExists();
164 void SingleAllocPolicy::Cancel() {
165 MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
166 mPendingPromise.RejectIfExists(true, __func__);
167 mTokenRequest.DisconnectIfExists();
168 RejectAll();
171 AllocationWrapper::AllocationWrapper(
172 already_AddRefed<MediaDataDecoder> aDecoder, already_AddRefed<Token> aToken)
173 : mDecoder(aDecoder), mToken(aToken) {
174 DecoderDoctorLogger::LogConstructionAndBase(
175 "AllocationWrapper", this, static_cast<const MediaDataDecoder*>(this));
176 DecoderDoctorLogger::LinkParentAndChild("AllocationWrapper", this, "decoder",
177 mDecoder.get());
180 AllocationWrapper::~AllocationWrapper() {
181 DecoderDoctorLogger::LogDestruction("AllocationWrapper", this);
184 RefPtr<ShutdownPromise> AllocationWrapper::Shutdown() {
185 RefPtr<MediaDataDecoder> decoder = std::move(mDecoder);
186 RefPtr<Token> token = std::move(mToken);
187 return decoder->Shutdown()->Then(
188 GetCurrentSerialEventTarget(), __func__,
189 [token]() { return ShutdownPromise::CreateAndResolve(true, __func__); });
191 /* static */ RefPtr<AllocationWrapper::AllocateDecoderPromise>
192 AllocationWrapper::CreateDecoder(const CreateDecoderParams& aParams,
193 AllocPolicy* aPolicy) {
194 RefPtr<AllocateDecoderPromise> p =
195 (aPolicy ? aPolicy : GlobalAllocPolicy::Instance(aParams.mType))
196 ->Alloc()
197 ->Then(
198 GetCurrentSerialEventTarget(), __func__,
199 [params =
200 CreateDecoderParamsForAsync(aParams)](RefPtr<Token> aToken) {
201 // result may not always be updated by
202 // PDMFactory::CreateDecoder either when the creation
203 // succeeded or failed, as such it must be initialized to a
204 // fatal error by default.
205 MediaResult result =
206 MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
207 nsPrintfCString("error creating %s decoder",
208 TrackTypeToStr(params.mType)));
209 RefPtr<PDMFactory> pdm = new PDMFactory();
210 RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
211 pdm->CreateDecoder(params)->Then(
212 GetCurrentSerialEventTarget(), __func__,
213 [aToken](RefPtr<MediaDataDecoder>&& aDecoder) mutable {
214 RefPtr<AllocationWrapper> wrapper =
215 new AllocationWrapper(aDecoder.forget(),
216 aToken.forget());
217 return AllocateDecoderPromise::CreateAndResolve(
218 wrapper, __func__);
220 [](const MediaResult& aError) {
221 return AllocateDecoderPromise::CreateAndReject(
222 aError, __func__);
224 return p;
226 []() {
227 return AllocateDecoderPromise::CreateAndReject(
228 MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
229 "Allocation policy expired"),
230 __func__);
232 return p;
235 } // namespace mozilla