[Mac] Muted videos should not automatically play to AppleTV
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Jun 2015 23:33:21 +0000 (23:33 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Jun 2015 23:33:21 +0000 (23:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=146366

Reviewed by Dean Jackson.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_initiallyMuted.
(WebCore::HTMLMediaElement::scheduleDelayedAction): Support CheckMediaState.
(WebCore::HTMLMediaElement::setReadyState): Set m_initiallyMuted to true if the element is
  muted or the volume is less than 5%.
(WebCore::HTMLMediaElement::setMuted): Update media state asynchronously so multiple state
  changes can be coalesced.
(WebCore::HTMLMediaElement::mediaPlayerEngineUpdated): Ditto.
(WebCore::HTMLMediaElement::setPlaying): Ditto.
(WebCore::HTMLMediaElement::mediaPlayerCurrentPlaybackTargetIsWirelessChanged): Ditto.
(WebCore::HTMLMediaElement::removeEventListener): Ditto.
(WebCore::HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent): Ditto.
(WebCore::HTMLMediaElement::updateMediaState): Update after a timer when passed UpdateMediaState::Asynchronously.
(WebCore::HTMLMediaElement::mediaState): Don't set the ExternalDeviceAutoPlayCandidate flag if
  m_initiallyMuted is true.
* html/HTMLMediaElement.h:
* html/HTMLMediaElementEnums.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@186016 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/html/HTMLMediaElementEnums.h

index c40269f..58fb0b2 100644 (file)
@@ -1,3 +1,28 @@
+2015-06-26  Eric Carlson  <eric.carlson@apple.com>
+
+        [Mac] Muted videos should not automatically play to AppleTV
+        https://bugs.webkit.org/show_bug.cgi?id=146366
+
+        Reviewed by Dean Jackson.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize m_initiallyMuted.
+        (WebCore::HTMLMediaElement::scheduleDelayedAction): Support CheckMediaState.
+        (WebCore::HTMLMediaElement::setReadyState): Set m_initiallyMuted to true if the element is
+          muted or the volume is less than 5%.
+        (WebCore::HTMLMediaElement::setMuted): Update media state asynchronously so multiple state
+          changes can be coalesced.
+        (WebCore::HTMLMediaElement::mediaPlayerEngineUpdated): Ditto.
+        (WebCore::HTMLMediaElement::setPlaying): Ditto.
+        (WebCore::HTMLMediaElement::mediaPlayerCurrentPlaybackTargetIsWirelessChanged): Ditto.
+        (WebCore::HTMLMediaElement::removeEventListener): Ditto.
+        (WebCore::HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent): Ditto.
+        (WebCore::HTMLMediaElement::updateMediaState): Update after a timer when passed UpdateMediaState::Asynchronously.
+        (WebCore::HTMLMediaElement::mediaState): Don't set the ExternalDeviceAutoPlayCandidate flag if
+          m_initiallyMuted is true.
+        * html/HTMLMediaElement.h:
+        * html/HTMLMediaElementEnums.h:
+
 2015-06-26  Daniel Bates  <dabates@apple.com>
 
         Rolling out r184660
index 64380ed..0f7c0c8 100644 (file)
@@ -326,6 +326,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
     , m_autoplaying(true)
     , m_muted(false)
     , m_explicitlyMuted(false)
+    , m_initiallyMuted(false)
     , m_paused(true)
     , m_seeking(false)
     , m_sentStalledEvent(false)
@@ -758,6 +759,9 @@ void HTMLMediaElement::scheduleDelayedAction(DelayedActionType actionType)
         setFlags(m_pendingActionFlags, CheckPlaybackTargetCompatablity);
 #endif
 
+    if (actionType & CheckMediaState)
+        setFlags(m_pendingActionFlags, CheckMediaState);
+
     m_pendingActionTimer.startOneShot(0);
 }
 
@@ -807,6 +811,9 @@ void HTMLMediaElement::pendingActionTimerFired()
         LOG(Media, "HTMLMediaElement::pendingActionTimerFired(%p) - calling setShouldPlayToPlaybackTarget(false)", this);
         m_player->setShouldPlayToPlaybackTarget(false);
     }
+
+    if (m_pendingActionFlags & CheckMediaState)
+        updateMediaState();
 #endif
 
     m_pendingActionFlags = 0;
@@ -2068,7 +2075,8 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
         if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent))
             enqueuePlaybackTargetAvailabilityChangedEvent();
 #endif
-        
+        m_initiallyMuted = m_volume < 0.05 || muted();
+
         if (hasMediaControls())
             mediaControls()->loadedMetadata();
         if (renderer())
@@ -3087,7 +3095,7 @@ void HTMLMediaElement::setMuted(bool muted)
         document().updateIsPlayingMedia();
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-        updateMediaState();
+        updateMediaState(UpdateMediaState::Asynchronously);
 #endif
     }
 #endif
@@ -4402,7 +4410,7 @@ void HTMLMediaElement::mediaPlayerEngineUpdated(MediaPlayer*)
     m_player->setVideoFullscreenLayer(m_videoFullscreenLayer.get());
 #endif
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    updateMediaState();
+    updateMediaState(UpdateMediaState::Asynchronously);
 #endif
 }
 
@@ -4700,7 +4708,7 @@ void HTMLMediaElement::setPlaying(bool playing)
     document().updateIsPlayingMedia();
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    updateMediaState();
+    updateMediaState(UpdateMediaState::Asynchronously);
 #endif
 }
 
@@ -4963,7 +4971,7 @@ void HTMLMediaElement::mediaPlayerCurrentPlaybackTargetIsWirelessChanged(MediaPl
 
     configureMediaControls();
     scheduleEvent(eventNames().webkitcurrentplaybacktargetiswirelesschangedEvent);
-    updateMediaState();
+    updateMediaState(UpdateMediaState::Asynchronously);
 }
 
 bool HTMLMediaElement::dispatchEvent(PassRefPtr<Event> prpEvent)
@@ -5007,7 +5015,7 @@ bool HTMLMediaElement::removeEventListener(const AtomicString& eventType, EventL
     if (didRemoveLastAvailabilityChangedListener) {
         m_hasPlaybackTargetAvailabilityListeners = false;
         m_mediaSession->setHasPlaybackTargetAvailabilityListeners(*this, false);
-        updateMediaState();
+        updateMediaState(UpdateMediaState::Asynchronously);
     }
 
     return true;
@@ -5020,7 +5028,7 @@ void HTMLMediaElement::enqueuePlaybackTargetAvailabilityChangedEvent()
     RefPtr<Event> event = WebKitPlaybackTargetAvailabilityEvent::create(eventNames().webkitplaybacktargetavailabilitychangedEvent, hasTargets);
     event->setTarget(this);
     m_asyncEventQueue.enqueueEvent(event.release());
-    updateMediaState();
+    updateMediaState(UpdateMediaState::Asynchronously);
 }
 
 void HTMLMediaElement::setWirelessPlaybackTarget(Ref<MediaPlaybackTarget>&& device)
@@ -6295,8 +6303,13 @@ bool HTMLMediaElement::overrideBackgroundPlaybackRestriction() const
 }
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-void HTMLMediaElement::updateMediaState()
+void HTMLMediaElement::updateMediaState(UpdateMediaState updateState)
 {
+    if (updateState == UpdateMediaState::Asynchronously) {
+        scheduleDelayedAction(CheckMediaState);
+        return;
+    }
+
     MediaProducer::MediaStateFlags state = mediaState();
     if (m_mediaState == state)
         return;
@@ -6321,7 +6334,7 @@ MediaProducer::MediaStateFlags HTMLMediaElement::mediaState() const
         state |= RequiresPlaybackTargetMonitoring;
 
     bool requireUserGesture = m_mediaSession->hasBehaviorRestriction(MediaElementSession::RequireUserGestureToAutoplayToExternalDevice);
-    if (hasActiveVideo && (!requireUserGesture || (hasAudio && !loop())))
+    if (hasActiveVideo && (!requireUserGesture || (hasAudio && !m_initiallyMuted && !loop())))
         state |= ExternalDeviceAutoPlayCandidate;
 #endif
 
index 2d58aba..d4b9db8 100644 (file)
@@ -725,7 +725,12 @@ private:
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     virtual void documentWillSuspendForPageCache() override final;
     virtual void documentDidResumeFromPageCache() override final;
-    void updateMediaState();
+
+    enum class UpdateMediaState {
+        Asynchronously,
+        Synchronously,
+    };
+    void updateMediaState(UpdateMediaState updateState = UpdateMediaState::Synchronously);
 #endif
 
     Timer m_pendingActionTimer;
@@ -837,6 +842,7 @@ private:
     bool m_autoplaying : 1;
     bool m_muted : 1;
     bool m_explicitlyMuted : 1;
+    bool m_initiallyMuted : 1;
     bool m_paused : 1;
     bool m_seeking : 1;
 
index 9079791..519def8 100644 (file)
@@ -40,8 +40,9 @@ public:
         TextTrackChangesNotification = 1 << 2,
         ConfigureTextTrackDisplay = 1 << 3,
         CheckPlaybackTargetCompatablity = 1 << 4,
+        CheckMediaState = 1 << 5,
 
-        EveryDelayedAction = LoadMediaResource | ConfigureTextTracks | TextTrackChangesNotification | ConfigureTextTrackDisplay | CheckPlaybackTargetCompatablity,
+        EveryDelayedAction = LoadMediaResource | ConfigureTextTracks | TextTrackChangesNotification | ConfigureTextTrackDisplay | CheckPlaybackTargetCompatablity | CheckMediaState,
     };
 
     enum ReadyState { HAVE_NOTHING, HAVE_METADATA, HAVE_CURRENT_DATA, HAVE_FUTURE_DATA, HAVE_ENOUGH_DATA };