Bug 1578615 - part1 : provide function GetAudibleState() on media element. r=chunmin
authoralwu <alwu@mozilla.com>
Wed, 25 Sep 2019 20:07:06 +0000
changeset 495043 6690d621d726c579344ad9adbb3cd3bd8e092814
parent 495042 750bba4665926d2c79f5bec1a5760d0e2362951f
child 495044 b38eec7c0555dcd9d53ac6e785d7187ed856f261
push id36621
push userdluca@mozilla.com
push dateThu, 26 Sep 2019 09:42:00 +0000
treeherdermozilla-central@1dc1a755079a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerschunmin
bugs1578615
milestone71.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 1578615 - part1 : provide function GetAudibleState() on media element. r=chunmin As we have another usage to know whether media is audible or not, we remove this function from AudioChannelWrapper and make it as media element's function. In addition, it also makes sense to have this function for media element, because the result is decided by media element's own attributes. Differential Revision: https://phabricator.services.mozilla.com/D44744
dom/audiochannel/AudioChannelService.h
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -46,16 +46,51 @@ class AudioPlaybackConfig {
 };
 
 class AudioChannelService final : public nsIObserver {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   /**
+   * We use `AudibleState` to represent the audible state of an owner of audio
+   * channel agent. Those information in AudioChannelWindow could help us to
+   * determine if a tab is being audible or not, in order to tell Chrome JS to
+   * show the sound indicator or delayed autoplay icon on the tab bar.
+   *
+   * - Sound indicator
+   * When a tab is playing sound, we would show the sound indicator on tab bar
+   * to tell users that this tab is producing sound now. In addition, the sound
+   * indicator also give users an ablility to mute or unmute tab.
+   *
+   * When an AudioChannelWindow first contains an agent with state `eAudible`,
+   * or an AudioChannelWindow losts its last agent with state `eAudible`, we
+   * would notify Chrome JS about those changes, to tell them that a tab has
+   * been being audible or not, in order to display or remove the indicator for
+   * a corresponding tab.
+   *
+   * - Delayed autoplay icon (Play Tab icon)
+   * When we enable delaying autoplay, which is to postpone the autoplay media
+   * for unvisited tab until it first goes to foreground, or user click the
+   * play tab icon to resume the delayed media.
+   *
+   * When an AudioChannelWindow first contains an agent with state `eAudible` or
+   * `eMaybeAudible`, we would notify Chrome JS about this change, in order to
+   * show the delayed autoplay tab icon to user, which is used to notice user
+   * there is a media being delayed starting, and then user can click the play
+   * tab icon to resume the start of media, or visit that tab to resume delayed
+   * media automatically.
+   *
+   * According to our UX design, we don't show this icon for inaudible media.
+   * The reason of showing the icon for a tab, where the agent starts with state
+   * `eMaybeAudible`, is because some video might be silent in the beginning
+   * but would soon become audible later.
+   *
+   * ---------------------------------------------------------------------------
+   *
    * 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
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -4,17 +4,16 @@
  * 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/. */
 
 #ifdef XP_WIN
 #  include "objbase.h"
 #endif
 
 #include "mozilla/dom/HTMLMediaElement.h"
-#include "AudioChannelService.h"
 #include "AudioDeviceInfo.h"
 #include "AudioStreamTrack.h"
 #include "AutoplayPolicy.h"
 #include "ChannelMediaDecoder.h"
 #include "DOMMediaStream.h"
 #include "DecoderDoctorDiagnostics.h"
 #include "DecoderDoctorLogger.h"
 #include "DecoderTraits.h"
@@ -143,16 +142,18 @@ using namespace mozilla::dom::HTMLMediaE
 
 namespace mozilla {
 namespace dom {
 
 extern void NotifyMediaStarted(uint64_t aWindowID);
 extern void NotifyMediaStopped(uint64_t aWindowID);
 extern void NotifyMediaAudibleChanged(uint64_t aWindowID, bool aAudible);
 
+using AudibleState = AudioChannelService::AudibleState;
+
 // Number of milliseconds between progress events as defined by spec
 static const uint32_t PROGRESS_MS = 350;
 
 // Number of milliseconds of no data before a stall event is fired as defined by
 // spec
 static const uint32_t STALL_MS = 3000;
 
 // Used by AudioChannel for suppresssing the volume to this ratio.
@@ -1318,35 +1319,21 @@ class HTMLMediaElement::AudioChannelAgen
 
   bool IsSuspended() const {
     return (mSuspended == nsISuspendedTypes::SUSPENDED_PAUSE ||
             mSuspended == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE ||
             mSuspended == nsISuspendedTypes::SUSPENDED_BLOCK);
   }
 
   AudibleState IsOwnerAudible() const {
-    // No audio track.
-    if (!mOwner->HasAudio()) {
-      return AudioChannelService::AudibleState::eNotAudible;
-    }
-
-    // Muted or the volume should not be ~0
-    if (mOwner->mMuted || (std::fabs(mOwner->Volume()) <= 1e-7)) {
-      return AudioChannelService::AudibleState::eMaybeAudible;
-    }
-
     // Suspended or paused media doesn't produce any sound.
     if (mSuspended != nsISuspendedTypes::NONE_SUSPENDED || mOwner->mPaused) {
-      return AudioChannelService::AudibleState::eNotAudible;
-    }
-
-    // Might be audible but not yet.
-    return mOwner->mIsAudioTrackAudible
-               ? AudioChannelService::AudibleState::eAudible
-               : AudioChannelService::AudibleState::eMaybeAudible;
+      return AudibleState::eNotAudible;
+    }
+    return mOwner->GetAudibleState();
   }
 
   bool IsPlayingThroughTheAudioChannel() const {
     // If we have an error, we are not playing.
     if (mOwner->GetError()) {
       return false;
     }
 
@@ -7227,16 +7214,31 @@ void HTMLMediaElement::NotifyDecoderActi
   if (mDecoder) {
     mDecoder->NotifyOwnerActivityChanged(!IsHidden(), mVisibilityState,
                                          IsInComposedDoc());
   }
 }
 
 Document* HTMLMediaElement::GetDocument() const { return OwnerDoc(); }
 
+AudibleState HTMLMediaElement::GetAudibleState() const {
+  // No audio track.
+  if (!HasAudio()) {
+    return AudibleState::eNotAudible;
+  }
+
+  // Muted or the volume should not be ~0
+  if (mMuted || (std::fabs(Volume()) <= 1e-7)) {
+    return AudibleState::eMaybeAudible;
+  }
+
+  return mIsAudioTrackAudible ? AudibleState::eAudible
+                              : AudibleState::eMaybeAudible;
+}
+
 void HTMLMediaElement::ConstructMediaTracks(const MediaInfo* aInfo) {
   if (mMediaTracksConstructed || !aInfo) {
     return;
   }
 
   mMediaTracksConstructed = true;
 
   AudioTrackList* audioList = AudioTracks();
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -3,16 +3,17 @@
 /* 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/. */
 #ifndef mozilla_dom_HTMLMediaElement_h
 #define mozilla_dom_HTMLMediaElement_h
 
 #include "nsAutoPtr.h"
 #include "nsGenericHTMLElement.h"
+#include "AudioChannelService.h"
 #include "MediaEventSource.h"
 #include "SeekTarget.h"
 #include "MediaDecoderOwner.h"
 #include "MediaPromiseDefs.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIObserver.h"
 #include "mozilla/CORSMode.h"
 #include "DecoderTraits.h"
@@ -36,17 +37,16 @@
 
 // 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 AbstractThread;
 class ChannelMediaDecoder;
 class DecoderDoctorDiagnostics;
 class DOMMediaStream;
 class ErrorResult;
 class MediaResource;
@@ -720,16 +720,18 @@ class HTMLMediaElement : public nsGeneri
 
   // This is used to notify MediaElementAudioSourceNode that media element is
   // allowed to play when media element is used as a source for web audio, so
   // that we can start AudioContext if it was not allowed to start.
   RefPtr<GenericNonExclusivePromise> GetAllowedToPlayPromise();
 
   bool GetShowPosterFlag() const { return mShowPoster; }
 
+  AudioChannelService::AudibleState GetAudibleState() const;
+
  protected:
   virtual ~HTMLMediaElement();
 
   class AudioChannelAgentCallback;
   class ChannelLoader;
   class ErrorSink;
   class MediaLoadListener;
   class MediaStreamRenderer;