tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AudioChannelService.h (8521B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_audiochannelservice_h__
      8 #define mozilla_dom_audiochannelservice_h__
      9 
     10 #include <functional>
     11 
     12 #include "AudioChannelAgent.h"
     13 #include "mozilla/DefineEnum.h"
     14 #include "mozilla/Logging.h"
     15 #include "mozilla/UniquePtr.h"
     16 #include "nsAttrValue.h"
     17 #include "nsIObserver.h"
     18 #include "nsTArray.h"
     19 #include "nsTObserverArray.h"
     20 
     21 class nsPIDOMWindowOuter;
     22 struct PRLogModuleInfo;
     23 
     24 namespace mozilla::dom {
     25 
     26 class AudioPlaybackConfig {
     27 public:
     28  AudioPlaybackConfig()
     29      : mVolume(1.0),
     30        mMuted(false),
     31        mSuspend(nsISuspendedTypes::NONE_SUSPENDED),
     32        mNumberOfAgents(0) {}
     33 
     34  AudioPlaybackConfig(float aVolume, bool aMuted, uint32_t aSuspended)
     35      : mVolume(aVolume),
     36        mMuted(aMuted),
     37        mSuspend(aSuspended),
     38        mNumberOfAgents(0) {}
     39 
     40  float mVolume;
     41  bool mMuted;
     42  uint32_t mSuspend;
     43  bool mCapturedAudio = false;
     44  uint32_t mNumberOfAgents;
     45 };
     46 
     47 class AudioChannelService final : public nsIObserver {
     48 public:
     49  NS_DECL_ISUPPORTS
     50  NS_DECL_NSIOBSERVER
     51 
     52  /**
     53   * We use `AudibleState` to represent the audible state of an owner of audio
     54   * channel agent. Those information in AudioChannelWindow could help us to
     55   * determine if a tab is being audible or not, in order to tell Chrome JS to
     56   * show the sound indicator or delayed autoplay icon on the tab bar.
     57   *
     58   * - Sound indicator
     59   * When a tab is playing sound, we would show the sound indicator on tab bar
     60   * to tell users that this tab is producing sound now. In addition, the sound
     61   * indicator also give users an ablility to mute or unmute tab.
     62   *
     63   * When an AudioChannelWindow first contains an agent with state `eAudible`,
     64   * or an AudioChannelWindow losts its last agent with state `eAudible`, we
     65   * would notify Chrome JS about those changes, to tell them that a tab has
     66   * been being audible or not, in order to display or remove the indicator for
     67   * a corresponding tab.
     68   *
     69   * - Delayed autoplay icon (Play Tab icon)
     70   * When we enable delaying autoplay, which is to postpone the autoplay media
     71   * for unvisited tab until it first goes to foreground, or user click the
     72   * play tab icon to resume the delayed media.
     73   *
     74   * When an AudioChannelWindow first contains an agent with state `eAudible` or
     75   * `eMaybeAudible`, we would notify Chrome JS about this change, in order to
     76   * show the delayed autoplay tab icon to user, which is used to notice user
     77   * there is a media being delayed starting, and then user can click the play
     78   * tab icon to resume the start of media, or visit that tab to resume delayed
     79   * media automatically.
     80   *
     81   * According to our UX design, we don't show this icon for inaudible media.
     82   * The reason of showing the icon for a tab, where the agent starts with state
     83   * `eMaybeAudible`, is because some video might be silent in the beginning
     84   * but would soon become audible later.
     85   *
     86   * ---------------------------------------------------------------------------
     87   *
     88   * eNotAudible : agent is not audible
     89   * eMaybeAudible : agent is not audible now, but it might be audible later
     90   * eAudible : agent is audible now
     91   */
     92  MOZ_DEFINE_ENUM_WITH_BASE_AND_TOSTRING_AT_CLASS_SCOPE(
     93      AudibleState, uint8_t, (eNotAudible, eMaybeAudible, eAudible));
     94 
     95  enum AudioCaptureState : bool { eCapturing = true, eNotCapturing = false };
     96 
     97  MOZ_DEFINE_ENUM_WITH_BASE_AND_TOSTRING_AT_CLASS_SCOPE(
     98      AudibleChangedReasons, uint32_t,
     99      (eVolumeChanged, eDataAudibleChanged, ePauseStateChanged));
    100 
    101  /**
    102   * Returns the AudioChannelServce singleton.
    103   * If AudioChannelService doesn't exist, create and return new one.
    104   * Only to be called from main thread.
    105   */
    106  static already_AddRefed<AudioChannelService> GetOrCreate();
    107 
    108  /**
    109   * Returns the AudioChannelService singleton if one exists.
    110   * If AudioChannelService doesn't exist, returns null.
    111   */
    112  static already_AddRefed<AudioChannelService> Get();
    113 
    114  static LogModule* GetAudioChannelLog();
    115 
    116  static bool IsEnableAudioCompeting();
    117 
    118  /**
    119   * Any audio channel agent that starts playing should register itself to
    120   * this service, sharing the AudioChannel.
    121   */
    122  void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
    123                                 AudibleState aAudible);
    124 
    125  /**
    126   * Any audio channel agent that stops playing should unregister itself to
    127   * this service.
    128   */
    129  void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
    130 
    131  /**
    132   * Return the state to indicate this audioChannel for his window should keep
    133   * playing/muted/suspended.
    134   */
    135  AudioPlaybackConfig GetMediaConfig(nsPIDOMWindowOuter* aWindow) const;
    136 
    137  /**
    138   * Called this method when the audible state of the audio playback changed,
    139   * it would dispatch the playback event to observers which want to know the
    140   * actual audible state of the window.
    141   */
    142  void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible,
    143                           AudibleChangedReasons aReason);
    144 
    145  bool IsWindowActive(nsPIDOMWindowOuter* aWindow);
    146 
    147  void RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow, float aVolume,
    148                           bool aMuted);
    149 
    150  // This method needs to know the inner window that wants to capture audio. We
    151  // group agents per top outer window, but we can have multiple innerWindow per
    152  // top outerWindow (subiframes, etc.) and we have to identify all the agents
    153  // just for a particular innerWindow.
    154  void SetWindowAudioCaptured(nsPIDOMWindowOuter* aWindow,
    155                              uint64_t aInnerWindowID, bool aCapture);
    156 
    157  void NotifyResumingDelayedMedia(nsPIDOMWindowOuter* aWindow);
    158 
    159 private:
    160  AudioChannelService();
    161  ~AudioChannelService();
    162 
    163  void RefreshAgents(nsPIDOMWindowOuter* aWindow,
    164                     const std::function<void(AudioChannelAgent*)>& aFunc);
    165 
    166  void RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
    167                            nsSuspendedTypes aSuspend);
    168 
    169  static void CreateServiceIfNeeded();
    170 
    171  /**
    172   * Shutdown the singleton.
    173   */
    174  static void Shutdown();
    175 
    176  void RefreshAgentsAudioFocusChanged(AudioChannelAgent* aAgent);
    177 
    178  class AudioChannelWindow final {
    179   public:
    180    explicit AudioChannelWindow(uint64_t aWindowID)
    181        : mWindowID(aWindowID),
    182          mIsAudioCaptured(false),
    183          mShouldSendActiveMediaBlockStopEvent(false) {}
    184 
    185    void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible,
    186                             AudibleChangedReasons aReason);
    187 
    188    void AppendAgent(AudioChannelAgent* aAgent, AudibleState aAudible);
    189    void RemoveAgent(AudioChannelAgent* aAgent);
    190 
    191    void NotifyMediaBlockStop(nsPIDOMWindowOuter* aWindow);
    192 
    193    uint64_t mWindowID;
    194    bool mIsAudioCaptured;
    195    AudioPlaybackConfig mConfig;
    196 
    197    // Raw pointer because the AudioChannelAgent must unregister itself.
    198    nsTObserverArray<AudioChannelAgent*> mAgents;
    199    nsTObserverArray<AudioChannelAgent*> mAudibleAgents;
    200 
    201    // If we've dispatched "activeMediaBlockStart" event, we must dispatch
    202    // another event "activeMediablockStop" when the window is resumed from
    203    // suspend-block.
    204    bool mShouldSendActiveMediaBlockStopEvent;
    205 
    206   private:
    207    void AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
    208                                          AudibleChangedReasons aReason);
    209    void RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent,
    210                                       AudibleChangedReasons aReason);
    211 
    212    void AppendAgentAndIncreaseAgentsNum(AudioChannelAgent* aAgent);
    213    void RemoveAgentAndReduceAgentsNum(AudioChannelAgent* aAgent);
    214 
    215    bool IsFirstAudibleAgent() const;
    216    bool IsLastAudibleAgent() const;
    217 
    218    void NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
    219                                   AudibleState aAudible,
    220                                   AudibleChangedReasons aReason);
    221 
    222    void MaybeNotifyMediaBlockStart(AudioChannelAgent* aAgent);
    223  };
    224 
    225  AudioChannelWindow* GetOrCreateWindowData(nsPIDOMWindowOuter* aWindow);
    226 
    227  AudioChannelWindow* GetWindowData(uint64_t aWindowID) const;
    228 
    229  nsTObserverArray<UniquePtr<AudioChannelWindow>> mWindows;
    230 };
    231 
    232 const char* SuspendTypeToStr(const nsSuspendedTypes& aSuspend);
    233 
    234 }  // namespace mozilla::dom
    235 
    236 #endif