Backed out 3 changesets (bug 1513733) for frequent failures at browser_autoplay_policy_web_audio_mediaElementAudioSourceNode.js on a CLOSED TREE
authorGurzau Raul <rgurzau@mozilla.com>
Thu, 03 Jan 2019 05:19:23 +0200
changeset 509471 6a89226d8c15f0b8b9dbcb23f76f371fdefc289b
parent 509470 15af035c0cf4da68e737aee400ac96a182d5c1a1
child 509472 e38c1fa062ad9912027c5c9e4f4eeb8ac6c64da3
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1513733
milestone66.0a1
backs out5ce7c992bd81c2426c5be3c3be57e7dfa72fdd9c
7ab6eb45e6b8ca96d5bc890bfc96af96cb6e0ded
6d105dcaa3dfd622e0dbfda3d0405b69d08557c1
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 3 changesets (bug 1513733) for frequent failures at browser_autoplay_policy_web_audio_mediaElementAudioSourceNode.js on a CLOSED TREE Backed out changeset 5ce7c992bd81 (bug 1513733) Backed out changeset 7ab6eb45e6b8 (bug 1513733) Backed out changeset 6d105dcaa3df (bug 1513733)
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/webaudio/AudioBufferSourceNode.cpp
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioContext.h
dom/media/webaudio/ConstantSourceNode.cpp
dom/media/webaudio/MediaElementAudioSourceNode.cpp
dom/media/webaudio/MediaElementAudioSourceNode.h
dom/media/webaudio/MediaStreamAudioSourceNode.h
dom/media/webaudio/OscillatorNode.cpp
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_autoplay_policy_web_audio_mediaElementAudioSourceNode.js
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3184,28 +3184,16 @@ already_AddRefed<DOMMediaStream> HTMLMed
   if (!stream) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return stream.forget();
 }
 
-RefPtr<GenericNonExclusivePromise> HTMLMediaElement::GetAllowedToPlayPromise() {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mOutputStreams.IsEmpty(),
-             "This method should only be called during stream capturing!");
-  if (AutoplayPolicy::IsAllowedToPlay(*this)) {
-    AUTOPLAY_LOG("MediaElement %p has allowed to play, resolve promise", this);
-    return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
-  }
-  AUTOPLAY_LOG("create allow-to-play promise for MediaElement %p", this);
-  return mAllowedToPlayPromise.Ensure(__func__);
-}
-
 already_AddRefed<DOMMediaStream> HTMLMediaElement::MozCaptureStream(
     ErrorResult& aRv) {
   MediaStreamGraph::GraphDriverType graphDriverType =
       HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
                  : MediaStreamGraph::SYSTEM_THREAD_DRIVER;
 
   nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
   if (!window) {
@@ -3491,18 +3479,16 @@ HTMLMediaElement::~HTMLMediaElement() {
 
   if (mVideoFrameContainer) {
     mVideoFrameContainer->ForgetElement();
   }
   UnregisterActivityObserver();
 
   mSetCDMRequest.DisconnectIfExists();
   mAutoplayPermissionRequest.DisconnectIfExists();
-  mAllowedToPlayPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
-
   if (mDecoder) {
     ShutdownDecoder();
   }
   if (mProgressTimer) {
     StopProgress();
   }
   if (mVideoDecodeSuspendTimer) {
     mVideoDecodeSuspendTimer->Cancel();
@@ -3642,17 +3628,16 @@ already_AddRefed<Promise> HTMLMediaEleme
     DispatchEventsWhenPlayWasNotAllowed();
     return promise.forget();
   }
 
   UpdateHadAudibleAutoplayState();
 
   const bool handlingUserInput = EventStateManager::IsHandlingUserInput();
   if (AutoplayPolicy::IsAllowedToPlay(*this)) {
-    mAllowedToPlayPromise.ResolveIfExists(true, __func__);
     mPendingPlayPromises.AppendElement(promise);
     PlayInternal(handlingUserInput);
     UpdateCustomPolicyAfterPlayed();
   } else {
     // Prompt the user for permission to play.
     mPendingPlayPromises.AppendElement(promise);
     EnsureAutoplayRequested(handlingUserInput);
   }
@@ -5611,17 +5596,16 @@ void HTMLMediaElement::CheckAutoplayData
   }
 
   UpdateHadAudibleAutoplayState();
   if (!AutoplayPolicy::IsAllowedToPlay(*this)) {
     EnsureAutoplayRequested(false);
     return;
   }
 
-  mAllowedToPlayPromise.ResolveIfExists(true, __func__);
   mPaused = false;
   // We changed mPaused which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
   UpdateSrcMediaStreamPlaying();
   UpdateAudioChannelPlayingState();
 
   if (mDecoder) {
     SetPlayedOrSeeked(true);
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -718,21 +718,16 @@ class HTMLMediaElement : public nsGeneri
                                       ErrorResult& aRv);
   // Get the sink id of the device that audio is being played. Initial value is
   // empty and the default device is being used.
   void GetSinkId(nsString& aSinkId) {
     MOZ_ASSERT(NS_IsMainThread());
     aSinkId = mSink.first();
   }
 
-  // This is used to notify MediaElementAudioSourceNode that media element is
-  // allowed to play when media element is used as a source for web audio, so
-  // that we can start AudioContext if it was not allowed to start.
-  RefPtr<GenericNonExclusivePromise> GetAllowedToPlayPromise();
-
  protected:
   virtual ~HTMLMediaElement();
 
   class AudioChannelAgentCallback;
   class ChannelLoader;
   class ErrorSink;
   class MediaLoadListener;
   class MediaStreamTrackListener;
@@ -1658,21 +1653,16 @@ class HTMLMediaElement : public nsGeneri
   // Note this flag is false when the element is in a phase after creation and
   // before attaching to the DOM tree.
   bool mUnboundFromTree = false;
 
   // True if the autoplay media was blocked because it hadn't loaded metadata
   // yet.
   bool mBlockedAsWithoutMetadata = false;
 
-  // This promise is used to notify MediaElementAudioSourceNode that media
-  // element is allowed to play when MediaElement is used as a source for web
-  // audio.
-  MozPromiseHolder<GenericNonExclusivePromise> mAllowedToPlayPromise;
-
  public:
   // Helper class to measure times for MSE telemetry stats
   class TimeDurationAccumulator {
    public:
     TimeDurationAccumulator() : mCount(0) {}
     void Start() {
       if (IsStarted()) {
         return;
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -700,17 +700,17 @@ void AudioBufferSourceNode::Start(double
     SendOffsetAndDurationParametersToStream(ns);
   }
 
   // Don't set parameter unnecessarily
   if (aWhen > 0.0) {
     ns->SetDoubleParameter(START, aWhen);
   }
 
-  Context()->StartBlockedAudioContextIfAllowed();
+  Context()->NotifyScheduledSourceNodeStarted();
 }
 
 void AudioBufferSourceNode::Start(double aWhen, ErrorResult& aRv) {
   Start(aWhen, 0 /* offset */, Optional<double>(), aRv);
 }
 
 void AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx) {
   AudioNodeStream* ns = mStream;
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -175,17 +175,17 @@ AudioContext::AudioContext(nsPIDOMWindow
     mWasAllowedToStart = false;
     SuspendInternal(nullptr);
     DispatchBlockedEvent();
   }
 
   FFTBlock::MainThreadInit();
 }
 
-void AudioContext::StartBlockedAudioContextIfAllowed() {
+void AudioContext::NotifyScheduledSourceNodeStarted() {
   MOZ_ASSERT(NS_IsMainThread());
   // Only try to start AudioContext when AudioContext was not allowed to start.
   if (mWasAllowedToStart) {
     return;
   }
 
   const bool isAllowedToPlay = AutoplayPolicy::IsAllowedToPlay(*this);
   AUTOPLAY_LOG("Trying to start AudioContext %p, IsAllowedToPlay=%d", this,
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -178,19 +178,19 @@ class AudioContext final : public DOMEve
   AudioListener* Listener();
 
   AudioContextState State() const { return mAudioContextState; }
 
   Worklet* GetAudioWorklet(ErrorResult& aRv);
 
   bool IsRunning() const;
 
-  // Called when an AudioScheduledSourceNode started or the source node starts,
-  // this method might resume the AudioContext if it was not allowed to start.
-  void StartBlockedAudioContextIfAllowed();
+  // Called when an AudioScheduledSourceNode started, this method might resume
+  // the AudioContext if it was not allowed to start.
+  void NotifyScheduledSourceNodeStarted();
 
   // Those three methods return a promise to content, that is resolved when an
   // (possibly long) operation is completed on the MSG (and possibly other)
   // thread(s). To avoid having to match the calls and asychronous result when
   // the operation is completed, we keep a reference to the promises on the main
   // thread, and then send the promises pointers down the MSG thread, as a void*
   // (to make it very clear that the pointer is to merely be treated as an ID).
   // When back on the main thread, we can resolve or reject the promise, by
--- a/dom/media/webaudio/ConstantSourceNode.cpp
+++ b/dom/media/webaudio/ConstantSourceNode.cpp
@@ -219,17 +219,17 @@ void ConstantSourceNode::Start(double aW
   if (!mStream) {
     return;
   }
 
   mStream->SetStreamTimeParameter(ConstantSourceNodeEngine::START, Context(),
                                   aWhen);
 
   MarkActive();
-  Context()->StartBlockedAudioContextIfAllowed();
+  Context()->NotifyScheduledSourceNodeStarted();
 }
 
 void ConstantSourceNode::Stop(double aWhen, ErrorResult& aRv) {
   if (!WebAudioUtils::IsTimeValid(aWhen)) {
     aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>(NS_LITERAL_STRING("stop time"));
     return;
   }
 
--- a/dom/media/webaudio/MediaElementAudioSourceNode.cpp
+++ b/dom/media/webaudio/MediaElementAudioSourceNode.cpp
@@ -38,40 +38,18 @@ MediaElementAudioSourceNode::Create(
     return nullptr;
   }
 
   node->Init(stream, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  node->ListenForAllowedToPlay(aOptions);
   return node.forget();
 }
 
 JSObject* MediaElementAudioSourceNode::WrapObject(
     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
   return MediaElementAudioSourceNode_Binding::Wrap(aCx, this, aGivenProto);
 }
 
-void MediaElementAudioSourceNode::ListenForAllowedToPlay(
-    const MediaElementAudioSourceOptions& aOptions) {
-  aOptions.mMediaElement->GetAllowedToPlayPromise()
-      ->Then(
-          AbstractMainThread(), __func__,
-          // Capture by reference to bypass the mozilla-refcounted-inside-lambda
-          // static analysis. We capture a non-owning reference so as to allow
-          // cycle collection of the node. The reference is cleared via
-          // DisconnectIfExists() from Destroy() when the node is collected.
-          [& self = *this]() {
-            self.Context()->StartBlockedAudioContextIfAllowed();
-            self.mAllowedToPlayRequest.Complete();
-          })
-      ->Track(mAllowedToPlayRequest);
-}
-
-void MediaElementAudioSourceNode::Destroy() {
-  mAllowedToPlayRequest.DisconnectIfExists();
-  MediaStreamAudioSourceNode::Destroy();
-}
-
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/media/webaudio/MediaElementAudioSourceNode.h
+++ b/dom/media/webaudio/MediaElementAudioSourceNode.h
@@ -39,22 +39,14 @@ class MediaElementAudioSourceNode final 
   }
 
   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 
  private:
   explicit MediaElementAudioSourceNode(AudioContext* aContext);
-
-  void Destroy() override;
-
-  // If AudioContext was not allowed to start, we would try to start it when
-  // source starts.
-  void ListenForAllowedToPlay(const MediaElementAudioSourceOptions& aOptions);
-
-  MozPromiseRequestHolder<GenericNonExclusivePromise> mAllowedToPlayRequest;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif
--- a/dom/media/webaudio/MediaStreamAudioSourceNode.h
+++ b/dom/media/webaudio/MediaStreamAudioSourceNode.h
@@ -88,17 +88,17 @@ class MediaStreamAudioSourceNode
   void NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack) override;
 
   // From PrincipalChangeObserver<MediaStreamTrack>.
   void PrincipalChanged(MediaStreamTrack* aMediaStreamTrack) override;
 
  protected:
   explicit MediaStreamAudioSourceNode(AudioContext* aContext);
   void Init(DOMMediaStream* aMediaStream, ErrorResult& aRv);
-  virtual void Destroy();
+  void Destroy();
   virtual ~MediaStreamAudioSourceNode();
 
  private:
   RefPtr<MediaInputPort> mInputPort;
   RefPtr<DOMMediaStream> mInputStream;
 
   // On construction we set this to the first audio track of mInputStream.
   RefPtr<MediaStreamTrack> mInputTrack;
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -483,17 +483,17 @@ void OscillatorNode::Start(double aWhen,
     return;
   }
 
   // TODO: Perhaps we need to do more here.
   mStream->SetStreamTimeParameter(OscillatorNodeEngine::START, Context(),
                                   aWhen);
 
   MarkActive();
-  Context()->StartBlockedAudioContextIfAllowed();
+  Context()->NotifyScheduledSourceNodeStarted();
 }
 
 void OscillatorNode::Stop(double aWhen, ErrorResult& aRv) {
   if (!WebAudioUtils::IsTimeValid(aWhen)) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -50,20 +50,16 @@ support-files =
 [browser_autoplay_policy_user_gestures.js]
 support-files =
   gizmo.mp4
   file_video.html
 [browser_autoplay_policy_touchScroll.js]
 [browser_autoplay_policy_web_audio.js]
 support-files =
   file_empty.html
-[browser_autoplay_policy_web_audio_mediaElementAudioSourceNode.js]
-support-files =
-  file_video.html
-  gizmo.mp4
 [browser_autoplay_policy_webRTC_permission.js]
 support-files =
   file_empty.html
   gizmo.mp4
 [browser_autoplay_videoDocument.js]
 [browser_autoscroll_disabled.js]
 skip-if = true # Bug 1312652
 [browser_block_autoplay_media.js]
deleted file mode 100644
--- a/toolkit/content/tests/browser/browser_autoplay_policy_web_audio_mediaElementAudioSourceNode.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * This test is used to ensure blocked AudioContext would be resumed when the
- * source media element of MediaElementAudioSouceNode which has been created and
- * connected to destinationnode has started.
- */
-"use strict";
-
-const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_video.html";
-
-function setup_test_preference() {
-  return SpecialPowers.pushPrefEnv({"set": [
-    ["media.autoplay.default", SpecialPowers.Ci.nsIAutoplay.BLOCKED],
-    ["media.autoplay.enabled.user-gestures-needed", true],
-    ["media.autoplay.block-webaudio", true],
-    ["media.autoplay.block-event.enabled", true],
-  ]});
-}
-
-function createAudioContext() {
-  content.ac = new content.AudioContext();
-  const ac = content.ac;
-
-  ac.allowedToStart = new Promise(resolve => {
-    ac.addEventListener("statechange", function() {
-      if (ac.state === "running") {
-        resolve();
-      }
-    }, {once: true});
-  });
-
-  ac.notAllowedToStart = new Promise(resolve => {
-    ac.addEventListener("blocked", function() {
-      resolve();
-    }, {once: true});
-  });
-}
-
-async function checkIfAudioContextIsAllowedToStart(isAllowedToStart) {
-  const ac = content.ac;
-  if (isAllowedToStart) {
-    await ac.allowedToStart;
-    ok(ac.state === "running", `AudioContext is running.`);
-  } else {
-    await ac.notAllowedToStart;
-    ok(ac.state === "suspended", `AudioContext is not started yet.`);
-  }
-}
-
-async function createMediaElementSourceNode() {
-  const ac = content.ac;
-  const video = content.document.getElementById("v");
-  if (!video) {
-    ok(false, `can not get video element`);
-  }
-  let source = ac.createMediaElementSource(video);
-  source.connect(ac.destination);
-}
-
-async function playVideo() {
-  const video = content.document.getElementById("v");
-  if (!video) {
-    ok(false, `can not get video element`);
-  }
-  // simulate user gesture in order to start video.
-  content.document.notifyUserGestureActivation();
-  ok(await video.play().then(() => true, () => false), `video started playing`);
-}
-
-async function testResumeAudioContextWhenMediaElementSourceStarted() {
-  const tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser, PAGE);
-  const browser = tab.linkedBrowser;
-
-  info(`- create audio context -`);
-  loadFrameScript(browser, createAudioContext);
-
-  info(`- check AudioContext status -`);
-  let isAllowedToStart = false;
-  await ContentTask.spawn(browser, isAllowedToStart,
-                          checkIfAudioContextIsAllowedToStart);
-
-  info(`- create and start MediaElementAudioSourceNode -`);
-  await ContentTask.spawn(browser, null, createMediaElementSourceNode);
-  await ContentTask.spawn(browser, null, playVideo);
-
-  info(`- AudioContext should be resumed after MediaElementAudioSourceNode started -`);
-  isAllowedToStart = true;
-  await ContentTask.spawn(browser, isAllowedToStart,
-                          checkIfAudioContextIsAllowedToStart);
-
-  info(`- remove tab -`);
-  await BrowserTestUtils.removeTab(tab);
-}
-
-add_task(async function start_tests() {
-  info(`- setup test preference -`);
-  await setup_test_preference();
-
-  info(`- start 'testResumeAudioContextWhenMediaElementSourceStarted' -`);
-  await testResumeAudioContextWhenMediaElementSourceStarted();
-});