--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "ChromiumCDMParent.h"
#include "mozilla/gmp/GMPTypes.h"
#include "GMPContentChild.h"
+#include "GMPContentParent.h"
#include "mozilla/Unused.h"
#include "ChromiumCDMProxy.h"
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
#include "content_decryption_module.h"
#include "GMPLog.h"
namespace mozilla {
namespace gmp {
@@ -28,84 +29,117 @@ ChromiumCDMParent::ChromiumCDMParent(GMP
}
bool
ChromiumCDMParent::Init(ChromiumCDMProxy* aProxy,
bool aAllowDistinctiveIdentifier,
bool aAllowPersistentState)
{
GMP_LOG("ChromiumCDMParent::Init(this=%p)", this);
+ if (!aProxy) {
+ return false;
+ }
mProxy = aProxy;
return SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState);
}
void
ChromiumCDMParent::CreateSession(uint32_t aCreateSessionToken,
uint32_t aSessionType,
uint32_t aInitDataType,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aInitData)
{
GMP_LOG("ChromiumCDMParent::CreateSession(this=%p)", this);
+ if (mIsShutdown) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("CDM is shutdown."));
+ return;
+ }
if (!SendCreateSessionAndGenerateRequest(
aPromiseId, aSessionType, aInitDataType, aInitData)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send generateRequest to CDM process."));
return;
}
mPromiseToCreateSessionToken.Put(aPromiseId, aCreateSessionToken);
}
void
ChromiumCDMParent::SetServerCertificate(uint32_t aPromiseId,
const nsTArray<uint8_t>& aCert)
{
GMP_LOG("ChromiumCDMParent::SetServerCertificate(this=%p)", this);
+ if (mIsShutdown) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("CDM is shutdown."));
+ return;
+ }
if (!SendSetServerCertificate(aPromiseId, aCert)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send setServerCertificate to CDM process"));
}
}
void
ChromiumCDMParent::UpdateSession(const nsCString& aSessionId,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aResponse)
{
GMP_LOG("ChromiumCDMParent::UpdateSession(this=%p)", this);
+ if (mIsShutdown) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("CDM is shutdown."));
+ return;
+ }
if (!SendUpdateSession(aPromiseId, aSessionId, aResponse)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send updateSession to CDM process"));
}
}
void
ChromiumCDMParent::CloseSession(const nsCString& aSessionId,
uint32_t aPromiseId)
{
GMP_LOG("ChromiumCDMParent::CloseSession(this=%p)", this);
+ if (mIsShutdown) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("CDM is shutdown."));
+ return;
+ }
if (!SendCloseSession(aPromiseId, aSessionId)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send closeSession to CDM process"));
}
}
void
ChromiumCDMParent::RemoveSession(const nsCString& aSessionId,
uint32_t aPromiseId)
{
GMP_LOG("ChromiumCDMParent::RemoveSession(this=%p)", this);
+ if (mIsShutdown) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("CDM is shutdown."));
+ return;
+ }
if (!SendRemoveSession(aPromiseId, aSessionId)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send removeSession to CDM process"));
}
}
@@ -130,16 +164,20 @@ InitCDMInputBuffer(gmp::CDMInputBuffer&
crypto.mEncryptedSizes,
crypto.mValid);
return true;
}
RefPtr<DecryptPromise>
ChromiumCDMParent::Decrypt(MediaRawData* aSample)
{
+ if (mIsShutdown) {
+ return DecryptPromise::CreateAndReject(DecryptResult(GenericErr, aSample),
+ __func__);
+ }
CDMInputBuffer buffer;
if (!InitCDMInputBuffer(buffer, aSample)) {
return DecryptPromise::CreateAndReject(DecryptResult(GenericErr, aSample),
__func__);
}
RefPtr<DecryptJob> job = new DecryptJob(aSample);
if (!SendDecrypt(job->mId, buffer)) {
GMP_LOG(
@@ -151,30 +189,35 @@ ChromiumCDMParent::Decrypt(MediaRawData*
RefPtr<DecryptPromise> promise = job->Ensure();
mDecrypts.AppendElement(job);
return promise;
}
ipc::IPCResult
ChromiumCDMParent::Recv__delete__()
{
+ MOZ_ASSERT(mIsShutdown);
GMP_LOG("ChromiumCDMParent::Recv__delete__(this=%p)", this);
+ if (mContentParent) {
+ mContentParent->ChromiumCDMDestroyed(this);
+ mContentParent = nullptr;
+ }
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
const nsCString& aSessionId)
{
GMP_LOG("ChromiumCDMParent::RecvOnResolveNewSessionPromise(this=%p, pid=%u, "
"sid=%s)",
this,
aPromiseId,
aSessionId.get());
- if (!mProxy) {
+ if (!mProxy || mIsShutdown) {
return IPC_OK();
}
Maybe<uint32_t> token = mPromiseToCreateSessionToken.GetAndRemove(aPromiseId);
if (token.isNothing()) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Lost session token for new session."));
@@ -194,17 +237,19 @@ ChromiumCDMParent::RecvOnResolveNewSessi
}
void
ChromiumCDMParent::ResolvePromise(uint32_t aPromiseId)
{
GMP_LOG(
"ChromiumCDMParent::ResolvePromise(this=%p, pid=%u)", this, aPromiseId);
- if (!mProxy) {
+ // Note: The MediaKeys rejects all pending DOM promises when it
+ // initiates shutdown.
+ if (!mProxy || mIsShutdown) {
return;
}
NS_DispatchToMainThread(NewRunnableMethod<uint32_t>(
mProxy, &ChromiumCDMProxy::ResolvePromise, aPromiseId));
}
ipc::IPCResult
ChromiumCDMParent::RecvOnResolvePromise(const uint32_t& aPromiseId)
@@ -242,17 +287,19 @@ ToNsresult(uint32_t aError)
void
ChromiumCDMParent::RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage)
{
GMP_LOG(
"ChromiumCDMParent::RejectPromise(this=%p, pid=%u)", this, aPromiseId);
- if (!mProxy) {
+ // Note: The MediaKeys rejects all pending DOM promises when it
+ // initiates shutdown.
+ if (!mProxy || mIsShutdown) {
return;
}
NS_DispatchToMainThread(NewRunnableMethod<uint32_t, nsresult, nsCString>(
mProxy,
&ChromiumCDMProxy::RejectPromise,
aPromiseId,
aError,
aErrorMessage));
@@ -286,17 +333,17 @@ ToDOMMessageType(uint32_t aMessageType)
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionMessage(const nsCString& aSessionId,
const uint32_t& aMessageType,
nsTArray<uint8_t>&& aMessage)
{
GMP_LOG("ChromiumCDMParent::RecvOnSessionMessage(this=%p, sid=%s)",
this,
aSessionId.get());
- if (!mProxy) {
+ if (!mProxy || mIsShutdown) {
return IPC_OK();
}
RefPtr<CDMProxy> proxy = mProxy;
nsString sid = NS_ConvertUTF8toUTF16(aSessionId);
dom::MediaKeyMessageType messageType = ToDOMMessageType(aMessageType);
nsTArray<uint8_t> msg(Move(aMessage));
NS_DispatchToMainThread(
NS_NewRunnableFunction([proxy, sid, messageType, msg]() mutable {
@@ -329,17 +376,17 @@ ToDOMMediaKeyStatus(uint32_t aStatus)
}
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionKeysChange(
const nsCString& aSessionId,
nsTArray<CDMKeyInformation>&& aKeysInfo)
{
GMP_LOG("ChromiumCDMParent::RecvOnSessionKeysChange(this=%p)", this);
- if (!mProxy) {
+ if (!mProxy || mIsShutdown) {
return IPC_OK();
}
bool keyStatusesChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
for (size_t i = 0; i < aKeysInfo.Length(); i++) {
keyStatusesChange |=
caps.SetKeyStatus(aKeysInfo[i].mKeyId(),
@@ -359,49 +406,49 @@ ChromiumCDMParent::RecvOnSessionKeysChan
ipc::IPCResult
ChromiumCDMParent::RecvOnExpirationChange(const nsCString& aSessionId,
const double& aSecondsSinceEpoch)
{
GMP_LOG("ChromiumCDMParent::RecvOnExpirationChange(this=%p) time=%lf",
this,
aSecondsSinceEpoch);
- if (!mProxy) {
+ if (!mProxy || mIsShutdown) {
return IPC_OK();
}
NS_DispatchToMainThread(NewRunnableMethod<nsString, UnixTime>(
mProxy,
&ChromiumCDMProxy::OnExpirationChange,
NS_ConvertUTF8toUTF16(aSessionId),
GMPTimestamp(aSecondsSinceEpoch * 1000)));
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvOnSessionClosed(const nsCString& aSessionId)
{
GMP_LOG("ChromiumCDMParent::RecvOnSessionClosed(this=%p)", this);
- if (!mProxy) {
+ if (!mProxy || mIsShutdown) {
return IPC_OK();
}
NS_DispatchToMainThread(
NewRunnableMethod<nsString>(mProxy,
&ChromiumCDMProxy::OnSessionClosed,
NS_ConvertUTF8toUTF16(aSessionId)));
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvOnLegacySessionError(const nsCString& aSessionId,
const uint32_t& aError,
const uint32_t& aSystemCode,
const nsCString& aMessage)
{
GMP_LOG("ChromiumCDMParent::RecvOnLegacySessionError(this=%p)", this);
- if (!mProxy) {
+ if (!mProxy || mIsShutdown) {
return IPC_OK();
}
NS_DispatchToMainThread(
NewRunnableMethod<nsString, nsresult, uint32_t, nsString>(
mProxy,
&ChromiumCDMProxy::OnSessionError,
NS_ConvertUTF8toUTF16(aSessionId),
ToNsresult(aError),
@@ -427,30 +474,34 @@ ipc::IPCResult
ChromiumCDMParent::RecvDecrypted(const uint32_t& aId,
const uint32_t& aStatus,
nsTArray<uint8_t>&& aData)
{
GMP_LOG("ChromiumCDMParent::RecvDecrypted(this=%p, id=%u, status=%u)",
this,
aId,
aStatus);
+ if (mIsShutdown) {
+ MOZ_ASSERT(mDecrypts.IsEmpty());
+ return IPC_OK();
+ }
for (size_t i = 0; i < mDecrypts.Length(); i++) {
if (mDecrypts[i]->mId == aId) {
mDecrypts[i]->PostResult(ToDecryptStatus(aStatus), aData);
mDecrypts.RemoveElementAt(i);
break;
}
}
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvDecoded(const CDMVideoFrame& aFrame)
{
- if (mDecodePromise.IsEmpty()) {
+ if (mIsShutdown || mDecodePromise.IsEmpty()) {
return IPC_OK();
}
VideoData::YCbCrBuffer b;
nsTArray<uint8_t> data;
data = aFrame.mData();
if (data.IsEmpty()) {
mDecodePromise.ResolveIfExists(nsTArray<RefPtr<MediaData>>(), __func__);
@@ -500,77 +551,121 @@ ChromiumCDMParent::RecvDecoded(const CDM
}
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvDecodeFailed(const uint32_t& aStatus)
{
+ if (mIsShutdown) {
+ MOZ_ASSERT(mDecodePromise.IsEmpty());
+ return IPC_OK();
+ }
mDecodePromise.RejectIfExists(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("ChromiumCDMParent::RecvDecodeFailed")),
__func__);
return IPC_OK();
}
ipc::IPCResult
ChromiumCDMParent::RecvShutdown()
{
GMP_LOG("ChromiumCDMParent::RecvShutdown(this=%p)", this);
- // TODO: SendDestroy(), call Terminated.
+ Shutdown();
return IPC_OK();
}
void
ChromiumCDMParent::ActorDestroy(ActorDestroyReason aWhy)
{
GMP_LOG("ChromiumCDMParent::ActorDestroy(this=%p, reason=%d)", this, aWhy);
+ MOZ_ASSERT(!mActorDestroyed);
+ mActorDestroyed = true;
+ if (!mIsShutdown) {
+ // Plugin crash.
+ MOZ_ASSERT(aWhy == AbnormalShutdown);
+ Shutdown();
+ }
+ MOZ_ASSERT(mIsShutdown);
+ RefPtr<ChromiumCDMParent> kungFuDeathGrip(this);
+ if (mContentParent) {
+ mContentParent->ChromiumCDMDestroyed(this);
+ mContentParent = nullptr;
+ }
+ bool abnormalShutdown = (aWhy == AbnormalShutdown);
+ if (abnormalShutdown && mProxy) {
+ RefPtr<Runnable> task =
+ NewRunnableMethod(mProxy, &ChromiumCDMProxy::Terminated);
+ NS_DispatchToMainThread(task);
+ }
+ MaybeDisconnect(abnormalShutdown);
}
RefPtr<MediaDataDecoder::InitPromise>
ChromiumCDMParent::InitializeVideoDecoder(
const gmp::CDMVideoDecoderConfig& aConfig,
const VideoInfo& aInfo,
RefPtr<layers::ImageContainer> aImageContainer)
{
+ if (mIsShutdown) {
+ return MediaDataDecoder::InitPromise::CreateAndReject(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("ChromiumCDMParent is shutdown")),
+ __func__);
+ }
+
if (!SendInitializeVideoDecoder(aConfig)) {
return MediaDataDecoder::InitPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("Failed to send init video decoder to CDM")),
__func__);
}
+ mVideoDecoderInitialized = true;
mImageContainer = aImageContainer;
mVideoInfo = aInfo;
return mInitVideoDecoderPromise.Ensure(__func__);
}
ipc::IPCResult
ChromiumCDMParent::RecvOnDecoderInitDone(const uint32_t& aStatus)
{
GMP_LOG("ChromiumCDMParent::RecvOnDecoderInitDone(this=%p, status=%u)",
this,
aStatus);
+ if (mIsShutdown) {
+ MOZ_ASSERT(mInitVideoDecoderPromise.IsEmpty());
+ return IPC_OK();
+ }
if (aStatus == static_cast<uint32_t>(cdm::kSuccess)) {
mInitVideoDecoderPromise.ResolveIfExists(TrackInfo::kVideoTrack, __func__);
} else {
+ mVideoDecoderInitialized = false;
mInitVideoDecoderPromise.RejectIfExists(
MediaResult(
NS_ERROR_DOM_MEDIA_FATAL_ERR,
RESULT_DETAIL("CDM init decode failed with %" PRIu32, aStatus)),
__func__);
}
return IPC_OK();
}
RefPtr<MediaDataDecoder::DecodePromise>
ChromiumCDMParent::DecryptAndDecodeFrame(MediaRawData* aSample)
{
+ if (mIsShutdown) {
+ return MediaDataDecoder::DecodePromise::CreateAndReject(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("ChromiumCDMParent is shutdown")),
+ __func__);
+ }
+
CDMInputBuffer buffer;
if (!InitCDMInputBuffer(buffer, aSample)) {
return MediaDataDecoder::DecodePromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "Failed to init CDM buffer."),
__func__);
}
@@ -587,57 +682,123 @@ ChromiumCDMParent::DecryptAndDecodeFrame
}
return mDecodePromise.Ensure(__func__);
}
RefPtr<MediaDataDecoder::FlushPromise>
ChromiumCDMParent::FlushVideoDecoder()
{
+ if (mIsShutdown) {
+ return MediaDataDecoder::FlushPromise::CreateAndReject(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("ChromiumCDMParent is shutdown")),
+ __func__);
+ }
+
mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
if (!SendResetVideoDecoder()) {
return MediaDataDecoder::FlushPromise::CreateAndReject(
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "Failed to send flush to CDM."),
__func__);
}
return mFlushDecoderPromise.Ensure(__func__);
}
ipc::IPCResult
ChromiumCDMParent::RecvResetVideoDecoderComplete()
{
- mFlushDecoderPromise.Resolve(true, __func__);
+ if (mIsShutdown) {
+ MOZ_ASSERT(mFlushDecoderPromise.IsEmpty());
+ return IPC_OK();
+ }
+ mFlushDecoderPromise.ResolveIfExists(true, __func__);
return IPC_OK();
}
RefPtr<MediaDataDecoder::DecodePromise>
ChromiumCDMParent::Drain()
{
MOZ_ASSERT(mDecodePromise.IsEmpty(), "Must wait for decoding to complete");
+ if (mIsShutdown) {
+ return MediaDataDecoder::DecodePromise::CreateAndReject(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("ChromiumCDMParent is shutdown")),
+ __func__);
+ }
RefPtr<MediaDataDecoder::DecodePromise> p = mDecodePromise.Ensure(__func__);
if (!SendDrain()) {
mDecodePromise.Resolve(MediaDataDecoder::DecodedData(), __func__);
}
return p;
}
ipc::IPCResult
ChromiumCDMParent::RecvDrainComplete()
{
+ if (mIsShutdown) {
+ MOZ_ASSERT(mDecodePromise.IsEmpty());
+ return IPC_OK();
+ }
mDecodePromise.ResolveIfExists(MediaDataDecoder::DecodedData(), __func__);
return IPC_OK();
}
RefPtr<ShutdownPromise>
ChromiumCDMParent::ShutdownVideoDecoder()
{
+ if (mIsShutdown || !mVideoDecoderInitialized) {
+ return ShutdownPromise::CreateAndResolve(true, __func__);
+ }
mInitVideoDecoderPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED,
__func__);
- MOZ_ASSERT(mDecodePromise.IsEmpty());
+ mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
MOZ_ASSERT(mFlushDecoderPromise.IsEmpty());
if (!SendDeinitializeVideoDecoder()) {
return ShutdownPromise::CreateAndResolve(true, __func__);
}
+ mVideoDecoderInitialized = false;
return ShutdownPromise::CreateAndResolve(true, __func__);
}
+void
+ChromiumCDMParent::Shutdown()
+{
+ GMP_LOG("ChromiumCDMParent::Shutdown(this=%p)", this);
+
+ if (mIsShutdown) {
+ return;
+ }
+ mIsShutdown = true;
+
+ for (RefPtr<DecryptJob>& decrypt : mDecrypts) {
+ decrypt->PostResult(AbortedErr);
+ }
+ mDecrypts.Clear();
+
+ if (mVideoDecoderInitialized && !mActorDestroyed) {
+ Unused << SendDeinitializeVideoDecoder();
+ mVideoDecoderInitialized = false;
+ }
+
+ // Note: MediaKeys rejects all outstanding promises when it initiates shutdown.
+ mPromiseToCreateSessionToken.Clear();
+
+ mInitVideoDecoderPromise.RejectIfExists(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("ChromiumCDMParent is shutdown")),
+ __func__);
+ mDecodePromise.RejectIfExists(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("ChromiumCDMParent is shutdown")),
+ __func__);
+ mFlushDecoderPromise.RejectIfExists(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("ChromiumCDMParent is shutdown")),
+ __func__);
+
+ if (!mActorDestroyed) {
+ Unused << SendDestroy();
+ }
+}
+
} // namespace gmp
} // namespace mozilla
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -197,16 +197,23 @@ ChromiumCDMProxy::CreateSession(uint32_t
(int)aSessionType,
aPromiseId,
aInitData.Length());
uint32_t sessionType = ToCDMSessionType(aSessionType);
uint32_t initDataType = ToCDMInitDataType(aInitDataType);
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
+ if (!cdm) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in CreateSession"));
+ return;
+ }
+
mGMPThread->Dispatch(
NewRunnableMethod<uint32_t,
uint32_t,
uint32_t,
uint32_t,
nsTArray<uint8_t>>(cdm,
&gmp::ChromiumCDMParent::CreateSession,
aCreateSessionToken,
@@ -231,16 +238,23 @@ ChromiumCDMProxy::SetServerCertificate(P
nsTArray<uint8_t>& aCert)
{
MOZ_ASSERT(NS_IsMainThread());
EME_LOG("ChromiumCDMProxy::SetServerCertificate(pid=%u) certLen=%zu",
aPromiseId,
aCert.Length());
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
+ if (!cdm) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in SetServerCertificate"));
+ return;
+ }
+
mGMPThread->Dispatch(NewRunnableMethod<uint32_t, nsTArray<uint8_t>>(
cdm,
&gmp::ChromiumCDMParent::SetServerCertificate,
aPromiseId,
Move(aCert)));
}
void
@@ -250,16 +264,22 @@ ChromiumCDMProxy::UpdateSession(const ns
{
MOZ_ASSERT(NS_IsMainThread());
EME_LOG("ChromiumCDMProxy::UpdateSession(sid='%s', pid=%u) responseLen=%zu",
NS_ConvertUTF16toUTF8(aSessionId).get(),
aPromiseId,
aResponse.Length());
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
+ if (!cdm) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in UpdateSession"));
+ return;
+ }
mGMPThread->Dispatch(
NewRunnableMethod<nsCString, uint32_t, nsTArray<uint8_t>>(
cdm,
&gmp::ChromiumCDMParent::UpdateSession,
NS_ConvertUTF16toUTF8(aSessionId),
aPromiseId,
Move(aResponse)));
}
@@ -269,16 +289,22 @@ ChromiumCDMProxy::CloseSession(const nsA
PromiseId aPromiseId)
{
MOZ_ASSERT(NS_IsMainThread());
EME_LOG("ChromiumCDMProxy::CloseSession(sid='%s', pid=%u)",
NS_ConvertUTF16toUTF8(aSessionId).get(),
aPromiseId);
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
+ if (!cdm) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in CloseSession"));
+ return;
+ }
mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
cdm,
&gmp::ChromiumCDMParent::CloseSession,
NS_ConvertUTF16toUTF8(aSessionId),
aPromiseId));
}
void
@@ -286,27 +312,45 @@ ChromiumCDMProxy::RemoveSession(const ns
PromiseId aPromiseId)
{
MOZ_ASSERT(NS_IsMainThread());
EME_LOG("ChromiumCDMProxy::RemoveSession(sid='%s', pid=%u)",
NS_ConvertUTF16toUTF8(aSessionId).get(),
aPromiseId);
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
+ if (!cdm) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Null CDM in RemoveSession"));
+ return;
+ }
mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
cdm,
&gmp::ChromiumCDMParent::RemoveSession,
NS_ConvertUTF16toUTF8(aSessionId),
aPromiseId));
}
void
ChromiumCDMProxy::Shutdown()
{
+ MOZ_ASSERT(NS_IsMainThread());
EME_LOG("ChromiumCDMProxy::Shutdown()");
+ mKeys.Clear();
+ RefPtr<gmp::ChromiumCDMParent> cdm;
+ {
+ MutexAutoLock lock(mCDMMutex);
+ cdm.swap(mCDM);
+ }
+ if (cdm) {
+ nsCOMPtr<nsIRunnable> task =
+ NewRunnableMethod(mCDM, &gmp::ChromiumCDMParent::Shutdown);
+ mGMPThread->Dispatch(task.forget());
+ }
}
void
ChromiumCDMProxy::RejectPromise(PromiseId aId,
nsresult aCode,
const nsCString& aReason)
{
if (!NS_IsMainThread()) {
@@ -486,16 +530,20 @@ ChromiumCDMProxy::Capabilites()
{
return mCapabilites;
}
RefPtr<DecryptPromise>
ChromiumCDMProxy::Decrypt(MediaRawData* aSample)
{
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
+ if (!cdm) {
+ return DecryptPromise::CreateAndReject(DecryptResult(AbortedErr, aSample),
+ __func__);
+ }
RefPtr<MediaRawData> sample = aSample;
return InvokeAsync(
mGMPThread, __func__, [cdm, sample]() { return cdm->Decrypt(sample); });
}
void
ChromiumCDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
nsTArray<nsCString>& aSessionIds)