Bug 1320005 - don't show the 'play tab' icon for the media element without audio track. r=baku a=jcristau
authorAlastor Wu <alwu@mozilla.com>
Tue, 13 Dec 2016 22:47:13 +0800
changeset 353051 4d428919f82ffdab4943ffe7055f739423e0793b
parent 353050 7a9e103be35066bd7c06e770a73b7401ce1e2620
child 353052 6f0be357dd95d0180e500fffa87ac88230f556ae
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, jcristau
bugs1320005
milestone52.0a2
Bug 1320005 - don't show the 'play tab' icon for the media element without audio track. r=baku a=jcristau MozReview-Commit-ID: K42I0yWaI7N
dom/audiochannel/AudioChannelAgent.cpp
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
dom/audiochannel/nsIAudioChannelAgent.idl
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
--- a/dom/audiochannel/AudioChannelAgent.cpp
+++ b/dom/audiochannel/AudioChannelAgent.cpp
@@ -186,30 +186,31 @@ AudioChannelAgent::InitInternal(nsPIDOMW
           "owner = %p, hasCallback = %d\n", this, mAudioChannelType,
           mWindow.get(), (!!mCallback || !!mWeakCallback)));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AudioChannelAgent::NotifyStartedPlaying(AudioPlaybackConfig* aConfig,
-                                        bool aAudible)
+                                        uint8_t aAudible)
 {
   if (NS_WARN_IF(!aConfig)) {
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
   if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR ||
       service == nullptr || mIsRegToService) {
     return NS_ERROR_FAILURE;
   }
 
-  MOZ_ASSERT(AudioChannelService::AudibleState::eAudible == true &&
-             AudioChannelService::AudibleState::eNotAudible == false);
+  MOZ_ASSERT(AudioChannelService::AudibleState::eNotAudible == 0 &&
+             AudioChannelService::AudibleState::eMaybeAudible == 1 &&
+             AudioChannelService::AudibleState::eAudible == 2);
   service->RegisterAudioChannelAgent(this,
     static_cast<AudioChannelService::AudibleState>(aAudible));
 
   AudioPlaybackConfig config = service->GetMediaConfig(mWindow,
                                                        mAudioChannelType);
 
   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
          ("AudioChannelAgent, NotifyStartedPlaying, this = %p, "
@@ -237,17 +238,17 @@ AudioChannelAgent::NotifyStoppedPlaying(
     service->UnregisterAudioChannelAgent(this);
   }
 
   mIsRegToService = false;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-AudioChannelAgent::NotifyStartedAudible(bool aAudible, uint32_t aReason)
+AudioChannelAgent::NotifyStartedAudible(uint8_t aAudible, uint32_t aReason)
 {
   MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
          ("AudioChannelAgent, NotifyStartedAudible, this = %p, "
           "audible = %d, reason = %d\n", this, aAudible, aReason));
 
   RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
   if (NS_WARN_IF(!service)) {
     return NS_ERROR_FAILURE;
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -1239,24 +1239,24 @@ void
 AudioChannelService::AudioChannelWindow::AppendAgent(AudioChannelAgent* aAgent,
                                                      AudibleState aAudible)
 {
   MOZ_ASSERT(aAgent);
 
   RequestAudioFocus(aAgent);
   AppendAgentAndIncreaseAgentsNum(aAgent);
   AudioCapturedChanged(aAgent, AudioCaptureState::eCapturing);
-  if (aAudible) {
+  if (aAudible == AudibleState::eAudible) {
     AudioAudibleChanged(aAgent,
                         AudibleState::eAudible,
                         AudibleChangedReasons::eDataAudibleChanged);
-  } else if (IsEnableAudioCompetingForAllAgents() && !aAudible) {
+  } else if (IsEnableAudioCompetingForAllAgents() &&
+             aAudible != AudibleState::eAudible) {
     NotifyAudioCompetingChanged(aAgent, true);
   }
-  MaybeNotifyMediaBlocked(aAgent);
 }
 
 void
 AudioChannelService::AudioChannelWindow::RemoveAgent(AudioChannelAgent* aAgent)
 {
   MOZ_ASSERT(aAgent);
 
   RemoveAgentAndReduceAgentsNum(aAgent);
@@ -1317,23 +1317,26 @@ AudioChannelService::AudioChannelWindow:
 
 void
 AudioChannelService::AudioChannelWindow::AudioAudibleChanged(AudioChannelAgent* aAgent,
                                                              AudibleState aAudible,
                                                              AudibleChangedReasons aReason)
 {
   MOZ_ASSERT(aAgent);
 
-  if (aAudible) {
+  if (aAudible == AudibleState::eAudible) {
     AppendAudibleAgentIfNotContained(aAgent, aReason);
   } else {
     RemoveAudibleAgentIfContained(aAgent, aReason);
   }
 
-  NotifyAudioCompetingChanged(aAgent, aAudible);
+  NotifyAudioCompetingChanged(aAgent, aAudible == AudibleState::eAudible);
+  if (aAudible != AudibleState::eNotAudible) {
+    MaybeNotifyMediaBlocked(aAgent);
+  }
 }
 
 void
 AudioChannelService::AudioChannelWindow::AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
                                                                           AudibleChangedReasons aReason)
 {
   MOZ_ASSERT(aAgent);
   MOZ_ASSERT(mAgents.Contains(aAgent));
@@ -1380,17 +1383,19 @@ AudioChannelService::AudioChannelWindow:
 }
 
 void
 AudioChannelService::AudioChannelWindow::NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
                                                                    AudibleState aAudible,
                                                                    AudibleChangedReasons aReason)
 {
   RefPtr<AudioPlaybackRunnable> runnable =
-    new AudioPlaybackRunnable(aWindow, aAudible, aReason);
+    new AudioPlaybackRunnable(aWindow,
+                              aAudible == AudibleState::eAudible,
+                              aReason);
   DebugOnly<nsresult> rv = NS_DispatchToCurrentThread(runnable);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToCurrentThread failed");
 }
 
 void
 AudioChannelService::AudioChannelWindow::NotifyChannelActive(uint64_t aWindowID,
                                                              AudioChannel aChannel,
                                                              bool aActive)
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -63,19 +63,25 @@ public:
 class AudioChannelService final : public nsIAudioChannelService
                                 , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIAUDIOCHANNELSERVICE
 
-  enum AudibleState : bool {
-    eAudible = true,
-    eNotAudible = false
+  /**
+   * eNotAudible : agent is not audible
+   * eMaybeAudible : agent is not audible now, but it might be audible later
+   * eAudible : agent is audible now
+   */
+  enum AudibleState : uint8_t {
+    eNotAudible = 0,
+    eMaybeAudible = 1,
+    eAudible = 2
   };
 
   enum AudioCaptureState : bool {
     eCapturing = true,
     eNotCapturing = false
   };
 
   enum AudibleChangedReasons : uint32_t {
--- a/dom/audiochannel/nsIAudioChannelAgent.idl
+++ b/dom/audiochannel/nsIAudioChannelAgent.idl
@@ -158,17 +158,17 @@ interface nsIAudioChannelAgent : nsISupp
   /**
    * Notify the agent that we want to start playing.
    * Note: Gecko component SHOULD call this function first then start to
    *          play audio stream only when return value is true.
    *
    * @param config
    *    It contains the playback related states (volume/mute/suspend)
    */
-  void notifyStartedPlaying(in AudioPlaybackConfig config, in bool audible);
+  void notifyStartedPlaying(in AudioPlaybackConfig config, in uint8_t audible);
 
   /**
    * Notify the agent we no longer want to play.
    *
    * Note : even if notifyStartedPlaying() returned false, the agent would
    * still be registered with the audio channel service and receive callbacks
    * for status changes. So notifyStoppedPlaying must still eventually be
    * called to unregister the agent with the channel service.
@@ -178,10 +178,10 @@ interface nsIAudioChannelAgent : nsISupp
 
   /**
    * Notify agent that we already start producing audible data.
    *
    * Note : sometime audio might become silent during playing, this method is used to
    * notify the actually audible state to other services which want to know
    * about that, ex. tab sound indicator.
    */
-  void notifyStartedAudible(in bool audible, in uint32_t reason);
+  void notifyStartedAudible(in uint8_t audible, in uint32_t reason);
 };
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -6589,35 +6589,35 @@ HTMLMediaElement::NotifyAudioPlaybackCha
   if (mAudible == IsAudible()) {
     return;
   }
 
   mAudible = IsAudible();
   mAudioChannelAgent->NotifyStartedAudible(mAudible, aReason);
 }
 
-bool
+AudibleState
 HTMLMediaElement::IsAudible() const
 {
   // Muted or the volume should not be ~0
   if (Muted() || (std::fabs(Volume()) <= 1e-7)) {
-    return false;
-  }
-
-  // No sound can be heard during suspending.
-  if (IsSuspendedByAudioChannel()) {
-    return false;
-  }
-
-  // Silent audio track.
-  if (!mIsAudioTrackAudible) {
-    return false;
-  }
-
-  return true;
+    return AudioChannelService::AudibleState::eNotAudible;
+  }
+
+  // No audio track.
+  if (!HasAudio()) {
+    return AudioChannelService::AudibleState::eNotAudible;
+  }
+
+  // Might be audible but not yet.
+  if (HasAudio() && !mIsAudioTrackAudible) {
+    return AudioChannelService::AudibleState::eMaybeAudible;
+  }
+
+  return AudioChannelService::AudibleState::eAudible;
 }
 
 void
 HTMLMediaElement::MaybeNotifyMediaResumed(SuspendTypes aSuspend)
 {
   // In fennec, we should send the notification when media is resumed from the
   // pause-disposable which was called by media control.
   if (mAudioChannelSuspended != nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE &&
@@ -6656,17 +6656,22 @@ HTMLMediaElement::ShouldElementBePaused(
   }
 
   return false;
 }
 
 void
 HTMLMediaElement::SetMediaInfo(const MediaInfo& aInfo)
 {
+  const bool oldHasAudio = mMediaInfo.HasAudio();
   mMediaInfo = aInfo;
+  if (aInfo.HasAudio() != oldHasAudio) {
+    NotifyAudioPlaybackChanged(
+      AudioChannelService::AudibleChangedReasons::eDataAudibleChanged);
+  }
   AudioCaptureStreamChangeIfNeeded();
 }
 
 void
 HTMLMediaElement::AudioCaptureStreamChangeIfNeeded()
 {
   // No need to capture a silence media element.
   if (!HasAudio()) {
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -34,16 +34,17 @@
 
 // Define to output information on decoding and painting framerate
 /* #define DEBUG_FRAME_RATE 1 */
 
 typedef uint16_t nsMediaNetworkState;
 typedef uint16_t nsMediaReadyState;
 typedef uint32_t SuspendTypes;
 typedef uint32_t AudibleChangedReasons;
+typedef uint8_t AudibleState;
 
 namespace mozilla {
 class DecoderDoctorDiagnostics;
 class DOMMediaStream;
 class ErrorResult;
 class MediaResource;
 class MediaDecoder;
 class VideoFrameContainer;
@@ -1275,17 +1276,17 @@ protected:
 
   // If the network state is empty and then we would trigger DoLoad().
   void MaybeDoLoad();
 
   // True if the tab which media element belongs to has been to foreground at
   // least once or activated by manually clicking the unblocking tab icon.
   bool IsTabActivated() const;
 
-  bool IsAudible() const;
+  AudibleState IsAudible() const;
 
   // It's used for fennec only, send the notification when the user resumes the
   // media which was paused by media control.
   void MaybeNotifyMediaResumed(SuspendTypes aSuspend);
 
   class nsAsyncEventRunner;
   using nsGenericHTMLElement::DispatchEvent;
   // For nsAsyncEventRunner.
@@ -1732,18 +1733,18 @@ private:
   // Media elements also have a default playback start position, which must
   // initially be set to zero seconds. This time is used to allow the element to
   // be seeked even before the media is loaded.
   double mDefaultPlaybackStartPosition;
 
   // True if the audio track is not silent.
   bool mIsAudioTrackAudible;
 
-  // True if media element is audible for users.
-  bool mAudible;
+  // Indicate whether media element is audible for users.
+  AudibleState mAudible;
 
   Visibility mVisibilityState;
 
   UniquePtr<ErrorSink> mErrorSink;
 };
 
 } // namespace dom
 } // namespace mozilla