RemoteDecoderChild.cpp (10731B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 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/. */ 6 #include "RemoteDecoderChild.h" 7 8 #include "RemoteMediaManagerChild.h" 9 #include "mozilla/RemoteDecodeUtils.h" 10 11 namespace mozilla { 12 13 RemoteDecoderChild::RemoteDecoderChild(RemoteMediaIn aLocation) 14 : ShmemRecycleAllocator(this), 15 mLocation(aLocation), 16 mThread(GetCurrentSerialEventTarget()) { 17 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 18 auto managerThread = RemoteMediaManagerChild::GetManagerThread(); 19 MOZ_DIAGNOSTIC_ASSERT(managerThread); 20 MOZ_DIAGNOSTIC_ASSERT(managerThread->IsOnCurrentThread()); 21 #endif 22 } 23 24 RemoteDecoderChild::~RemoteDecoderChild() = default; 25 26 // ActorDestroy is called if the channel goes down while waiting for a response. 27 void RemoteDecoderChild::ActorDestroy(ActorDestroyReason aWhy) { 28 mRemoteDecoderCrashed = (aWhy == AbnormalShutdown); 29 mDecodedData.Clear(); 30 CleanupShmemRecycleAllocator(); 31 RecordShutdownTelemetry(mRemoteDecoderCrashed); 32 } 33 34 void RemoteDecoderChild::DestroyIPDL() { 35 AssertOnManagerThread(); 36 MOZ_DIAGNOSTIC_ASSERT(mInitPromise.IsEmpty() && mDecodePromise.IsEmpty() && 37 mDrainPromise.IsEmpty() && 38 mFlushPromise.IsEmpty() && 39 mShutdownPromise.IsEmpty(), 40 "All promises should have been rejected"); 41 if (CanSend()) { 42 PRemoteDecoderChild::Send__delete__(this); 43 } 44 } 45 46 void RemoteDecoderChild::IPDLActorDestroyed() { mIPDLSelfRef = nullptr; } 47 48 // MediaDataDecoder methods 49 50 RefPtr<MediaDataDecoder::InitPromise> RemoteDecoderChild::Init() { 51 AssertOnManagerThread(); 52 53 mRemoteDecoderCrashed = false; 54 55 RefPtr<RemoteDecoderChild> self = this; 56 SendInit() 57 ->Then( 58 mThread, __func__, 59 [self, this](InitResultIPDL&& aResponse) { 60 mInitPromiseRequest.Complete(); 61 if (aResponse.type() == InitResultIPDL::TMediaResult) { 62 mInitPromise.Reject(aResponse.get_MediaResult(), __func__); 63 return; 64 } 65 const auto& initResponse = aResponse.get_InitCompletionIPDL(); 66 mDescription = initResponse.decoderDescription(); 67 mDescription.Append(" ("); 68 mDescription.Append(RemoteMediaInToStr(GetManager()->Location())); 69 mDescription.Append(" remote)"); 70 71 mProcessName = initResponse.decoderProcessName(); 72 mCodecName = initResponse.decoderCodecName(); 73 74 mIsHardwareAccelerated = initResponse.hardware(); 75 mHardwareAcceleratedReason = initResponse.hardwareReason(); 76 mConversion = initResponse.conversion(); 77 mShouldDecoderAlwaysBeRecycled = 78 initResponse.shouldDecoderAlwaysBeRecycled(); 79 for (auto p : initResponse.decodeProperties()) { 80 mDecodeProperties[p.name()] = Some(p.value()); 81 } 82 // Either the promise has not yet been resolved or the handler has 83 // been disconnected and we can't get here. 84 mInitPromise.Resolve(initResponse.type(), __func__); 85 }, 86 [self](const mozilla::ipc::ResponseRejectReason& aReason) { 87 self->mInitPromiseRequest.Complete(); 88 RemoteMediaManagerChild::HandleRejectionError( 89 self->GetManager(), self->mLocation, aReason, 90 [self](const MediaResult& aError) { 91 self->mInitPromise.RejectIfExists(aError, __func__); 92 }); 93 }) 94 ->Track(mInitPromiseRequest); 95 96 return mInitPromise.Ensure(__func__); 97 } 98 99 RefPtr<MediaDataDecoder::DecodePromise> RemoteDecoderChild::Decode( 100 const nsTArray<RefPtr<MediaRawData>>& aSamples) { 101 AssertOnManagerThread(); 102 103 if (mRemoteDecoderCrashed) { 104 nsresult err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR; 105 if (mLocation == RemoteMediaIn::GpuProcess || 106 mLocation == RemoteMediaIn::RddProcess) { 107 err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR; 108 } else if (mLocation == RemoteMediaIn::UtilityProcess_MFMediaEngineCDM) { 109 err = NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR; 110 } 111 return MediaDataDecoder::DecodePromise::CreateAndReject(err, __func__); 112 } 113 114 auto samples = MakeRefPtr<ArrayOfRemoteMediaRawData>(); 115 if (!samples->Fill(aSamples, 116 [&](size_t aSize) { return AllocateBuffer(aSize); })) { 117 return MediaDataDecoder::DecodePromise::CreateAndReject( 118 NS_ERROR_OUT_OF_MEMORY, __func__); 119 } 120 SendDecode(samples)->Then( 121 mThread, __func__, 122 [self = RefPtr{this}, this]( 123 PRemoteDecoderChild::DecodePromise::ResolveOrRejectValue&& aValue) { 124 // We no longer need the samples as the data has been 125 // processed by the parent. 126 // If the parent died, the error being fatal will cause the 127 // decoder to be torn down and all shmem in the pool will be 128 // deallocated. 129 ReleaseAllBuffers(); 130 131 if (aValue.IsReject()) { 132 RemoteMediaManagerChild::HandleRejectionError( 133 self->GetManager(), self->mLocation, aValue.RejectValue(), 134 [self](const MediaResult& aError) { 135 self->mDecodePromise.RejectIfExists(aError, __func__); 136 }); 137 return; 138 } 139 MOZ_DIAGNOSTIC_ASSERT(CanSend(), 140 "The parent unexpectedly died, promise should " 141 "have been rejected first"); 142 if (mDecodePromise.IsEmpty()) { 143 // We got flushed. 144 return; 145 } 146 auto response = std::move(aValue.ResolveValue()); 147 if (response.type() == DecodeResultIPDL::TMediaResult && 148 NS_FAILED(response.get_MediaResult())) { 149 mDecodePromise.Reject(response.get_MediaResult(), __func__); 150 return; 151 } 152 if (response.type() == DecodeResultIPDL::TDecodedOutputIPDL) { 153 ProcessOutput(std::move(response.get_DecodedOutputIPDL())); 154 } 155 mDecodePromise.Resolve(std::move(mDecodedData), __func__); 156 mDecodedData = MediaDataDecoder::DecodedData(); 157 }); 158 159 return mDecodePromise.Ensure(__func__); 160 } 161 162 RefPtr<MediaDataDecoder::FlushPromise> RemoteDecoderChild::Flush() { 163 AssertOnManagerThread(); 164 mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 165 mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 166 167 RefPtr<RemoteDecoderChild> self = this; 168 SendFlush()->Then( 169 mThread, __func__, 170 [self](const MediaResult& aResult) { 171 if (NS_SUCCEEDED(aResult)) { 172 self->mFlushPromise.ResolveIfExists(true, __func__); 173 } else { 174 self->mFlushPromise.RejectIfExists(aResult, __func__); 175 } 176 }, 177 [self](const mozilla::ipc::ResponseRejectReason& aReason) { 178 RemoteMediaManagerChild::HandleRejectionError( 179 self->GetManager(), self->mLocation, aReason, 180 [self](const MediaResult& aError) { 181 self->mFlushPromise.RejectIfExists(aError, __func__); 182 }); 183 }); 184 return mFlushPromise.Ensure(__func__); 185 } 186 187 RefPtr<MediaDataDecoder::DecodePromise> RemoteDecoderChild::Drain() { 188 AssertOnManagerThread(); 189 190 RefPtr<RemoteDecoderChild> self = this; 191 SendDrain()->Then( 192 mThread, __func__, 193 [self, this](DecodeResultIPDL&& aResponse) { 194 if (mDrainPromise.IsEmpty()) { 195 // We got flushed. 196 return; 197 } 198 if (aResponse.type() == DecodeResultIPDL::TMediaResult && 199 NS_FAILED(aResponse.get_MediaResult())) { 200 mDrainPromise.Reject(aResponse.get_MediaResult(), __func__); 201 return; 202 } 203 MOZ_DIAGNOSTIC_ASSERT(CanSend(), 204 "The parent unexpectedly died, promise should " 205 "have been rejected first"); 206 if (aResponse.type() == DecodeResultIPDL::TDecodedOutputIPDL) { 207 ProcessOutput(std::move(aResponse.get_DecodedOutputIPDL())); 208 } 209 mDrainPromise.Resolve(std::move(mDecodedData), __func__); 210 mDecodedData = MediaDataDecoder::DecodedData(); 211 }, 212 [self](const mozilla::ipc::ResponseRejectReason& aReason) { 213 RemoteMediaManagerChild::HandleRejectionError( 214 self->GetManager(), self->mLocation, aReason, 215 [self](const MediaResult& aError) { 216 self->mDrainPromise.RejectIfExists(aError, __func__); 217 }); 218 }); 219 return mDrainPromise.Ensure(__func__); 220 } 221 222 RefPtr<mozilla::ShutdownPromise> RemoteDecoderChild::Shutdown() { 223 AssertOnManagerThread(); 224 // Shutdown() can be called while an InitPromise is pending. 225 mInitPromiseRequest.DisconnectIfExists(); 226 mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 227 mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 228 mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 229 mFlushPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 230 231 RefPtr<RemoteDecoderChild> self = this; 232 SendShutdown()->Then( 233 mThread, __func__, 234 [self]( 235 PRemoteDecoderChild::ShutdownPromise::ResolveOrRejectValue&& aValue) { 236 self->mShutdownPromise.Resolve(aValue.IsResolve(), __func__); 237 }); 238 return mShutdownPromise.Ensure(__func__); 239 } 240 241 bool RemoteDecoderChild::IsHardwareAccelerated( 242 nsACString& aFailureReason) const { 243 AssertOnManagerThread(); 244 aFailureReason = mHardwareAcceleratedReason; 245 return mIsHardwareAccelerated; 246 } 247 248 nsCString RemoteDecoderChild::GetDescriptionName() const { 249 AssertOnManagerThread(); 250 return mDescription; 251 } 252 253 nsCString RemoteDecoderChild::GetProcessName() const { 254 AssertOnManagerThread(); 255 return mProcessName; 256 } 257 258 nsCString RemoteDecoderChild::GetCodecName() const { 259 AssertOnManagerThread(); 260 return mCodecName; 261 } 262 263 void RemoteDecoderChild::SetSeekThreshold(const media::TimeUnit& aTime) { 264 AssertOnManagerThread(); 265 (void)SendSetSeekThreshold(aTime); 266 } 267 268 MediaDataDecoder::ConversionRequired RemoteDecoderChild::NeedsConversion() 269 const { 270 AssertOnManagerThread(); 271 return mConversion; 272 } 273 274 bool RemoteDecoderChild::ShouldDecoderAlwaysBeRecycled() const { 275 AssertOnManagerThread(); 276 return mShouldDecoderAlwaysBeRecycled; 277 } 278 279 void RemoteDecoderChild::AssertOnManagerThread() const { 280 MOZ_ASSERT(mThread->IsOnCurrentThread()); 281 } 282 283 RemoteMediaManagerChild* RemoteDecoderChild::GetManager() { 284 if (!CanSend()) { 285 return nullptr; 286 } 287 return static_cast<RemoteMediaManagerChild*>(Manager()); 288 } 289 290 } // namespace mozilla