Line data Source code
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 "nsAutoPtr.h"
11 : #include "nsIObserver.h"
12 : #include "nsTObserverArray.h"
13 : #include "nsTArray.h"
14 :
15 : #include "AudioChannelAgent.h"
16 : #include "nsAttrValue.h"
17 : #include "mozilla/dom/AudioChannelBinding.h"
18 : #include "mozilla/Logging.h"
19 :
20 : #include <functional>
21 :
22 : class nsPIDOMWindowOuter;
23 : struct PRLogModuleInfo;
24 :
25 : namespace mozilla {
26 : namespace dom {
27 :
28 : #define NUMBER_OF_AUDIO_CHANNELS (uint32_t)AudioChannel::EndGuard_
29 :
30 : class AudioPlaybackConfig
31 : {
32 : public:
33 0 : AudioPlaybackConfig()
34 0 : : mVolume(1.0)
35 : , mMuted(false)
36 0 : , mSuspend(nsISuspendedTypes::NONE_SUSPENDED)
37 0 : {}
38 :
39 0 : AudioPlaybackConfig(float aVolume, bool aMuted, uint32_t aSuspended)
40 0 : : mVolume(aVolume)
41 : , mMuted(aMuted)
42 0 : , mSuspend(aSuspended)
43 0 : {}
44 :
45 0 : void SetConfig(float aVolume, bool aMuted, uint32_t aSuspended)
46 : {
47 0 : mVolume = aVolume;
48 0 : mMuted = aMuted;
49 0 : mSuspend = aSuspended;
50 0 : }
51 :
52 : float mVolume;
53 : bool mMuted;
54 : uint32_t mSuspend;
55 : };
56 :
57 : class AudioChannelService final : public nsIObserver
58 : {
59 : public:
60 : NS_DECL_ISUPPORTS
61 : NS_DECL_NSIOBSERVER
62 :
63 : /**
64 : * eNotAudible : agent is not audible
65 : * eMaybeAudible : agent is not audible now, but it might be audible later
66 : * eAudible : agent is audible now
67 : */
68 : enum AudibleState : uint8_t {
69 : eNotAudible = 0,
70 : eMaybeAudible = 1,
71 : eAudible = 2
72 : };
73 :
74 : enum AudioCaptureState : bool {
75 : eCapturing = true,
76 : eNotCapturing = false
77 : };
78 :
79 : enum AudibleChangedReasons : uint32_t {
80 : eVolumeChanged = 0,
81 : eDataAudibleChanged = 1,
82 : ePauseStateChanged = 2
83 : };
84 :
85 : /**
86 : * Returns the AudioChannelServce singleton.
87 : * If AudioChannelService doesn't exist, create and return new one.
88 : * Only to be called from main thread.
89 : */
90 : static already_AddRefed<AudioChannelService> GetOrCreate();
91 :
92 : /**
93 : * Returns the AudioChannelService singleton if one exists.
94 : * If AudioChannelService doesn't exist, returns null.
95 : */
96 : static already_AddRefed<AudioChannelService> Get();
97 :
98 : static LogModule* GetAudioChannelLog();
99 :
100 : static bool IsEnableAudioCompeting();
101 :
102 : /**
103 : * Any audio channel agent that starts playing should register itself to
104 : * this service, sharing the AudioChannel.
105 : */
106 : void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
107 : AudibleState aAudible);
108 :
109 : /**
110 : * Any audio channel agent that stops playing should unregister itself to
111 : * this service.
112 : */
113 : void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
114 :
115 : /**
116 : * Return the state to indicate this audioChannel for his window should keep
117 : * playing/muted/suspended.
118 : */
119 : AudioPlaybackConfig GetMediaConfig(nsPIDOMWindowOuter* aWindow,
120 : uint32_t aAudioChannel) const;
121 :
122 : /**
123 : * Called this method when the audible state of the audio playback changed,
124 : * it would dispatch the playback event to observers which want to know the
125 : * actual audible state of the window.
126 : */
127 : void AudioAudibleChanged(AudioChannelAgent* aAgent,
128 : AudibleState aAudible,
129 : AudibleChangedReasons aReason);
130 :
131 : bool IsWindowActive(nsPIDOMWindowOuter* aWindow);
132 :
133 : void RefreshAgentsVolume(nsPIDOMWindowOuter* aWindow);
134 : void RefreshAgentsSuspend(nsPIDOMWindowOuter* aWindow,
135 : nsSuspendedTypes aSuspend);
136 :
137 : // This method needs to know the inner window that wants to capture audio. We
138 : // group agents per top outer window, but we can have multiple innerWindow per
139 : // top outerWindow (subiframes, etc.) and we have to identify all the agents
140 : // just for a particular innerWindow.
141 : void SetWindowAudioCaptured(nsPIDOMWindowOuter* aWindow,
142 : uint64_t aInnerWindowID,
143 : bool aCapture);
144 :
145 : static const nsAttrValue::EnumTable* GetAudioChannelTable();
146 : static AudioChannel GetAudioChannel(const nsAString& aString);
147 : static AudioChannel GetDefaultAudioChannel();
148 :
149 : void NotifyMediaResumedFromBlock(nsPIDOMWindowOuter* aWindow);
150 :
151 : private:
152 : AudioChannelService();
153 : ~AudioChannelService();
154 :
155 : void RefreshAgents(nsPIDOMWindowOuter* aWindow,
156 : const std::function<void(AudioChannelAgent*)>& aFunc);
157 :
158 : static void CreateServiceIfNeeded();
159 :
160 : /**
161 : * Shutdown the singleton.
162 : */
163 : static void Shutdown();
164 :
165 : void RefreshAgentsAudioFocusChanged(AudioChannelAgent* aAgent);
166 :
167 : class AudioChannelConfig final : public AudioPlaybackConfig
168 : {
169 : public:
170 0 : AudioChannelConfig()
171 0 : : AudioPlaybackConfig(1.0, false, nsISuspendedTypes::NONE_SUSPENDED)
172 0 : , mNumberOfAgents(0)
173 0 : {}
174 :
175 : uint32_t mNumberOfAgents;
176 : };
177 :
178 0 : class AudioChannelWindow final
179 : {
180 : public:
181 0 : explicit AudioChannelWindow(uint64_t aWindowID)
182 0 : : mWindowID(aWindowID)
183 : , mIsAudioCaptured(false)
184 0 : , mOwningAudioFocus(!AudioChannelService::IsEnableAudioCompeting())
185 0 : , mShouldSendActiveMediaBlockStopEvent(false)
186 0 : {}
187 :
188 : void AudioFocusChanged(AudioChannelAgent* aNewPlayingAgent);
189 : void AudioAudibleChanged(AudioChannelAgent* aAgent,
190 : AudibleState aAudible,
191 : AudibleChangedReasons aReason);
192 :
193 : void AppendAgent(AudioChannelAgent* aAgent, AudibleState aAudible);
194 : void RemoveAgent(AudioChannelAgent* aAgent);
195 :
196 : void NotifyMediaBlockStop(nsPIDOMWindowOuter* aWindow);
197 :
198 : uint64_t mWindowID;
199 : bool mIsAudioCaptured;
200 : AudioChannelConfig mChannels[NUMBER_OF_AUDIO_CHANNELS];
201 :
202 : // Raw pointer because the AudioChannelAgent must unregister itself.
203 : nsTObserverArray<AudioChannelAgent*> mAgents;
204 : nsTObserverArray<AudioChannelAgent*> mAudibleAgents;
205 :
206 : // Owning audio focus when the window starts playing audible sound, and
207 : // lose audio focus when other windows starts playing.
208 : bool mOwningAudioFocus;
209 :
210 : // If we've dispatched "activeMediaBlockStart" event, we must dispatch
211 : // another event "activeMediablockStop" when the window is resumed from
212 : // suspend-block.
213 : bool mShouldSendActiveMediaBlockStopEvent;
214 : private:
215 : void AudioCapturedChanged(AudioChannelAgent* aAgent,
216 : AudioCaptureState aCapture);
217 :
218 : void AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent,
219 : AudibleChangedReasons aReason);
220 : void RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent,
221 : AudibleChangedReasons aReason);
222 :
223 : void AppendAgentAndIncreaseAgentsNum(AudioChannelAgent* aAgent);
224 : void RemoveAgentAndReduceAgentsNum(AudioChannelAgent* aAgent);
225 :
226 : bool IsFirstAudibleAgent() const;
227 : bool IsLastAudibleAgent() const;
228 :
229 : void NotifyAudioAudibleChanged(nsPIDOMWindowOuter* aWindow,
230 : AudibleState aAudible,
231 : AudibleChangedReasons aReason);
232 :
233 : void NotifyChannelActive(uint64_t aWindowID, bool aActive);
234 : void MaybeNotifyMediaBlockStart(AudioChannelAgent* aAgent);
235 :
236 : void RequestAudioFocus(AudioChannelAgent* aAgent);
237 :
238 : // We need to do audio competing only when the new incoming agent started.
239 : void NotifyAudioCompetingChanged(AudioChannelAgent* aAgent);
240 :
241 : uint32_t GetCompetingBehavior(AudioChannelAgent* aAgent,
242 : int32_t aIncomingChannelType) const;
243 : bool IsAgentInvolvingInAudioCompeting(AudioChannelAgent* aAgent) const;
244 : bool IsAudioCompetingInSameTab() const;
245 : bool IsContainingPlayingAgent(AudioChannelAgent* aAgent) const;
246 :
247 : bool IsInactiveWindow() const;
248 : };
249 :
250 : AudioChannelWindow*
251 : GetOrCreateWindowData(nsPIDOMWindowOuter* aWindow);
252 :
253 : AudioChannelWindow*
254 : GetWindowData(uint64_t aWindowID) const;
255 :
256 : nsTObserverArray<nsAutoPtr<AudioChannelWindow>> mWindows;
257 : };
258 :
259 : const char* SuspendTypeToStr(const nsSuspendedTypes& aSuspend);
260 : const char* AudibleStateToStr(const AudioChannelService::AudibleState& aAudible);
261 : const char* AudibleChangedReasonToStr(const AudioChannelService::AudibleChangedReasons& aReason);
262 :
263 : } // namespace dom
264 : } // namespace mozilla
265 :
266 : #endif
|