Backed out changeset 9d8b4c0b99ed (bug 1945683) for causing btime failures. CLOSED...
[gecko.git] / dom / audiochannel / AudioChannelAgent.cpp
blob924e983a82bb35e69c9e50cbd2f506622bc69267
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "AudioChannelAgent.h"
7 #include "AudioChannelService.h"
8 #include "mozilla/Preferences.h"
9 #include "mozilla/dom/Document.h"
10 #include "nsContentUtils.h"
11 #include "nsPIDOMWindow.h"
13 using namespace mozilla::dom;
15 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioChannelAgent)
17 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioChannelAgent)
18 tmp->Shutdown();
19 NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
20 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
21 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
23 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioChannelAgent)
24 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
25 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioChannelAgent)
29 NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgent)
30 NS_INTERFACE_MAP_ENTRY(nsISupports)
31 NS_INTERFACE_MAP_END
33 NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioChannelAgent)
34 NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgent)
36 AudioChannelAgent::AudioChannelAgent()
37 : mInnerWindowID(0), mIsRegToService(false) {
38 // Init service in the begining, it can help us to know whether there is any
39 // created media component via AudioChannelService::IsServiceStarted().
40 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
43 AudioChannelAgent::~AudioChannelAgent() { Shutdown(); }
45 void AudioChannelAgent::Shutdown() {
46 if (mIsRegToService) {
47 NotifyStoppedPlaying();
51 NS_IMETHODIMP
52 AudioChannelAgent::Init(mozIDOMWindow* aWindow,
53 nsIAudioChannelAgentCallback* aCallback) {
54 return InitInternal(nsPIDOMWindowInner::From(aWindow), aCallback,
55 /* useWeakRef = */ false);
58 NS_IMETHODIMP
59 AudioChannelAgent::InitWithWeakCallback(
60 mozIDOMWindow* aWindow, nsIAudioChannelAgentCallback* aCallback) {
61 return InitInternal(nsPIDOMWindowInner::From(aWindow), aCallback,
62 /* useWeakRef = */ true);
65 nsresult AudioChannelAgent::FindCorrectWindow(nsPIDOMWindowInner* aWindow) {
66 mWindow = aWindow->GetInProcessScriptableTop();
67 if (NS_WARN_IF(!mWindow)) {
68 return NS_OK;
71 // From here we do an hack for nested iframes.
72 // The system app doesn't have access to the nested iframe objects so it
73 // cannot control the volume of the agents running in nested apps. What we do
74 // here is to assign those Agents to the top scriptable window of the parent
75 // iframe (what is controlled by the system app).
76 // For doing this we go recursively back into the chain of windows until we
77 // find apps that are not the system one.
78 nsCOMPtr<nsPIDOMWindowOuter> outerParent = mWindow->GetInProcessParent();
79 if (!outerParent || outerParent == mWindow) {
80 return NS_OK;
83 nsCOMPtr<nsPIDOMWindowInner> parent = outerParent->GetCurrentInnerWindow();
84 if (!parent) {
85 return NS_OK;
88 nsCOMPtr<Document> doc = parent->GetExtantDoc();
89 if (!doc) {
90 return NS_OK;
93 if (nsContentUtils::IsChromeDoc(doc)) {
94 return NS_OK;
97 return FindCorrectWindow(parent);
100 nsresult AudioChannelAgent::InitInternal(
101 nsPIDOMWindowInner* aWindow, nsIAudioChannelAgentCallback* aCallback,
102 bool aUseWeakRef) {
103 if (NS_WARN_IF(!aWindow)) {
104 return NS_ERROR_FAILURE;
107 mInnerWindowID = aWindow->WindowID();
109 nsresult rv = FindCorrectWindow(aWindow);
110 if (NS_WARN_IF(NS_FAILED(rv))) {
111 return rv;
114 if (aUseWeakRef) {
115 mWeakCallback = do_GetWeakReference(aCallback);
116 } else {
117 mCallback = aCallback;
120 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
121 ("AudioChannelAgent, InitInternal, this = %p, "
122 "owner = %p, hasCallback = %d\n",
123 this, mWindow.get(), (!!mCallback || !!mWeakCallback)));
125 return NS_OK;
128 void AudioChannelAgent::PullInitialUpdate() {
129 RefPtr<AudioChannelService> service = AudioChannelService::Get();
130 MOZ_ASSERT(service);
131 MOZ_ASSERT(mIsRegToService);
133 AudioPlaybackConfig config = service->GetMediaConfig(mWindow);
134 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
135 ("AudioChannelAgent, PullInitialUpdate, this=%p, "
136 "mute=%s, volume=%f, suspend=%s, audioCapturing=%s\n",
137 this, config.mMuted ? "true" : "false", config.mVolume,
138 SuspendTypeToStr(config.mSuspend),
139 config.mCapturedAudio ? "true" : "false"));
140 WindowVolumeChanged(config.mVolume, config.mMuted);
141 WindowSuspendChanged(config.mSuspend);
142 WindowAudioCaptureChanged(InnerWindowID(), config.mCapturedAudio);
145 NS_IMETHODIMP
146 AudioChannelAgent::NotifyStartedPlaying(uint8_t aAudible) {
147 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
148 if (service == nullptr || mIsRegToService) {
149 return NS_ERROR_FAILURE;
152 MOZ_ASSERT(AudioChannelService::AudibleState::eNotAudible == 0 &&
153 AudioChannelService::AudibleState::eMaybeAudible == 1 &&
154 AudioChannelService::AudibleState::eAudible == 2);
155 service->RegisterAudioChannelAgent(
156 this, static_cast<AudioChannelService::AudibleState>(aAudible));
158 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
159 ("AudioChannelAgent, NotifyStartedPlaying, this = %p, audible = %s\n",
160 this,
161 AudioChannelService::EnumValueToString(
162 static_cast<AudioChannelService::AudibleState>(aAudible))));
164 mIsRegToService = true;
165 return NS_OK;
168 NS_IMETHODIMP
169 AudioChannelAgent::NotifyStoppedPlaying() {
170 if (!mIsRegToService) {
171 return NS_ERROR_FAILURE;
174 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
175 ("AudioChannelAgent, NotifyStoppedPlaying, this = %p\n", this));
177 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
178 if (service) {
179 service->UnregisterAudioChannelAgent(this);
182 mIsRegToService = false;
183 return NS_OK;
186 NS_IMETHODIMP
187 AudioChannelAgent::NotifyStartedAudible(uint8_t aAudible, uint32_t aReason) {
188 MOZ_LOG(
189 AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
190 ("AudioChannelAgent, NotifyStartedAudible, this = %p, "
191 "audible = %s, reason = %s\n",
192 this,
193 AudioChannelService::EnumValueToString(
194 static_cast<AudioChannelService::AudibleState>(aAudible)),
195 AudioChannelService::EnumValueToString(
196 static_cast<AudioChannelService::AudibleChangedReasons>(aReason))));
198 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
199 if (NS_WARN_IF(!service)) {
200 return NS_ERROR_FAILURE;
203 service->AudioAudibleChanged(
204 this, static_cast<AudioChannelService::AudibleState>(aAudible),
205 static_cast<AudioChannelService::AudibleChangedReasons>(aReason));
206 return NS_OK;
209 already_AddRefed<nsIAudioChannelAgentCallback>
210 AudioChannelAgent::GetCallback() {
211 nsCOMPtr<nsIAudioChannelAgentCallback> callback = mCallback;
212 if (!callback) {
213 callback = do_QueryReferent(mWeakCallback);
215 return callback.forget();
218 void AudioChannelAgent::WindowVolumeChanged(float aVolume, bool aMuted) {
219 nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
220 if (!callback) {
221 return;
224 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
225 ("AudioChannelAgent, WindowVolumeChanged, this = %p, mute = %s, "
226 "volume = %f\n",
227 this, aMuted ? "true" : "false", aVolume));
228 callback->WindowVolumeChanged(aVolume, aMuted);
231 void AudioChannelAgent::WindowSuspendChanged(nsSuspendedTypes aSuspend) {
232 nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
233 if (!callback) {
234 return;
237 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
238 ("AudioChannelAgent, WindowSuspendChanged, this = %p, "
239 "suspended = %s\n",
240 this, SuspendTypeToStr(aSuspend)));
241 callback->WindowSuspendChanged(aSuspend);
244 AudioPlaybackConfig AudioChannelAgent::GetMediaConfig() const {
245 RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
246 AudioPlaybackConfig config(1.0, false, nsISuspendedTypes::NONE_SUSPENDED);
247 if (service) {
248 config = service->GetMediaConfig(mWindow);
250 return config;
253 uint64_t AudioChannelAgent::WindowID() const {
254 return mWindow ? mWindow->WindowID() : 0;
257 uint64_t AudioChannelAgent::InnerWindowID() const { return mInnerWindowID; }
259 void AudioChannelAgent::WindowAudioCaptureChanged(uint64_t aInnerWindowID,
260 bool aCapture) {
261 if (aInnerWindowID != mInnerWindowID) {
262 return;
265 nsCOMPtr<nsIAudioChannelAgentCallback> callback = GetCallback();
266 if (!callback) {
267 return;
270 MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
271 ("AudioChannelAgent, WindowAudioCaptureChanged, this = %p, "
272 "capture = %d\n",
273 this, aCapture));
275 callback->WindowAudioCaptureChanged(aCapture);
278 bool AudioChannelAgent::IsWindowAudioCapturingEnabled() const {
279 return GetMediaConfig().mCapturedAudio;
282 bool AudioChannelAgent::IsPlayingStarted() const { return mIsRegToService; }