Bug 1375119 - Consider a page active if it has running AudioContexts. r=ehsan
☠☠ backed out by 1165fd9f0b43 ☠ ☠
authorPaul Adenot <paul@paul.cx>
Fri, 21 Jul 2017 12:41:52 +0200
changeset 370340 cd615bff6069fe4072c67364f2dbb8266a2708c6
parent 370339 04e3649ca8fc5d0eb8bda167889e01b3c2a68c9b
child 370341 01ec9f33545a2f461a044500bddf746c81bf24f3
push id32215
push userarchaeopteryx@coole-files.de
push dateSat, 22 Jul 2017 09:39:04 +0000
treeherdermozilla-central@a599289ac64b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1375119
milestone56.0a1
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
Bug 1375119 - Consider a page active if it has running AudioContexts. r=ehsan MozReview-Commit-ID: IOQ2DY9LoTw
dom/base/nsGlobalWindow.cpp
dom/base/test/file_webaudioLoop.html
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioContext.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4420,16 +4420,21 @@ void
 nsPIDOMWindowInner::SyncStateFromParentWindow()
 {
   nsGlobalWindow::Cast(this)->SyncStateFromParentWindow();
 }
 
 bool
 nsPIDOMWindowInner::IsPlayingAudio()
 {
+  for (uint32_t i = 0; i < mAudioContexts.Length(); i++) {
+    if (mAudioContexts[i]->IsRunning()) {
+      return true;
+    }
+  }
   RefPtr<AudioChannelService> acs = AudioChannelService::Get();
   if (!acs) {
     return false;
   }
   auto outer = GetOuterWindow();
   if (!outer) {
     // We've been unlinked and are about to die.  Not a good time to pretend to
     // be playing audio.
--- a/dom/base/test/file_webaudioLoop.html
+++ b/dom/base/test/file_webaudioLoop.html
@@ -3,29 +3,22 @@
 var ac = new AudioContext();
 var runningPromise = new Promise(resolve => {
   ac.onstatechange = event => {
     if (ac.state == "running") {
       resolve();
     }
   };
 });
-fetch("audio.ogg").then(response => {
-  return response.arrayBuffer();
-}).then(ab => {
-  return ac.decodeAudioData(ab);
-}).then(ab => {
-  var src = ac.createBufferSource();
-  src.buffer = ab;
-  src.loop = true;
-  src.loopStart = 0;
-  src.loopEnd = ab.duration;
-  src.start();
-  src.connect(ac.destination);
-});
+
+var osc = ac.createOscillator();
+osc.connect(ac.destination);
+osc.start(0);
+osc.stop(ac.currentTime + 2);
+
 
 var suspendPromise;
 function suspendAC() {
   runningPromise.then(() => {
     suspendPromise = ac.suspend();
   });
 }
 
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -487,16 +487,22 @@ AudioListener*
 AudioContext::Listener()
 {
   if (!mListener) {
     mListener = new AudioListener(this);
   }
   return mListener;
 }
 
+bool
+AudioContext::IsRunning() const
+{
+  return mAudioContextState == AudioContextState::Running;
+}
+
 already_AddRefed<Promise>
 AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
                               const Optional<OwningNonNull<DecodeSuccessCallback> >& aSuccessCallback,
                               const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback,
                               ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject());
   RefPtr<Promise> promise;
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -176,16 +176,17 @@ public:
 
   bool ShouldSuspendNewStream() const { return mSuspendCalled; }
 
   double CurrentTime() const;
 
   AudioListener* Listener();
 
   AudioContextState State() const { return mAudioContextState; }
+  bool IsRunning() const;
 
   // 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