/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/GMPVideoDecoderTrialCreator.h" #include "mozilla/Preferences.h" #include "prsystem.h" #include "GMPVideoHost.h" #include "mozilla/EMEUtils.h" #include "nsServiceManagerUtils.h" #include "GMPService.h" #include "VideoUtils.h" #include "nsPrintfCString.h" #include "nsXULAppAPI.h" namespace mozilla { namespace dom { static already_AddRefed GetGMPThread() { nsCOMPtr gmps = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); if (!gmps) { return nullptr; } nsCOMPtr gmpThread; nsresult rv = gmps->GetThread(getter_AddRefs(gmpThread)); if (NS_FAILED(rv)) { return nullptr; } return gmpThread.forget(); } #ifdef DEBUG static bool OnGMPThread() { nsCOMPtr currentThread; NS_GetCurrentThread(getter_AddRefs(currentThread)); nsCOMPtr gmpThread(GetGMPThread()); return !!gmpThread && !!currentThread && gmpThread == currentThread; } #endif static const char* TrialCreatePrefName(const nsAString& aKeySystem) { if (aKeySystem.EqualsLiteral("com.adobe.primetime")) { return "media.gmp-eme-adobe.trial-create"; } if (aKeySystem.EqualsLiteral("org.w3.clearkey")) { return "media.gmp-eme-clearkey.trial-create"; } return nullptr; } /* static */ GMPVideoDecoderTrialCreator::TrialCreateState GMPVideoDecoderTrialCreator::GetCreateTrialState(const nsAString& aKeySystem) { if (Preferences::GetBool("media.gmp.always-trial-create", false)) { return Pending; } const char* pref = TrialCreatePrefName(aKeySystem); if (!pref) { return Pending; } switch (Preferences::GetInt(pref, (int)Pending)) { case 0: return Pending; case 1: return Succeeded; case 2: return Failed; default: return Pending; } } /* static */ void GMPVideoDecoderTrialCreator::UpdateTrialCreateState(const nsAString& aKeySystem, uint32_t aState) { UpdateTrialCreateState(aKeySystem, (TrialCreateState)aState); } /* static */ void GMPVideoDecoderTrialCreator::UpdateTrialCreateState(const nsAString& aKeySystem, TrialCreateState aState) { MOZ_ASSERT(NS_IsMainThread()); if (XRE_GetProcessType() == GeckoProcessType_Content) { // Pref has to be set from the chrome process. Dispatch to chrome via // GMPService. nsCOMPtr service = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); NS_ENSURE_TRUE_VOID(service); service->UpdateTrialCreateState(aKeySystem, (uint32_t)aState); return; } const char* pref = TrialCreatePrefName(aKeySystem); if (pref) { Preferences::SetInt(pref, (int)aState); } } void GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed(const nsAString& aKeySystem, const nsACString& aReason) { MOZ_ASSERT(NS_IsMainThread()); EME_LOG("GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed(%s)", NS_ConvertUTF16toUTF8(aKeySystem).get()); TrialCreateData* data = mTestCreate.Get(aKeySystem); if (!data) { return; } data->mStatus = Failed; UpdateTrialCreateState(aKeySystem, Failed); for (RefPtr& promise: data->mPending) { promise->Reject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, aReason); } data->mPending.Clear(); data->mTest = nullptr; } void GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded(const nsAString& aKeySystem) { MOZ_ASSERT(NS_IsMainThread()); EME_LOG("GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded(%s)", NS_ConvertUTF16toUTF8(aKeySystem).get()); TrialCreateData* data = mTestCreate.Get(aKeySystem); if (!data) { return; } data->mStatus = Succeeded; UpdateTrialCreateState(aKeySystem, Succeeded); for (RefPtr& promise : data->mPending) { promise->Resolve(); } data->mPending.Clear(); data->mTest = nullptr; } nsresult TestGMPVideoDecoder::Start() { MOZ_ASSERT(NS_IsMainThread()); mGMPService = do_GetService("@mozilla.org/gecko-media-plugin-service;1"); if (!mGMPService) { return NS_ERROR_FAILURE; } nsCOMPtr thread(GetGMPThread()); if (!thread) { return NS_ERROR_FAILURE; } RefPtr task(NS_NewRunnableMethod(this, &TestGMPVideoDecoder::CreateGMPVideoDecoder)); return thread->Dispatch(task, NS_DISPATCH_NORMAL); } struct ExpectedPlaneDecodePlane { GMPPlaneType mPlane; size_t mLength; uint8_t mValue; int32_t mSize; // width & height }; static const ExpectedPlaneDecodePlane sExpectedPlanes[3] = { { kGMPYPlane, 112 * 112, // 12544 0x4c, 112 }, { // U kGMPUPlane, 56 * 56, // 3136 0x55, 56, }, { // V kGMPVPlane, 56 * 56, // 3136 0xff, 56, } }; static bool TestDecodedFrame(GMPVideoi420Frame* aDecodedFrame) { MOZ_ASSERT(OnGMPThread()); if (aDecodedFrame->Width() != 112 || aDecodedFrame->Height() != 112) { EME_LOG("TestDecodedFrame() - Invalid decoded frame dimensions"); return false; } for (const ExpectedPlaneDecodePlane& plane : sExpectedPlanes) { int32_t stride = aDecodedFrame->Stride(plane.mPlane); if (stride < plane.mSize) { EME_LOG("TestDecodedFrame() - Insufficient decoded frame stride"); return false; } int32_t length = plane.mSize * plane.mSize; if (aDecodedFrame->AllocatedSize(plane.mPlane) < length) { EME_LOG("TestDecodedFrame() - Insufficient decoded frame allocated size"); return false; } const uint8_t* data = aDecodedFrame->Buffer(plane.mPlane); for (int32_t row = 0; row < plane.mSize; row++) { for (int32_t i = 0; i < plane.mSize; i++) { size_t off = (stride * row) + i; if (data[off] != plane.mValue) { EME_LOG("TestDecodedFrame() - Invalid decoded frame contents"); return false; } } } } return true; } void TestGMPVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame) { MOZ_ASSERT(OnGMPThread()); if (!mReceivedDecoded) { mReceivedDecoded = true; } else { EME_LOG("Received multiple decoded frames"); ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder received multiple decoded frames")); return; } GMPUniquePtr decodedFrame(aDecodedFrame); if (!TestDecodedFrame(aDecodedFrame)) { EME_LOG("decoded frame failed verification"); ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder decoded frame failed verification")); } } void TestGMPVideoDecoder::DrainComplete() { EME_LOG("TestGMPVideoDecoder::DrainComplete()"); MOZ_ASSERT(OnGMPThread()); ReportSuccess(); } void TestGMPVideoDecoder::Error(GMPErr aErr) { EME_LOG("TestGMPVideoDecoder::ReceivedDecodedFrame()"); MOZ_ASSERT(OnGMPThread()); ReportFailure(nsPrintfCString("TestGMPVideoDecoder error %d", aErr)); } void TestGMPVideoDecoder::Terminated() { EME_LOG("TestGMPVideoDecoder::Terminated()"); MOZ_ASSERT(OnGMPThread()); ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder GMP terminated")); } void TestGMPVideoDecoder::ReportFailure(const nsACString& aReason) { MOZ_ASSERT(OnGMPThread()); if (mGMP) { mGMP->Close(); mGMP = nullptr; } RefPtr task; task = NS_NewRunnableMethodWithArgs(mInstance, &GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderFailed, mKeySystem, aReason); NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL); } void TestGMPVideoDecoder::ReportSuccess() { MOZ_ASSERT(OnGMPThread()); if (mGMP) { mGMP->Close(); mGMP = nullptr; } RefPtr task; task = NS_NewRunnableMethodWithArg(mInstance, &GMPVideoDecoderTrialCreator::TrialCreateGMPVideoDecoderSucceeded, mKeySystem); NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL); } // A solid red, 112x112 frame. Display size 100x100 pixels. // Generated with ImageMagick/ffmpeg // $ convert -size 100x100 xc:rgb\(255, 0, 0\) red.png // $ ffmpeg -f image2 -i red.png -r 24 -b:v 200k -c:v libx264 -profile:v baseline -level 1 -v:r 24 red.mp4 -y static const uint8_t sTestH264Frame[] = { 0x00, 0x00, 0x02, 0x81, 0x06, 0x05, 0xff, 0xff, 0x7d, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x31, 0x33, 0x35, 0x20, 0x72, 0x32, 0x33, 0x34, 0x35, 0x20, 0x66, 0x30, 0x63, 0x31, 0x63, 0x35, 0x33, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, 0x31, 0x33, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x33, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x31, 0x32, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x31, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x34, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, 0x34, 0x30, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x3d, 0x30, 0x20, 0x72, 0x63, 0x5f, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x3d, 0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x6d, 0x62, 0x74, 0x72, 0x65, 0x65, 0x3d, 0x31, 0x20, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x32, 0x30, 0x30, 0x20, 0x72, 0x61, 0x74, 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f, 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, 0x6e, 0x3d, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x36, 0x39, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69, 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30, 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x39, 0x65, 0x88, 0x84, 0x0c, 0xf1, 0x18, 0xa0, 0x00, 0x23, 0xbf, 0x1c, 0x00, 0x04, 0x3c, 0x63, 0x80, 0x00, 0x98, 0x44, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xd7, 0x5d, 0x75, 0xe0 }; static GMPUniquePtr CreateFrame(GMPVideoHost* aHost) { MOZ_ASSERT(OnGMPThread()); GMPVideoFrame* ftmp = nullptr; GMPErr err = aHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp); if (GMP_FAILED(err)) { return nullptr; } GMPUniquePtr frame(static_cast(ftmp)); err = frame->CreateEmptyFrame(MOZ_ARRAY_LENGTH(sTestH264Frame)); if (GMP_FAILED(err)) { return nullptr; } memcpy(frame->Buffer(), sTestH264Frame, MOZ_ARRAY_LENGTH(sTestH264Frame)); frame->SetBufferType(GMP_BufferLength32); frame->SetEncodedWidth(100); frame->SetEncodedHeight(100); frame->SetTimeStamp(0); frame->SetCompleteFrame(true); frame->SetDuration(41666); frame->SetFrameType(kGMPKeyFrame); return frame; } static const uint8_t sTestH264CodecSpecific[] = { 0x01, 0x42, 0xc0, 0x0a, 0xff, 0xe1, 0x00, 0x18, 0x67, 0x42, 0xc0, 0x0a, 0xd9, 0x07, 0x3f, 0x9e, 0x79, 0xb2, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x60, 0x1e, 0x24, 0x4c, 0x90, 0x01, 0x00, 0x04, 0x68, 0xcb, 0x8c, 0xb2 }; void TestGMPVideoDecoder::Callback::Done(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) { MOZ_ASSERT(OnGMPThread()); if (!aHost || !aGMP) { mInstance->ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder null host or GMP on Get")); return; } RefPtr task; task = NS_NewRunnableMethodWithArgs(mInstance, &TestGMPVideoDecoder::ActorCreated, aGMP, aHost); NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL); } void TestGMPVideoDecoder::ActorCreated(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aHost && aGMP); // Add crash handler. RefPtr service = gmp::GeckoMediaPluginService::GetGeckoMediaPluginService(); service->AddPluginCrashedEventTarget(aGMP->GetPluginId(), mWindow); nsCOMPtr thread(GetGMPThread()); if (!thread) { mInstance->TrialCreateGMPVideoDecoderFailed(mKeySystem, NS_LITERAL_CSTRING("Failed to get GMP thread in TestGMPVideoDecoder::ActorCreated")); return; } RefPtr task; task = NS_NewRunnableMethodWithArgs(this, &TestGMPVideoDecoder::InitGMPDone, aGMP, aHost); thread->Dispatch(task, NS_DISPATCH_NORMAL); } void TestGMPVideoDecoder::InitGMPDone(GMPVideoDecoderProxy* aGMP, GMPVideoHost* aHost) { MOZ_ASSERT(OnGMPThread()); MOZ_ASSERT(aHost && aGMP); mGMP = aGMP; mHost = aHost; GMPVideoCodec codec; memset(&codec, 0, sizeof(codec)); codec.mGMPApiVersion = kGMPVersion33; codec.mCodecType = kGMPVideoCodecH264; codec.mWidth = 100; codec.mHeight = 100; nsTArray codecSpecific; codecSpecific.AppendElement(0); // mPacketizationMode. codecSpecific.AppendElements(sTestH264CodecSpecific, MOZ_ARRAY_LENGTH(sTestH264CodecSpecific)); nsresult rv = mGMP->InitDecode(codec, codecSpecific, this, PR_GetNumberOfProcessors()); if (NS_FAILED(rv)) { EME_LOG("InitGMPDone() - InitDecode() failed!"); ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder InitDecode() returned failure")); return; } GMPUniquePtr frame = CreateFrame(aHost); if (!frame) { EME_LOG("InitGMPDone() - Decode() failed to create frame!"); ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Decode() failed to create frame")); return; } nsTArray info; // No codec specific per-frame info to pass. rv = mGMP->Decode(Move(frame), false, info, 0); if (NS_FAILED(rv)) { EME_LOG("InitGMPDone() - Decode() failed to send Decode message!"); ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Decode() returned failure")); return; } rv = mGMP->Drain(); if (NS_FAILED(rv)) { EME_LOG("InitGMPDone() - Drain() failed to send Drain message!"); ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder Drain() returned failure")); return; } } void TestGMPVideoDecoder::CreateGMPVideoDecoder() { MOZ_ASSERT(OnGMPThread()); nsTArray tags; tags.AppendElement(NS_LITERAL_CSTRING("h264")); tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem)); UniquePtr callback(new Callback(this)); if (NS_FAILED(mGMPService->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("fakeNodeId1234567890fakeNodeId12"), Move(callback)))) { ReportFailure(NS_LITERAL_CSTRING("TestGMPVideoDecoder GMPService GetGMPVideoDecoder returned failure")); } } void GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(const nsAString& aKeySystem, AbstractPromiseLike* aPromisey, nsPIDOMWindow* aParent) { MOZ_ASSERT(NS_IsMainThread()); if (!mTestCreate.Contains(aKeySystem)) { mTestCreate.Put(aKeySystem, new TrialCreateData(aKeySystem)); } TrialCreateData* data = mTestCreate.Get(aKeySystem); MOZ_ASSERT(data); switch (data->mStatus) { case TrialCreateState::Succeeded: { EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) already succeeded", NS_ConvertUTF16toUTF8(aKeySystem).get()); aPromisey->Resolve(); break; } case TrialCreateState::Failed: { // Something is broken about this configuration. Report as unsupported. EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) already failed", NS_ConvertUTF16toUTF8(aKeySystem).get()); aPromisey->Reject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, NS_LITERAL_CSTRING("navigator.requestMediaKeySystemAccess trial CDM creation failed")); break; } case TrialCreateState::Pending: { EME_LOG("GMPVideoDecoderTrialCreator::MaybeAwaitTrialCreate(%s) pending", NS_ConvertUTF16toUTF8(aKeySystem).get()); // Add request to the list of pending items waiting. data->mPending.AppendElement(aPromisey); if (!data->mTest) { // Not already waiting for CDM to be created. Create and Init // a CDM, to test whether it will work. data->mTest = new TestGMPVideoDecoder(this, aKeySystem, aParent); if (NS_FAILED(data->mTest->Start())) { TrialCreateGMPVideoDecoderFailed(aKeySystem, NS_LITERAL_CSTRING("TestGMPVideoDecoder::Start() failed")); return; } // Promise will call InitMediaKeysPromiseHandler when Init() // succeeds/fails. } break; } } return; } } // namespace dom } // namespace mozilla