Backed out 6 changesets (bug 1395922) for failing Media tests test_eme_sample_groups_playback.html and test_eme_sample_groups_playback.html r=backout a=backout
authorCsoregi Natalia <ncsoregi@mozilla.com>
Mon, 06 Nov 2017 12:34:02 +0200
changeset 390274 8b9167b8a937e09f6673d4d7d693c6ac1c25a3d7
parent 390273 a73e202ca31d30bc2b96418fa81d1096f8dc731e
child 390300 70f38f59f9fa45dda5d70d44881dc1d906de15f6
push id97010
push userncsoregi@mozilla.com
push dateMon, 06 Nov 2017 10:51:44 +0000
treeherdermozilla-inbound@ec85e0d36746 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout, backout
bugs1395922
milestone58.0a1
backs outf856af63682efa003abcbf478c6e0ad875408775
f59a7e727f39201d8af28b9cb08b26a45d22007e
9cd31c6a8e2c30132865e7d2a73a91ebb5faffa6
d46f952f94f8428f6d4bea54f8dd54b42546da5d
f786d928b1e0b2dae17b9c07e905c83805d5910a
bacda0f99f710c6a1b03de91ab64979229ef1829
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 6 changesets (bug 1395922) for failing Media tests test_eme_sample_groups_playback.html and test_eme_sample_groups_playback.html r=backout a=backout Backed out changeset f856af63682e (bug 1395922) Backed out changeset f59a7e727f39 (bug 1395922) Backed out changeset 9cd31c6a8e2c (bug 1395922) Backed out changeset d46f952f94f8 (bug 1395922) Backed out changeset f786d928b1e0 (bug 1395922) Backed out changeset bacda0f99f71 (bug 1395922)
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
dom/media/MediaPromiseDefs.h
dom/media/moz.build
dom/media/test/bipbop_225w_175kbps.mp4^headers^
dom/media/test/mochitest.ini
dom/media/test/test_eme_detach_reattach_same_mediakeys_during_playback.html
dom/media/test/test_eme_unsetMediaKeys_then_capture.html
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1481,21 +1481,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   for (uint32_t i = 0; i < tmp->mOutputStreams.Length(); ++i) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutputStreams[i].mStream)
   }
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlayed);
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioTrackList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncomingMediaKeys)
   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)
   tmp->RemoveMutationObserver(tmp);
   if (tmp->mSrcStream) {
     // Need to EndMediaStreamPlayback to clear mSrcStream and make sure everything
     // gets unhooked correctly.
     tmp->EndSrcMediaStreamPlayback();
@@ -1512,21 +1510,19 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioChannelWrapper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mErrorSink->mError)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputStreams)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPlayed)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTrackManager)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioTrackList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoTrackList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncomingMediaKeys)
   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)
   NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLMediaElement)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
 
 // nsIDOMHTMLMediaElement
 NS_IMPL_URI_ATTR(HTMLMediaElement, Src, src)
@@ -1711,17 +1707,16 @@ HTMLMediaElement::OnChannelRedirect(nsIC
   MOZ_ASSERT(mChannelLoader);
   return mChannelLoader->Redirect(aChannel, aNewChannel, aFlags);
 }
 
 void HTMLMediaElement::ShutdownDecoder()
 {
   RemoveMediaElementFromURITable();
   NS_ASSERTION(mDecoder, "Must have decoder to shut down");
-  mSetCDMRequest.DisconnectIfExists();
   mWaitingForKeyListener.DisconnectIfExists();
   if (mMediaSource) {
     mMediaSource->CompletePendingTransactions();
   }
   mDecoder->Shutdown();
   mDecoder = nullptr;
 }
 
@@ -3975,17 +3970,16 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mPreloadAction(PRELOAD_UNDEFINED),
     mLastCurrentTime(0.0),
     mFragmentStart(-1.0),
     mFragmentEnd(-1.0),
     mDefaultPlaybackRate(1.0),
     mPlaybackRate(1.0),
     mPreservesPitch(true),
     mPlayed(new TimeRanges(ToSupports(OwnerDoc()))),
-    mAttachingMediaKey(false),
     mCurrentPlayRangeStart(-1.0),
     mLoadedDataFired(false),
     mAutoplaying(true),
     mAutoplayEnabled(true),
     mPaused(true, *this),
     mStatsShowing(false),
     mAllowCasting(false),
     mIsCasting(false),
@@ -7007,190 +7001,16 @@ HTMLMediaElement::GetMediaKeys() const
 }
 
 bool
 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()
-{
-  LOG(LogLevel::Debug, ("%s", __func__));
-  // 5.2.3 Stop using the CDM instance represented by the mediaKeys attribute
-  // to decrypt media data and remove the association with the media element.
-  mMediaKeys->Unbind();
-  mMediaKeys = nullptr;
-}
-
-bool
-HTMLMediaElement::TryRemoveMediaKeysAssociation()
-{
-  MOZ_ASSERT(mMediaKeys);
-  LOG(LogLevel::Debug, ("%s", __func__));
-  // 5.2.1 If the user agent or CDM do not support removing the association,
-  // let this object's attaching media keys value be false and reject promise
-  // with a new DOMException whose name is NotSupportedError.
-  // 5.2.2 If the association cannot currently be removed, let this object's
-  // attaching media keys value be false and reject promise with a new
-  // DOMException whose name is InvalidStateError.
-  if (mDecoder) {
-    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();
-  return true;
-}
-
-bool
-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()) {
-    SetCDMProxyFailure(MediaResult(
-      NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
-      "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();
-  }
-  return true;
-}
-
-void
-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.
-  mSetMediaKeysDOMPromise->MaybeResolveWithUndefined();
-  mSetMediaKeysDOMPromise = nullptr;
-}
-
-bool
-HTMLMediaElement::TryMakeAssociationWithCDM(CDMProxy* 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) {
-    // 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()
-{
-  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) {
-      SetCDMProxyFailure(MediaResult(
-        NS_ERROR_DOM_INVALID_STATE_ERR,
-        "CDM crashed before binding MediaKeys object to HTMLMediaElement"));
-      return false;
-    }
-
-    // 5.3.1 Associate the CDM instance represented by mediaKeys with the
-    // media element for decrypting media data.
-    if (NS_FAILED(mIncomingMediaKeys->Bind(this))) {
-      // 5.3.2 If the preceding step failed, run the following steps:
-
-      // 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.
-      // 5.3.2.3 Reject promise with a new DOMException whose name is
-      // the appropriate error name.
-      SetCDMProxyFailure(
-        MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
-                    "Failed to bind MediaKeys object to HTMLMediaElement"));
-      return false;
-    }
-    return TryMakeAssociationWithCDM(cdmProxy);
-  }
-  return true;
-}
-
-void
-HTMLMediaElement::ResetSetMediaKeysTempVariables()
-{
-  mAttachingMediaKey = false;
-  mIncomingMediaKeys = nullptr;
-}
-
 already_AddRefed<Promise>
 HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
                                ErrorResult& aRv)
 {
   LOG(LogLevel::Debug, ("%p SetMediaKeys(%p) mMediaKeys=%p mDecoder=%p",
     this, aMediaKeys, mMediaKeys.get(), mDecoder.get()));
 
   if (MozAudioCaptured()) {
@@ -7212,41 +7032,99 @@ HTMLMediaElement::SetMediaKeys(mozilla::
 
   // 1. If mediaKeys and the mediaKeys attribute are the same object,
   // return a resolved promise.
   if (mMediaKeys == aMediaKeys) {
     promise->MaybeResolveWithUndefined();
     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) {
-    promise->MaybeReject(
-      NS_ERROR_DOM_INVALID_STATE_ERR,
-      NS_LITERAL_CSTRING("A MediaKeys object is in attaching operation."));
-    return promise.forget();
-  }
-
   // 3. Let this object's attaching media keys value be true.
-  mAttachingMediaKey = true;
-  mIncomingMediaKeys = aMediaKeys;
-
   // 4. Let promise be a new promise.
-  mSetMediaKeysDOMPromise = promise;
-
   // 5. Run the following steps in parallel:
 
-  // 5.1 & 5.2 & 5.3
-  if (!DetachExistingMediaKeys() || !AttachNewMediaKeys()) {
+  // 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 (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
+    promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR,
+      NS_LITERAL_CSTRING("MediaKeys object is already bound to another HTMLMediaElement"));
     return promise.forget();
   }
 
-  // 5.4, 5.5, 5.6
-  MakeAssociationWithCDMResolved();
+  // 5.2 If the mediaKeys attribute is not null, run the following steps:
+  if (mMediaKeys) {
+    // 5.2.1 If the user agent or CDM do not support removing the association,
+    // let this object's attaching media keys value be false and reject promise
+    // with a new DOMException whose name is NotSupportedError.
+
+    // 5.2.2 If the association cannot currently be removed, let this object's
+    // 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.
+      promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+        NS_LITERAL_CSTRING("Can't change MediaKeys on HTMLMediaElement after load has started"));
+      return promise.forget();
+    }
+
+    // 5.2.3 Stop using the CDM instance represented by the mediaKeys attribute
+    // to decrypt media data and remove the association with the media element.
+    mMediaKeys->Unbind();
+    mMediaKeys = nullptr;
+
+    // 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.
+  }
+
+  // 5.3. If mediaKeys is not null, run the following steps:
+  if (aMediaKeys) {
+    if (!aMediaKeys->GetCDMProxy()) {
+      promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+        NS_LITERAL_CSTRING("CDM crashed before binding MediaKeys object to HTMLMediaElement"));
+      return promise.forget();
+    }
+
+    // 5.3.1 Associate the CDM instance represented by mediaKeys with the
+    // media element for decrypting media data.
+    if (NS_FAILED(aMediaKeys->Bind(this))) {
+      // 5.3.2 If the preceding step failed, run the following steps:
+      // 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.
+      // 5.3.2.3 Reject promise with a new DOMException whose name is
+      // the appropriate error name.
+      promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
+                           NS_LITERAL_CSTRING("Failed to bind MediaKeys object to HTMLMediaElement"));
+      return promise.forget();
+    }
+    // 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(aMediaKeys->GetCDMProxy());
+    }
+  }
+
+  // 5.4 Set the mediaKeys attribute to mediaKeys.
+  mMediaKeys = aMediaKeys;
+
+  // 5.5 Let this object's attaching media keys value be false.
+
+  // 5.6 Resolve promise.
+  promise->MaybeResolveWithUndefined();
 
   // 6. Return promise.
   return promise.forget();
 }
 
 EventHandlerNonNull*
 HTMLMediaElement::GetOnencrypted()
 {
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -7,17 +7,16 @@
 #define mozilla_dom_HTMLMediaElement_h
 
 #include "nsAutoPtr.h"
 #include "nsIDOMHTMLMediaElement.h"
 #include "nsGenericHTMLElement.h"
 #include "MediaEventSource.h"
 #include "SeekTarget.h"
 #include "MediaDecoderOwner.h"
-#include "MediaPromiseDefs.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIObserver.h"
 #include "mozilla/CORSMode.h"
 #include "DecoderTraits.h"
 #include "nsIAudioChannelAgent.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TextTrackManager.h"
 #include "mozilla/WeakPtr.h"
@@ -1328,25 +1327,16 @@ protected:
                                 const nsAttrValue* aValue,
                                 const nsAttrValue* aOldValue,
                                 nsIPrincipal* aMaybeScriptedPrincipal,
                                 bool aNotify) override;
   virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
                                           const nsAttrValueOrString& aValue,
                                           bool aNotify) override;
 
-  bool DetachExistingMediaKeys();
-  bool TryRemoveMediaKeysAssociation();
-  void RemoveMediaKeys();
-  bool AttachNewMediaKeys();
-  bool TryMakeAssociationWithCDM(CDMProxy* aProxy);
-  void MakeAssociationWithCDMResolved();
-  void SetCDMProxyFailure(const MediaResult& aResult);
-  void ResetSetMediaKeysTempVariables();
-
   // The current decoder. Load() has been called on this decoder.
   // At most one of mDecoder and mSrcStream can be non-null.
   RefPtr<MediaDecoder> mDecoder;
 
   // The DocGroup-specific nsISerialEventTarget of this HTML element on the main
   // thread.
   nsCOMPtr<nsISerialEventTarget> mMainThreadEventTarget;
 
@@ -1539,22 +1529,16 @@ protected:
   // Timer used for updating progress events.
   nsCOMPtr<nsITimer> mProgressTimer;
 
   // Timer used to simulate video-suspend.
   nsCOMPtr<nsITimer> mVideoDecodeSuspendTimer;
 
   // Encrypted Media Extension media keys.
   RefPtr<MediaKeys> mMediaKeys;
-  RefPtr<MediaKeys> mIncomingMediaKeys;
-  // The dom promise is used for HTMLMediaElement::SetMediaKeys.
-  RefPtr<DetailedPromise> mSetMediaKeysDOMPromise;
-  // Used to indicate if the MediaKeys attaching operation is on-going or not.
-  bool mAttachingMediaKey;
-  MozPromiseRequestHolder<SetCDMPromise> mSetCDMRequest;
 
   // Stores the time at the start of the current 'played' range.
   double mCurrentPlayRangeStart;
 
   // True if loadeddata has been fired.
   bool mLoadedDataFired;
 
   // Indicates whether current playback is a result of user action
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1418,25 +1418,28 @@ MediaDecoder::CanPlayThrough()
   bool val = CanPlayThroughImpl();
   if (val != mCanPlayThrough) {
     mCanPlayThrough = val;
     mDecoderStateMachine->DispatchCanPlayThrough(val);
   }
   return val;
 }
 
-RefPtr<SetCDMPromise>
+void
 MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return InvokeAsync<RefPtr<CDMProxy>>(mReader->OwnerThread(),
-                                       mReader.get(),
-                                       __func__,
-                                       &MediaFormatReader::SetCDMProxy,
-                                       aProxy);
+  RefPtr<CDMProxy> proxy = aProxy;
+  RefPtr<MediaFormatReader> reader = mReader;
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+    "MediaFormatReader::SetCDMProxy",
+    [reader, proxy]() {
+    reader->SetCDMProxy(proxy);
+    });
+  mReader->OwnerThread()->Dispatch(r.forget());
 }
 
 bool
 MediaDecoder::IsOpusEnabled()
 {
   return Preferences::GetBool("media.opus.enabled");
 }
 
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -7,17 +7,16 @@
 #if !defined(MediaDecoder_h_)
 #define MediaDecoder_h_
 
 #include "DecoderDoctorDiagnostics.h"
 #include "MediaContainerType.h"
 #include "MediaDecoderOwner.h"
 #include "MediaEventSource.h"
 #include "MediaMetadataManager.h"
-#include "MediaPromiseDefs.h"
 #include "MediaResource.h"
 #include "MediaStatistics.h"
 #include "MediaStreamGraph.h"
 #include "SeekTarget.h"
 #include "TimeUnits.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/MozPromise.h"
@@ -351,17 +350,17 @@ private:
 
   MediaDecoderOwner* GetOwner() const;
 
   AbstractThread* AbstractMainThread() const
   {
     return mAbstractMainThread;
   }
 
-  RefPtr<SetCDMPromise> SetCDMProxy(CDMProxy* aProxy);
+  void SetCDMProxy(CDMProxy* aProxy);
 
   void EnsureTelemetryReported();
 
   static bool IsOggEnabled();
   static bool IsOpusEnabled();
   static bool IsWaveEnabled();
   static bool IsWebMEnabled();
 
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1223,20 +1223,16 @@ MediaFormatReader::Shutdown()
   MOZ_ASSERT(OnTaskQueue());
   LOG("");
 
   mDemuxerInitRequest.DisconnectIfExists();
   mNotifyDataArrivedPromise.DisconnectIfExists();
   mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   mSkipRequest.DisconnectIfExists();
-  mSetCDMPromise.RejectIfExists(
-    MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
-                "MediaFormatReader is shutting down"),
-    __func__);
 
   if (mAudio.HasPromise()) {
     mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   }
   if (mVideo.HasPromise()) {
     mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   }
 
@@ -1317,111 +1313,33 @@ MediaFormatReader::Init()
 
   mVideo.mTaskQueue = new TaskQueue(
     GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
     "MFR::mVideo::mTaskQueue");
 
   return NS_OK;
 }
 
-bool
-MediaFormatReader::ResolveSetCDMPromiseIfDone(TrackType aTrack)
-{
-  // When a CDM proxy is set, MFR would shutdown the existing MediaDataDecoder
-  // and would create new one for specific track in the next Update.
-  MOZ_ASSERT(OnTaskQueue());
-
-  if (mSetCDMPromise.IsEmpty()) {
-    return true;
-  }
-
-  MOZ_ASSERT(mCDMProxy);
-  if (mSetCDMForTracks.contains(aTrack)) {
-    mSetCDMForTracks -= aTrack;
-  }
-
-  if (mSetCDMForTracks.isEmpty()) {
-    LOGV("%s : Done ", __func__);
-    mSetCDMPromise.Resolve(/* aIgnored = */ true, __func__);
-    ScheduleUpdate(TrackInfo::kAudioTrack);
-    ScheduleUpdate(TrackInfo::kVideoTrack);
-    return true;
-  }
-  LOGV("%s : %s track is ready.", __func__, TrackTypeToStr(aTrack));
-  return false;
-}
-
 void
-MediaFormatReader::PrepareToSetCDMForTrack(TrackType aTrack)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  LOGV("%s : %s", __func__, TrackTypeToStr(aTrack));
-
-  mSetCDMForTracks += aTrack;
-  if (mCDMProxy) {
-    // An old cdm proxy exists, so detaching old cdm proxy by shutting down
-    // MediaDataDecoder.
-    ShutdownDecoder(aTrack);
-  }
-  ScheduleUpdate(aTrack);
-}
-
-bool
-MediaFormatReader::IsDecoderWaitingForCDM(TrackType aTrack)
-{
-  MOZ_ASSERT(OnTaskQueue());
-  return IsEncrypted() && mSetCDMForTracks.contains(aTrack) && !mCDMProxy;
-}
-
-RefPtr<SetCDMPromise>
 MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
 {
-  MOZ_ASSERT(OnTaskQueue());
-  LOGV("SetCDMProxy (%p)", aProxy);
-
-  if (mShutdown) {
-    return SetCDMPromise::CreateAndReject(
-      MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
-                  "MediaFormatReader is shutting down"),
-      __func__);
-  }
-
-  mSetCDMPromise.RejectIfExists(
-    MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
-                "Another new CDM proxy is being set."),
-    __func__);
-
-  // Shutdown all decoders as switching CDM proxy indicates that it's
-  // inappropriate for the existing decoders to continue decoding via the old
-  // CDM proxy.
-  if (HasAudio()) {
-    PrepareToSetCDMForTrack(TrackInfo::kAudioTrack);
-  }
-  if (HasVideo()) {
-    PrepareToSetCDMForTrack(TrackInfo::kVideoTrack);
-  }
-
-  mCDMProxy = aProxy;
-
-  if (IsEncrypted() && !mCDMProxy) {
-    // Release old PDMFactory which contains an EMEDecoderModule.
-    mPlatform = nullptr;
-  }
-
-  if (!mInitDone || mSetCDMForTracks.isEmpty() || !mCDMProxy) {
-    // 1) MFR is not initialized yet or
-    // 2) Demuxer is initialized without active audio and video or
-    // 3) A null cdm proxy is set
-    // the promise can be resolved directly.
-    mSetCDMForTracks.clear();
-    return SetCDMPromise::CreateAndResolve(/* aIgnored = */ true, __func__);
-  }
-
-  RefPtr<SetCDMPromise> p = mSetCDMPromise.Ensure(__func__);
-  return p;
+  RefPtr<CDMProxy> proxy = aProxy;
+  RefPtr<MediaFormatReader> self = this;
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction("MediaFormatReader::SetCDMProxy", [=]() {
+      MOZ_ASSERT(self->OnTaskQueue());
+      self->mCDMProxy = proxy;
+      if (HasAudio()) {
+        self->ScheduleUpdate(TrackInfo::kAudioTrack);
+      }
+      if (HasVideo()) {
+        self->ScheduleUpdate(TrackInfo::kVideoTrack);
+      }
+    });
+  OwnerThread()->Dispatch(r.forget());
 }
 
 bool
 MediaFormatReader::IsWaitingOnCDMResource()
 {
   MOZ_ASSERT(OnTaskQueue());
   return IsEncrypted() && !mCDMProxy;
 }
@@ -2468,23 +2386,16 @@ MediaFormatReader::Update(TrackType aTra
       // There is no more samples left to be decoded and we are already in
       // EOS state. We can immediately reject the data promise.
       LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
       decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
     } else if (decoder.mWaitingForKey) {
       LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key",
           TrackTypeToStr(aTrack));
       decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
-    } else if (IsDecoderWaitingForCDM(aTrack)) {
-      // Rejecting the promise could lead to entering buffering state for MDSM,
-      // once a qualified(with the same key system and sessions created by the
-      // same InitData) new cdm proxy is set, decoding can be resumed.
-      LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for CDM",
-          TrackTypeToStr(aTrack));
-      decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
     }
   }
 
   if (decoder.mDrainState == DrainState::DrainRequested ||
       decoder.mDrainState == DrainState::PartialDrainPending) {
     if (decoder.mOutput.IsEmpty()) {
       DrainDecoder(aTrack);
     }
@@ -2532,46 +2443,43 @@ MediaFormatReader::Update(TrackType aTra
     }
     return;
   }
 
   bool needInput = NeedInput(decoder);
 
   LOGV("Update(%s) ni=%d no=%d in:%" PRIu64 " out:%" PRIu64
        " qs=%u decoding:%d flushing:%d desc:%s pending:%u waiting:%d eos:%d "
-       "ds:%d sid:%u waitcdm:%d",
+       "ds:%d sid:%u",
        TrackTypeToStr(aTrack),
        needInput,
        needOutput,
        decoder.mNumSamplesInput,
        decoder.mNumSamplesOutput,
        uint32_t(size_t(decoder.mSizeOfQueue)),
        decoder.mDecodeRequest.Exists(),
        decoder.mFlushing,
        decoder.mDescription.get(),
        uint32_t(decoder.mOutput.Length()),
        decoder.mWaitingForData,
        decoder.mDemuxEOS,
        int32_t(decoder.mDrainState),
-       decoder.mLastStreamSourceID,
-       IsDecoderWaitingForCDM(aTrack));
-
-  if (IsWaitingOnCDMResource() || !ResolveSetCDMPromiseIfDone(aTrack)) {
+       decoder.mLastStreamSourceID);
+
+  if (IsWaitingOnCDMResource()) {
     // If the content is encrypted, MFR won't start to create decoder until
     // CDMProxy is set.
     return;
   }
 
   if ((decoder.mWaitingForData &&
        (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting)) ||
       (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
     // Nothing more we can do at present.
-    LOGV("Still waiting for data or key. data(%d)/key(%d)",
-         decoder.mWaitingForData,
-         decoder.mWaitingForKey);
+    LOGV("Still waiting for data or key.");
     return;
   }
 
   if (decoder.CancelWaitingForKey()) {
     LOGV("No longer waiting for key. Resolving waiting promise");
     return;
   }
 
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -13,17 +13,16 @@
 #include "mozilla/TaskQueue.h"
 #include "mozilla/Mutex.h"
 
 #include "FrameStatistics.h"
 #include "MediaEventSource.h"
 #include "MediaDataDemuxer.h"
 #include "MediaMetadataManager.h"
 #include "MediaPrefs.h"
-#include "MediaPromiseDefs.h"
 #include "nsAutoPtr.h"
 #include "PDMFactory.h"
 #include "SeekTarget.h"
 
 namespace mozilla {
 
 class CDMProxy;
 class GMPCrashHelper;
@@ -87,16 +86,17 @@ struct MOZ_STACK_CLASS MediaFormatReader
   MediaDecoderOwnerID mMediaDecoderOwnerID = nullptr;
 };
 
 class MediaFormatReader final
 {
   static const bool IsExclusive = true;
   typedef TrackInfo::TrackType TrackType;
   typedef MozPromise<bool, MediaResult, IsExclusive> NotifyDataArrivedPromise;
+
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaFormatReader)
 
 public:
   using TrackSet = EnumSet<TrackInfo::TrackType>;
   using MetadataPromise = MozPromise<MetadataHolder, MediaResult, IsExclusive>;
 
   template<typename Type>
   using DataPromise = MozPromise<RefPtr<Type>, MediaResult, IsExclusive>;
@@ -189,17 +189,17 @@ public:
   RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType);
 
   // The MediaDecoderStateMachine uses various heuristics that assume that
   // raw media data is arriving sequentially from a network channel. This
   // makes sense in the <video src="foo"> case, but not for more advanced use
   // cases like MSE.
   bool UseBufferingHeuristics() const { return mTrackDemuxersMayBlock; }
 
-  RefPtr<SetCDMPromise> SetCDMProxy(CDMProxy* aProxy);
+  void SetCDMProxy(CDMProxy* aProxy);
 
   // Returns a string describing the state of the decoder data.
   // Used for debugging purposes.
   void GetMozDebugReaderData(nsACString& aString);
 
   // Switch the video decoder to NullDecoderModule. It might takes effective
   // since a few samples later depends on how much demuxed samples are already
   // queued in the original video decoder.
@@ -787,19 +787,13 @@ private:
   MediaEventProducer<void> mOnWaitingForKey;
 
   MediaEventProducer<MediaResult> mOnDecodeWarning;
 
   RefPtr<FrameStatistics> mFrameStats;
 
   // Used in bug 1393399 for telemetry.
   const MediaDecoderOwnerID mMediaDecoderOwnerID;
-
-  bool ResolveSetCDMPromiseIfDone(TrackType aTrack);
-  void PrepareToSetCDMForTrack(TrackType aTrack);
-  MozPromiseHolder<SetCDMPromise> mSetCDMPromise;
-  TrackSet mSetCDMForTracks{};
-  bool IsDecoderWaitingForCDM(TrackType aTrack);
 };
 
 } // namespace mozilla
 
 #endif
deleted file mode 100644
--- a/dom/media/MediaPromiseDefs.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- 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/. */
-#ifndef MediaPromiseDefs_h_
-#define MediaPromiseDefs_h_
-
-#include "MediaResult.h"
-#include "mozilla/MozPromise.h"
-
-namespace mozilla {
-
-using SetCDMPromise =
-  MozPromise<bool /* aIgnored */, MediaResult, /* IsExclusive */ true>;
-
-} // namespace mozilla
-
-#endif
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -116,17 +116,16 @@ EXPORTS += [
     'MediaDecoderOwner.h',
     'MediaDecoderStateMachine.h',
     'MediaEventSource.h',
     'MediaFormatReader.h',
     'MediaInfo.h',
     'MediaMetadataManager.h',
     'MediaMIMETypes.h',
     'MediaPrefs.h',
-    'MediaPromiseDefs.h',
     'MediaQueue.h',
     'MediaRecorder.h',
     'MediaResource.h',
     'MediaResourceCallback.h',
     'MediaResult.h',
     'MediaSegment.h',
     'MediaShutdownManager.h',
     'MediaStatistics.h',
deleted file mode 100644
--- a/dom/media/test/bipbop_225w_175kbps.mp4^headers^
+++ /dev/null
@@ -1,1 +0,0 @@
-Cache-Control: no-store
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -69,18 +69,16 @@ support-files =
   bipbop-cenc-video1.m4s
   bipbop-cenc-video1.m4s^headers^
   bipbop-cenc-video2.m4s
   bipbop-cenc-video2.m4s^headers^
   bipbop-cenc-videoinit.mp4
   bipbop-cenc-videoinit.mp4^headers^
   bipbop-cenc-video-10s.mp4
   bipbop-cenc-video-10s.mp4^headers^
-  bipbop_225w_175kbps.mp4
-  bipbop_225w_175kbps.mp4^headers^
   bipbop_225w_175kbps-cenc-audio-key1-1.m4s
   bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^
   bipbop_225w_175kbps-cenc-audio-key1-2.m4s
   bipbop_225w_175kbps-cenc-audio-key1-2.m4s^headers^
   bipbop_225w_175kbps-cenc-audio-key1-3.m4s
   bipbop_225w_175kbps-cenc-audio-key1-3.m4s^headers^
   bipbop_225w_175kbps-cenc-audio-key1-4.m4s
   bipbop_225w_175kbps-cenc-audio-key1-4.m4s^headers^
@@ -755,18 +753,16 @@ skip-if = android_version == '17' # andr
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_pssh_in_moof.html]
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_session_callable_value.html]
 [test_eme_canvas_blocked.html]
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_detach_media_keys.html]
 skip-if = toolkit == 'android' # bug 1149374
-[test_eme_detach_reattach_same_mediakeys_during_playback.html]
-skip-if = toolkit == 'android' # bug 1149374
 [test_eme_initDataTypes.html]
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_missing_pssh.html]
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_non_mse_fails.html]
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_request_notifications.html]
 skip-if = toolkit == 'android' # bug 1149374
@@ -782,18 +778,16 @@ skip-if = toolkit == 'android' # bug 114
 tags=msg capturestream
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_stream_capture_blocked_case2.html]
 tags=msg capturestream
 skip-if = toolkit == 'android' # bug 1149374
 [test_eme_stream_capture_blocked_case3.html]
 tags=msg capturestream
 skip-if = toolkit == 'android' # bug 1149374
-[test_eme_unsetMediaKeys_then_capture.html]
-skip-if = toolkit == 'android' # bug 1149374
 [test_eme_waitingforkey.html]
 skip-if = toolkit == 'android' # bug 1149374
 [test_empty_resource.html]
 [test_error_in_video_document.html]
 [test_error_on_404.html]
 [test_fastSeek.html]
 skip-if = toolkit == 'android' # android(bug 1232305)
 [test_fastSeek-forwards.html]
deleted file mode 100644
--- a/dom/media/test/test_eme_detach_reattach_same_mediakeys_during_playback.html
+++ /dev/null
@@ -1,144 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test Encrypted Media Extensions</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-  <script type="text/javascript" src="manifest.js"></script>
-  <script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
-</head>
-<body>
-<pre id="test">
-<video id="v" controls></video>
-<script class="testbody" type="text/javascript">
-var manager = new MediaTestManager;
-
-var EMEmanifest = [
-  {
-    name:"bipbop 10s",
-    tracks: [
-      {
-          name:"video",
-          type:"video/mp4; codecs=\"avc1.4d4015\"",
-          fragments:[ "bipbop-cenc-video-10s.mp4",
-                    ]
-      }
-    ],
-    keys: {
-      "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
-    },
-    sessionType:"temporary",
-    sessionCount:1,
-    duration:10.01
-  },
-];
-
-function sleep(time) {
-  return new Promise((resolve) => setTimeout(resolve, time));
-}
-
-// To check if playback can be blocked and resumed correctly after
-// detaching original mediakeys and reattach it back.
-function startTest(test, token)
-{
-  manager.started(token);
-
-  var mk_ori;
-  let finish = new EMEPromise;
-
-  let v = document.getElementById("v");
-  let sessions = [];
-  function onSessionCreated(session) {
-    sessions.push(session);
-  }
-
-  function closeSessions() {
-    let p = new EMEPromise;
-    Promise.all(sessions.map(s => s.close()))
-    .then(p.resolve, p.reject);
-    return p.promise;
-  }
-
-  function setMediaKeysToElement(mk, solve, reject) {
-    v.setMediaKeys(mk).then(solve, reject);
-  }
-
-  function ReattachOriMediaKeys() {
-    function onOriMediaKeysSetOK() {
-      ok(true, TimeStamp(token) + " (ENCRYPTED) Set original MediaKeys back OK!");
-    }
-    function onOriMediaKeysSetFailed() {
-      ok(false, " Failed to set original mediakeys back.");
-    }
-
-    function onCanPlayAgain(ev) {
-      Promise.all([closeSessions()])
-      .then(() => {
-        ok(true, " (ENCRYPTED) Playback can be resumed.");
-        manager.finished(token);
-      }, () => {
-        ok(false, TimeStamp(token) + " Sessions are closed incorrectly.");
-        manager.finished(token);
-      });
-    }
-
-    once(v, "canplay", onCanPlayAgain);
-    setMediaKeysToElement(mk_ori, onOriMediaKeysSetOK, onOriMediaKeysSetFailed)
-  }
-
-  function triggerSeek() {
-    v.currentTime = v.duration / 2;
-  }
-
-  function onCanPlay(ev) {
-    function onSetMediaKeysToNullOK() {
-      ok(true, TimeStamp(token) + " Set MediaKeys to null. OK!");
-
-      triggerSeek();
-
-      SimpleTest.requestFlakyTimeout("To reattach mediakeys back again in 5s.");
-      sleep(5000).then(ReattachOriMediaKeys);
-    }
-    function onSetMediaKeysToNullFailed() {
-      ok(false, TimeStamp(token) + " Set MediaKeys to null. FAILED!");
-    }
-
-    SimpleTest.requestFlakyTimeout("To detach mediakeys after receiving 'canplay' event in 2s");
-    sleep(2000).then(() => {
-      setMediaKeysToElement(null, onSetMediaKeysToNullOK, onSetMediaKeysToNullFailed);
-    });
-  }
-
-  once(v, "canplay", onCanPlay);
-
-  var p1 = LoadInitData(v, test, token);
-  var p2 = CreateAndSetMediaKeys(v, test, token);
-  var p3 = LoadTest(test, v, token);
-  Promise.all([p1, p2, p3])
-  .then(values => {
-    let initData = values[0];
-    // stash the mediakeys
-    mk_ori = v.mediaKeys;
-    initData.map(ev => {
-      let session = v.mediaKeys.createSession();
-      onSessionCreated(session);
-      MakeRequest(test, token, ev, session);
-    });
-  })
-  .then(() => {
-    return finish.promise;
-  })
-  .catch(reason => ok(false, reason))
-}
-
-function beginTest() {
-  manager.runTests(EMEmanifest, startTest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SetupEMEPref(beginTest);
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/media/test/test_eme_unsetMediaKeys_then_capture.html
+++ /dev/null
@@ -1,117 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test Encrypted Media Extensions</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-  <script type="text/javascript" src="manifest.js"></script>
-  <script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
-</head>
-<body>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-var manager = new MediaTestManager;
-
-// Test that if we can capture a video frame while playing clear content after
-// removing the MediaKeys object which was used for a previous encrypted content
-// playback on the same video element
-function startTest(test, token)
-{
-  manager.started(token);
-  var sessions = [];
-  function onSessionCreated(session) {
-    sessions.push(session);
-  }
-
-  function closeSessions() {
-    let p = new EMEPromise;
-    Promise.all(sessions.map(s => s.close()))
-    .then(p.resolve, p.reject);
-    return p.promise;
-  }
-
-  let v = document.createElement("video");
-  document.body.appendChild(v);
-
-  let finish = new EMEPromise;
-
-  function onVideoEnded(ev) {
-    ok(true, TimeStamp(token) + " (ENCRYPTED) content playback ended.");
-    v.removeEventListener("ended", onVideoEnded);
-
-    function playClearVideo() {
-      var p1 = once(v, 'ended', (e) => {
-        ok(true, TimeStamp(token) + " (CLEAR) content playback ended.");
-        console.log(" bipbop.mp4 playback ended !!");
-      });
-      var p2 = once(v, 'loadeddata', (e) => {
-        ok(true, TimeStamp(token) + " Receiving event 'loadeddata' for (CLEAR) content.");
-        canvasElem = document.createElement('canvas');
-        document.body.appendChild(canvasElem);
-        ctx2d = canvasElem.getContext('2d');
-
-        var gotTypeError = false;
-        try {
-          ctx2d.drawImage(v, 0, 0);
-        } catch (e) {
-          if (e instanceof TypeError) {
-            gotTypeError = true;
-          }
-        }
-        ok(!gotTypeError, TimeStamp(token) + " Canvas2D context drawImage succeed.")
-      });
-      v.src = 'bipbop_225w_175kbps.mp4';
-      v.play();
-      Promise.all([p1, p2, closeSessions()]).then(() => {
-        manager.finished(token);
-      }, () => {
-        ok(false, TimeStamp(token) + " Something wrong.");
-        manager.finished(token);
-      });
-    }
-
-    Promise.all(sessions.map(s => s.close()))
-    .then(() => {
-      v.setMediaKeys(null)
-      .then(() => {
-        ok(true, TimeStamp(token) + " Setting MediaKeys to null.");
-        playClearVideo();
-      }, () => {
-        ok(false, TimeStamp(token) + " Setting MediaKeys to null.");
-      });;
-    });
-  }
-
-  v.addEventListener("ended", onVideoEnded);
-
-  // Create a MediaKeys object and set to HTMLMediaElement then start the playback.
-  Promise.all([
-    LoadInitData(v, test, token),
-    CreateAndSetMediaKeys(v, test, token),
-    LoadTest(test, v, token)])
-  .then(values => {
-    let initData = values[0];
-    v.play();
-    initData.map(ev => {
-      let session = v.mediaKeys.createSession();
-      onSessionCreated(session);
-      MakeRequest(test, token, ev, session);
-    });
-  })
-  .then(() => {
-    return finish.promise;
-  })
-  .catch(reason => ok(false, reason))
-}
-
-function beginTest() {
-  manager.runTests(gEMETests, startTest);
-}
-
-SimpleTest.waitForExplicitFinish();
-SetupEMEPref(beginTest);
-
-</script>
-</pre>
-</body>
-</html>