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
,
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
26 return aIsAudible
? AudibleState::eAudible
: AudibleState::eMaybeAudible
;
29 ResumeDelayedPlaybackAgent::~ResumeDelayedPlaybackAgent() {
36 bool ResumeDelayedPlaybackAgent::InitDelegate(const HTMLMediaElement
* aElement
,
38 MOZ_ASSERT(!mDelegate
, "Delegate has been initialized!");
39 mDelegate
= new ResumePlayDelegate();
40 if (!mDelegate
->Init(aElement
, aIsAudible
)) {
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
) {
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
) {
71 if (!aElement
->OwnerDoc()->GetInnerWindow()) {
75 MOZ_ASSERT(!mAudioChannelAgent
);
76 mAudioChannelAgent
= new AudioChannelAgent();
78 mAudioChannelAgent
->Init(aElement
->OwnerDoc()->GetInnerWindow(), this);
79 if (NS_WARN_IF(NS_FAILED(rv
))) {
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
))) {
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
) {
117 AudibleState audibleState
= DetermineMediaAudibleState(aElement
, aIsAudible
);
118 mAudioChannelAgent
->NotifyStartedAudible(
120 AudioChannelService::AudibleChangedReasons::eDataAudibleChanged
);
124 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowVolumeChanged(
125 float aVolume
, bool aMuted
) {
130 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowAudioCaptureChanged(
136 ResumeDelayedPlaybackAgent::ResumePlayDelegate::WindowSuspendChanged(
137 SuspendTypes aSuspend
) {
138 if (aSuspend
== nsISuspendedTypes::NONE_SUSPENDED
) {
139 mPromise
.ResolveIfExists(true, __func__
);
145 bool MediaPlaybackDelayPolicy::ShouldDelayPlayback(
146 const HTMLMediaElement
* aElement
) {
147 MOZ_ASSERT(aElement
);
148 if (!StaticPrefs::media_block_autoplay_until_in_foreground()) {
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