Bug 828283 - Apps playing sound should not be muted when the screen is put to sleep., a=tef+, r=sicking
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 28 Jan 2013 13:07:06 +0100
changeset 118354 b30d5224b47beeb483ce4b3298bd14f1a5d4df95
parent 118353 dc3e991c5ef0830c8186e01fd5a69984f53fb958
child 118355 1f22eda11281de87c5b6bdf4600916a1623494cc
push id5
push useramarchesini@mozilla.com
push dateMon, 28 Jan 2013 12:08:05 +0000
reviewerstef, sicking
bugs828283
milestone18.0
Bug 828283 - Apps playing sound should not be muted when the screen is put to sleep., a=tef+, r=sicking
b2g/chrome/content/shell.js
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
dom/ipc/ProcessPriorityManager.cpp
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -393,16 +393,17 @@ var shell = {
       this.sendChromeEvent({type: type});
     }
   },
 
   lastHardwareButtonEventType: null, // property for the hack above
   needBufferSysMsgs: true,
   bufferedSysMsgs: [],
   timer: null,
+  visibleAudioActive: false,
 
   handleEvent: function shell_handleEvent(evt) {
     let content = this.contentBrowser.contentWindow;
     switch (evt.type) {
       case 'keydown':
       case 'keyup':
       case 'keypress':
         this.filterHardwareKeys(evt);
@@ -410,17 +411,17 @@ var shell = {
       case 'mozfullscreenchange':
         // When the screen goes fullscreen make sure to set the focus to the
         // main window so noboby can prevent the ESC key to get out fullscreen
         // mode
         if (document.mozFullScreen)
           Services.fm.focusedWindow = window;
         break;
       case 'sizemodechange':
-        if (window.windowState == window.STATE_MINIMIZED) {
+        if (window.windowState == window.STATE_MINIMIZED && !this.visibleAudioActive) {
           this.contentBrowser.setVisible(false);
         } else {
           this.contentBrowser.setVisible(true);
         }
         break;
       case 'mozbrowserloadstart':
         if (content.document.location == 'about:blank')
           return;
@@ -1047,16 +1048,26 @@ window.addEventListener('ContentStart', 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     shell.sendChromeEvent({
       type: 'audio-channel-changed',
       channel: aData
     });
 }, "audio-channel-changed", false);
 })();
 
+(function visibleAudioChannelChangedTracker() {
+  Services.obs.addObserver(function(aSubject, aTopic, aData) {
+    shell.sendChromeEvent({
+      type: 'visible-audio-channel-changed',
+      channel: aData
+    });
+    shell.visibleAudioActive = (aData !== 'none');
+}, "visible-audio-channel-changed", false);
+})();
+
 (function recordingStatusTracker() {
   let gRecordingActiveCount = 0;
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     let oldCount = gRecordingActiveCount;
     if (aData == "starting") {
       gRecordingActiveCount += 1;
     } else if (aData == "shutdown") {
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -62,16 +62,17 @@ AudioChannelService::Shutdown()
     gAudioChannelService = nullptr;
   }
 }
 
 NS_IMPL_ISUPPORTS0(AudioChannelService)
 
 AudioChannelService::AudioChannelService()
 : mCurrentHigherChannel(AUDIO_CHANNEL_LAST)
+, mCurrentVisibleHigherChannel(AUDIO_CHANNEL_LAST)
 , mActiveContentChildIDsFrozen(false)
 {
   // Creation of the hash table.
   mAgents.Init();
 
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
@@ -209,20 +210,21 @@ AudioChannelService::GetMutedInternal(Au
     MOZ_ASSERT(newType != AUDIO_CHANNEL_INT_NORMAL_HIDDEN);
     muted = ChannelsActiveWithHigherPriorityThan(newType);
   }
 
   return muted;
 }
 
 bool
-AudioChannelService::ContentChannelIsActive()
+AudioChannelService::ContentOrNormalChannelIsActive()
 {
   return !mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].IsEmpty() ||
-         !mChannelCounters[AUDIO_CHANNEL_INT_CONTENT_HIDDEN].IsEmpty();
+         !mChannelCounters[AUDIO_CHANNEL_INT_CONTENT_HIDDEN].IsEmpty() ||
+         !mChannelCounters[AUDIO_CHANNEL_INT_NORMAL].IsEmpty();
 }
 
 void
 AudioChannelService::SendAudioChannelChangedNotification()
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     return;
   }
@@ -254,55 +256,73 @@ AudioChannelService::SendAudioChannelCha
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].IsEmpty()) {
     higher = AUDIO_CHANNEL_CONTENT;
   }
 
   else if (!mChannelCounters[AUDIO_CHANNEL_INT_NORMAL].IsEmpty()) {
     higher = AUDIO_CHANNEL_NORMAL;
   }
 
+  AudioChannelType visibleHigher = higher;
+
   // Top-Down in the hierarchy for non-visible elements
-  else if (!mChannelCounters[AUDIO_CHANNEL_INT_PUBLICNOTIFICATION_HIDDEN].IsEmpty()) {
-    higher = AUDIO_CHANNEL_PUBLICNOTIFICATION;
-  }
+  if (higher == AUDIO_CHANNEL_LAST) {
+    if (!mChannelCounters[AUDIO_CHANNEL_INT_PUBLICNOTIFICATION_HIDDEN].IsEmpty()) {
+      higher = AUDIO_CHANNEL_PUBLICNOTIFICATION;
+    }
 
-  else if (!mChannelCounters[AUDIO_CHANNEL_INT_RINGER_HIDDEN].IsEmpty()) {
-    higher = AUDIO_CHANNEL_RINGER;
-  }
+    else if (!mChannelCounters[AUDIO_CHANNEL_INT_RINGER_HIDDEN].IsEmpty()) {
+      higher = AUDIO_CHANNEL_RINGER;
+    }
 
-  else if (!mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].IsEmpty()) {
-    higher = AUDIO_CHANNEL_TELEPHONY;
-  }
+    else if (!mChannelCounters[AUDIO_CHANNEL_INT_TELEPHONY_HIDDEN].IsEmpty()) {
+      higher = AUDIO_CHANNEL_TELEPHONY;
+    }
 
-  else if (!mChannelCounters[AUDIO_CHANNEL_INT_ALARM_HIDDEN].IsEmpty()) {
-    higher = AUDIO_CHANNEL_ALARM;
-  }
+    else if (!mChannelCounters[AUDIO_CHANNEL_INT_ALARM_HIDDEN].IsEmpty()) {
+      higher = AUDIO_CHANNEL_ALARM;
+    }
 
-  else if (!mChannelCounters[AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN].IsEmpty()) {
-    higher = AUDIO_CHANNEL_NOTIFICATION;
-  }
+    else if (!mChannelCounters[AUDIO_CHANNEL_INT_NOTIFICATION_HIDDEN].IsEmpty()) {
+      higher = AUDIO_CHANNEL_NOTIFICATION;
+    }
 
-  // Content channels play in background if just one is active.
-  else if (!mActiveContentChildIDs.IsEmpty()) {
-    higher = AUDIO_CHANNEL_CONTENT;
+    // Content channels play in background if just one is active.
+    else if (!mActiveContentChildIDs.IsEmpty()) {
+      higher = AUDIO_CHANNEL_CONTENT;
+    }
   }
 
   if (higher != mCurrentHigherChannel) {
     mCurrentHigherChannel = higher;
 
     nsString channelName;
     if (mCurrentHigherChannel != AUDIO_CHANNEL_LAST) {
       channelName.AssignASCII(ChannelName(mCurrentHigherChannel));
     } else {
       channelName.AssignLiteral("none");
     }
 
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     obs->NotifyObservers(nullptr, "audio-channel-changed", channelName.get());
   }
+
+  if (visibleHigher != mCurrentVisibleHigherChannel) {
+    mCurrentVisibleHigherChannel = visibleHigher;
+
+    nsString channelName;
+    if (mCurrentVisibleHigherChannel != AUDIO_CHANNEL_LAST) {
+      channelName.AssignASCII(ChannelName(mCurrentVisibleHigherChannel));
+    } else {
+      channelName.AssignLiteral("none");
+    }
+
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    obs->NotifyObservers(nullptr, "visible-audio-channel-changed", channelName.get());
+  }
 }
 
 PLDHashOperator
 AudioChannelService::NotifyEnumerator(AudioChannelAgent* aAgent,
                                       AudioChannelAgentData* aData, void* aUnused)
 {
   MOZ_ASSERT(aAgent);
   aAgent->NotifyAudioChannelStateChanged();
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -52,17 +52,17 @@ public:
    * Return true if this type should be muted.
    */
   virtual bool GetMuted(AudioChannelAgent* aAgent, bool aElementHidden);
 
   /**
    * Return true if there is a content channel active in this process
    * or one of its subprocesses.
    */
-  virtual bool ContentChannelIsActive();
+  virtual bool ContentOrNormalChannelIsActive();
 
 protected:
   void Notify();
 
   /**
    * Send the audio-channel-changed notification if needed.
    */
   void SendAudioChannelChangedNotification();
@@ -122,16 +122,17 @@ protected:
   NotifyEnumerator(AudioChannelAgent* aAgent,
                    AudioChannelAgentData* aData, void *aUnused);
 
   nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
 
   nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];
 
   AudioChannelType mCurrentHigherChannel;
+  AudioChannelType mCurrentVisibleHigherChannel;
 
   nsTArray<uint64_t> mActiveContentChildIDs;
   bool mActiveContentChildIDsFrozen;
 
   // This is needed for IPC comunication between
   // AudioChannelServiceChild and this class.
   friend class ContentParent;
   friend class ContentChild;
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -71,17 +71,17 @@ static PRLogModuleInfo* logModule = PR_N
 
 /**
  * Get the appropriate backround priority for this process.
  */
 ProcessPriority
 GetBackgroundPriority()
 {
   AudioChannelService* service = AudioChannelService::GetAudioChannelService();
-  if (service->ContentChannelIsActive()) {
+  if (service->ContentOrNormalChannelIsActive()) {
     return PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE;
   }
 
   bool isHomescreen = false;
 
   ContentChild* contentChild = ContentChild::GetSingleton();
   if (contentChild) {
     const InfallibleTArray<PBrowserChild*>& browsers =