Title: [182240] trunk/Source/WebCore
Revision
182240
Author
eric.carl...@apple.com
Date
2015-04-01 11:07:16 -0700 (Wed, 01 Apr 2015)

Log Message

[Mac] Do not include route button if element does not support target playback
https://bugs.webkit.org/show_bug.cgi?id=143251

Reviewed by Jer Noble.

* Modules/mediacontrols/mediaControlsApple.js:
(Controller.prototype.currentPlaybackTargetIsWireless): Return false if target playback is disabled.
(Controller.prototype.updateWirelessTargetAvailable): Do not show the picker if target 
    playback is disabled.
(Controller.prototype.handleWirelessPlaybackChange): Call updateWirelessTargetAvailable.

* dom/Document.cpp:
(WebCore::Document::showPlaybackTargetPicker): Update for Page::showPlaybackTargetPicker change.
(WebCore::Document::didChoosePlaybackTarget): Notify clients in vector-order, lower level code
    now tracks which one requested the picker.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::loadResource): Don't call applyMediaPlayerRestrictions, it is done
    in mediaPlayerEngineFailedToLoad.
(WebCore::HTMLMediaElement::setReadyState): Enqueue a target availability event if there are
    listeners readyState reaches HAVE_METADATA so controls are setup correctly.
(WebCore::HTMLMediaElement::mediaPlayerEngineFailedToLoad): Call applyMediaPlayerRestrictions.
(WebCore::HTMLMediaElement::clearMediaPlayer): Enqueue a target availability event in so controls
    have a chance to hide the picker.
(WebCore::HTMLMediaElement::webkitCurrentPlaybackTargetIsSupported): New, passthrough to the
    media engine.
(WebCore::HTMLMediaElement::canPlayToWirelessPlaybackTarget): Ditto.
(WebCore::HTMLMediaElement::startPlayingToPlaybackTarget): Ditto.
(WebCore::HTMLMediaElement::stopPlayingToPlaybackTarget): Ditto.
* html/HTMLMediaElement.h:
* html/HTMLMediaElement.idl:

* html/HTMLMediaSession.cpp:
(WebCore::HTMLMediaSession::HTMLMediaSession): Initialize m_playbackTarget.
(WebCore::HTMLMediaSession::currentPlaybackTargetIsSupported): New.
(WebCore::HTMLMediaSession::showPlaybackTargetPicker): Pull logic from showingPlaybackTargetPickerPermitted 
    inline. Don't refuse to show a picker if the element doesn't support target playback, it is up
    to script to decide which elements can display a picker.
(WebCore::HTMLMediaSession::wirelessVideoPlaybackDisabled): Return true if there is no player.
(WebCore::HTMLMediaSession::didChoosePlaybackTarget): Call startPlayingToPlaybackTarget or 
    stopPlayingToPlaybackTarget because setWirelessPlaybackTarget doesn't apply the target.
(WebCore::HTMLMediaSession::externalOutputDeviceAvailableDidChange): Add logging.
(WebCore::HTMLMediaSession::showingPlaybackTargetPickerPermitted): Deleted.
* html/HTMLMediaSession.h:

* page/Page.cpp:
(WebCore::Page::Page): Initialize m_playbackTarget.
(WebCore::Page::showPlaybackTargetPicker): Don't set m_documentRequestingPlaybackTargetPicker.
(WebCore::Page::didChoosePlaybackTarget): Notify Pages in vector-order, lower level code
    now tracks which one requested the picker.
(WebCore::Page::configurePlaybackTargetMonitoring): Don't track m_requiresPlaybackTargetMonitoring, it
    is too easy for it to get out of sync with the UI process state.
* page/Page.h:

* platform/audio/MediaSession.cpp:
(WebCore::MediaSession::canPlayToWirelessPlaybackTarget): New, client passthrough.
(WebCore::MediaSession::startPlayingToPlaybackTarget): Ditto.
(WebCore::MediaSession::stopPlayingToPlaybackTarget): Ditto.
* platform/audio/MediaSession.h:
(WebCore::MediaSessionClient::canPlayToWirelessPlaybackTarget):
(WebCore::MediaSessionClient::startPlayingToPlaybackTarget):
(WebCore::MediaSessionClient::stopPlayingToPlaybackTarget):

* platform/audio/MediaSessionManager.cpp:
(WebCore::MediaSessionManager::sessionWillBeginPlayback): Call startPlayingToPlaybackTarget &
    stopPlayingToPlaybackTarget as necessary.
* platform/audio/MediaSessionManager.h:

* platform/graphics/MediaPlaybackTarget.h:
(WebCore::MediaPlaybackTarget::hasActiveRoute): New.
* platform/graphics/MediaPlaybackTargetPickerClient.h:
* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::isCurrentPlaybackTargetSupported): New, engine passthrough.
(WebCore::MediaPlayer::canPlayToWirelessPlaybackTarget): Ditto.
(WebCore::MediaPlayer::startPlayingToPlaybackTarget): Ditto.
(WebCore::MediaPlayer::stopPlayingToPlaybackTarget): Ditto.
* platform/graphics/MediaPlayer.h:
* platform/graphics/MediaPlayerPrivate.h:
(WebCore::MediaPlayerPrivateInterface::isCurrentPlaybackTargetSupported):
(WebCore::MediaPlayerPrivateInterface::wirelessVideoPlaybackDisabled):
(WebCore::MediaPlayerPrivateInterface::canPlayToWirelessPlaybackTarget):
(WebCore::MediaPlayerPrivateInterface::startPlayingToPlaybackTarget):
(WebCore::MediaPlayerPrivateInterface::stopPlayingToPlaybackTarget):

* platform/graphics/avfoundation/MediaPlaybackTargetMac.mm:
(WebCore::MediaPlaybackTarget::hasActiveRoute): New.

* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
(WebCore::MediaPlayerPrivateAVFoundationObjC::canPlayToWirelessPlaybackTarget):
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::cancelLoad): Use playerKVOProperties. Drive-by
    code cleanup.
(WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer): Use playerKVOProperties.
(WebCore::MediaPlayerPrivateAVFoundationObjC::wirelessPlaybackTargetName): Implement for Mac.
(WebCore::MediaPlayerPrivateAVFoundationObjC::setWirelessVideoPlaybackDisabled): Delay callbacks
    while setting AVPlayer property.
(WebCore::MediaPlayerPrivateAVFoundationObjC::setWirelessPlaybackTarget): Add logging. Don't set
    the AVPlayer outputContext immediately.
(WebCore::MediaPlayerPrivateAVFoundationObjC::startPlayingToPlaybackTarget): New.
(WebCore::MediaPlayerPrivateAVFoundationObjC::stopPlayingToPlaybackTarget): New.
(WebCore::playerKVOProperties): New.
(-[WebCoreAVFMovieObserver observeValueForKeyPath:ofObject:change:context:]): Notify when
    allowsExternalPlayback changes.

* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::isCurrentPlaybackTargetSupported): New.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::setWirelessPlaybackTarget): Ditto.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::togglePlayingToPlaybackTarget): Ditto.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::startPlayingToPlaybackTarget): Ditto.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::stopPlayingToPlaybackTarget): Ditto.

* platform/graphics/mac/MediaPlayerPrivateQTKit.h:
* platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
(WebCore::MediaPlayerPrivateQTKit::isCurrentPlaybackTargetSupported): Ditto.
(WebCore::MediaPlayerPrivateQTKit::setWirelessPlaybackTarget): Ditto.
(WebCore::MediaPlayerPrivateQTKit::togglePlayingToPlaybackTarget): Ditto.
(WebCore::MediaPlayerPrivateQTKit::startPlayingToPlaybackTarget): Ditto.
(WebCore::MediaPlayerPrivateQTKit::stopPlayingToPlaybackTarget): Ditto.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (182239 => 182240)


--- trunk/Source/WebCore/ChangeLog	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/ChangeLog	2015-04-01 18:07:16 UTC (rev 182240)
@@ -1,3 +1,125 @@
+2015-04-01  Eric Carlson  <eric.carl...@apple.com>
+
+        [Mac] Do not include route button if element does not support target playback
+        https://bugs.webkit.org/show_bug.cgi?id=143251
+
+        Reviewed by Jer Noble.
+
+        * Modules/mediacontrols/mediaControlsApple.js:
+        (Controller.prototype.currentPlaybackTargetIsWireless): Return false if target playback is disabled.
+        (Controller.prototype.updateWirelessTargetAvailable): Do not show the picker if target 
+            playback is disabled.
+        (Controller.prototype.handleWirelessPlaybackChange): Call updateWirelessTargetAvailable.
+
+        * dom/Document.cpp:
+        (WebCore::Document::showPlaybackTargetPicker): Update for Page::showPlaybackTargetPicker change.
+        (WebCore::Document::didChoosePlaybackTarget): Notify clients in vector-order, lower level code
+            now tracks which one requested the picker.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::loadResource): Don't call applyMediaPlayerRestrictions, it is done
+            in mediaPlayerEngineFailedToLoad.
+        (WebCore::HTMLMediaElement::setReadyState): Enqueue a target availability event if there are
+            listeners readyState reaches HAVE_METADATA so controls are setup correctly.
+        (WebCore::HTMLMediaElement::mediaPlayerEngineFailedToLoad): Call applyMediaPlayerRestrictions.
+        (WebCore::HTMLMediaElement::clearMediaPlayer): Enqueue a target availability event in so controls
+            have a chance to hide the picker.
+        (WebCore::HTMLMediaElement::webkitCurrentPlaybackTargetIsSupported): New, passthrough to the
+            media engine.
+        (WebCore::HTMLMediaElement::canPlayToWirelessPlaybackTarget): Ditto.
+        (WebCore::HTMLMediaElement::startPlayingToPlaybackTarget): Ditto.
+        (WebCore::HTMLMediaElement::stopPlayingToPlaybackTarget): Ditto.
+        * html/HTMLMediaElement.h:
+        * html/HTMLMediaElement.idl:
+
+        * html/HTMLMediaSession.cpp:
+        (WebCore::HTMLMediaSession::HTMLMediaSession): Initialize m_playbackTarget.
+        (WebCore::HTMLMediaSession::currentPlaybackTargetIsSupported): New.
+        (WebCore::HTMLMediaSession::showPlaybackTargetPicker): Pull logic from showingPlaybackTargetPickerPermitted 
+            inline. Don't refuse to show a picker if the element doesn't support target playback, it is up
+            to script to decide which elements can display a picker.
+        (WebCore::HTMLMediaSession::wirelessVideoPlaybackDisabled): Return true if there is no player.
+        (WebCore::HTMLMediaSession::didChoosePlaybackTarget): Call startPlayingToPlaybackTarget or 
+            stopPlayingToPlaybackTarget because setWirelessPlaybackTarget doesn't apply the target.
+        (WebCore::HTMLMediaSession::externalOutputDeviceAvailableDidChange): Add logging.
+        (WebCore::HTMLMediaSession::showingPlaybackTargetPickerPermitted): Deleted.
+        * html/HTMLMediaSession.h:
+
+        * page/Page.cpp:
+        (WebCore::Page::Page): Initialize m_playbackTarget.
+        (WebCore::Page::showPlaybackTargetPicker): Don't set m_documentRequestingPlaybackTargetPicker.
+        (WebCore::Page::didChoosePlaybackTarget): Notify Pages in vector-order, lower level code
+            now tracks which one requested the picker.
+        (WebCore::Page::configurePlaybackTargetMonitoring): Don't track m_requiresPlaybackTargetMonitoring, it
+            is too easy for it to get out of sync with the UI process state.
+        * page/Page.h:
+
+        * platform/audio/MediaSession.cpp:
+        (WebCore::MediaSession::canPlayToWirelessPlaybackTarget): New, client passthrough.
+        (WebCore::MediaSession::startPlayingToPlaybackTarget): Ditto.
+        (WebCore::MediaSession::stopPlayingToPlaybackTarget): Ditto.
+        * platform/audio/MediaSession.h:
+        (WebCore::MediaSessionClient::canPlayToWirelessPlaybackTarget):
+        (WebCore::MediaSessionClient::startPlayingToPlaybackTarget):
+        (WebCore::MediaSessionClient::stopPlayingToPlaybackTarget):
+
+        * platform/audio/MediaSessionManager.cpp:
+        (WebCore::MediaSessionManager::sessionWillBeginPlayback): Call startPlayingToPlaybackTarget &
+            stopPlayingToPlaybackTarget as necessary.
+        * platform/audio/MediaSessionManager.h:
+
+        * platform/graphics/MediaPlaybackTarget.h:
+        (WebCore::MediaPlaybackTarget::hasActiveRoute): New.
+        * platform/graphics/MediaPlaybackTargetPickerClient.h:
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::isCurrentPlaybackTargetSupported): New, engine passthrough.
+        (WebCore::MediaPlayer::canPlayToWirelessPlaybackTarget): Ditto.
+        (WebCore::MediaPlayer::startPlayingToPlaybackTarget): Ditto.
+        (WebCore::MediaPlayer::stopPlayingToPlaybackTarget): Ditto.
+        * platform/graphics/MediaPlayer.h:
+        * platform/graphics/MediaPlayerPrivate.h:
+        (WebCore::MediaPlayerPrivateInterface::isCurrentPlaybackTargetSupported):
+        (WebCore::MediaPlayerPrivateInterface::wirelessVideoPlaybackDisabled):
+        (WebCore::MediaPlayerPrivateInterface::canPlayToWirelessPlaybackTarget):
+        (WebCore::MediaPlayerPrivateInterface::startPlayingToPlaybackTarget):
+        (WebCore::MediaPlayerPrivateInterface::stopPlayingToPlaybackTarget):
+
+        * platform/graphics/avfoundation/MediaPlaybackTargetMac.mm:
+        (WebCore::MediaPlaybackTarget::hasActiveRoute): New.
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::canPlayToWirelessPlaybackTarget):
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::cancelLoad): Use playerKVOProperties. Drive-by
+            code cleanup.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer): Use playerKVOProperties.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::wirelessPlaybackTargetName): Implement for Mac.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::setWirelessVideoPlaybackDisabled): Delay callbacks
+            while setting AVPlayer property.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::setWirelessPlaybackTarget): Add logging. Don't set
+            the AVPlayer outputContext immediately.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::startPlayingToPlaybackTarget): New.
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::stopPlayingToPlaybackTarget): New.
+        (WebCore::playerKVOProperties): New.
+        (-[WebCoreAVFMovieObserver observeValueForKeyPath:ofObject:change:context:]): Notify when
+            allowsExternalPlayback changes.
+
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::isCurrentPlaybackTargetSupported): New.
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::setWirelessPlaybackTarget): Ditto.
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::togglePlayingToPlaybackTarget): Ditto.
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::startPlayingToPlaybackTarget): Ditto.
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::stopPlayingToPlaybackTarget): Ditto.
+
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.h:
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
+        (WebCore::MediaPlayerPrivateQTKit::isCurrentPlaybackTargetSupported): Ditto.
+        (WebCore::MediaPlayerPrivateQTKit::setWirelessPlaybackTarget): Ditto.
+        (WebCore::MediaPlayerPrivateQTKit::togglePlayingToPlaybackTarget): Ditto.
+        (WebCore::MediaPlayerPrivateQTKit::startPlayingToPlaybackTarget): Ditto.
+        (WebCore::MediaPlayerPrivateQTKit::stopPlayingToPlaybackTarget): Ditto.
+
 2015-04-01  Alex Christensen  <achristen...@webkit.org>
 
         [Content Extensions] Properly handle regexes that match everything.

Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js (182239 => 182240)


--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js	2015-04-01 18:07:16 UTC (rev 182240)
@@ -1695,7 +1695,13 @@
     },
 
     currentPlaybackTargetIsWireless: function() {
-        return Controller.gSimulateWirelessPlaybackTarget || (('webkitCurrentPlaybackTargetIsWireless' in this.video) && this.video.webkitCurrentPlaybackTargetIsWireless);
+        if (Controller.gSimulateWirelessPlaybackTarget)
+            return true;
+
+        if (!this.video.webkitCurrentPlaybackTargetIsWireless || this.video.webkitWirelessVideoPlaybackDisabled)
+            return false;
+
+        return true;
     },
 
     updateShouldListenForPlaybackTargetAvailabilityEvent: function() {
@@ -1740,7 +1746,11 @@
     },
 
     updateWirelessTargetAvailable: function() {
-        if (Controller.gSimulateWirelessPlaybackTarget || this.hasWirelessPlaybackTargets)
+        var wirelessPlaybackTargetsAvailable = Controller.gSimulateWirelessPlaybackTarget || this.hasWirelessPlaybackTargets;
+        if (this.video.webkitWirelessVideoPlaybackDisabled)
+            wirelessPlaybackTargetsAvailable = false;
+
+        if (wirelessPlaybackTargetsAvailable)
             this.controls.wirelessTargetPicker.classList.remove(this.ClassNames.hidden);
         else
             this.controls.wirelessTargetPicker.classList.add(this.ClassNames.hidden);
@@ -1753,6 +1763,7 @@
     },
 
     handleWirelessPlaybackChange: function(event) {
+        this.updateWirelessTargetAvailable();
         this.updateWirelessPlaybackStatus();
         this.setNeedsTimelineMetricsUpdate();
     },

Modified: trunk/Source/WebCore/dom/Document.cpp (182239 => 182240)


--- trunk/Source/WebCore/dom/Document.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/dom/Document.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -6550,7 +6550,7 @@
     if (!page)
         return;
 
-    page->showPlaybackTargetPicker(this, view()->lastKnownMousePosition(), is<HTMLVideoElement>(element));
+    page->showPlaybackTargetPicker(view()->lastKnownMousePosition(), is<HTMLVideoElement>(element));
 }
 
 void Document::addPlaybackTargetPickerClient(MediaPlaybackTargetPickerClient& client)
@@ -6604,22 +6604,8 @@
 
 void Document::didChoosePlaybackTarget(const MediaPlaybackTarget& device)
 {
-    MediaPlaybackTargetPickerClient* clientThatRequestedPicker = nullptr;
-
-    for (auto* client : m_playbackTargetClients) {
-        if (client->requestedPlaybackTargetPicker()) {
-            clientThatRequestedPicker = client;
-            continue;
-        }
-
+    for (auto* client : m_playbackTargetClients)
         client->didChoosePlaybackTarget(device);
-    }
-
-    // Notify the client that requested the chooser last because if more than one
-    // is playing, only the last one to set the context will actually get to play
-    //  to the external device.
-    if (clientThatRequestedPicker)
-        clientThatRequestedPicker->didChoosePlaybackTarget(device);
 }
 
 #endif

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (182239 => 182240)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -1179,8 +1179,6 @@
     if (!m_player->load(url, contentType, keySystem))
         mediaLoadingFailed(MediaPlayer::FormatError);
 
-    m_mediaSession->applyMediaPlayerRestrictions(*this);
-
     // If there is no poster to display, allow the media engine to render video frames as soon as
     // they are available.
     updateDisplayState();
@@ -1987,6 +1985,11 @@
         prepareMediaFragmentURI();
         scheduleEvent(eventNames().durationchangeEvent);
         scheduleEvent(eventNames().loadedmetadataEvent);
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+        if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent))
+            enqueuePlaybackTargetAvailabilityChangedEvent();
+#endif
+        
         if (hasMediaControls())
             mediaControls()->loadedMetadata();
         if (renderer())
@@ -4268,6 +4271,8 @@
 
     m_havePreparedToPlay = false;
 
+    m_mediaSession->applyMediaPlayerRestrictions(*this);
+
 #if PLATFORM(IOS)
     if (!m_player)
         return;
@@ -4654,8 +4659,13 @@
 #endif
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent))
+    if (hasEventListeners(eventNames().webkitplaybacktargetavailabilitychangedEvent)) {
         m_mediaSession->setHasPlaybackTargetAvailabilityListeners(*this, false);
+
+        // Send an availability event in case scripts want to hide the picker when the element
+        // doesn't support playback to a target.
+        enqueuePlaybackTargetAvailabilityChangedEvent();
+    }
 #endif
 
     m_player = nullptr;
@@ -4810,6 +4820,11 @@
     return m_mediaSession->currentPlaybackTargetIsWireless(*this);
 }
 
+bool HTMLMediaElement::webkitCurrentPlaybackTargetIsSupported() const
+{
+    return m_mediaSession->currentPlaybackTargetIsSupported(*this);
+}
+
 void HTMLMediaElement::wirelessRoutesAvailableDidChange()
 {
     enqueuePlaybackTargetAvailabilityChangedEvent();
@@ -4869,6 +4884,27 @@
     if (m_player)
         m_player->setWirelessPlaybackTarget(device);
 }
+
+bool HTMLMediaElement::canPlayToWirelessPlaybackTarget()
+{
+    bool canPlay = m_player && m_player->canPlayToWirelessPlaybackTarget();
+
+    LOG(Media, "HTMLMediaElement::canPlayToWirelessPlaybackTarget(%p) - returning %s", this, boolString(canPlay));
+
+    return canPlay;
+}
+
+void HTMLMediaElement::startPlayingToPlaybackTarget()
+{
+    if (m_player)
+        m_player->startPlayingToPlaybackTarget();
+}
+
+void HTMLMediaElement::stopPlayingToPlaybackTarget()
+{
+    if (m_player)
+        m_player->stopPlayingToPlaybackTarget();
+}
 #endif
 
 double HTMLMediaElement::minFastReverseRate() const

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (182239 => 182240)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -354,12 +354,16 @@
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     void webkitShowPlaybackTargetPicker();
     bool webkitCurrentPlaybackTargetIsWireless() const;
+    bool webkitCurrentPlaybackTargetIsSupported() const;
 
     virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture) override;
     virtual bool removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture) override;
 
     virtual void wirelessRoutesAvailableDidChange() override;
+    virtual bool canPlayToWirelessPlaybackTarget() override;
     virtual void setWirelessPlaybackTarget(const MediaPlaybackTarget&) override;
+    virtual void startPlayingToPlaybackTarget() override;
+    virtual void stopPlayingToPlaybackTarget() override;
 #endif
 
     // EventTarget function.

Modified: trunk/Source/WebCore/html/HTMLMediaElement.idl (182239 => 182240)


--- trunk/Source/WebCore/html/HTMLMediaElement.idl	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/html/HTMLMediaElement.idl	2015-04-01 18:07:16 UTC (rev 182240)
@@ -116,4 +116,5 @@
 
     [Conditional=WIRELESS_PLAYBACK_TARGET] void webkitShowPlaybackTargetPicker();
     [Conditional=WIRELESS_PLAYBACK_TARGET] readonly attribute boolean webkitCurrentPlaybackTargetIsWireless;
+    [Conditional=WIRELESS_PLAYBACK_TARGET] readonly attribute boolean webkitCurrentPlaybackTargetIsSupported;
 };

Modified: trunk/Source/WebCore/html/HTMLMediaSession.cpp (182239 => 182240)


--- trunk/Source/WebCore/html/HTMLMediaSession.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/html/HTMLMediaSession.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -76,6 +76,7 @@
     , m_restrictions(NoRestrictions)
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     , m_targetAvailabilityChangedTimer(*this, &HTMLMediaSession::targetAvailabilityChangedTimerFired)
+    , m_playbackTarget(std::make_unique<MediaPlaybackTarget>())
 #endif
 {
 }
@@ -163,43 +164,49 @@
 }
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-bool HTMLMediaSession::showingPlaybackTargetPickerPermitted(const HTMLMediaElement& element) const
+bool HTMLMediaSession::currentPlaybackTargetIsWireless(const HTMLMediaElement& element) const
 {
-    if (m_restrictions & RequireUserGestureToShowPlaybackTargetPicker && !ScriptController::processingUserGesture()) {
-        LOG(Media, "HTMLMediaSession::showingPlaybackTargetPickerPermitted - returning FALSE because of permissions");
+    MediaPlayer* player = element.player();
+    if (!player) {
+        LOG(Media, "HTMLMediaSession::currentPlaybackTargetIsWireless - returning FALSE because player is NULL");
         return false;
     }
 
-    if (!element.document().page()) {
-        LOG(Media, "HTMLMediaSession::showingPlaybackTargetPickerPermitted - returning FALSE because page is NULL");
-        return false;
-    }
+    bool isWireless = player->isCurrentPlaybackTargetWireless();
+    LOG(Media, "HTMLMediaSession::currentPlaybackTargetIsWireless - returning %s", isWireless ? "TRUE" : "FALSE");
 
-    return !wirelessVideoPlaybackDisabled(element);
+    return isWireless;
 }
 
-bool HTMLMediaSession::currentPlaybackTargetIsWireless(const HTMLMediaElement& element) const
+bool HTMLMediaSession::currentPlaybackTargetIsSupported(const HTMLMediaElement& element) const
 {
     MediaPlayer* player = element.player();
     if (!player) {
-        LOG(Media, "HTMLMediaSession::currentPlaybackTargetIsWireless - returning FALSE because player is NULL");
+        LOG(Media, "HTMLMediaSession::currentPlaybackTargetIsSupported - returning FALSE because player is NULL");
         return false;
     }
 
-    bool isWireless = player->isCurrentPlaybackTargetWireless();
-    LOG(Media, "HTMLMediaSession::currentPlaybackTargetIsWireless - returning %s", isWireless ? "TRUE" : "FALSE");
-
-    return isWireless;
+    bool isSupported = player->isCurrentPlaybackTargetSupported();
+    LOG(Media, "HTMLMediaSession::currentPlaybackTargetIsSupported - returning %s", isSupported ? "TRUE" : "FALSE");
+    
+    return isSupported;
 }
 
 void HTMLMediaSession::showPlaybackTargetPicker(const HTMLMediaElement& element)
 {
     LOG(Media, "HTMLMediaSession::showPlaybackTargetPicker");
 
-    if (!showingPlaybackTargetPickerPermitted(element))
+    if (m_restrictions & RequireUserGestureToShowPlaybackTargetPicker && !ScriptController::processingUserGesture()) {
+        LOG(Media, "HTMLMediaSession::showPlaybackTargetPicker - returning early because of permissions");
         return;
+    }
 
-    m_haveRequestedPlaybackTargetPicker = true;
+    if (!element.document().page()) {
+        LOG(Media, "HTMLMediaSession::showingPlaybackTargetPickerPermitted - returning early because page is NULL");
+        return;
+    }
+
+    MediaSessionManager::sharedManager().setCurrentSession(*this);
     element.document().showPlaybackTargetPicker(element);
 }
 
@@ -238,7 +245,7 @@
 
     MediaPlayer* player = element.player();
     if (!player)
-        return false;
+        return true;
 
     bool disabled = player->wirelessVideoPlaybackDisabled();
     LOG(Media, "HTMLMediaSession::wirelessVideoPlaybackDisabled - returning %s because media engine says so", disabled ? "TRUE" : "FALSE");
@@ -277,8 +284,12 @@
 
 void HTMLMediaSession::didChoosePlaybackTarget(const MediaPlaybackTarget& device)
 {
-    m_haveRequestedPlaybackTargetPicker = false;
-    client().setWirelessPlaybackTarget(device);
+    m_playbackTarget->setDevicePickerContext(device.devicePickerContext());
+    client().setWirelessPlaybackTarget(*m_playbackTarget.get());
+    if (device.hasActiveRoute() && MediaSessionManager::sharedManager().currentSession() == this)
+        startPlayingToPlaybackTarget();
+    else
+        stopPlayingToPlaybackTarget();
 }
 
 void HTMLMediaSession::targetAvailabilityChangedTimerFired()
@@ -291,6 +302,8 @@
     if (m_hasPlaybackTargets == hasTargets)
         return;
 
+    LOG(Media, "HTMLMediaSession::externalOutputDeviceAvailableDidChange - hasTargets %s", hasTargets ? "TRUE" : "FALSE");
+
     m_hasPlaybackTargets = hasTargets;
     if (!m_targetAvailabilityChangedTimer.isActive())
         m_targetAvailabilityChangedTimer.startOneShot(0);

Modified: trunk/Source/WebCore/html/HTMLMediaSession.h (182239 => 182240)


--- trunk/Source/WebCore/html/HTMLMediaSession.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/html/HTMLMediaSession.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -54,8 +54,8 @@
     bool pageAllowsPlaybackAfterResuming(const HTMLMediaElement&) const;
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    bool showingPlaybackTargetPickerPermitted(const HTMLMediaElement&) const;
     bool currentPlaybackTargetIsWireless(const HTMLMediaElement&) const;
+    bool currentPlaybackTargetIsSupported(const HTMLMediaElement&) const;
     void showPlaybackTargetPicker(const HTMLMediaElement&);
     bool hasWirelessPlaybackTargets(const HTMLMediaElement&) const;
 
@@ -102,16 +102,15 @@
     virtual void didChoosePlaybackTarget(const MediaPlaybackTarget&) override;
     virtual void externalOutputDeviceAvailableDidChange(bool) const override;
     virtual bool requiresPlaybackTargetRouteMonitoring() const override;
-    virtual bool requestedPlaybackTargetPicker() const override { return m_haveRequestedPlaybackTargetPicker; }
 #endif
 
     BehaviorRestrictions m_restrictions;
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     mutable Timer m_targetAvailabilityChangedTimer;
+    std::unique_ptr<MediaPlaybackTarget> m_playbackTarget;
     bool m_hasPlaybackTargetAvailabilityListeners { false };
     mutable bool m_hasPlaybackTargets { false };
-    mutable bool m_haveRequestedPlaybackTargetPicker { false };
 #endif
 };
 

Modified: trunk/Source/WebCore/page/Page.cpp (182239 => 182240)


--- trunk/Source/WebCore/page/Page.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/page/Page.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -212,6 +212,9 @@
     , m_userContentController(WTF::move(pageConfiguration.userContentController))
     , m_visitedLinkStore(*WTF::move(pageConfiguration.visitedLinkStore))
     , m_sessionID(SessionID::defaultSessionID())
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+    , m_playbackTarget(std::make_unique<MediaPlaybackTarget>())
+#endif
     , m_isClosing(false)
     , m_isPlayingAudio(false)
 {
@@ -1681,10 +1684,8 @@
 }
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-void Page::showPlaybackTargetPicker(Document* document, const WebCore::IntPoint& location, bool isVideo)
+void Page::showPlaybackTargetPicker(const WebCore::IntPoint& location, bool isVideo)
 {
-    m_documentRequestingPlaybackTargetPicker = document;
-
 #if PLATFORM(IOS)
     // FIXME: refactor iOS implementation.
     UNUSED_PARAM(location);
@@ -1696,25 +1697,9 @@
 
 void Page::didChoosePlaybackTarget(const MediaPlaybackTarget& target)
 {
-    Document* documentThatRequestedPicker = nullptr;
-
-    m_playbackTarget = std::make_unique<MediaPlaybackTarget>(target.devicePickerContext());
-    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
-        Document* document = frame->document();
-        if (frame->document() == m_documentRequestingPlaybackTargetPicker) {
-            documentThatRequestedPicker = document;
-            continue;
-        }
+    m_playbackTarget->setDevicePickerContext(target.devicePickerContext());
+    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
         frame->document()->didChoosePlaybackTarget(target);
-    }
-
-    // Notify the document that requested the chooser last because if more than one element
-    // is playing the last one to set the context will be the one that actually gets to
-    //  play to the external device.
-    if (documentThatRequestedPicker)
-        documentThatRequestedPicker->didChoosePlaybackTarget(target);
-
-    m_documentRequestingPlaybackTargetPicker = nullptr;
 }
 
 void Page::playbackTargetAvailabilityDidChange(bool available)
@@ -1734,10 +1719,6 @@
         }
     }
 
-    if (m_requiresPlaybackTargetMonitoring == monitoringRequired)
-        return;
-    m_requiresPlaybackTargetMonitoring = monitoringRequired;
-
     if (monitoringRequired)
         chrome().client().startingMonitoringPlaybackTargets();
     else

Modified: trunk/Source/WebCore/page/Page.h (182239 => 182240)


--- trunk/Source/WebCore/page/Page.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/page/Page.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -426,7 +426,7 @@
     WEBCORE_EXPORT void setMuted(bool);
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    void showPlaybackTargetPicker(Document*, const WebCore::IntPoint&, bool);
+    void showPlaybackTargetPicker(const WebCore::IntPoint&, bool);
     bool hasWirelessPlaybackTarget() const { return m_hasWirelessPlaybackTarget; }
     MediaPlaybackTarget& playbackTarget() const { return *m_playbackTarget.get(); }
     void configurePlaybackTargetMonitoring();
@@ -587,9 +587,7 @@
     SessionID m_sessionID;
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    Document* m_documentRequestingPlaybackTargetPicker { nullptr };
     std::unique_ptr<MediaPlaybackTarget> m_playbackTarget;
-    bool m_requiresPlaybackTargetMonitoring { false };
     bool m_hasWirelessPlaybackTarget { false };
 #endif
 

Modified: trunk/Source/WebCore/platform/audio/MediaSession.cpp (182239 => 182240)


--- trunk/Source/WebCore/platform/audio/MediaSession.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/audio/MediaSession.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -227,6 +227,21 @@
     return m_client.displayType();
 }
 
+bool MediaSession::canPlayToWirelessPlaybackTarget() const
+{
+    return m_client.canPlayToWirelessPlaybackTarget();
+}
+
+void MediaSession::startPlayingToPlaybackTarget()
+{
+    client().startPlayingToPlaybackTarget();
+}
+
+void MediaSession::stopPlayingToPlaybackTarget()
+{
+    client().stopPlayingToPlaybackTarget();
+}
+
 String MediaSessionClient::mediaSessionTitle() const
 {
     return String();
@@ -241,6 +256,5 @@
 {
     return MediaPlayer::invalidTime();
 }
-
 }
 #endif

Modified: trunk/Source/WebCore/platform/audio/MediaSession.h (182239 => 182240)


--- trunk/Source/WebCore/platform/audio/MediaSession.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/audio/MediaSession.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -117,12 +117,15 @@
 
     bool isHidden() const;
 
+    bool canPlayToWirelessPlaybackTarget() const;
+    void startPlayingToPlaybackTarget();
+    void stopPlayingToPlaybackTarget();
+
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     // MediaPlaybackTargetPickerClient
     virtual void didChoosePlaybackTarget(const MediaPlaybackTarget&) override { }
     virtual void externalOutputDeviceAvailableDidChange(bool) const override { }
     virtual bool requiresPlaybackTargetRouteMonitoring() const override { return false; }
-    virtual bool requestedPlaybackTargetPicker() const override { return false; }
 #endif
 
 protected:
@@ -164,10 +167,11 @@
 
     virtual bool overrideBackgroundPlaybackRestriction() const = 0;
 
-#if ENABLE(WIRELESS_PLAYBACK_TARGET)
     virtual void wirelessRoutesAvailableDidChange() { }
     virtual void setWirelessPlaybackTarget(const MediaPlaybackTarget&) { }
-#endif
+    virtual bool canPlayToWirelessPlaybackTarget() { return false; }
+    virtual void startPlayingToPlaybackTarget() { }
+    virtual void stopPlayingToPlaybackTarget() { }
 
 protected:
     virtual ~MediaSessionClient() { }

Modified: trunk/Source/WebCore/platform/audio/MediaSessionManager.cpp (182239 => 182240)


--- trunk/Source/WebCore/platform/audio/MediaSessionManager.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/audio/MediaSessionManager.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -186,19 +186,18 @@
     if (m_interrupted)
         endInterruption(MediaSession::NoFlags);
 
-    if (!restrictions & ConcurrentPlaybackNotPermitted)
-        return true;
-
+    bool newSessionCanPlayToPlaybackTarget = session.canPlayToWirelessPlaybackTarget();
     Vector<MediaSession*> sessions = m_sessions;
     for (auto* oneSession : sessions) {
         if (_oneSession_ == &session)
             continue;
-        if (oneSession->mediaType() != sessionType)
-            continue;
-        if (restrictions & ConcurrentPlaybackNotPermitted)
+        if (newSessionCanPlayToPlaybackTarget)
+            oneSession->stopPlayingToPlaybackTarget();
+        if (oneSession->mediaType() == sessionType && restrictions & ConcurrentPlaybackNotPermitted)
             oneSession->pauseSession();
     }
-    
+    session.startPlayingToPlaybackTarget();
+
     updateSessionState();
     return true;
 }

Modified: trunk/Source/WebCore/platform/audio/MediaSessionManager.h (182239 => 182240)


--- trunk/Source/WebCore/platform/audio/MediaSessionManager.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/audio/MediaSessionManager.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -85,6 +85,9 @@
     virtual bool hasWirelessTargetsAvailable() { return false; }
 #endif
 
+    void setCurrentSession(MediaSession&);
+    MediaSession* currentSession();
+
 protected:
     friend class MediaSession;
     explicit MediaSessionManager();
@@ -92,9 +95,6 @@
     void addSession(MediaSession&);
     void removeSession(MediaSession&);
 
-    void setCurrentSession(MediaSession&);
-    MediaSession* currentSession();
-
     Vector<MediaSession*> sessions() { return m_sessions; }
 
 private:

Modified: trunk/Source/WebCore/platform/graphics/MediaPlaybackTarget.h (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/MediaPlaybackTarget.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/MediaPlaybackTarget.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -50,6 +50,11 @@
 
     void setDevicePickerContext(AVOutputContext *context) { m_devicePickerContext = context; }
     AVOutputContext *devicePickerContext() const { return m_devicePickerContext.get(); }
+    bool hasActiveRoute() const;
+#else
+    void setDevicePickerContext(AVOutputContext *) { }
+    AVOutputContext *devicePickerContext() const { return nullptr; }
+    bool hasActiveRoute() const { return false; }
 #endif
 
 protected:

Modified: trunk/Source/WebCore/platform/graphics/MediaPlaybackTargetPickerClient.h (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/MediaPlaybackTargetPickerClient.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/MediaPlaybackTargetPickerClient.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -42,7 +42,6 @@
     virtual void externalOutputDeviceAvailableDidChange(bool) const = 0;
 
     virtual bool requiresPlaybackTargetRouteMonitoring() const = 0;
-    virtual bool requestedPlaybackTargetPicker() const = 0;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -843,6 +843,11 @@
     return m_private->isCurrentPlaybackTargetWireless();
 }
 
+bool MediaPlayer::isCurrentPlaybackTargetSupported() const
+{
+    return m_private->isCurrentPlaybackTargetSupported();
+}
+
 String MediaPlayer::wirelessPlaybackTargetName() const
 {
     return m_private->wirelessPlaybackTargetName();
@@ -868,10 +873,25 @@
     m_client.mediaPlayerCurrentPlaybackTargetIsWirelessChanged(this);
 }
 
+bool MediaPlayer::canPlayToWirelessPlaybackTarget() const
+{
+    return m_private->canPlayToWirelessPlaybackTarget();
+}
+
 void MediaPlayer::setWirelessPlaybackTarget(const MediaPlaybackTarget& device)
 {
     m_private->setWirelessPlaybackTarget(device);
 }
+
+void MediaPlayer::startPlayingToPlaybackTarget()
+{
+    m_private->startPlayingToPlaybackTarget();
+}
+
+void MediaPlayer::stopPlayingToPlaybackTarget()
+{
+    m_private->stopPlayingToPlaybackTarget();
+}
 #endif
 
 double MediaPlayer::maxFastForwardRate() const

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -466,6 +466,7 @@
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     bool isCurrentPlaybackTargetWireless() const;
+    bool isCurrentPlaybackTargetSupported() const;
 
     enum WirelessPlaybackTargetType { TargetTypeNone, TargetTypeAirPlay, TargetTypeTVOut };
     WirelessPlaybackTargetType wirelessPlaybackTargetType() const;
@@ -478,7 +479,11 @@
     void currentPlaybackTargetIsWirelessChanged();
     void playbackTargetAvailabilityChanged();
 
+    bool canPlayToWirelessPlaybackTarget() const;
     void setWirelessPlaybackTarget(const MediaPlaybackTarget&);
+
+    void startPlayingToPlaybackTarget();
+    void stopPlayingToPlaybackTarget();
 #endif
 
     double minFastReverseRate() const;

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -161,14 +161,19 @@
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     virtual bool isCurrentPlaybackTargetWireless() const { return false; }
+    virtual bool isCurrentPlaybackTargetSupported() const { return true; }
 
     virtual String wirelessPlaybackTargetName() const { return emptyString(); }
     virtual MediaPlayer::WirelessPlaybackTargetType wirelessPlaybackTargetType() const { return MediaPlayer::TargetTypeNone; }
 
-    virtual bool wirelessVideoPlaybackDisabled() const { return false; }
+    virtual bool wirelessVideoPlaybackDisabled() const { return true; }
     virtual void setWirelessVideoPlaybackDisabled(bool) { }
 
+    virtual bool canPlayToWirelessPlaybackTarget() const { return false; }
     virtual void setWirelessPlaybackTarget(const MediaPlaybackTarget&) { }
+
+    virtual void startPlayingToPlaybackTarget() { }
+    virtual void stopPlayingToPlaybackTarget() { }
 #endif
 
 #if USE(NATIVE_FULLSCREEN_VIDEO)

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlaybackTargetMac.mm (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlaybackTargetMac.mm	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlaybackTargetMac.mm	2015-04-01 18:07:16 UTC (rev 182240)
@@ -28,7 +28,7 @@
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS)
 
-#import <WebCore/MediaPlaybackTarget.h>
+#import <WebCore/AVFoundationSPI.h>
 #import <WebCore/SoftLinking.h>
 #import <objc/runtime.h>
 
@@ -63,6 +63,12 @@
     return true;
 }
 
+bool MediaPlaybackTarget::hasActiveRoute() const
+{
+    return m_devicePickerContext && m_devicePickerContext.get().deviceName;
+}
+
+
 } // namespace WebCore
 
 #endif // ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS)

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp	2015-04-01 18:07:16 UTC (rev 182240)
@@ -619,7 +619,7 @@
 
 void MediaPlayerPrivateAVFoundation::rateChanged()
 {
-#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+#if ENABLE(WIRELESS_PLAYBACK_TARGET) && PLATFORM(IOS)
     if (isCurrentPlaybackTargetWireless())
         m_player->handlePlaybackCommand(rate() ? MediaSession::PlayCommand : MediaSession::PauseCommand);
 #endif

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -276,13 +276,17 @@
     virtual String wirelessPlaybackTargetName() const override;
     virtual MediaPlayer::WirelessPlaybackTargetType wirelessPlaybackTargetType() const override;
     virtual bool wirelessVideoPlaybackDisabled() const override;
-#if !PLATFORM(IOS)
-    virtual void setWirelessPlaybackTarget(const MediaPlaybackTarget&) override;
-#endif
     virtual void setWirelessVideoPlaybackDisabled(bool) override;
     void updateDisableExternalPlayback();
+    bool canPlayToWirelessPlaybackTarget() const { return true; }
 #endif
 
+#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS)
+    virtual void setWirelessPlaybackTarget(const MediaPlaybackTarget&) override;
+    virtual void startPlayingToPlaybackTarget() override;
+    virtual void stopPlayingToPlaybackTarget() override;
+#endif
+
     virtual double maxFastForwardRate() const override { return m_cachedCanPlayFastForward ? std::numeric_limits<double>::infinity() : 2.0; }
     virtual double minFastReverseRate() const override { return m_cachedCanPlayFastReverse ? -std::numeric_limits<double>::infinity() : 0.0; }
 

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2015-04-01 18:07:16 UTC (rev 182240)
@@ -347,7 +347,8 @@
 
 static NSArray *assetMetadataKeyNames();
 static NSArray *itemKVOProperties();
-static NSArray* assetTrackMetadataKeyNames();
+static NSArray *assetTrackMetadataKeyNames();
+static NSArray *playerKVOProperties();
 
 #if !LOG_DISABLED
 static const char *boolString(bool val)
@@ -545,11 +546,9 @@
         if (m_timeObserver)
             [m_avPlayer.get() removeTimeObserver:m_timeObserver.get()];
         m_timeObserver = nil;
-        [m_avPlayer.get() removeObserver:m_objcObserver.get() forKeyPath:@"rate"];
-#if ENABLE(WIRELESS_PLAYBACK_TARGET)
-        [m_avPlayer.get() removeObserver:m_objcObserver.get() forKeyPath:@"externalPlaybackActive"];
-        [m_avPlayer.get() removeObserver:m_objcObserver.get() forKeyPath:@"outputContext"];
-#endif
+
+        for (NSString *keyName in playerKVOProperties())
+            [m_avPlayer.get() removeObserver:m_objcObserver.get() forKeyPath:keyName];
         m_avPlayer = nil;
     }
 
@@ -927,28 +926,22 @@
     setDelayCallbacks(true);
 
     m_avPlayer = adoptNS([allocAVPlayerInstance() init]);
-    [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:(void *)MediaPlayerAVFoundationObservationContextPlayer];
-#if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:@"externalPlaybackActive" options:NSKeyValueObservingOptionNew context:(void *)MediaPlayerAVFoundationObservationContextPlayer];
-    [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:@"outputContext" options:NSKeyValueObservingOptionNew context:(void *)MediaPlayerAVFoundationObservationContextPlayer];
-#endif
+    for (NSString *keyName in playerKVOProperties())
+        [m_avPlayer.get() addObserver:m_objcObserver.get() forKeyPath:keyName options:NSKeyValueObservingOptionNew context:(void *)MediaPlayerAVFoundationObservationContextPlayer];
 
-#if ENABLE(WIRELESS_PLAYBACK_TARGET)
-    updateDisableExternalPlayback();
-#endif
-
 #if HAVE(AVFOUNDATION_MEDIA_SELECTION_GROUP) && HAVE(AVFOUNDATION_LEGIBLE_OUTPUT_SUPPORT)
     [m_avPlayer.get() setAppliesMediaSelectionCriteriaAutomatically:NO];
 #endif
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
+    updateDisableExternalPlayback();
     [m_avPlayer.get() setAllowsExternalPlayback:m_allowsWirelessVideoPlayback];
-#endif
 
-#if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS)
+#if !PLATFORM(IOS)
     if (m_outputContext)
         m_avPlayer.get().outputContext = m_outputContext.get();
 #endif
+#endif
 
     if (player()->client().mediaPlayerIsVideo())
         createAVPlayerLayer();
@@ -2731,8 +2724,14 @@
 {
     if (!m_avPlayer)
         return emptyString();
-    
-    String wirelessTargetName = wkExernalDeviceDisplayNameForPlayer(m_avPlayer.get());
+
+    String wirelessTargetName;
+#if !PLATFORM(IOS)
+    if (m_outputContext)
+        wirelessTargetName = m_outputContext.get().deviceName;
+#else
+    wirelessTargetName = wkExernalDeviceDisplayNameForPlayer(m_avPlayer.get());
+#endif
     LOG(Media, "MediaPlayerPrivateAVFoundationObjC::wirelessPlaybackTargetName(%p) - returning %s", this, wirelessTargetName.utf8().data());
 
     return wirelessTargetName;
@@ -2756,21 +2755,41 @@
     if (!m_avPlayer)
         return;
 
+    setDelayCallbacks(true);
     [m_avPlayer.get() setAllowsExternalPlayback:!disabled];
+    setDelayCallbacks(false);
 }
 
 #if !PLATFORM(IOS)
 void MediaPlayerPrivateAVFoundationObjC::setWirelessPlaybackTarget(const MediaPlaybackTarget& target)
 {
     m_outputContext = target.devicePickerContext();
-
     LOG(Media, "MediaPlayerPrivateAVFoundationObjC::setWirelessPlaybackTarget(%p) - target = %p", this, m_outputContext.get());
+}
 
+void MediaPlayerPrivateAVFoundationObjC::startPlayingToPlaybackTarget()
+{
     if (!m_avPlayer)
         return;
 
+    if ([m_avPlayer.get().outputContext isEqual:m_outputContext.get()])
+        return;
+
+    setDelayCallbacks(true);
     m_avPlayer.get().outputContext = m_outputContext.get();
+    setDelayCallbacks(false);
 }
+
+void MediaPlayerPrivateAVFoundationObjC::stopPlayingToPlaybackTarget()
+{
+    if (!m_avPlayer)
+        return;
+
+    setDelayCallbacks(true);
+    // FIXME: uncomment the following line once rdar://20335217 has been fixed.
+    // m_avPlayer.get().outputContext = nil;
+    setDelayCallbacks(false);
+}
 #endif
 
 void MediaPlayerPrivateAVFoundationObjC::updateDisableExternalPlayback()
@@ -3084,6 +3103,15 @@
     return keys;
 }
 
+NSArray* playerKVOProperties()
+{
+    static NSArray* keys = [[NSArray alloc] initWithObjects:@"rate",
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+                            @"externalPlaybackActive", @"outputContext", @"allowsExternalPlayback",
+#endif
+                            nil];
+    return keys;
+}
 } // namespace WebCore
 
 @implementation WebCoreAVFMovieObserver
@@ -3200,10 +3228,8 @@
         if ([keyPath isEqualToString:@"rate"])
             function = WTF::bind(&MediaPlayerPrivateAVFoundationObjC::rateDidChange, m_callback, [newValue doubleValue]);
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
-        else if ([keyPath isEqualToString:@"externalPlaybackActive"])
+        else if ([keyPath isEqualToString:@"externalPlaybackActive"] || [keyPath isEqualToString:@"outputContext"] || [keyPath isEqualToString:@"allowsExternalPlayback"])
             function = WTF::bind(&MediaPlayerPrivateAVFoundationObjC::playbackTargetIsWirelessDidChange, m_callback);
-        else if ([keyPath isEqualToString:@"outputContext"])
-            function = WTF::bind(&MediaPlayerPrivateAVFoundationObjC::playbackTargetIsWirelessDidChange, m_callback);
 #endif
     }
     

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -171,6 +171,14 @@
     virtual unsigned long corruptedVideoFrames() override;
     virtual MediaTime totalFrameDelay() override;
 
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+    virtual bool isCurrentPlaybackTargetSupported() const override;
+    virtual void setWirelessPlaybackTarget(const MediaPlaybackTarget&);
+    virtual void startPlayingToPlaybackTarget() override;
+    virtual void stopPlayingToPlaybackTarget() override;
+    void togglePlayingToPlaybackTarget();
+#endif
+
     void ensureLayer();
     void destroyLayer();
     bool shouldBePlaying() const;
@@ -212,6 +220,10 @@
     bool m_seekCompleted;
     mutable bool m_loadingProgressed;
     bool m_hasAvailableVideoFrame;
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+    std::unique_ptr<MediaPlaybackTarget> m_playbackTarget;
+    bool m_currentPlaybackTargetIsSupported { true };
+#endif
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm	2015-04-01 18:07:16 UTC (rev 182240)
@@ -806,6 +806,42 @@
     m_player->characteristicChanged();
 }
 
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+bool MediaPlayerPrivateMediaSourceAVFObjC::isCurrentPlaybackTargetSupported() const
+{
+    if (!m_playbackTarget)
+        return true;
+
+    return !m_playbackTarget->hasActiveRoute();
 }
 
+void MediaPlayerPrivateMediaSourceAVFObjC::setWirelessPlaybackTarget(const MediaPlaybackTarget& target)
+{
+    if (!m_playbackTarget)
+        m_playbackTarget = std::make_unique<MediaPlaybackTarget>();
+    m_playbackTarget->setDevicePickerContext(target.devicePickerContext());
+}
+
+void MediaPlayerPrivateMediaSourceAVFObjC::togglePlayingToPlaybackTarget()
+{
+    bool oldSupported = m_currentPlaybackTargetIsSupported;
+    m_currentPlaybackTargetIsSupported = !m_playbackTarget || !m_playbackTarget->hasActiveRoute();
+
+    if (m_player && oldSupported != m_currentPlaybackTargetIsSupported)
+        m_player->currentPlaybackTargetIsWirelessChanged();
+}
+
+void MediaPlayerPrivateMediaSourceAVFObjC::startPlayingToPlaybackTarget()
+{
+    togglePlayingToPlaybackTarget();
+}
+
+void MediaPlayerPrivateMediaSourceAVFObjC::stopPlayingToPlaybackTarget()
+{
+    togglePlayingToPlaybackTarget();
+}
 #endif
+
+}
+
+#endif

Modified: trunk/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h	2015-04-01 18:07:16 UTC (rev 182240)
@@ -179,6 +179,14 @@
     virtual String engineDescription() const { return "QTKit"; }
     virtual long platformErrorCode() const;
 
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+    virtual bool isCurrentPlaybackTargetSupported() const override;
+    virtual void setWirelessPlaybackTarget(const MediaPlaybackTarget&);
+    virtual void startPlayingToPlaybackTarget() override;
+    virtual void stopPlayingToPlaybackTarget() override;
+    void togglePlayingToPlaybackTarget();
+#endif
+
     MediaPlayer* m_player;
     RetainPtr<QTMovie> m_qtMovie;
     RetainPtr<QTVideoRendererWebKitOnly> m_qtVideoRenderer;
@@ -206,6 +214,10 @@
     bool m_privateBrowsing;
     mutable MediaTime m_maxTimeLoadedAtLastDidLoadingProgress;
     mutable FloatSize m_cachedNaturalSize;
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+    std::unique_ptr<MediaPlaybackTarget> m_playbackTarget;
+    bool m_currentPlaybackTargetIsSupported { true };
+#endif
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm (182239 => 182240)


--- trunk/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm	2015-04-01 17:48:57 UTC (rev 182239)
+++ trunk/Source/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm	2015-04-01 18:07:16 UTC (rev 182240)
@@ -1540,6 +1540,42 @@
     return false;
 }
 
+#if ENABLE(WIRELESS_PLAYBACK_TARGET)
+bool MediaPlayerPrivateQTKit::isCurrentPlaybackTargetSupported() const
+{
+    if (!m_playbackTarget)
+        return true;
+
+    return !m_playbackTarget->hasActiveRoute();
+}
+
+void MediaPlayerPrivateQTKit::setWirelessPlaybackTarget(const MediaPlaybackTarget& target)
+{
+    if (!m_playbackTarget)
+        m_playbackTarget = std::make_unique<MediaPlaybackTarget>();
+    m_playbackTarget->setDevicePickerContext(target.devicePickerContext());
+}
+
+void MediaPlayerPrivateQTKit::togglePlayingToPlaybackTarget()
+{
+    bool oldSupported = m_currentPlaybackTargetIsSupported;
+    m_currentPlaybackTargetIsSupported = !m_playbackTarget || !m_playbackTarget->hasActiveRoute();
+
+    if (m_player && oldSupported != m_currentPlaybackTargetIsSupported)
+        m_player->currentPlaybackTargetIsWirelessChanged();
+}
+
+void MediaPlayerPrivateQTKit::startPlayingToPlaybackTarget()
+{
+    togglePlayingToPlaybackTarget();
+}
+
+void MediaPlayerPrivateQTKit::stopPlayingToPlaybackTarget()
+{
+    togglePlayingToPlaybackTarget();
+}
+#endif
+
 } // namespace WebCore
 
 @implementation WebCoreMovieObserver
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to