no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / media / MediaPlaybackDelayPolicy.cpp
blob1ac326db7c21c575298c678251c2d1484294171d
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "MediaPlaybackDelayPolicy.h"
8 #include "nsPIDOMWindow.h"
9 #include "mozilla/dom/Document.h"
10 #include "mozilla/dom/HTMLMediaElement.h"
11 #include "mozilla/StaticPrefs_media.h"
13 namespace mozilla::dom {
15 using AudibleState = AudioChannelService::AudibleState;
17 static AudibleState DetermineMediaAudibleState(const HTMLMediaElement* aElement,
18 bool aIsAudible) {
19 MOZ_ASSERT(aElement);
20 if (!aElement->HasAudio()) {
21 return AudibleState::eNotAudible;
23 // `eMaybeAudible` is used to distinguish if the media has audio track or not,
24 // because we would only show the delayed media playback icon for media with
25 // an audio track.
26 return aIsAudible ? AudibleState::eAudible : AudibleState::eMaybeAudible;
29 ResumeDelayedPlaybackAgent::~ResumeDelayedPlaybackAgent() {
30 if (mDelegate) {
31 mDelegate->Clear();
32 mDelegate = nullptr;
36 bool ResumeDelayedPlaybackAgent::InitDelegate(const HTMLMediaElement* aElement,
37 bool aIsAudible) {
38 MOZ_ASSERT(!mDelegate, "Delegate has been initialized!");
39 mDelegate = new ResumePlayDelegate();
40 if (!mDelegate->Init(aElement, aIsAudible)) {
41 mDelegate->Clear();
42 mDelegate = nullptr;
43 return false;
45 return true;
48 RefPtr<ResumeDelayedPlaybackAgent::ResumePromise>
49 ResumeDelayedPlaybackAgent::GetResumePromise() {
50 MOZ_ASSERT(mDelegate);
51 return mDelegate->GetResumePromise();
54 void ResumeDelayedPlaybackAgent::UpdateAudibleState(
55 const HTMLMediaElement* aElement, bool aIsAudible) {
56 MOZ_ASSERT(aElement);
57 MOZ_ASSERT(mDelegate);
58 mDelegate->UpdateAudibleState(aElement, aIsAudible);
61 NS_IMPL_ISUPPORTS(ResumeDelayedPlaybackAgent::ResumePlayDelegate,
62 nsIAudioChannelAgentCallback)
64 ResumeDelayedPlaybackAgent::ResumePlayDelegate::~ResumePlayDelegate() {
65 MOZ_ASSERT(!mAudioChannelAgent);
68 bool ResumeDelayedPlaybackAgent::ResumePlayDelegate::Init(
69 const HTMLMediaElement* aElement, bool aIsAudible) {
70 MOZ_ASSERT(aElement);
71 if (!aElement->OwnerDoc()->GetInnerWindow()) {
72 return false;
75 MOZ_ASSERT(!mAudioChannelAgent);
76 mAudioChannelAgent = new AudioChannelAgent();
77 nsresult rv =
78 mAudioChannelAgent->Init(aElement->OwnerDoc()->GetInnerWindow(), this);
79 if (NS_WARN_IF(NS_FAILED(rv))) {
80 Clear();
81 return false;
84 // Start AudioChannelAgent in order to wait the suspended state change when we
85 // are able to resume delayed playback.
86 AudibleState audibleState = DetermineMediaAudibleState(aElement, aIsAudible);
87 rv = mAudioChannelAgent->NotifyStartedPlaying(audibleState);
88 if (NS_WARN_IF(NS_FAILED(rv))) {
89 Clear();
90 return false;
93 return true;
96 void ResumeDelayedPlaybackAgent::ResumePlayDelegate::Clear() {
97 if (mAudioChannelAgent) {
98 mAudioChannelAgent->NotifyStoppedPlaying();
99 mAudioChannelAgent = nullptr;
101 mPromise.RejectIfExists(true, __func__);
104 RefPtr<ResumeDelayedPlaybackAgent::ResumePromise>
105 ResumeDelayedPlaybackAgent::ResumePlayDelegate::GetResumePromise() {
106 return mPromise.Ensure(__func__);
109 void ResumeDelayedPlaybackAgent::ResumePlayDelegate::UpdateAudibleState(
110 const HTMLMediaElement* aElement, bool aIsAudible) {
111 MOZ_ASSERT(aElement);
112 // It's possible for the owner of `ResumeDelayedPlaybackAgent` to call
113 // `UpdateAudibleState()` after we resolve the promise and clean resource.
114 if (!mAudioChannelAgent) {
115 return;
117 AudibleState audibleState = DetermineMediaAudibleState(aElement, aIsAudible);
118 mAudioChannelAgent->NotifyStartedAudible(
119 audibleState,
120 AudioChannelService::AudibleChangedReasons::eDataAudibleChanged);
123 NS_IMETHODIMP
124 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowVolumeChanged(
125 float aVolume, bool aMuted) {
126 return NS_OK;
129 NS_IMETHODIMP
130 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowAudioCaptureChanged(
131 bool aCapture) {
132 return NS_OK;
135 NS_IMETHODIMP
136 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowSuspendChanged(
137 SuspendTypes aSuspend) {
138 if (aSuspend == nsISuspendedTypes::NONE_SUSPENDED) {
139 mPromise.ResolveIfExists(true, __func__);
140 Clear();
142 return NS_OK;
145 bool MediaPlaybackDelayPolicy::ShouldDelayPlayback(
146 const HTMLMediaElement* aElement) {
147 MOZ_ASSERT(aElement);
148 if (!StaticPrefs::media_block_autoplay_until_in_foreground()) {
149 return false;
152 const Document* doc = aElement->OwnerDoc();
153 nsPIDOMWindowInner* inner = nsPIDOMWindowInner::From(doc->GetInnerWindow());
154 nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::GetFromCurrentInner(inner);
155 return outer && outer->ShouldDelayMediaFromStart();
158 RefPtr<ResumeDelayedPlaybackAgent>
159 MediaPlaybackDelayPolicy::CreateResumeDelayedPlaybackAgent(
160 const HTMLMediaElement* aElement, bool aIsAudible) {
161 MOZ_ASSERT(aElement);
162 RefPtr<ResumeDelayedPlaybackAgent> agent = new ResumeDelayedPlaybackAgent();
163 return agent->InitDelegate(aElement, aIsAudible) ? agent : nullptr;
166 } // namespace mozilla::dom