Bug 1228564 - part 2 : check audio capturing when the agent is registered/unregistered. draft
authorAlastor Wu <alwu@mozilla.com>
Tue, 22 Dec 2015 17:04:39 +0800
changeset 316840 1cec720e8faa50e7e11834b76affa0e7b19590ff
parent 316838 7316d8968abadc2ba6f7e51b3dd7db290e2b1b30
child 512233 c57e94e2e2d2dfec41bdf45730dcb107c243c92b
push id8627
push useralwu@mozilla.com
push dateTue, 22 Dec 2015 09:10:29 +0000
bugs1228564
milestone45.0a1
Bug 1228564 - part 2 : check audio capturing when the agent is registered/unregistered.
dom/audiochannel/AudioChannelAgent.cpp
dom/audiochannel/AudioChannelAgent.h
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
dom/audiochannel/nsIAudioChannelAgent.idl
dom/base/nsGlobalWindow.cpp
dom/fmradio/FMRadio.cpp
dom/html/HTMLMediaElement.cpp
dom/media/webaudio/AudioDestinationNode.cpp
dom/media/webspeech/synth/nsSpeechTask.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/telephony/Telephony.cpp
--- a/dom/audiochannel/AudioChannelAgent.cpp
+++ b/dom/audiochannel/AudioChannelAgent.cpp
@@ -222,22 +222,33 @@ AudioChannelAgent::WindowVolumeChanged()
 }
 
 uint64_t
 AudioChannelAgent::WindowID() const
 {
   return mWindow ? mWindow->WindowID() : 0;
 }
 
+uint64_t
+AudioChannelAgent::InnerWindowID() const
+{
+  return mInnerWindowID;
+}
+
 void
-AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID)
+AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID,
+                                             bool aCapture)
 {
   if (aInnerWindowID != mInnerWindowID) {
     return;
   }
 
   nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
   if (!callback) {
     return;
   }
 
-  callback->WindowAudioCaptureChanged();
+  MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
+         ("AudioChannelAgent, WindowAudioCaptureChanged, this = %p, "
+          "capture = %d\n", this, aCapture));
+
+  callback->WindowAudioCaptureChanged(aCapture);
 }
--- a/dom/audiochannel/AudioChannelAgent.h
+++ b/dom/audiochannel/AudioChannelAgent.h
@@ -29,24 +29,25 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIAUDIOCHANNELAGENT
 
   NS_DECL_CYCLE_COLLECTION_CLASS(AudioChannelAgent)
 
   AudioChannelAgent();
 
   void WindowVolumeChanged();
-  void WindowAudioCaptureChanged(uint64_t aInnerWindowID);
+  void WindowAudioCaptureChanged(uint64_t aInnerWindowID, bool aCapture);
 
   nsPIDOMWindow* Window() const
   {
     return mWindow;
   }
 
   uint64_t WindowID() const;
+  uint64_t InnerWindowID() const;
 
 private:
   virtual ~AudioChannelAgent();
 
   // Returns mCallback if that's non-null, or otherwise tries to get an
   // nsIAudioChannelAgentCallback out of mWeakCallback.
   already_AddRefed<nsIAudioChannelAgentCallback> GetCallback();
 
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -287,16 +287,23 @@ AudioChannelService::RegisterAudioChanne
 
   // If this is the first agent for this window, we must notify the observers.
   if (winData->mAgents.Length() == 1) {
     RefPtr<MediaPlaybackRunnable> runnable =
       new MediaPlaybackRunnable(aAgent->Window(), true /* active */);
     NS_DispatchToCurrentThread(runnable);
   }
 
+  // If the window has already been captured, the agent of that window should
+  // also be captured.
+  if (winData->mIsAudioCaptured) {
+    aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(),
+                                      winData->mIsAudioCaptured);
+  }
+
   MaybeSendStatusUpdate();
 }
 
 void
 AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
 {
   AudioChannelWindow* winData = GetWindowData(aAgent->WindowID());
   if (!winData) {
@@ -329,16 +336,21 @@ AudioChannelService::UnregisterAudioChan
 
   // If this is the last agent for this window, we must notify the observers.
   if (winData->mAgents.IsEmpty()) {
     RefPtr<MediaPlaybackRunnable> runnable =
       new MediaPlaybackRunnable(aAgent->Window(), false /* active */);
     NS_DispatchToCurrentThread(runnable);
   }
 
+  // No need to capture non-audible object.
+  if (winData->mIsAudioCaptured) {
+    aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(), false);
+  }
+
   MaybeSendStatusUpdate();
 }
 
 void
 AudioChannelService::GetState(nsPIDOMWindow* aWindow, uint32_t aAudioChannel,
                               float* aVolume, bool* aMuted)
 {
   MOZ_ASSERT(!aWindow || aWindow->IsOuterWindow());
@@ -575,42 +587,51 @@ AudioChannelService::RefreshAgentsVolume
   nsTObserverArray<AudioChannelAgent*>::ForwardIterator
     iter(winData->mAgents);
   while (iter.HasMore()) {
     iter.GetNext()->WindowVolumeChanged();
   }
 }
 
 void
-AudioChannelService::RefreshAgentsCapture(nsPIDOMWindow* aWindow,
-                                          uint64_t aInnerWindowID)
+AudioChannelService::SetWindowAudioCaptured(nsPIDOMWindow* aWindow,
+                                            uint64_t aInnerWindowID,
+                                            bool aCapture)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsOuterWindow());
 
+  MOZ_LOG(GetAudioChannelLog(), LogLevel::Debug,
+         ("AudioChannelService, SetWindowAudioCaptured, window = %p, "
+          "aCapture = %d\n", aWindow, aCapture));
+
   nsCOMPtr<nsPIDOMWindow> topWindow = aWindow->GetScriptableTop();
   if (!topWindow) {
     return;
   }
 
   AudioChannelWindow* winData = GetWindowData(topWindow->WindowID());
 
   // This can happen, but only during shutdown, because the the outer window
   // changes ScriptableTop, so that its ID is different.
   // In this case either we are capturing, and it's too late because the window
   // has been closed anyways, or we are un-capturing, and everything has already
   // been cleaned up by the HTMLMediaElements or the AudioContexts.
   if (!winData) {
     return;
   }
 
-  nsTObserverArray<AudioChannelAgent*>::ForwardIterator
-    iter(winData->mAgents);
-  while (iter.HasMore()) {
-    iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID);
+  if (aCapture != winData->mIsAudioCaptured) {
+    winData->mIsAudioCaptured = aCapture;
+    nsTObserverArray<AudioChannelAgent*>::ForwardIterator
+      iter(winData->mAgents);
+    while (iter.HasMore()) {
+      iter.GetNext()->WindowAudioCaptureChanged(aInnerWindowID, aCapture);
+    }
   }
 }
 
 /* static */ const nsAttrValue::EnumTable*
 AudioChannelService::GetAudioChannelTable()
 {
   return kMozAudioChannelAttributeTable;
 }
@@ -738,17 +759,17 @@ AudioChannelService::SetAudioChannelVolu
                                            float aVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsOuterWindow());
 
   MOZ_LOG(GetAudioChannelLog(), LogLevel::Debug,
          ("AudioChannelService, SetAudioChannelVolume, window = %p, type = %d, "
-          "volume = %d\n", aWindow, aAudioChannel, aVolume));
+          "volume = %f\n", aWindow, aAudioChannel, aVolume));
 
   AudioChannelWindow* winData = GetOrCreateWindowData(aWindow);
   winData->mChannels[(uint32_t)aAudioChannel].mVolume = aVolume;
   RefreshAgentsVolume(aWindow);
 }
 
 NS_IMETHODIMP
 AudioChannelService::SetAudioChannelVolume(nsIDOMWindow* aWindow,
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -105,19 +105,19 @@ public:
   bool AnyAudioChannelIsActive();
 
   void RefreshAgentsVolume(nsPIDOMWindow* aWindow);
 
   // This method needs to know the inner window that wants to capture audio. We
   // group agents per top outer window, but we can have multiple innerWindow per
   // top outerWindow (subiframes, etc.) and we have to identify all the agents
   // just for a particular innerWindow.
-  void RefreshAgentsCapture(nsPIDOMWindow* aWindow,
-                            uint64_t aInnerWindowID);
-
+  void SetWindowAudioCaptured(nsPIDOMWindow* aWindow,
+                              uint64_t aInnerWindowID,
+                              bool aCapture);
 
 #ifdef MOZ_WIDGET_GONK
   void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
   {
     if (!mSpeakerManager.Contains(aSpeakerManager)) {
       mSpeakerManager.AppendElement(aSpeakerManager);
     }
   }
@@ -170,23 +170,25 @@ private:
     bool mMuted;
 
     uint32_t mNumberOfAgents;
   };
 
   struct AudioChannelWindow final
   {
     explicit AudioChannelWindow(uint64_t aWindowID)
-      : mWindowID(aWindowID)
+      : mWindowID(aWindowID),
+        mIsAudioCaptured(false)
     {
       // Workaround for bug1183033, system channel type can always playback.
       mChannels[(int16_t)AudioChannel::System].mMuted = false;
     }
 
     uint64_t mWindowID;
+    bool mIsAudioCaptured;
     AudioChannelConfig mChannels[NUMBER_OF_AUDIO_CHANNELS];
 
     // Raw pointer because the AudioChannelAgent must unregister itself.
     nsTObserverArray<AudioChannelAgent*> mAgents;
   };
 
   AudioChannelWindow*
   GetOrCreateWindowData(nsPIDOMWindow* aWindow);
--- a/dom/audiochannel/nsIAudioChannelAgent.idl
+++ b/dom/audiochannel/nsIAudioChannelAgent.idl
@@ -1,28 +1,28 @@
 /* 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 "nsISupports.idl"
 
 interface nsIDOMWindow;
 
-[uuid(5fe83b24-38b9-4901-a4a1-d1bd57d3fe18)]
+[uuid(0a451ee0-972e-11e5-a837-0800200c9a66)]
 interface nsIAudioChannelAgentCallback : nsISupports
 {
   /**
    * Notified when the window volume/mute is changed
    */
   void windowVolumeChanged(in float aVolume, in bool aMuted);
 
   /**
    * Notified when the capture state is changed.
    */
-  void windowAudioCaptureChanged();
+  void windowAudioCaptureChanged(in bool aCapture);
 };
 
 /**
  * This interface provides an agent for gecko components to participate
  * in the audio channel service. Gecko components are responsible for
  *   1. Indicating what channel type they are using (via the init() member
  *      function).
  *   2. Before playing, checking the playable status of the channel.
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1224,17 +1224,17 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 
   if (gRefCnt == 1) {
     Preferences::AddIntVarCache(&gMinTimeoutValue,
                                 "dom.min_timeout_value",
                                 DEFAULT_MIN_TIMEOUT_VALUE);
     Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue,
                                 "dom.min_background_timeout_value",
                                 DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
-    Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled, 
+    Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled,
                                  "dom.idle-observers-api.fuzz_time.disabled",
                                  false);
   }
 
   if (gDumpFile == nullptr) {
     const nsAdoptingCString& fname =
       Preferences::GetCString("browser.dom.window.dump.file");
     if (!fname.IsEmpty()) {
@@ -2067,17 +2067,17 @@ nsGlobalWindow::WouldReuseInnerWindow(ns
 
   if (!mDoc || !aNewDocument) {
     return false;
   }
 
   if (!mDoc->IsInitialDocument()) {
     return false;
   }
-  
+
   NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
                "How'd this happen?");
 
   // Great, we're the original document, check for one of the other
   // conditions.
 
   if (mDoc == aNewDocument) {
     return true;
@@ -3739,17 +3739,17 @@ nsresult
 nsPIDOMWindow::SetAudioCapture(bool aCapture)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   mAudioCaptured = aCapture;
 
   RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
   if (service) {
-    service->RefreshAgentsCapture(GetOuterWindow(), mWindowID);
+    service->SetWindowAudioCaptured(GetOuterWindow(), mWindowID, aCapture);
   }
 
   return NS_OK;
 }
 
 // nsISpeechSynthesisGetter
 
 #ifdef MOZ_WEBSPEECH
@@ -4357,17 +4357,17 @@ nsGlobalWindow::GetControllersOuter(Erro
 
     // Add in the default controller
     nsCOMPtr<nsIController> controller = do_CreateInstance(
                                NS_WINDOWCONTROLLER_CONTRACTID, &rv);
     if (NS_FAILED(rv)) {
       aError.Throw(rv);
       return nullptr;
     }
-    
+
     mControllers->InsertControllerAt(0, controller);
     nsCOMPtr<nsIControllerContext> controllerContext = do_QueryInterface(controller);
     if (!controllerContext) {
       aError.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));
@@ -4968,17 +4968,17 @@ nsGlobalWindow::SetOuterSize(int32_t aLe
   }
 
   int32_t lengthDevPixels = CSSToDevIntPixels(aLengthCSSPixels);
   if (aIsWidth) {
     width = lengthDevPixels;
   } else {
     height = lengthDevPixels;
   }
-  aError = treeOwnerAsWin->SetSize(width, height, true);    
+  aError = treeOwnerAsWin->SetSize(width, height, true);
 }
 
 void
 nsGlobalWindow::SetOuterWidthOuter(int32_t aOuterWidth, ErrorResult& aError, bool aCallerIsChrome)
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   SetOuterSize(aOuterWidth, true, aError, aCallerIsChrome);
@@ -6413,18 +6413,18 @@ nsGlobalWindow::AlertOrConfirm(bool aAle
 
   // Before bringing up the window, unsuppress painting and flush
   // pending reflows.
   EnsureReflowFlushAndPaint();
 
   nsAutoString title;
   MakeScriptDialogTitle(title);
 
-  // Remove non-terminating null characters from the 
-  // string. See bug #310037. 
+  // Remove non-terminating null characters from the
+  // string. See bug #310037.
   nsAutoString final;
   nsContentUtils::StripNullChars(aMessage, final);
 
   nsresult rv;
   nsCOMPtr<nsIPromptFactory> promptFac =
     do_GetService("@mozilla.org/prompter;1", &rv);
   if (NS_FAILED(rv)) {
     aError.Throw(rv);
@@ -6530,19 +6530,19 @@ nsGlobalWindow::PromptOuter(const nsAStr
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
   // Before bringing up the window, unsuppress painting and flush
   // pending reflows.
   EnsureReflowFlushAndPaint();
 
   nsAutoString title;
   MakeScriptDialogTitle(title);
-  
-  // Remove non-terminating null characters from the 
-  // string. See bug #310037. 
+
+  // Remove non-terminating null characters from the
+  // string. See bug #310037.
   nsAutoString fixedMessage, fixedInitial;
   nsContentUtils::StripNullChars(aMessage, fixedMessage);
   nsContentUtils::StripNullChars(aInitial, fixedInitial);
 
   nsresult rv;
   nsCOMPtr<nsIPromptFactory> promptFac =
     do_GetService("@mozilla.org/prompter;1", &rv);
   if (NS_FAILED(rv)) {
@@ -6899,21 +6899,21 @@ nsGlobalWindow::PrintOuter(ErrorResult& 
   if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
     aError.Throw(NS_ERROR_NOT_AVAILABLE);
     return;
   }
 
   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
   if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
                                 getter_AddRefs(webBrowserPrint)))) {
-    nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
+    nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ?
                                GetCurrentInnerWindowInternal()->mDoc :
                                nullptr);
 
-    nsCOMPtr<nsIPrintSettingsService> printSettingsService = 
+    nsCOMPtr<nsIPrintSettingsService> printSettingsService =
       do_GetService("@mozilla.org/gfx/printsettings-service;1");
 
     nsCOMPtr<nsIPrintSettings> printSettings;
     if (printSettingsService) {
       bool printSettingsAreGlobal =
         Preferences::GetBool("print.use_global_printsettings", false);
 
       if (printSettingsAreGlobal) {
@@ -6921,18 +6921,18 @@ nsGlobalWindow::PrintOuter(ErrorResult& 
 
         nsXPIDLString printerName;
         printSettings->GetPrinterName(getter_Copies(printerName));
         if (printerName.IsEmpty()) {
           printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));
           printSettings->SetPrinterName(printerName);
         }
         printSettingsService->InitPrintSettingsFromPrinter(printerName, printSettings);
-        printSettingsService->InitPrintSettingsFromPrefs(printSettings, 
-                                                         true, 
+        printSettingsService->InitPrintSettingsFromPrefs(printSettings,
+                                                         true,
                                                          nsIPrintSettings::kInitSaveAll);
       } else {
         printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));
       }
 
       EnterModalState();
       webBrowserPrint->Print(printSettings, nullptr);
       LeaveModalState();
@@ -7027,17 +7027,17 @@ nsGlobalWindow::MoveByOuter(int32_t aXDi
     return;
   }
 
   // mild abuse of a "size" object so we don't need more helper functions
   nsIntSize cssPos(DevToCSSIntPixels(nsIntSize(x, y)));
 
   cssPos.width += aXDif;
   cssPos.height += aYDif;
-  
+
   CheckSecurityLeftAndTop(&cssPos.width, &cssPos.height, aCallerIsChrome);
 
   nsIntSize newDevPos(CSSToDevIntPixels(cssPos));
 
   aError = treeOwnerAsWin->SetPosition(newDevPos.width, newDevPos.height);
 }
 
 void
@@ -7084,17 +7084,17 @@ nsGlobalWindow::ResizeToOuter(int32_t aW
     return;
   }
 
   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = GetTreeOwnerWindow();
   if (!treeOwnerAsWin) {
     aError.Throw(NS_ERROR_FAILURE);
     return;
   }
-  
+
   nsIntSize cssSize(aWidth, aHeight);
   CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerIsChrome);
 
   nsIntSize devSz(CSSToDevIntPixels(cssSize));
 
   aError = treeOwnerAsWin->SetSize(devSz.width, devSz.height, true);
 }
 
@@ -7557,17 +7557,17 @@ nsGlobalWindow::PopupWhitelisted()
  * Returns a value from the PopupControlState enum.
  */
 PopupControlState
 nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
 {
   MOZ_ASSERT(IsOuterWindow());
 
   NS_ASSERTION(mDocShell, "Must have docshell");
-  
+
   if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) {
     return openAllowed;
   }
 
   PopupControlState abuse = aControl;
   switch (abuse) {
   case openControlled:
   case openAbused:
@@ -9042,17 +9042,17 @@ nsGlobalWindow::FindOuter(const nsAStrin
   // as the search root, but uses focus to set the current search
   // frame. If we're being called from JS (as here), this window
   // should be the current search frame.
   nsCOMPtr<nsIWebBrowserFindInFrames> framesFinder(do_QueryInterface(finder));
   if (framesFinder) {
     framesFinder->SetRootSearchFrame(this);   // paranoia
     framesFinder->SetCurrentSearchFrame(this);
   }
-  
+
   // The Find API does not accept empty strings. Launch the Find Dialog.
   if (aString.IsEmpty() || aShowDialog) {
     // See if the find dialog is already up using nsIWindowMediator
     nsCOMPtr<nsIWindowMediator> windowMediator =
       do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
 
     nsCOMPtr<nsIDOMWindow> findDialog;
 
@@ -9629,17 +9629,17 @@ nsGlobalWindow::GetKeyboardIndicators(bo
 bool
 nsGlobalWindow::TakeFocus(bool aFocus, uint32_t aFocusMethod)
 {
   FORWARD_TO_INNER(TakeFocus, (aFocus, aFocusMethod), false);
 
   if (mCleanedUp) {
     return false;
   }
-  
+
   if (aFocus)
     mFocusMethod = aFocusMethod & FOCUSMETHOD_MASK;
 
   if (mHasFocus != aFocus) {
     mHasFocus = aFocus;
     UpdateCanvasFocus(true, mFocusedNode);
   }
 
@@ -12174,17 +12174,17 @@ nsresult nsGlobalWindow::ResetTimersForN
       NS_ASSERTION(firingTime < timeout->mWhen,
                    "Our firing time should strictly decrease!");
 
       TimeDuration delay = firingTime - now;
       timeout->mWhen = firingTime;
 
       // Since we reset mWhen we need to move |timeout| to the right
       // place in the list so that it remains sorted by mWhen.
-      
+
       // Get the pointer to the next timeout now, before we move the
       // current timeout in the list.
       nsTimeout* nextTimeout = timeout->getNext();
 
       // It is safe to remove and re-insert because mWhen is now
       // strictly smaller than it used to be, so we know we'll insert
       // |timeout| before nextTimeout.
       NS_ASSERTION(!nextTimeout ||
@@ -12534,22 +12534,22 @@ nsGlobalWindow::SuspendTimeouts(uint32_t
 
     TimeStamp now = TimeStamp::Now();
     for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
       // Set mTimeRemaining to be the time remaining for this timer.
       if (t->mWhen > now)
         t->mTimeRemaining = t->mWhen - now;
       else
         t->mTimeRemaining = TimeDuration(0);
-  
+
       // Drop the XPCOM timer; we'll reschedule when restoring the state.
       if (t->mTimer) {
         t->mTimer->Cancel();
         t->mTimer = nullptr;
-  
+
         // Drop the reference that the timer's closure had on this timeout, we'll
         // add it back in ResumeTimeouts. Note that it shouldn't matter that we're
         // passing null for the context, since this shouldn't actually release this
         // timeout.
         t->Release();
       }
     }
 
--- a/dom/fmradio/FMRadio.cpp
+++ b/dom/fmradio/FMRadio.cpp
@@ -464,17 +464,17 @@ NS_IMETHODIMP
 FMRadio::WindowVolumeChanged(float aVolume, bool aMuted)
 {
   IFMRadioService::Singleton()->EnableAudio(!aMuted);
   // TODO: what about the volume?
   return NS_OK;
 }
 
 NS_IMETHODIMP
-FMRadio::WindowAudioCaptureChanged()
+FMRadio::WindowAudioCaptureChanged(bool aCapture)
 {
   return NS_OK;
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4735,16 +4735,21 @@ HTMLMediaElement::MaybeCreateAudioChanne
                                              this);
   }
   return true;
 }
 
 bool
 HTMLMediaElement::IsPlayingThroughTheAudioChannel() const
 {
+  // If this element doesn't have any audio tracks.
+  if (!HasAudio()) {
+    return false;
+  }
+
   // Are we paused or muted
   if (mPaused || Muted()) {
     return false;
   }
 
   // The volume should not be ~0
   if (std::fabs(Volume()) <= 1e-7) {
     return false;
@@ -4795,25 +4800,16 @@ HTMLMediaElement::UpdateAudioChannelPlay
       NotifyAudioChannelAgent(mPlayingThroughTheAudioChannel);
     }
   }
 }
 
 void
 HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying)
 {
-  // Don't do anything if this element doesn't have any audio tracks.
-  if (!HasAudio()) {
-    return;
-  }
-
-  // Immediately check if this should go to the MSG instead of the normal
-  // media playback route.
-  WindowAudioCaptureChanged();
-
   // This is needed to pass nsContentUtils::IsCallerChrome().
   // AudioChannel API should not called from content but it can happen that
   // this method has some content JS in its stack.
   AutoNoJSAPI nojsapi;
 
   if (aPlaying) {
     float volume = 0.0;
     bool muted = true;
@@ -4974,27 +4970,27 @@ HTMLMediaElement::GetTopLevelPrincipal()
   if (!doc) {
     return nullptr;
   }
   principal = doc->NodePrincipal();
   return principal.forget();
 }
 #endif // MOZ_EME
 
-NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
+NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged(bool aCapture)
 {
   MOZ_ASSERT(mAudioChannelAgent);
+  MOZ_ASSERT(HasAudio());
 
   if (!OwnerDoc()->GetInnerWindow()) {
     return NS_OK;
   }
-  bool captured = OwnerDoc()->GetInnerWindow()->GetAudioCaptured();
-
-  if (captured != mAudioCapturedByWindow) {
-    if (captured) {
+
+  if (aCapture != mAudioCapturedByWindow) {
+    if (aCapture) {
       mAudioCapturedByWindow = true;
       nsCOMPtr<nsPIDOMWindow> window =
         do_QueryInterface(OwnerDoc()->GetParentObject());
       uint64_t id = window->WindowID();
       MediaStreamGraph* msg =
         MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
                                       mAudioChannel);
 
@@ -5020,17 +5016,17 @@ NS_IMETHODIMP HTMLMediaElement::WindowAu
 
         mDecoder->RemoveOutputStream(ps);
       }
       mCaptureStreamPort->Destroy();
       mCaptureStreamPort = nullptr;
     }
   }
 
-   return NS_OK;
+  return NS_OK;
 }
 
 AudioTrackList*
 HTMLMediaElement::AudioTracks()
 {
   if (!mAudioTrackList) {
     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(OwnerDoc()->GetParentObject());
     mAudioTrackList = new AudioTrackList(window, this);
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -532,41 +532,39 @@ AudioDestinationNode::WindowVolumeChange
     }
   }
 
   SetCanPlay(aVolume, aMuted);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-AudioDestinationNode::WindowAudioCaptureChanged()
+AudioDestinationNode::WindowAudioCaptureChanged(bool aCapture)
 {
   MOZ_ASSERT(mAudioChannelAgent);
 
   if (!mStream || Context()->IsOffline()) {
     return NS_OK;
   }
 
   nsCOMPtr<nsPIDOMWindow> ownerWindow = GetOwner();
   if (!ownerWindow) {
     return NS_OK;
   }
 
-  bool captured = ownerWindow->GetAudioCaptured();
-
-  if (captured != mCaptured) {
-    if (captured) {
+  if (aCapture != mCaptured) {
+    if (aCapture) {
       nsCOMPtr<nsPIDOMWindow> window = Context()->GetParentObject();
       uint64_t id = window->WindowID();
       mCaptureStreamPort =
         mStream->Graph()->ConnectToCaptureStream(id, mStream);
     } else {
       mCaptureStreamPort->Destroy();
     }
-    mCaptured = captured;
+    mCaptured = aCapture;
   }
 
   return NS_OK;
 }
 
 AudioChannel
 AudioDestinationNode::MozAudioChannelType() const
 {
@@ -648,20 +646,17 @@ AudioDestinationNode::CreateAudioChannel
   mAudioChannelAgent = new AudioChannelAgent();
   rv = mAudioChannelAgent->InitWithWeakCallback(GetOwner(),
                                            static_cast<int32_t>(mAudioChannel),
                                            this);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  rv = WindowAudioCaptureChanged();
-  NS_WARN_IF(NS_FAILED(rv));
-  return rv;
-
+  return NS_OK;
 }
 
 void
 AudioDestinationNode::NotifyStableState()
 {
   mExtraCurrentTimeUpdatedSinceLastStableState = false;
 }
 
@@ -746,14 +741,13 @@ AudioDestinationNode::InputMuted(bool aM
 
   float volume = 0.0;
   bool muted = true;
   nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
-  WindowAudioCaptureChanged();
   WindowVolumeChanged(volume, muted);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -712,17 +712,17 @@ nsSpeechTask::DestroyAudioChannelAgent()
 NS_IMETHODIMP
 nsSpeechTask::WindowVolumeChanged(float aVolume, bool aMuted)
 {
   SetAudioOutputVolume(aMuted ? 0.0 : mVolume * aVolume);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSpeechTask::WindowAudioCaptureChanged()
+nsSpeechTask::WindowAudioCaptureChanged(bool aCapture)
 {
   // This is not supported yet.
   return NS_OK;
 }
 
 void
 nsSpeechTask::SetAudioOutputVolume(float aVolume)
 {
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -1855,17 +1855,17 @@ nsNPAPIPluginInstance::WindowVolumeChang
 {
   // We just support mute/unmute
   nsresult rv = SetMuted(aMuted);
   NS_WARN_IF(NS_FAILED(rv));
   return rv;
 }
 
 NS_IMETHODIMP
-nsNPAPIPluginInstance::WindowAudioCaptureChanged()
+nsNPAPIPluginInstance::WindowAudioCaptureChanged(bool aCapture)
 {
   return NS_OK;
 }
 
 nsresult
 nsNPAPIPluginInstance::SetMuted(bool aIsMuted)
 {
   if (RUNNING != mRunning)
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -706,17 +706,17 @@ Telephony::WindowVolumeChanged(float aVo
       mHaveDispatchedInterruptBeginEvent = mMuted;
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-Telephony::WindowAudioCaptureChanged()
+Telephony::WindowAudioCaptureChanged(bool aCapture)
 {
   // Do nothing, it's useless for the telephony object.
   return NS_OK;
 }
 
 // nsITelephonyListener
 
 NS_IMETHODIMP