Bug 1395922 - [P3] Make HTMLMediaElement::SetMediaKeys asynchronously. r=cpearce
MozReview-Commit-ID: 5M8CTHMsmIh
This commit is contained in:
@@ -1489,6 +1489,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPlayPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSeekDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSetMediaKeysDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
||||
@@ -1519,6 +1520,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedVideoStreamTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPlayPromises)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSeekDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSetMediaKeysDOMPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLMediaElement)
|
||||
@@ -1724,6 +1726,7 @@ void HTMLMediaElement::ShutdownDecoder()
|
||||
{
|
||||
RemoveMediaElementFromURITable();
|
||||
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
|
||||
mSetCDMRequest.DisconnectIfExists();
|
||||
mWaitingForKeyListener.DisconnectIfExists();
|
||||
if (mMediaSource) {
|
||||
mMediaSource->CompletePendingTransactions();
|
||||
@@ -7018,6 +7021,17 @@ HTMLMediaElement::ContainsRestrictedContent()
|
||||
return GetMediaKeys() != nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetCDMProxyFailure(const MediaResult& aResult)
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
|
||||
ResetSetMediaKeysTempVariables();
|
||||
|
||||
mSetMediaKeysDOMPromise->MaybeReject(aResult.Code(), aResult.Message());
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::RemoveMediaKeys()
|
||||
{
|
||||
@@ -7029,7 +7043,7 @@ HTMLMediaElement::RemoveMediaKeys()
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::TryRemoveMediaKeysAssociation(DetailedPromise* aPromise)
|
||||
HTMLMediaElement::TryRemoveMediaKeysAssociation()
|
||||
{
|
||||
MOZ_ASSERT(mMediaKeys);
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
@@ -7040,88 +7054,117 @@ HTMLMediaElement::TryRemoveMediaKeysAssociation(DetailedPromise* aPromise)
|
||||
// attaching media keys value be false and reject promise with a new
|
||||
// DOMException whose name is InvalidStateError.
|
||||
if (mDecoder) {
|
||||
// We don't support swapping out the MediaKeys once we've started to
|
||||
// setup the playback pipeline. Note this also means we don't need to worry
|
||||
// about handling disassociating the MediaKeys from the MediaDecoder.
|
||||
aPromise->MaybeReject(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING(
|
||||
"Can't change MediaKeys on HTMLMediaElement after load has started"));
|
||||
RefPtr<HTMLMediaElement> self = this;
|
||||
mDecoder->SetCDMProxy(nullptr)
|
||||
->Then(mAbstractMainThread,
|
||||
__func__,
|
||||
[self]() {
|
||||
self->mSetCDMRequest.Complete();
|
||||
|
||||
self->RemoveMediaKeys();
|
||||
if (self->AttachNewMediaKeys()) {
|
||||
// No incoming MediaKeys object or MediaDecoder is not created yet.
|
||||
self->MakeAssociationWithCDMResolved();
|
||||
}
|
||||
},
|
||||
[self](const MediaResult& aResult) {
|
||||
self->mSetCDMRequest.Complete();
|
||||
// 5.2.4 If the preceding step failed, let this object's attaching media
|
||||
// keys value be false and reject promise with a new DOMException whose
|
||||
// name is the appropriate error name.
|
||||
self->SetCDMProxyFailure(aResult);
|
||||
})
|
||||
->Track(mSetCDMRequest);
|
||||
return false;
|
||||
}
|
||||
RemoveMediaKeys();
|
||||
|
||||
// 5.2.4 If the preceding step failed, let this object's attaching media
|
||||
// keys value be false and reject promise with a new DOMException whose
|
||||
// name is the appropriate error name.
|
||||
RemoveMediaKeys();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::DetachExistingMediaKeys(DetailedPromise* aPromise)
|
||||
HTMLMediaElement::DetachExistingMediaKeys()
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
// 5.1 If mediaKeys is not null, CDM instance represented by mediaKeys is
|
||||
// already in use by another media element, and the user agent is unable
|
||||
// to use it with this element, let this object's attaching media keys
|
||||
// value be false and reject promise with a new DOMException whose name
|
||||
// is QuotaExceededError.
|
||||
if (mIncomingMediaKeys && mIncomingMediaKeys->IsBoundToMediaElement()) {
|
||||
aPromise->MaybeReject(
|
||||
SetCDMProxyFailure(MediaResult(
|
||||
NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
|
||||
NS_LITERAL_CSTRING(
|
||||
"MediaKeys object is already bound to another HTMLMediaElement"));
|
||||
"MediaKeys object is already bound to another HTMLMediaElement"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5.2 If the mediaKeys attribute is not null, run the following steps:
|
||||
if (mMediaKeys) {
|
||||
return TryRemoveMediaKeysAssociation(aPromise);
|
||||
return TryRemoveMediaKeysAssociation();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::MakeAssociationWithCDMResolved(DetailedPromise* aPromise)
|
||||
HTMLMediaElement::MakeAssociationWithCDMResolved()
|
||||
{
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
|
||||
// 5.4 Set the mediaKeys attribute to mediaKeys.
|
||||
mMediaKeys = mIncomingMediaKeys;
|
||||
// 5.5 Let this object's attaching media keys value be false.
|
||||
ResetSetMediaKeysTempVariables();
|
||||
// 5.6 Resolve promise.
|
||||
aPromise->MaybeResolveWithUndefined();
|
||||
mSetMediaKeysDOMPromise->MaybeResolveWithUndefined();
|
||||
mSetMediaKeysDOMPromise = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::TryMakeAssociationWithCDM(CDMProxy* aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
LOG(LogLevel::Debug, ("%s", __func__));
|
||||
MOZ_ASSERT(aProxy);
|
||||
|
||||
// 5.3.3 Queue a task to run the "Attempt to Resume Playback If Necessary"
|
||||
// algorithm on the media element.
|
||||
// Note: Setting the CDMProxy on the MediaDecoder will unblock playback.
|
||||
if (mDecoder) {
|
||||
mDecoder->SetCDMProxy(aProxy);
|
||||
// CDMProxy is set asynchronously in MediaFormatReader, once it's done,
|
||||
// HTMLMediaElement should resolve or reject the DOM promise.
|
||||
RefPtr<HTMLMediaElement> self = this;
|
||||
mDecoder->SetCDMProxy(aProxy)
|
||||
->Then(mAbstractMainThread,
|
||||
__func__,
|
||||
[self]() {
|
||||
self->mSetCDMRequest.Complete();
|
||||
self->MakeAssociationWithCDMResolved();
|
||||
},
|
||||
[self](const MediaResult& aResult) {
|
||||
self->mSetCDMRequest.Complete();
|
||||
self->SetCDMProxyFailure(aResult);
|
||||
})
|
||||
->Track(mSetCDMRequest);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::AttachNewMediaKeys(DetailedPromise* aPromise)
|
||||
HTMLMediaElement::AttachNewMediaKeys()
|
||||
{
|
||||
LOG(LogLevel::Debug,
|
||||
("%s incoming MediaKeys(%p)", __func__, mIncomingMediaKeys.get()));
|
||||
MOZ_ASSERT(mSetMediaKeysDOMPromise);
|
||||
|
||||
// 5.3. If mediaKeys is not null, run the following steps:
|
||||
if (mIncomingMediaKeys) {
|
||||
auto cdmProxy = mIncomingMediaKeys->GetCDMProxy();
|
||||
if (!cdmProxy) {
|
||||
aPromise->MaybeReject(
|
||||
SetCDMProxyFailure(MediaResult(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING(
|
||||
"CDM crashed before binding MediaKeys object to HTMLMediaElement"));
|
||||
"CDM crashed before binding MediaKeys object to HTMLMediaElement"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7133,13 +7176,11 @@ HTMLMediaElement::AttachNewMediaKeys(DetailedPromise* aPromise)
|
||||
// 5.3.2.1 Set the mediaKeys attribute to null.
|
||||
mMediaKeys = nullptr;
|
||||
// 5.3.2.2 Let this object's attaching media keys value be false.
|
||||
ResetSetMediaKeysTempVariables();
|
||||
// 5.3.2.3 Reject promise with a new DOMException whose name is
|
||||
// the appropriate error name.
|
||||
aPromise->MaybeReject(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
NS_LITERAL_CSTRING(
|
||||
"Failed to bind MediaKeys object to HTMLMediaElement"));
|
||||
SetCDMProxyFailure(
|
||||
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"Failed to bind MediaKeys object to HTMLMediaElement"));
|
||||
return false;
|
||||
}
|
||||
return TryMakeAssociationWithCDM(cdmProxy);
|
||||
@@ -7185,8 +7226,6 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Note: Our attaching code is synchronous, so we can skip the following steps.
|
||||
|
||||
// 2. If this object's attaching media keys value is true, return a
|
||||
// promise rejected with a new DOMException whose name is InvalidStateError.
|
||||
if (mAttachingMediaKey) {
|
||||
@@ -7201,22 +7240,17 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
mIncomingMediaKeys = aMediaKeys;
|
||||
|
||||
// 4. Let promise be a new promise.
|
||||
mSetMediaKeysDOMPromise = promise;
|
||||
|
||||
// 5. Run the following steps in parallel:
|
||||
|
||||
// 5.1 & 5.2
|
||||
if (!DetachExistingMediaKeys(promise)) {
|
||||
ResetSetMediaKeysTempVariables();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.3
|
||||
if (!AttachNewMediaKeys(promise)) {
|
||||
ResetSetMediaKeysTempVariables();
|
||||
// 5.1 & 5.2 & 5.3
|
||||
if (!DetachExistingMediaKeys() || !AttachNewMediaKeys()) {
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// 5.4, 5.5, 5.6
|
||||
MakeAssociationWithCDMResolved(promise);
|
||||
MakeAssociationWithCDMResolved();
|
||||
|
||||
// 6. Return promise.
|
||||
return promise.forget();
|
||||
|
||||
Reference in New Issue
Block a user