Bug 1290467 - part7 : enable audio competing for non-audible media. r=baku
authorAlastor Wu <alwu@mozilla.com>
Fri, 09 Sep 2016 09:50:40 +0800
changeset 354573 789d97d6ca60016c83b5b1b5dade71f681c9bfb7
parent 354572 7eb048d423d17b3b0a3360897b5f71ed602d670e
child 354574 9c459f432b365a3c209f150df5864d3299a91e1f
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1290467
milestone51.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 1290467 - part7 : enable audio competing for non-audible media. r=baku In general, the audio competing should only be for audible media and it helps user can focus on one media at the same time. However, we hope to treat all media as the same in the mobile device. First reason is we have media control on fennec and we just want to control one media at once time. Second reason is to reduce the bandwidth, avoiding to play any non-audible media in background which user doesn't notice about. MozReview-Commit-ID: yB3181cmVE
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -155,16 +155,32 @@ private:
     }
   }
 
   nsCOMPtr<nsPIDOMWindowOuter> mWindow;
   bool mActive;
   AudioChannelService::AudibleChangedReasons mReason;
 };
 
+bool
+IsEnableAudioCompetingForAllAgents()
+{
+  // In general, the audio competing should only be for audible media and it
+  // helps user can focus on one media at the same time. However, we hope to
+  // treat all media as the same in the mobile device. First reason is we have
+  // media control on fennec and we just want to control one media at once time.
+  // Second reason is to reduce the bandwidth, avoiding to play any non-audible
+  // media in background which user doesn't notice about.
+#ifdef MOZ_WIDGET_ANDROID
+  return true;
+#else
+  return false;
+#endif
+}
+
 } // anonymous namespace
 
 StaticRefPtr<AudioChannelService> gAudioChannelService;
 
 // Mappings from 'mozaudiochannel' attribute strings to an enumeration.
 static const nsAttrValue::EnumTable kMozAudioChannelAttributeTable[] = {
   { "normal",             (int16_t)AudioChannel::Normal },
   { "content",            (int16_t)AudioChannel::Content },
@@ -1119,35 +1135,38 @@ AudioChannelService::AudioChannelWindow:
   // TODO : add MediaSession::ambient kind, because it doens't interact with
   // other kinds.
   return true;
 }
 
 bool
 AudioChannelService::AudioChannelWindow::IsAudioCompetingInSameTab() const
 {
-  return (mOwningAudioFocus && mAudibleAgents.Length() > 1);
+  bool hasMultipleActiveAgents = IsEnableAudioCompetingForAllAgents() ?
+    mAgents.Length() > 1 : mAudibleAgents.Length() > 1;
+  return mOwningAudioFocus && hasMultipleActiveAgents;
 }
 
 void
 AudioChannelService::AudioChannelWindow::AudioFocusChanged(AudioChannelAgent* aNewPlayingAgent,
                                                            bool aActive)
 {
   // This agent isn't always known for the current window, because it can comes
   // from other window.
   MOZ_ASSERT(aNewPlayingAgent);
 
-  if (mAudibleAgents.IsEmpty()) {
+  if (IsInactiveWindow()) {
     // These would happen in two situations,
     // (1) Audio in page A was ended, and another page B want to play audio.
     //     Page A should abandon its focus.
     // (2) Audio was paused by remote-control, page should still own the focus.
     mOwningAudioFocus = IsContainingPlayingAgent(aNewPlayingAgent);
   } else {
-    nsTObserverArray<AudioChannelAgent*>::ForwardIterator iter(mAudibleAgents);
+    nsTObserverArray<AudioChannelAgent*>::ForwardIterator
+      iter(IsEnableAudioCompetingForAllAgents() ? mAgents : mAudibleAgents);
     while (iter.HasMore()) {
       AudioChannelAgent* agent = iter.GetNext();
       MOZ_ASSERT(agent);
 
       // Don't need to update the playing state of new playing agent.
       if (agent == aNewPlayingAgent) {
         continue;
       }
@@ -1183,17 +1202,18 @@ AudioChannelService::AudioChannelWindow:
 }
 
 uint32_t
 AudioChannelService::AudioChannelWindow::GetCompetingBehavior(AudioChannelAgent* aAgent,
                                                               int32_t aIncomingChannelType,
                                                               bool aIncomingChannelActive) const
 {
   MOZ_ASSERT(aAgent);
-  MOZ_ASSERT(mAudibleAgents.Contains(aAgent));
+  MOZ_ASSERT(IsEnableAudioCompetingForAllAgents() ?
+    mAgents.Contains(aAgent) : mAudibleAgents.Contains(aAgent));
 
   uint32_t competingBehavior = nsISuspendedTypes::NONE_SUSPENDED;
   int32_t presentChannelType = aAgent->AudioChannelType();
 
   // TODO : add other competing cases for MediaSession API
   if (presentChannelType == int32_t(AudioChannel::Normal) &&
       aIncomingChannelType == int32_t(AudioChannel::Normal) &&
       aIncomingChannelActive) {
@@ -1223,16 +1243,18 @@ AudioChannelService::AudioChannelWindow:
 
   RequestAudioFocus(aAgent);
   AppendAgentAndIncreaseAgentsNum(aAgent);
   AudioCapturedChanged(aAgent, AudioCaptureState::eCapturing);
   if (aAudible) {
     AudioAudibleChanged(aAgent,
                         AudibleState::eAudible,
                         AudibleChangedReasons::eDataAudibleChanged);
+  } else if (IsEnableAudioCompetingForAllAgents() && !aAudible) {
+    NotifyAudioCompetingChanged(aAgent, true);
   }
 }
 
 void
 AudioChannelService::AudioChannelWindow::RemoveAgent(AudioChannelAgent* aAgent)
 {
   MOZ_ASSERT(aAgent);
 
@@ -1344,16 +1366,23 @@ AudioChannelService::AudioChannelWindow:
 }
 
 bool
 AudioChannelService::AudioChannelWindow::IsLastAudibleAgent() const
 {
   return mAudibleAgents.IsEmpty();
 }
 
+bool
+AudioChannelService::AudioChannelWindow::IsInactiveWindow() const
+{
+  return IsEnableAudioCompetingForAllAgents() ?
+    mAudibleAgents.IsEmpty() && mAgents.IsEmpty() : mAudibleAgents.IsEmpty();
+}
+
 void
 AudioChannelService::AudioChannelWindow::NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
                                                                    AudibleState aAudible,
                                                                    AudibleChangedReasons aReason)
 {
   RefPtr<AudioPlaybackRunnable> runnable =
     new AudioPlaybackRunnable(aWindow, aAudible, aReason);
   DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -303,16 +303,18 @@ private:
     void NotifyAudioCompetingChanged(AudioChannelAgent* aAgent, bool aActive);
 
     uint32_t GetCompetingBehavior(AudioChannelAgent* aAgent,
                                   int32_t aIncomingChannelType,
                                   bool aIncomingChannelActive) const;
     bool IsAgentInvolvingInAudioCompeting(AudioChannelAgent* aAgent) const;
     bool IsAudioCompetingInSameTab() const;
     bool IsContainingPlayingAgent(AudioChannelAgent* aAgent) const;
+
+    bool IsInactiveWindow() const;
   };
 
   AudioChannelWindow*
   GetOrCreateWindowData(nsPIDOMWindowOuter* aWindow);
 
   AudioChannelWindow*
   GetWindowData(uint64_t aWindowID) const;