Changeset 186918 in webkit


Ignore:
Timestamp:
Jul 16, 2015 4:36:13 PM (9 years ago)
Author:
mrajca@apple.com
Message:

Media Session: handle 'Transient' and 'Transient Solo' interruption events https://bugs.webkit.org/show_bug.cgi?id=146840

Reviewed by Eric Carlson.

  • Modules/mediasession/MediaSession.cpp:

(WebCore::MediaSession::handleDuckInterruption): Added stub.
(WebCore::MediaSession::handleUnduckInterruption): Added stub.
(WebCore::MediaSession::handlePauseInterruption): Pause active media elements. We use our helper method to do this

"safely" since pausing a media element can change the collection we're iterating.

(WebCore::MediaSession::handleUnpauseInterruption): Unpause active media elements. We use our helper method to do this

"safely" since unpausing a media element can change the collection we're iterating.

(WebCore::MediaSession::togglePlayback): Factored out "safe" iteration into a helper method elsewhere.
(WebCore::MediaSession::safelyIterateActiveMediaElements): Safely iterate through the collection of active media

elements.

  • Modules/mediasession/MediaSession.h:
  • Modules/mediasession/MediaSessionManager.cpp:

(WebCore::MediaSessionManager::MediaSessionManager): On Mac, register for platform-specific interruptions.
(WebCore::MediaSessionManager::didReceiveStartOfInterruptionNotification): Implemented section 4.5.2 of Media Session spec.
(WebCore::MediaSessionManager::didReceiveEndOfInterruptionNotification): Ditto.

  • Modules/mediasession/MediaSessionManager.h:
Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r186917 r186918  
     12015-07-16  Matt Rajca  <mrajca@apple.com>
     2
     3        Media Session: handle 'Transient' and 'Transient Solo' interruption events
     4        https://bugs.webkit.org/show_bug.cgi?id=146840
     5
     6        Reviewed by Eric Carlson.
     7
     8        * Modules/mediasession/MediaSession.cpp:
     9        (WebCore::MediaSession::handleDuckInterruption): Added stub.
     10        (WebCore::MediaSession::handleUnduckInterruption): Added stub.
     11        (WebCore::MediaSession::handlePauseInterruption): Pause active media elements. We use our helper method to do this
     12          "safely" since pausing a media element can change the collection we're iterating.
     13        (WebCore::MediaSession::handleUnpauseInterruption): Unpause active media elements. We use our helper method to do this
     14          "safely" since unpausing a media element can change the collection we're iterating.
     15        (WebCore::MediaSession::togglePlayback): Factored out "safe" iteration into a helper method elsewhere.
     16        (WebCore::MediaSession::safelyIterateActiveMediaElements): Safely iterate through the collection of active media
     17          elements.
     18        * Modules/mediasession/MediaSession.h:
     19        * Modules/mediasession/MediaSessionManager.cpp:
     20        (WebCore::MediaSessionManager::MediaSessionManager): On Mac, register for platform-specific interruptions.
     21        (WebCore::MediaSessionManager::didReceiveStartOfInterruptionNotification): Implemented section 4.5.2 of Media Session spec.
     22        (WebCore::MediaSessionManager::didReceiveEndOfInterruptionNotification): Ditto.
     23        * Modules/mediasession/MediaSessionManager.h:
     24
    1252015-07-16  Matt Rajca  <mrajca@apple.com>
    226
  • trunk/Source/WebCore/Modules/mediasession/MediaSession.cpp

    r186593 r186918  
    239239}
    240240
     241void MediaSession::handleDuckInterruption()
     242{
     243    // FIXME: Duck media elements.
     244
     245    m_currentState = State::Interrupted;
     246}
     247
     248void MediaSession::handleUnduckInterruption()
     249{
     250    // FIXME: Unduck media elements.
     251
     252    m_currentState = State::Active;
     253}
     254
     255void MediaSession::handlePauseInterruption()
     256{
     257    m_currentState = State::Interrupted;
     258
     259    safelyIterateActiveMediaElements([](HTMLMediaElement* element) {
     260        element->pause();
     261    });
     262}
     263
     264void MediaSession::handleUnpauseInterruption()
     265{
     266    m_currentState = State::Active;
     267
     268    safelyIterateActiveMediaElements([](HTMLMediaElement* element) {
     269        element->play();
     270    });
     271}
     272
    241273void MediaSession::togglePlayback()
    242274{
    243     ASSERT(!m_iteratedActiveParticipatingElements);
    244 
    245     HashSet<HTMLMediaElement*> activeParticipatingElementsCopy = m_activeParticipatingElements;
    246     m_iteratedActiveParticipatingElements = &activeParticipatingElementsCopy;
    247 
    248     while (!activeParticipatingElementsCopy.isEmpty()) {
    249         HTMLMediaElement* element = activeParticipatingElementsCopy.takeAny();
    250 
     275    safelyIterateActiveMediaElements([](HTMLMediaElement* element) {
    251276        if (element->paused())
    252277            element->play();
    253278        else
    254279            element->pause();
    255     }
     280    });
     281}
     282
     283void MediaSession::safelyIterateActiveMediaElements(std::function<void(HTMLMediaElement*)> handler)
     284{
     285    ASSERT(!m_iteratedActiveParticipatingElements);
     286
     287    HashSet<HTMLMediaElement*> activeParticipatingElementsCopy = m_activeParticipatingElements;
     288    m_iteratedActiveParticipatingElements = &activeParticipatingElementsCopy;
     289
     290    while (!activeParticipatingElementsCopy.isEmpty())
     291        handler(activeParticipatingElementsCopy.takeAny());
    256292
    257293    m_iteratedActiveParticipatingElements = nullptr;
  • trunk/Source/WebCore/Modules/mediasession/MediaSession.h

    r186593 r186918  
    4646    };
    4747
     48    enum class Kind {
     49        Default,
     50        Content,
     51        Transient,
     52        TransientSolo,
     53        Ambient
     54    };
     55
    4856    static Ref<MediaSession> create(ScriptExecutionContext& context, const String& kind)
    4957    {
     
    5664
    5765    String kind() const;
     66    Kind kindEnum() const { return m_kind; }
    5867    MediaRemoteControls* controls(bool& isNull);
    5968
     
    6473
    6574    void releaseSession();
    66    
     75
    6776    // Runs the media session invocation algorithm and returns true on success.
    6877    bool invoke();
     78
     79    void handleDuckInterruption();
     80    void handlePauseInterruption();
     81    void handleUnduckInterruption();
     82    void handleUnpauseInterruption();
    6983
    7084    void togglePlayback();
     
    7589    friend class HTMLMediaElement;
    7690
    77     enum class Kind {
    78         Default,
    79         Content,
    80         Transient,
    81         TransientSolo,
    82         Ambient
    83     };
    84 
    8591    static Kind parseKind(const String&);
    86     Kind kindEnum() const { return m_kind; }
    8792
    8893    void addMediaElement(HTMLMediaElement&);
    8994    void removeMediaElement(HTMLMediaElement&);
    9095
     96    void safelyIterateActiveMediaElements(std::function<void(HTMLMediaElement*)>);
    9197    void changeActiveMediaElements(std::function<void(void)>);
    9298    void addActiveMediaElement(HTMLMediaElement&);
  • trunk/Source/WebCore/Modules/mediasession/MediaSessionManager.cpp

    r186593 r186918  
    3030
    3131#include "MediaSession.h"
    32 #include <wtf/NeverDestroyed.h>
     32#include "MediaSessionInterruptionProviderMac.h"
    3333
    3434namespace WebCore {
     
    4040    static NeverDestroyed<MediaSessionManager> manager;
    4141    return manager;
     42}
     43
     44MediaSessionManager::MediaSessionManager()
     45{
     46#if PLATFORM(MAC)
     47    m_interruptionProvider = adoptRef(new MediaSessionInterruptionProviderMac(*this));
     48#endif
    4249}
    4350
     
    93100}
    94101
     102void MediaSessionManager::didReceiveStartOfInterruptionNotification(MediaSessionInterruptingCategory interruptingCategory)
     103{
     104    // 4.5.2 Interrupting a media session
     105    // When a start-of-interruption notification event is received from the platform, then the user agent must run the
     106    // media session interruption algorithm against all known media sessions, passing in each media session as media session.
     107    for (auto* session : m_sessions) {
     108        // 1. If media session's current state is not active, then terminate these steps.
     109        if (session->currentState() != MediaSession::State::Active)
     110            continue;
     111
     112        // 2. Let interrupting media session category be the media session category that triggered this interruption.
     113        //    If this interruption has no known media session category, let interrupting media session category be Default.
     114
     115        // 3. Run these substeps:
     116        if (interruptingCategory == MediaSessionInterruptingCategory::Transient) {
     117            // - If interrupting media session category is Transient
     118            //   If media session's current media session type is Default or Content then duck all of media session's active
     119            //   audio-producing participants and set media session's current state to interrupted.
     120            if (session->kindEnum() == MediaSession::Kind::Default || session->kindEnum() == MediaSession::Kind::Content)
     121                session->handleDuckInterruption();
     122        } else if (interruptingCategory == MediaSessionInterruptingCategory::TransientSolo) {
     123            // - If interrupting media session category is Transient Solo:
     124            //   If media session's current media session type is Default, Content, Transient or Transient Solo then pause
     125            //   all of media session's active audio-producing participants and set current media session's current state to interrupted.
     126            if (session->kindEnum() != MediaSession::Kind::Ambient)
     127                session->handlePauseInterruption();
     128        }
     129    }
    95130}
    96131
     132void MediaSessionManager::didReceiveEndOfInterruptionNotification(MediaSessionInterruptingCategory interruptingCategory)
     133{
     134    // 4.5.2 Interrupting a media session
     135    // When an end-of-interruption notification event is received from the platform, then the user agent must run the
     136    // media session continuation algorithm against all known media sessions, passing in each media session as media session.
     137    for (auto* session : m_sessions) {
     138        // 1. If media session's current state is not interrupted, then terminate these steps.
     139        if (session->currentState() != MediaSession::State::Interrupted)
     140            continue;
     141
     142        // 2. Let interrupting media session category be the media session category that initially triggered this interruption.
     143        //    If this interruption has no known media session category, let interrupting media session category be Default.
     144
     145        // 3. Run these substeps:
     146        if (interruptingCategory == MediaSessionInterruptingCategory::Transient) {
     147            // - If interrupting media session category is Transient:
     148            //   If media session's current media session type is Default or Content, then unduck all of media session's
     149            //   active audio-producing participants and set media session's current state to active.
     150            if (session->kindEnum() == MediaSession::Kind::Default || session->kindEnum() == MediaSession::Kind::Content)
     151                session->handleUnduckInterruption();
     152        } else if (interruptingCategory == MediaSessionInterruptingCategory::TransientSolo) {
     153            // - If interrupting media session category is Transient Solo:
     154            //   If media session's current media session type is Default, Content, Transient, or Transient Solo, then
     155            //   unpause the media session's active audio-producing participants and set media session's current state to active.
     156            if (session->kindEnum() != MediaSession::Kind::Ambient)
     157                session->handleUnpauseInterruption();
     158        }
     159    }
     160}
     161
     162} // namespace WebCore
     163
    97164#endif /* ENABLE(MEDIA_SESSION) */
  • trunk/Source/WebCore/Modules/mediasession/MediaSessionManager.h

    r186593 r186918  
    2929#if ENABLE(MEDIA_SESSION)
    3030
     31#include "MediaSessionInterruptionProvider.h"
    3132#include <wtf/HashSet.h>
     33#include <wtf/NeverDestroyed.h>
    3234
    3335namespace WebCore {
     
    3537class MediaSession;
    3638
    37 class MediaSessionManager {
     39class MediaSessionManager : public MediaSessionInterruptionProviderClient {
     40    friend class NeverDestroyed<MediaSessionManager>;
    3841public:
    3942    static MediaSessionManager& singleton();
     
    4346    void skipToPreviousTrack();
    4447
     48    void didReceiveStartOfInterruptionNotification(MediaSessionInterruptingCategory) override;
     49    void didReceiveEndOfInterruptionNotification(MediaSessionInterruptingCategory) override;
     50
    4551private:
    4652    friend class MediaSession;
     53
     54    MediaSessionManager();
    4755
    4856    bool hasActiveMediaElements() const;
     
    5159    void removeMediaSession(MediaSession&);
    5260
     61    RefPtr<MediaSessionInterruptionProvider> m_interruptionProvider;
    5362    HashSet<MediaSession*> m_sessions;
    5463};
Note: See TracChangeset for help on using the changeset viewer.