Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / dom / audiochannel / AudioChannelService.h
blobbf7fa387e275ac6d79bbfe77dc814bb8b471ced3
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/. */
7 #ifndef mozilla_dom_audiochannelservice_h__
8 #define mozilla_dom_audiochannelservice_h__
10 #include "nsIObserver.h"
11 #include "nsTObserverArray.h"
12 #include "nsTArray.h"
14 #include "AudioChannelAgent.h"
15 #include "nsAttrValue.h"
16 #include "mozilla/Logging.h"
17 #include "mozilla/UniquePtr.h"
19 #include <functional>
21 class nsPIDOMWindowOuter;
22 struct PRLogModuleInfo;
24 namespace mozilla::dom {
26 class AudioPlaybackConfig {
27 public:
28 AudioPlaybackConfig()
29 : mVolume(1.0),
30 mMuted(false),
31 mSuspend(nsISuspendedTypes::NONE_SUSPENDED),
32 mNumberOfAgents(0) {}
34 AudioPlaybackConfig(float aVolume, bool aMuted, uint32_t aSuspended)
35 : mVolume(aVolume),
36 mMuted(aMuted),
37 mSuspend(aSuspended),
38 mNumberOfAgents(0) {}
40 float mVolume;
41 bool mMuted;
42 uint32_t mSuspend;
43 bool mCapturedAudio = false;
44 uint32_t mNumberOfAgents;
47 class AudioChannelService final : public nsIObserver {
48 public:
49 NS_DECL_ISUPPORTS
50 NS_DECL_NSIOBSERVER
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.
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.
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.
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.
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.
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.
86 * ---------------------------------------------------------------------------
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
92 enum AudibleState : uint8_t {
93 eNotAudible = 0,
94 eMaybeAudible = 1,
95 eAudible = 2
98 enum AudioCaptureState : bool { eCapturing = true, eNotCapturing = false };
100 enum AudibleChangedReasons : uint32_t {
101 eVolumeChanged = 0,
102 eDataAudibleChanged = 1,
103 ePauseStateChanged = 2
107 * Returns the AudioChannelServce singleton.
108 * If AudioChannelService doesn't exist, create and return new one.
109 * Only to be called from main thread.
111 static already_AddRefed<AudioChannelService> GetOrCreate();
114 * Returns the AudioChannelService singleton if one exists.
115 * If AudioChannelService doesn't exist, returns null.
117 static already_AddRefed<AudioChannelService> Get();
119 static LogModule* GetAudioChannelLog();
121 static bool IsEnableAudioCompeting();
124 * Any audio channel agent that starts playing should register itself to
125 * this service, sharing the AudioChannel.
127 void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
128 AudibleState aAudible);
131 * Any audio channel agent that stops playing should unregister itself to
132 * this service.
134 void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
137 * Return the state to indicate this audioChannel for his window should keep
138 * playing/muted/suspended.
140 AudioPlaybackConfig GetMediaConfig(nsPIDOMWindowOuter* aWindow) const;
143 * Called this method when the audible state of the audio playback changed,
144 * it would dispatch the playback event to observers which want to know the
145 * actual audible state of the window.
147 void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible,
148 AudibleChangedReasons aReason);
150 bool IsWindowActive(nsPIDOMWindowOuter* aWindow);
152 void RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow, float aVolume,
153 bool aMuted);
155 // This method needs to know the inner window that wants to capture audio. We
156 // group agents per top outer window, but we can have multiple innerWindow per
157 // top outerWindow (subiframes, etc.) and we have to identify all the agents
158 // just for a particular innerWindow.
159 void SetWindowAudioCaptured(nsPIDOMWindowOuter* aWindow,
160 uint64_t aInnerWindowID, bool aCapture);
162 void NotifyResumingDelayedMedia(nsPIDOMWindowOuter* aWindow);
164 private:
165 AudioChannelService();
166 ~AudioChannelService();
168 void RefreshAgents(nsPIDOMWindowOuter* aWindow,
169 const std::function<void(AudioChannelAgent*)>& aFunc);
171 void RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
172 nsSuspendedTypes aSuspend);
174 static void CreateServiceIfNeeded();
177 * Shutdown the singleton.
179 static void Shutdown();
181 void RefreshAgentsAudioFocusChanged(AudioChannelAgent* aAgent);
183 class AudioChannelWindow final {
184 public:
185 explicit AudioChannelWindow(uint64_t aWindowID)
186 : mWindowID(aWindowID),
187 mIsAudioCaptured(false),
188 mShouldSendActiveMediaBlockStopEvent(false) {}
190 void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible,
191 AudibleChangedReasons aReason);
193 void AppendAgent(AudioChannelAgent* aAgent, AudibleState aAudible);
194 void RemoveAgent(AudioChannelAgent* aAgent);
196 void NotifyMediaBlockStop(nsPIDOMWindowOuter* aWindow);
198 uint64_t mWindowID;
199 bool mIsAudioCaptured;
200 AudioPlaybackConfig mConfig;
202 // Raw pointer because the AudioChannelAgent must unregister itself.
203 nsTObserverArray<AudioChannelAgent*> mAgents;
204 nsTObserverArray<AudioChannelAgent*> mAudibleAgents;
206 // If we've dispatched "activeMediaBlockStart" event, we must dispatch
207 // another event "activeMediablockStop" when the window is resumed from
208 // suspend-block.
209 bool mShouldSendActiveMediaBlockStopEvent;
211 private:
212 void AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
213 AudibleChangedReasons aReason);
214 void RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent,
215 AudibleChangedReasons aReason);
217 void AppendAgentAndIncreaseAgentsNum(AudioChannelAgent* aAgent);
218 void RemoveAgentAndReduceAgentsNum(AudioChannelAgent* aAgent);
220 bool IsFirstAudibleAgent() const;
221 bool IsLastAudibleAgent() const;
223 void NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
224 AudibleState aAudible,
225 AudibleChangedReasons aReason);
227 void MaybeNotifyMediaBlockStart(AudioChannelAgent* aAgent);
230 AudioChannelWindow* GetOrCreateWindowData(nsPIDOMWindowOuter* aWindow);
232 AudioChannelWindow* GetWindowData(uint64_t aWindowID) const;
234 nsTObserverArray<UniquePtr<AudioChannelWindow>> mWindows;
237 const char* SuspendTypeToStr(const nsSuspendedTypes& aSuspend);
238 const char* AudibleStateToStr(
239 const AudioChannelService::AudibleState& aAudible);
240 const char* AudibleChangedReasonToStr(
241 const AudioChannelService::AudibleChangedReasons& aReason);
243 } // namespace mozilla::dom
245 #endif