зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1463919 - Move ask autoplay permission check into AutoplayPolicy. r=jya
MozReview-Commit-ID: KJcVI6gtGXw --HG-- extra : rebase_source : a2ccd2da32d77708fdeb6ea6361975a7759cb18d extra : source : 9b1c40f3e61ab351707f2d320ce8f87951e4868e
This commit is contained in:
Родитель
b309d364b6
Коммит
ea95e39bc9
|
@ -1998,7 +1998,7 @@ HTMLMediaElement::Load()
|
|||
HasSourceChildren(this),
|
||||
EventStateManager::IsHandlingUserInput(),
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay),
|
||||
IsAllowedToPlay(),
|
||||
AutoplayPolicy::IsAllowedToPlay(*this) == Authorization::Allowed,
|
||||
OwnerDoc(),
|
||||
DocumentOrigin(OwnerDoc()).get(),
|
||||
OwnerDoc() ? OwnerDoc()->HasBeenUserGestureActivated() : 0,
|
||||
|
@ -2520,7 +2520,7 @@ HTMLMediaElement::UpdatePreloadAction()
|
|||
PreloadAction nextAction = PRELOAD_UNDEFINED;
|
||||
// If autoplay is set, or we're playing, we should always preload data,
|
||||
// as we'll need it to play.
|
||||
if ((AutoplayPolicy::IsMediaElementAllowedToPlay(WrapNotNull(this)) &&
|
||||
if ((AutoplayPolicy::IsAllowedToPlay(*this) == Authorization::Allowed &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) ||
|
||||
!mPaused) {
|
||||
nextAction = HTMLMediaElement::PRELOAD_ENOUGH;
|
||||
|
@ -3053,7 +3053,7 @@ HTMLMediaElement::PauseIfShouldNotBePlaying()
|
|||
if (GetPaused()) {
|
||||
return;
|
||||
}
|
||||
if (!AutoplayPolicy::IsMediaElementAllowedToPlay(WrapNotNull(this))) {
|
||||
if (AutoplayPolicy::IsAllowedToPlay(*this) != Authorization::Allowed) {
|
||||
ErrorResult rv;
|
||||
Pause(rv);
|
||||
}
|
||||
|
@ -4053,26 +4053,32 @@ HTMLMediaElement::Play(ErrorResult& aRv)
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
const bool handlingUserInput = EventStateManager::IsHandlingUserInput();
|
||||
if (IsAllowedToPlay()) {
|
||||
mPendingPlayPromises.AppendElement(promise);
|
||||
PlayInternal(handlingUserInput);
|
||||
UpdateCustomPolicyAfterPlayed();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Otherwise, not allowed to play. We may still be allowed to play if we
|
||||
// ask for and are granted permission by the user.
|
||||
|
||||
if (!Preferences::GetBool("media.autoplay.ask-permission", false)) {
|
||||
LOG(LogLevel::Debug, ("%p play not allowed and prompting disabled.", this));
|
||||
if (AudioChannelAgentBlockedPlay()) {
|
||||
LOG(LogLevel::Debug, ("%p play blocked by AudioChannelAgent.", this));
|
||||
promise->MaybeReject(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// Prompt the user for permission to play.
|
||||
mPendingPlayPromises.AppendElement(promise);
|
||||
EnsureAutoplayRequested(handlingUserInput);
|
||||
const bool handlingUserInput = EventStateManager::IsHandlingUserInput();
|
||||
switch (AutoplayPolicy::IsAllowedToPlay(*this)) {
|
||||
case Authorization::Allowed: {
|
||||
mPendingPlayPromises.AppendElement(promise);
|
||||
PlayInternal(handlingUserInput);
|
||||
UpdateCustomPolicyAfterPlayed();
|
||||
break;
|
||||
}
|
||||
case Authorization::Blocked: {
|
||||
LOG(LogLevel::Debug, ("%p play not blocked.", this));
|
||||
promise->MaybeReject(NS_ERROR_DOM_MEDIA_NOT_ALLOWED_ERR);
|
||||
break;
|
||||
}
|
||||
case Authorization::Prompt: {
|
||||
// Prompt the user for permission to play.
|
||||
mPendingPlayPromises.AppendElement(promise);
|
||||
EnsureAutoplayRequested(handlingUserInput);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -4089,8 +4095,7 @@ HTMLMediaElement::EnsureAutoplayRequested(bool aHandlingUserInput)
|
|||
return;
|
||||
}
|
||||
|
||||
RefPtr<AutoplayRequest> request =
|
||||
AutoplayPolicy::RequestFor(WrapNotNull(OwnerDoc()));
|
||||
RefPtr<AutoplayRequest> request = AutoplayPolicy::RequestFor(*OwnerDoc());
|
||||
if (!request) {
|
||||
AsyncRejectPendingPlayPromises(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
|
@ -6114,7 +6119,8 @@ HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
|||
DispatchAsyncEvent(NS_LITERAL_STRING("canplay"));
|
||||
if (!mPaused) {
|
||||
if (mDecoder && !mPausedForInactiveDocumentOrChannel) {
|
||||
MOZ_ASSERT(IsAllowedToPlay());
|
||||
MOZ_ASSERT(AutoplayPolicy::IsAllowedToPlay(*this) ==
|
||||
Authorization::Allowed);
|
||||
mDecoder->Play();
|
||||
}
|
||||
NotifyAboutPlaying();
|
||||
|
@ -7017,48 +7023,22 @@ HTMLMediaElement::UpdateAudioChannelPlayingState(bool aForcePlaying)
|
|||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::IsAllowedToPlay()
|
||||
HTMLMediaElement::AudioChannelAgentBlockedPlay()
|
||||
{
|
||||
if (!AutoplayPolicy::IsMediaElementAllowedToPlay(WrapNotNull(this))) {
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
nsContentUtils::DispatchChromeEvent(
|
||||
OwnerDoc(),
|
||||
static_cast<nsIContent*>(this),
|
||||
NS_LITERAL_STRING("MozAutoplayMediaBlocked"),
|
||||
CanBubble::eNo,
|
||||
Cancelable::eNo);
|
||||
#endif
|
||||
if (!mAudioChannelWrapper) {
|
||||
// If the mAudioChannelWrapper doesn't exist that means the CC happened.
|
||||
LOG(LogLevel::Debug,
|
||||
("%p %s AutoplayPolicy blocked autoplay.", this, __func__));
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(LogLevel::Debug,
|
||||
("%p %s AutoplayPolicy did not block autoplay.", this, __func__));
|
||||
|
||||
// Check our custom playback policy.
|
||||
if (mAudioChannelWrapper) {
|
||||
// Note: SUSPENDED_PAUSE and SUSPENDED_BLOCK will be merged into one single
|
||||
// state.
|
||||
if (mAudioChannelWrapper->GetSuspendType() ==
|
||||
nsISuspendedTypes::SUSPENDED_PAUSE ||
|
||||
mAudioChannelWrapper->GetSuspendType() ==
|
||||
nsISuspendedTypes::SUSPENDED_BLOCK) {
|
||||
LOG(LogLevel::Debug,
|
||||
("%p IsAllowedToPlay() returning false due to AudioChannelAgent.",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(LogLevel::Debug, ("%p IsAllowedToPlay() returning true.", this));
|
||||
("%p AudioChannelAgentBlockedPlay() returning true due to null "
|
||||
"AudioChannelAgent.",
|
||||
this));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the mAudioChannelWrapper doesn't exist that means the CC happened.
|
||||
LOG(LogLevel::Debug,
|
||||
("%p IsAllowedToPlay() returning false due to null AudioChannelAgent.",
|
||||
this));
|
||||
return false;
|
||||
// Note: SUSPENDED_PAUSE and SUSPENDED_BLOCK will be merged into one single
|
||||
// state.
|
||||
const auto suspendType = mAudioChannelWrapper->GetSuspendType();
|
||||
return suspendType == nsISuspendedTypes::SUSPENDED_PAUSE ||
|
||||
suspendType == nsISuspendedTypes::SUSPENDED_BLOCK;
|
||||
}
|
||||
|
||||
static const char*
|
||||
|
|
|
@ -1284,7 +1284,7 @@ protected:
|
|||
void AudioCaptureStreamChange(bool aCapture);
|
||||
|
||||
// A method to check whether the media element is allowed to start playback.
|
||||
bool IsAllowedToPlay();
|
||||
bool AudioChannelAgentBlockedPlay();
|
||||
|
||||
// If the network state is empty and then we would trigger DoLoad().
|
||||
void MaybeDoLoad();
|
||||
|
|
|
@ -40,7 +40,7 @@ ApproverDocOf(const nsIDocument& aDocument)
|
|||
}
|
||||
|
||||
static bool
|
||||
IsAllowedToPlay(nsPIDOMWindowInner* aWindow)
|
||||
IsWindowAllowedToPlay(nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
if (!aWindow) {
|
||||
return false;
|
||||
|
@ -88,31 +88,36 @@ AutoplayPolicy::RequestFor(const nsIDocument& aDocument)
|
|||
return window->GetAutoplayRequest();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
AutoplayPolicy::IsMediaElementAllowedToPlay(NotNull<HTMLMediaElement*> aElement)
|
||||
/* static */ Authorization
|
||||
AutoplayPolicy::IsAllowedToPlay(const HTMLMediaElement& aElement)
|
||||
{
|
||||
if (Preferences::GetBool("media.autoplay.enabled")) {
|
||||
return true;
|
||||
return Authorization::Allowed;
|
||||
}
|
||||
|
||||
// TODO : this old way would be removed when user-gestures-needed becomes
|
||||
// as a default option to block autoplay.
|
||||
if (!Preferences::GetBool("media.autoplay.enabled.user-gestures-needed", false)) {
|
||||
// If element is blessed, it would always be allowed to play().
|
||||
return aElement->IsBlessed() ||
|
||||
EventStateManager::IsHandlingUserInput();
|
||||
return (aElement.IsBlessed() || EventStateManager::IsHandlingUserInput())
|
||||
? Authorization::Allowed
|
||||
: Authorization::Blocked;
|
||||
}
|
||||
|
||||
// Muted content
|
||||
if (aElement->Volume() == 0.0 || aElement->Muted()) {
|
||||
return true;
|
||||
if (aElement.Volume() == 0.0 || aElement.Muted()) {
|
||||
return Authorization::Allowed;
|
||||
}
|
||||
|
||||
if (IsAllowedToPlay(aElement->OwnerDoc()->GetInnerWindow())) {
|
||||
return true;
|
||||
if (IsWindowAllowedToPlay(aElement.OwnerDoc()->GetInnerWindow())) {
|
||||
return Authorization::Allowed;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (Preferences::GetBool("media.autoplay.ask-permission", false)) {
|
||||
return Authorization::Prompt;
|
||||
}
|
||||
|
||||
return Authorization::Blocked;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -131,7 +136,7 @@ AutoplayPolicy::IsAudioContextAllowedToPlay(NotNull<AudioContext*> aContext)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (IsAllowedToPlay(aContext->GetOwner())) {
|
||||
if (IsWindowAllowedToPlay(aContext->GetOwner())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,13 @@ namespace dom {
|
|||
class HTMLMediaElement;
|
||||
class AudioContext;
|
||||
|
||||
enum class Authorization
|
||||
{
|
||||
Allowed,
|
||||
Blocked,
|
||||
Prompt
|
||||
};
|
||||
|
||||
/**
|
||||
* AutoplayPolicy is used to manage autoplay logic for all kinds of media,
|
||||
* including MediaElement, Web Audio and Web Speech.
|
||||
|
@ -36,7 +43,7 @@ class AutoplayPolicy
|
|||
{
|
||||
public:
|
||||
// Returns whether a given media element is allowed to play.
|
||||
static bool IsMediaElementAllowedToPlay(NotNull<HTMLMediaElement*> aElement);
|
||||
static Authorization IsAllowedToPlay(const HTMLMediaElement& aElement);
|
||||
|
||||
// Returns whether a given AudioContext is allowed to play.
|
||||
static bool IsAudioContextAllowedToPlay(NotNull<AudioContext*> aContext);
|
||||
|
|
Загрузка…
Ссылка в новой задаче