Changeset 163390 in webkit


Ignore:
Timestamp:
Feb 4, 2014, 11:09:34 AM (11 years ago)
Author:
eric.carlson@apple.com
Message:

Refine MediaSession interruptions
https://bugs.webkit.org/show_bug.cgi?id=128125

Reviewed by Jer Noble.

Source/WebCore:

Test: media/video-background-playback.html

  • WebCore.exp.in: Export applicationWillEnterForeground and applicationWillEnterBackground for

Internals.

  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::play): Ask the media session if playback is allowed instead of check

to see if it is interrupted directly.

(WebCore::HTMLMediaElement::pause): Ask the media session if pausing is allowed instead of check

to see if it is interrupted directly.

(WebCore::HTMLMediaElement::mediaType): Return media type based on media characteristics once

the information is available.

(WebCore::HTMLMediaElement::resumePlayback): New.

  • html/HTMLMediaElement.h:
  • html/HTMLMediaSession.cpp:

(WebCore::restrictionName): New, use for logging only.
(WebCore::HTMLMediaSession::addBehaviorRestriction): Log restriction changes.
(WebCore::HTMLMediaSession::removeBehaviorRestriction): Ditto.

  • html/HTMLMediaSession.h:
  • platform/audio/MediaSession.cpp:

(WebCore::stateName): New, used for logging.
(WebCore::MediaSession::MediaSession): Don't cache client media type because it can change.
(WebCore::MediaSession::setState): Log state changes.
(WebCore::MediaSession::beginInterruption): Remember the current state in case we want to use it

to restore state when the interruption ends.

(WebCore::MediaSession::endInterruption): Resume playback if appropriate.
(WebCore::MediaSession::clientWillBeginPlayback): Track the client's playback state.
(WebCore::MediaSession::clientWillPausePlayback): Ditto.
(WebCore::MediaSession::mediaType): Ask client for state.

  • platform/audio/MediaSession.h:
  • platform/audio/MediaSessionManager.cpp:

(WebCore::MediaSessionManager::MediaSessionManager): m_interruptions -> m_interrupted.
(WebCore::MediaSessionManager::beginInterruption): Don't assume interruptions are always balanced.
(WebCore::MediaSessionManager::endInterruption): Ditto.
(WebCore::MediaSessionManager::addSession):
(WebCore::MediaSessionManager::applicationWillEnterBackground): Interrupt client if it is not

allowed to play in the background.

(WebCore::MediaSessionManager::applicationWillEnterForeground): End client interruption if it

was stopped by an interruption.

  • platform/audio/MediaSessionManager.h:
  • platform/audio/ios/MediaSessionManagerIOS.h:
  • platform/audio/ios/MediaSessionManagerIOS.mm:

(WebCore::MediaSessionManageriOS::~MediaSessionManageriOS): Clear the helper callback.
(WebCore::MediaSessionManageriOS::resetRestrictions): Mark video as not allowed to play

while the application is in the background. Register for application suspend/resume
notifications.

(-[WebMediaSessionHelper clearCallback]): Set _callback to nil.
(-[WebMediaSessionHelper applicationWillEnterForeground:]): New, notify client of application

state change.

(-[WebMediaSessionHelper applicationWillResignActive:]): Ditto.

  • platform/audio/mac/AudioDestinationMac.h: Add resumePlayback.
  • testing/Internals.cpp:

(WebCore::Internals::applicationWillEnterForeground): New, simulate application context switch.
(WebCore::Internals::applicationWillEnterBackground): Ditto.
(WebCore::Internals::setMediaSessionRestrictions): Add "BackgroundPlaybackNotPermitted" restriction.

  • testing/Internals.h:
  • testing/Internals.idl:

Source/WebKit:

  • WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in: Export applicationWillEnterForeground

and applicationWillEnterBackground for Internals.

LayoutTests:

  • media/video-background-playback-expected.txt: Added.
  • media/video-background-playback.html: Added.
  • media/video-interruption-active-when-element-created-expected.txt: Removed.
  • media/video-interruption-active-when-element-created.html: Removed.
  • media/video-interruption-with-resume-allowing-play-expected.txt:
  • media/video-interruption-with-resume-allowing-play.html:
  • media/video-interruption-with-resume-not-allowing-play-expected.txt:
  • media/video-interruption-with-resume-not-allowing-play.html:
Location:
trunk
Files:
2 added
2 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r163382 r163390  
     12014-02-04  Eric Carlson  <eric.carlson@apple.com>
     2
     3        Refine MediaSession interruptions
     4        https://bugs.webkit.org/show_bug.cgi?id=128125
     5
     6        Reviewed by Jer Noble.
     7
     8        * media/video-background-playback-expected.txt: Added.
     9        * media/video-background-playback.html: Added.
     10        * media/video-interruption-active-when-element-created-expected.txt: Removed.
     11        * media/video-interruption-active-when-element-created.html: Removed.
     12        * media/video-interruption-with-resume-allowing-play.html:
     13        * media/video-interruption-with-resume-not-allowing-play.html:
     14
    1152014-02-04  Radu Stavila  <stavila@adobe.com>
    216
  • trunk/LayoutTests/media/video-interruption-with-resume-allowing-play-expected.txt

    r163377 r163390  
    33
    44EVENT(canplaythrough)
     5RUN(video.play())
    56
     7EVENT(playing)
     8EXPECTED (video.paused == 'false') OK
    69RUN(internals.beginMediaSessionInterruption())
    7 RUN(video.play())
     10
    811100ms timer fired...
    912EXPECTED (video.paused == 'true') OK
    1013RUN(internals.endMediaSessionInterruption('MayResumePlaying'))
     14
    1115EVENT(playing)
     16EXPECTED (video.paused == 'false') OK
    1217
    1318END OF TEST
  • trunk/LayoutTests/media/video-interruption-with-resume-allowing-play.html

    r163377 r163390  
    88            function checkState()
    99            {
    10                 consoleWrite("100ms timer fired...");
    11                 testExpected("video.paused", true);
    12                 state = "resuming";
    13                 run("internals.endMediaSessionInterruption('MayResumePlaying')");
    14             }
    15 
    16             function playing()
    17             {
    18                 if (state != "resuming")
    19                 {
     10                switch (state) {
     11                case "playing":
     12                    testExpected("video.paused", false);
     13                    state = "interrupted";
     14                    run("internals.beginMediaSessionInterruption()");;
     15                    setTimeout(checkState, 100);
    2016                    consoleWrite("");
    21                     failTest("<b>Playback started during interruption.</b>");
    22                     return;
     17                    break;
     18                case "interrupted":
     19                    consoleWrite("100ms timer fired...");
     20                    testExpected("video.paused", true);
     21                    state = "resuming";
     22                    run("internals.endMediaSessionInterruption('MayResumePlaying')");
     23                    consoleWrite("");
     24                    break;
     25                case "resuming":
     26                    testExpected("video.paused", false);
     27                    consoleWrite("");
     28                    endTest();
     29                    break;
    2330                }
    24 
    25                 consoleWrite("");
    26                 endTest();
    2731            }
    2832
    2933            function canplaythrough()
    3034            {
     35                state = "playing";
     36                run("video.play()");
    3137                consoleWrite("");
    32 
    33                 run("internals.beginMediaSessionInterruption()");;
    34                 state = "interrupted";
    35                 run("video.play()");
    36                 setTimeout(checkState, 100);
    3738            }
    3839
     
    4647                findMediaElement();
    4748                waitForEvent('canplaythrough', canplaythrough);
    48                 waitForEvent('playing', playing);
     49                waitForEvent('playing', checkState);
    4950                video.src = findMediaFile("video", "content/test");
    5051            }
  • trunk/LayoutTests/media/video-interruption-with-resume-not-allowing-play-expected.txt

    r163377 r163390  
    11
    2 Test that play() during interruption does nothing, ending interruption does not allow playback to resume.
     2Test that playback is paused by an interruption, and that ending the interruption does automatically resume playback.
    33
    44EVENT(canplaythrough)
     5RUN(video.play())
    56
     7EVENT(playing)
    68RUN(internals.beginMediaSessionInterruption())
    7 RUN(video.play())
     9
    810100ms timer fired...
    911EXPECTED (video.paused == 'true') OK
    1012RUN(internals.endMediaSessionInterruption(''))
     13
    1114100ms timer fired...
    1215EXPECTED (video.paused == 'true') OK
  • trunk/LayoutTests/media/video-interruption-with-resume-not-allowing-play.html

    r163377 r163390  
    88            function playing()
    99            {
    10                 if (state == "resuming")
    11                     failTest("<b>Playback started after interruption.</b>");
    12                 else
    13                     failTest("<b>Playback started during interruption.</b>");
     10                run("internals.beginMediaSessionInterruption()");;
     11                setTimeout(checkState, 100);
    1412            }
    1513
    1614            function checkState()
    1715            {
    18                 consoleWrite("100ms timer fired...");
     16                consoleWrite("<br>100ms timer fired...");
    1917                testExpected("video.paused", true);
    2018                switch (state) {
     
    3331            function canplaythrough()
    3432            {
    35                 consoleWrite("");
    36 
    37                 run("internals.beginMediaSessionInterruption()");;
    3833                state = "interrupted";
    3934                run("video.play()");
    40                 setTimeout(checkState, 100);
     35                consoleWrite("");
    4136            }
    4237
     
    5853    <body onload="start()">
    5954        <video controls ></video>
    60         <p>Test that play() during interruption does nothing, ending interruption does not allow playback to resume.</p>
     55        <p>Test that playback is paused by an interruption, and that ending the interruption does automatically resume playback.</p>
    6156    </body>
    6257</html>
  • trunk/Source/WebCore/ChangeLog

    r163389 r163390  
     12014-02-04  Eric Carlson  <eric.carlson@apple.com>
     2
     3        Refine MediaSession interruptions
     4        https://bugs.webkit.org/show_bug.cgi?id=128125
     5
     6        Reviewed by Jer Noble.
     7
     8        Test: media/video-background-playback.html
     9
     10        * WebCore.exp.in: Export applicationWillEnterForeground and applicationWillEnterBackground for
     11            Internals.
     12
     13        * html/HTMLMediaElement.cpp:
     14        (WebCore::HTMLMediaElement::play): Ask the media session if playback is allowed instead of check
     15            to see if it is interrupted directly.
     16        (WebCore::HTMLMediaElement::pause): Ask the media session if pausing is allowed instead of check
     17            to see if it is interrupted directly.
     18        (WebCore::HTMLMediaElement::mediaType): Return media type based on media characteristics once
     19            the information is available.
     20        (WebCore::HTMLMediaElement::resumePlayback): New.
     21        * html/HTMLMediaElement.h:
     22
     23        * html/HTMLMediaSession.cpp:
     24        (WebCore::restrictionName): New, use for logging only.
     25        (WebCore::HTMLMediaSession::addBehaviorRestriction): Log  restriction changes.
     26        (WebCore::HTMLMediaSession::removeBehaviorRestriction): Ditto.
     27        * html/HTMLMediaSession.h:
     28
     29        * platform/audio/MediaSession.cpp:
     30        (WebCore::stateName): New, used for logging.
     31        (WebCore::MediaSession::MediaSession): Don't cache client media type because it can change.
     32        (WebCore::MediaSession::setState): Log state changes.
     33        (WebCore::MediaSession::beginInterruption): Remember the current state in case we want to use it
     34            to restore state when the interruption ends.
     35        (WebCore::MediaSession::endInterruption): Resume playback if appropriate.
     36        (WebCore::MediaSession::clientWillBeginPlayback): Track the client's playback state.
     37        (WebCore::MediaSession::clientWillPausePlayback): Ditto.
     38        (WebCore::MediaSession::mediaType): Ask client for state.
     39        * platform/audio/MediaSession.h:
     40
     41        * platform/audio/MediaSessionManager.cpp:
     42        (WebCore::MediaSessionManager::MediaSessionManager): m_interruptions -> m_interrupted.
     43        (WebCore::MediaSessionManager::beginInterruption): Don't assume interruptions are always balanced.
     44        (WebCore::MediaSessionManager::endInterruption): Ditto.
     45        (WebCore::MediaSessionManager::addSession):
     46        (WebCore::MediaSessionManager::applicationWillEnterBackground): Interrupt client if it is not
     47            allowed to play in the background.
     48        (WebCore::MediaSessionManager::applicationWillEnterForeground): End client interruption if it
     49            was stopped by an interruption.
     50        * platform/audio/MediaSessionManager.h:
     51
     52        * platform/audio/ios/MediaSessionManagerIOS.h:
     53        * platform/audio/ios/MediaSessionManagerIOS.mm:
     54        (WebCore::MediaSessionManageriOS::~MediaSessionManageriOS): Clear the helper callback.
     55        (WebCore::MediaSessionManageriOS::resetRestrictions): Mark video as not allowed to play
     56            while the application is in the background. Register for application suspend/resume
     57            notifications.
     58        (-[WebMediaSessionHelper clearCallback]): Set _callback to nil.
     59        (-[WebMediaSessionHelper applicationWillEnterForeground:]): New, notify client of application
     60            state change.
     61        (-[WebMediaSessionHelper applicationWillResignActive:]): Ditto.
     62
     63        * platform/audio/mac/AudioDestinationMac.h: Add resumePlayback.
     64
     65        * testing/Internals.cpp:
     66        (WebCore::Internals::applicationWillEnterForeground): New, simulate application context switch.
     67        (WebCore::Internals::applicationWillEnterBackground): Ditto.
     68        (WebCore::Internals::setMediaSessionRestrictions): Add "BackgroundPlaybackNotPermitted" restriction.
     69        * testing/Internals.h:
     70        * testing/Internals.idl:
     71
    1722014-02-04  Andreas Kling  <akling@apple.com>
    273
  • trunk/Source/WebCore/WebCore.exp.in

    r163377 r163390  
    761761__ZN7WebCore19MediaSessionManager17beginInterruptionEv
    762762__ZN7WebCore19MediaSessionManager17removeRestrictionENS_12MediaSession9MediaTypeEj
     763__ZNK7WebCore19MediaSessionManager30applicationWillEnterBackgroundEv
     764__ZNK7WebCore19MediaSessionManager30applicationWillEnterForegroundEv
    763765__ZN7WebCore19ResourceRequestBase11setHTTPBodyEN3WTF10PassRefPtrINS_8FormDataEEE
    764766__ZN7WebCore19ResourceRequestBase13setHTTPMethodERKN3WTF6StringE
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r163377 r163390  
    26492649        removeBehaviorsRestrictionsAfterFirstUserGesture();
    26502650
    2651     if (m_mediaSession->state() == MediaSession::Interrupted) {
    2652         m_resumePlaybackAfterInterruption = true;
     2651    if (!m_mediaSession->clientWillBeginPlayback()) {
     2652        LOG(Media, "  returning because of interruption");
    26532653        return;
    26542654    }
     
    26962696        return;
    26972697
    2698     if (m_mediaSession->state() == MediaSession::Interrupted) {
    2699         m_resumePlaybackAfterInterruption = false;
    2700         return;
    2701     }
    2702    
     2698    if (!m_mediaSession->clientWillPausePlayback()) {
     2699        LOG(Media, "  returning because of interruption");
     2700        return;
     2701    }
     2702
    27032703    pauseInternal();
    27042704}
     
    42694269
    42704270        if (playerPaused) {
    4271             m_mediaSession->clientWillBeginPlayback();
    4272 
    42734271            if (m_mediaSession->requiresFullscreenForVideoPlayback(*this))
    42744272                enterFullscreen();
     
    42904288        m_playing = true;
    42914289
    4292     } else { // Should not be playing right now
     4290    } else {
    42934291        if (!playerPaused)
    42944292            m_player->pause();
     
    57635761MediaSession::MediaType HTMLMediaElement::mediaType() const
    57645762{
     5763    if (m_player && m_readyState >= HAVE_METADATA)
     5764        return hasVideo() ? MediaSession::Video : MediaSession::Audio;
     5765
    57655766    if (hasTagName(HTMLNames::videoTag))
    57665767        return MediaSession::Video;
     
    57695770}
    57705771
    5771 void HTMLMediaElement::beginInterruption()
    5772 {
    5773     LOG(Media, "HTMLMediaElement::beginInterruption");
    5774    
    5775     m_resumePlaybackAfterInterruption = !paused();
    5776     if (m_resumePlaybackAfterInterruption)
    5777         pause();
    5778 }
    5779 
    5780 void HTMLMediaElement::endInterruption(MediaSession::EndInterruptionFlags flags)
    5781 {
    5782     bool shouldResumePlayback = m_resumePlaybackAfterInterruption;
    5783     m_resumePlaybackAfterInterruption = false;
    5784 
    5785     if (!flags & MediaSession::MayResumePlaying)
    5786         return;
    5787 
    5788     if (shouldResumePlayback)
    5789         play();
    5790 }
    5791 
    57925772void HTMLMediaElement::pausePlayback()
    57935773{
     5774    LOG(Media, "HTMLMediaElement::pausePlayback - paused = %s", boolString(paused()));
    57945775    if (!paused())
    57955776        pause();
    57965777}
    57975778
    5798 }
    5799 
    5800 #endif
     5779void HTMLMediaElement::resumePlayback()
     5780{
     5781    LOG(Media, "HTMLMediaElement::resumePlayback - paused = %s", boolString(paused()));
     5782    if (paused())
     5783        play();
     5784}
     5785
     5786}
     5787
     5788#endif
  • trunk/Source/WebCore/html/HTMLMediaElement.h

    r163377 r163390  
    670670
    671671    virtual MediaSession::MediaType mediaType() const override;
    672 
    673     virtual void beginInterruption() override;
    674     virtual void endInterruption(MediaSession::EndInterruptionFlags) override;
    675672    virtual void pausePlayback() override;
     673    virtual void resumePlayback() override;
    676674
    677675    Timer<HTMLMediaElement> m_loadTimer;
     
    781779#endif
    782780
    783     bool m_resumePlaybackAfterInterruption : 1;
    784 
    785781#if ENABLE(VIDEO_TRACK)
    786782    bool m_tracksAreReady : 1;
  • trunk/Source/WebCore/html/HTMLMediaSession.cpp

    r163377 r163390  
    4343namespace WebCore {
    4444
     45#if !LOG_DISABLED
     46static const char* restrictionName(HTMLMediaSession::BehaviorRestrictions restriction)
     47{
     48#define CASE(_restriction) case HTMLMediaSession::_restriction: return #_restriction; break;
     49    switch (restriction) {
     50    CASE(NoRestrictions);
     51    CASE(RequireUserGestureForLoad);
     52    CASE(RequireUserGestureForRateChange);
     53    CASE(RequireUserGestureForFullscreen);
     54    CASE(RequirePageConsentToLoadMedia);
     55    CASE(RequirePageConsentToResumeMedia);
     56#if ENABLE(IOS_AIRPLAY)
     57    CASE(RequireUserGestureToShowPlaybackTargetPicker);
     58#endif
     59    }
     60
     61    ASSERT_NOT_REACHED();
     62    return "";
     63}
     64#endif
     65
    4566static void initializeAudioSession()
    4667{
     
    7293void HTMLMediaSession::addBehaviorRestriction(BehaviorRestrictions restriction)
    7394{
     95    LOG(Media, "HTMLMediaSession::addBehaviorRestriction - adding %s", restrictionName(restriction));
    7496    m_restrictions |= restriction;
    7597}
     
    7799void HTMLMediaSession::removeBehaviorRestriction(BehaviorRestrictions restriction)
    78100{
     101    LOG(Media, "HTMLMediaSession::removeBehaviorRestriction - removing %s", restrictionName(restriction));
    79102    m_restrictions &= ~restriction;
    80103}
     
    160183}
    161184
    162 void HTMLMediaSession::clientWillBeginPlayback() const
    163 {
    164     MediaSessionManager::sharedManager().sessionWillBeginPlayback(*this);
    165 }
    166 
    167185bool HTMLMediaSession::requiresFullscreenForVideoPlayback(const HTMLMediaElement& element) const
    168186{
  • trunk/Source/WebCore/html/HTMLMediaSession.h

    r163377 r163390  
    4343    virtual ~HTMLMediaSession() { }
    4444
    45     void clientWillBeginPlayback() const;
    46 
    4745    bool playbackPermitted(const HTMLMediaElement&) const;
    4846    bool dataLoadingPermitted(const HTMLMediaElement&) const;
  • trunk/Source/WebCore/platform/audio/MediaSession.cpp

    r163377 r163390  
    3333namespace WebCore {
    3434
     35static const char* stateName(MediaSession::State state)
     36{
     37#define CASE(_state) case MediaSession::_state: return #_state; break;
     38    switch (state) {
     39    CASE(Idle);
     40    CASE(Playing);
     41    CASE(Paused);
     42    CASE(Interrupted);
     43    }
     44
     45    ASSERT_NOT_REACHED();
     46    return "";
     47}
     48   
    3549std::unique_ptr<MediaSession> MediaSession::create(MediaSessionClient& client)
    3650{
     
    4054MediaSession::MediaSession(MediaSessionClient& client)
    4155    : m_client(client)
    42     , m_state(Running)
     56    , m_state(Idle)
     57    , m_stateToRestore(Idle)
     58    , m_notifyingClient(false)
    4359{
    44     m_type = m_client.mediaType();
    45     ASSERT(m_type >= None && m_type <= WebAudio);
     60    ASSERT(m_client.mediaType() >= None && m_client.mediaType() <= WebAudio);
    4661    MediaSessionManager::sharedManager().addSession(*this);
    4762}
     
    5267}
    5368
     69void MediaSession::setState(State state)
     70{
     71    LOG(Media, "MediaSession::setState - %s", stateName(state));
     72    m_state = state;
     73}
     74
    5475void MediaSession::beginInterruption()
    5576{
    5677    LOG(Media, "MediaSession::beginInterruption");
    57     m_state = Interrupted;
    58     m_client.beginInterruption();
     78
     79    m_stateToRestore = state();
     80    m_notifyingClient = true;
     81    client().pausePlayback();
     82    setState(Interrupted);
     83    m_notifyingClient = false;
    5984}
    6085
    6186void MediaSession::endInterruption(EndInterruptionFlags flags)
    6287{
    63     LOG(Media, "MediaSession::endInterruption");
    64     m_state = Running;
    65     m_client.endInterruption(flags);
     88    LOG(Media, "MediaSession::endInterruption - flags = %i, stateToRestore = %s", (int)flags, stateName(m_stateToRestore));
     89
     90    State stateToRestore = m_stateToRestore;
     91    m_stateToRestore = Idle;
     92    setState(Paused);
     93
     94    if (flags & MayResumePlaying && stateToRestore == Playing) {
     95        LOG(Media, "MediaSession::endInterruption - resuming playback");
     96        client().resumePlayback();
     97    }
     98}
     99
     100bool MediaSession::clientWillBeginPlayback()
     101{
     102    setState(Playing);
     103    MediaSessionManager::sharedManager().sessionWillBeginPlayback(*this);
     104    return true;
     105}
     106
     107bool MediaSession::clientWillPausePlayback()
     108{
     109    if (state() == Interrupted) {
     110        if (!m_notifyingClient)
     111            m_stateToRestore = Paused;
     112        return false;
     113    }
     114   
     115    setState(Paused);
     116    return true;
    66117}
    67118
     
    72123}
    73124
     125MediaSession::MediaType MediaSession::mediaType() const
     126{
     127    return m_client.mediaType();
    74128}
     129   
     130}
  • trunk/Source/WebCore/platform/audio/MediaSession.h

    r163377 r163390  
    4646        WebAudio,
    4747    };
    48    
    49     MediaType mediaType() const { return m_type; }
     48    MediaType mediaType() const;
    5049
    5150    enum State {
    52         Running,
     51        Idle,
     52        Playing,
     53        Paused,
    5354        Interrupted,
    5455    };
    5556    State state() const { return m_state; }
    56     void setState(State state) { m_state = state; }
     57    void setState(State);
    5758
    5859    enum EndInterruptionFlags {
     
    6364    void endInterruption(EndInterruptionFlags);
    6465
     66    void applicationWillEnterForeground() const;
     67    void applicationWillEnterBackground() const;
     68
     69    bool clientWillBeginPlayback();
     70    bool clientWillPausePlayback();
     71
    6572    void pauseSession();
    6673
     
    7077private:
    7178    MediaSessionClient& m_client;
    72     MediaType m_type;
    7379    State m_state;
     80    State m_stateToRestore;
     81    bool m_notifyingClient;
    7482};
    7583
     
    8088   
    8189    virtual MediaSession::MediaType mediaType() const = 0;
    82    
    83     virtual void beginInterruption() { }
    84     virtual void endInterruption(MediaSession::EndInterruptionFlags) { }
    85 
     90    virtual void resumePlayback() = 0;
    8691    virtual void pausePlayback() = 0;
    8792
  • trunk/Source/WebCore/platform/audio/MediaSessionManager.cpp

    r163377 r163390  
    2727#include "MediaSessionManager.h"
    2828
     29#include "Logging.h"
    2930#include "MediaSession.h"
    3031
     
    4041
    4142MediaSessionManager::MediaSessionManager()
    42     : m_interruptions(0)
     43    : m_interrupted(false)
    4344{
    4445    resetRestrictions();
     
    7980void MediaSessionManager::beginInterruption()
    8081{
    81     if (++m_interruptions > 1)
    82         return;
     82    LOG(Media, "MediaSessionManager::beginInterruption");
    8383
     84    m_interrupted = true;
    8485    for (auto* session : m_sessions)
    8586        session->beginInterruption();
     
    8889void MediaSessionManager::endInterruption(MediaSession::EndInterruptionFlags flags)
    8990{
    90     ASSERT(m_interruptions > 0);
    91     if (--m_interruptions)
    92         return;
    93    
     91    LOG(Media, "MediaSessionManager::endInterruption");
     92
     93    m_interrupted = false;
    9494    for (auto* session : m_sessions)
    9595        session->endInterruption(flags);
     
    9999{
    100100    m_sessions.append(&session);
    101     session.setState(m_interruptions ? MediaSession::Interrupted : MediaSession::Running);
     101    if (m_interrupted)
     102        session.setState(MediaSession::Interrupted);
    102103    updateSessionState();
    103104}
     
    158159}
    159160
     161void MediaSessionManager::applicationWillEnterBackground() const
     162{
     163    LOG(Media, "MediaSessionManager::applicationWillEnterBackground");
     164    for (auto* session : m_sessions) {
     165        if (m_restrictions[session->mediaType()] & BackgroundPlaybackNotPermitted)
     166            session->beginInterruption();
     167    }
     168}
     169
     170void MediaSessionManager::applicationWillEnterForeground() const
     171{
     172    LOG(Media, "MediaSessionManager::applicationWillEnterForeground");
     173    for (auto* session : m_sessions) {
     174        if (m_restrictions[session->mediaType()] & BackgroundPlaybackNotPermitted)
     175            session->endInterruption(MediaSession::MayResumePlaying);
     176    }
     177}
     178
    160179#if !PLATFORM(MAC)
    161180void MediaSessionManager::updateSessionState()
  • trunk/Source/WebCore/platform/audio/MediaSessionManager.h

    r163377 r163390  
    4848    void endInterruption(MediaSession::EndInterruptionFlags);
    4949
     50    void applicationWillEnterForeground() const;
     51    void applicationWillEnterBackground() const;
     52
    5053    enum SessionRestrictionFlags {
    5154        NoRestrictions = 0,
     
    5457        MetadataPreloadingNotPermitted = 1 << 2,
    5558        AutoPreloadingNotPermitted = 1 << 3,
     59        BackgroundPlaybackNotPermitted = 1 << 4,
    5660    };
    5761    typedef unsigned SessionRestrictions;
     
    6367
    6468    void sessionWillBeginPlayback(const MediaSession&) const;
     69
    6570    bool sessionRestrictsInlineVideoPlayback(const MediaSession&) const;
    6671
     
    7883
    7984    Vector<MediaSession*> m_sessions;
    80     int m_interruptions;
     85    bool m_interrupted;
    8186};
    8287
  • trunk/Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.h

    r163377 r163390  
    3838class MediaSessionManageriOS : public MediaSessionManager {
    3939public:
    40     virtual ~MediaSessionManageriOS() { }
     40    virtual ~MediaSessionManageriOS();
    4141
    4242private:
  • trunk/Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.mm

    r163377 r163390  
    3232#import "MediaSession.h"
    3333#import "SoftLinking.h"
     34#import "WebCoreSystemInterface.h"
    3435#import "WebCoreThreadRun.h"
    35 #import "WebCoreSystemInterface.h"
    3636#import <AVFoundation/AVAudioSession.h>
     37#import <UIKit/UIApplication.h>
    3738#import <objc/runtime.h>
    3839#import <wtf/RetainPtr.h>
    3940
    4041SOFT_LINK_FRAMEWORK(AVFoundation)
     42SOFT_LINK_FRAMEWORK(UIKit)
    4143
    4244SOFT_LINK_CLASS(AVFoundation, AVAudioSession)
     
    4547SOFT_LINK_POINTER(AVFoundation, AVAudioSessionInterruptionTypeKey, NSString *)
    4648SOFT_LINK_POINTER(AVFoundation, AVAudioSessionInterruptionOptionKey, NSString *)
     49SOFT_LINK_POINTER(UIKit, UIApplicationWillResignActiveNotification, NSString *)
     50SOFT_LINK_POINTER(UIKit, UIApplicationWillEnterForegroundNotification, NSString *)
    4751
    4852#define AVAudioSession getAVAudioSessionClass()
     
    5054#define AVAudioSessionInterruptionTypeKey getAVAudioSessionInterruptionTypeKey()
    5155#define AVAudioSessionInterruptionOptionKey getAVAudioSessionInterruptionOptionKey()
     56#define UIApplicationWillResignActiveNotification getUIApplicationWillResignActiveNotification()
     57#define UIApplicationWillEnterForegroundNotification getUIApplicationWillEnterForegroundNotification()
    5258
    5359using namespace WebCore;
     
    5864
    5965- (id)initWithCallback:(MediaSessionManageriOS*)callback;
     66- (void)clearCallback;
    6067- (void)interruption:(NSNotification*)notification;
     68- (void)applicationWillEnterForeground:(NSNotification*)notification;
     69- (void)applicationWillResignActive:(NSNotification*)notification;
    6170@end
    62 
    6371
    6472namespace WebCore {
     
    7785}
    7886
     87MediaSessionManageriOS::~MediaSessionManageriOS()
     88{
     89    [m_objcObserver clearCallback];
     90}
     91
    7992void MediaSessionManageriOS::resetRestrictions()
    8093{
     
    8699
    87100    addRestriction(MediaSession::Video, ConcurrentPlaybackNotPermitted);
     101    addRestriction(MediaSession::Video, BackgroundPlaybackNotPermitted);
     102
    88103    removeRestriction(MediaSession::Audio, MetadataPreloadingNotPermitted);
    89104    removeRestriction(MediaSession::Video, MetadataPreloadingNotPermitted);
     
    105120    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    106121    [center addObserver:self selector:@selector(interruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    107    
     122
     123    // FIXME: These need to be piped through from the UI process in WK2 mode.
     124    [center addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
     125    [center addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
     126
    108127    return self;
    109128}
     
    113132    [[NSNotificationCenter defaultCenter] removeObserver:self];
    114133    [super dealloc];
     134}
     135
     136- (void)clearCallback
     137{
     138    _callback = nil;
    115139}
    116140
     
    138162}
    139163
     164- (void)applicationWillEnterForeground:(NSNotification *)notification
     165{
     166    UNUSED_PARAM(notification);
     167   
     168    if (!_callback)
     169        return;
     170
     171    WebThreadRun(^{
     172        if (!_callback)
     173            return;
     174       
     175        _callback->applicationWillEnterForeground();
     176    });
     177}
     178
     179- (void)applicationWillResignActive:(NSNotification *)notification
     180{
     181    UNUSED_PARAM(notification);
     182
     183    if (!_callback)
     184        return;
     185   
     186    WebThreadRun(^{
     187        if (!_callback)
     188            return;
     189       
     190        _callback->applicationWillEnterBackground();
     191    });
     192}
     193
    140194@end
    141195
  • trunk/Source/WebCore/platform/audio/mac/AudioDestinationMac.h

    r163377 r163390  
    4848    virtual void stop() override;
    4949    virtual bool isPlaying() override { return m_isPlaying; }
     50
    5051    virtual void pausePlayback() override { stop(); }
     52    virtual void resumePlayback() override { start(); }
    5153
    5254    virtual float sampleRate() const override { return m_sampleRate; }
  • trunk/Source/WebCore/testing/Internals.cpp

    r163377 r163390  
    21892189}
    21902190
     2191void Internals::applicationWillEnterForeground() const
     2192{
     2193    MediaSessionManager::sharedManager().applicationWillEnterForeground();
     2194}
     2195
     2196void Internals::applicationWillEnterBackground() const
     2197{
     2198    MediaSessionManager::sharedManager().applicationWillEnterBackground();
     2199}
     2200
    21912201void Internals::setMediaSessionRestrictions(const String& mediaTypeString, const String& restrictionsString, ExceptionCode& ec)
    21922202{
     
    22162226    if (equalIgnoringCase(restrictionsString, "AutoPreloadingNotPermitted"))
    22172227        restrictions += MediaSessionManager::AutoPreloadingNotPermitted;
     2228    if (equalIgnoringCase(restrictionsString, "BackgroundPlaybackNotPermitted"))
     2229        restrictions += MediaSessionManager::BackgroundPlaybackNotPermitted;
    22182230
    22192231    MediaSessionManager::sharedManager().addRestriction(mediaType, restrictions);
  • trunk/Source/WebCore/testing/Internals.h

    r163377 r163390  
    327327    void beginMediaSessionInterruption();
    328328    void endMediaSessionInterruption(const String&);
     329    void applicationWillEnterForeground() const;
     330    void applicationWillEnterBackground() const;
    329331    void setMediaSessionRestrictions(const String& mediaType, const String& restrictions, ExceptionCode& ec);
    330332
  • trunk/Source/WebCore/testing/Internals.idl

    r163377 r163390  
    275275    void beginMediaSessionInterruption();
    276276    void endMediaSessionInterruption(DOMString flags);
     277    void applicationWillEnterForeground();
     278    void applicationWillEnterBackground();
    277279    [RaisesException] void setMediaSessionRestrictions(DOMString mediaType, DOMString restrictions);
    278280};
  • trunk/Source/WebKit/ChangeLog

    r163377 r163390  
     12014-02-04  Eric Carlson  <eric.carlson@apple.com>
     2
     3        Refine MediaSession interruptions
     4        https://bugs.webkit.org/show_bug.cgi?id=128125
     5
     6        Reviewed by Jer Noble.
     7
     8        * WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in: Export applicationWillEnterForeground
     9            and applicationWillEnterBackground for Internals.
     10
    1112014-02-04  Commit Queue  <commit-queue@webkit.org>
    212
  • trunk/Source/WebKit/WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in

    r163377 r163390  
    251251        symbolWithPointer(?removeRestriction@MediaSessionManager@WebCore@@QAEXW4MediaType@MediaSession@2@I@Z, ?removeRestriction@MediaSessionManager@WebCore@@QEAAXW4MediaType@MediaSession@2@I@Z)
    252252        symbolWithPointer(?restrictions@MediaSessionManager@WebCore@@QAEIW4MediaType@MediaSession@2@@Z, ?restrictions@MediaSessionManager@WebCore@@QEAAIW4MediaType@MediaSession@2@@Z)
     253        symbolWithPointer(?applicationWillEnterForeground@MediaSessionManager@WebCore@@QBEXXZ, ?applicationWillEnterForeground@MediaSessionManager@WebCore@@QBEXXZ)
     254        symbolWithPointer(?applicationWillEnterBackground@MediaSessionManager@WebCore@@QBEXXZ, ?applicationWillEnterBackground@MediaSessionManager@WebCore@@QBEXXZ)
    253255        ?localUserSpecificStorageDirectory@WebCore@@YA?AVString@WTF@@XZ
    254256        symbolWithPointer(?namedItem@StaticNodeList@WebCore@@UBEPAVNode@2@ABVAtomicString@WTF@@@Z, ?namedItem@StaticNodeList@WebCore@@UEBAPEAVNode@2@AEBVAtomicString@WTF@@@Z)
Note: See TracChangeset for help on using the changeset viewer.