Changeset 231817 in webkit


Ignore:
Timestamp:
May 15, 2018, 4:01:14 PM (7 years ago)
Author:
jer.noble@apple.com
Message:

Media continues loading after rendered invisible (removed from DOM; scrolled off screen)
https://bugs.webkit.org/show_bug.cgi?id=185487

Reviewed by Eric Carlson.

Source/WebCore:

Test: media/video-buffering-allowed.html

When a media element is removed from the dom (e.g. through innerHTML=""), it doesn't
necessarily stop loading media data; it will continue to do so until its destructor is
called through garbage collection. Similarly, when a media element is rendered not-visible
by being scrolled off-screen or being made display:none, media loading continues. There
are legitimate use cases for out-of-DOM media loading, so only temporarily block loading
when the element transitions out of the document. Similarly, only block loading for non-visible
media elements when returning from the "page is hidden" state, and only until the media
element is asked to play or is otherwise made visible.

Note: this refactors a lot of code out of PlatformMediaSession and into MediaElementSession,
since this code is specific to "media elements".

  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::HTMLMediaElement):
(WebCore::HTMLMediaElement::insertedIntoAncestor):
(WebCore::HTMLMediaElement::removedFromAncestor):
(WebCore::HTMLMediaElement::playInternal):
(WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer):
(WebCore::HTMLMediaElement::resume):
(WebCore::HTMLMediaElement::visibilityStateChanged):
(WebCore::HTMLMediaElement::createMediaPlayer):
(WebCore::HTMLMediaElement::setShouldBufferData):
(WebCore::HTMLMediaElement::purgeBufferedDataIfPossible):
(WebCore::HTMLMediaElement::isVisibleInViewportChanged):
(WebCore::HTMLMediaElement::fullscreenModeChanged):
(WebCore::HTMLMediaElement::setInActiveDocument):

  • html/HTMLMediaElement.h:

(WebCore::HTMLMediaElement::shouldBufferData const):
(WebCore::HTMLMediaElement::elementIsHidden const):

  • html/MediaElementSession.cpp:

(WebCore::MediaElementSession::MediaElementSession):
(WebCore::MediaElementSession::clientWillBeginAutoplaying):
(WebCore::MediaElementSession::clientWillBeginPlayback):
(WebCore::MediaElementSession::clientWillPausePlayback):
(WebCore::MediaElementSession::visibilityChanged):
(WebCore::MediaElementSession::isVisibleInViewportChanged):
(WebCore::MediaElementSession::inActiveDocumentChanged):
(WebCore::MediaElementSession::scheduleClientDataBufferingCheck):
(WebCore::MediaElementSession::clientDataBufferingTimerFired):
(WebCore::MediaElementSession::updateClientDataBuffering):
(WebCore::MediaElementSession::dataBufferingPermitted const):
(WebCore::MediaElementSession::wantsToObserveViewportVisibilityForAutoplay const):

  • html/MediaElementSession.h:
  • platform/audio/PlatformMediaSession.cpp:

(WebCore::PlatformMediaSession::PlatformMediaSession):
(WebCore::PlatformMediaSession::clientWillBeginAutoplaying):
(WebCore::PlatformMediaSession::clientWillBeginPlayback):
(WebCore::PlatformMediaSession::clientWillPausePlayback):
(): Deleted.
(WebCore::PlatformMediaSession::visibilityChanged): Deleted.
(WebCore::PlatformMediaSession::scheduleClientDataBufferingCheck): Deleted.
(WebCore::PlatformMediaSession::clientDataBufferingTimerFired): Deleted.
(WebCore::PlatformMediaSession::updateClientDataBuffering): Deleted.
(WebCore::PlatformMediaSession::isHidden const): Deleted.

  • platform/audio/PlatformMediaSession.h:

(WebCore::PlatformMediaSessionClient::setShouldBufferData): Deleted.
(WebCore::PlatformMediaSessionClient::elementIsHidden const): Deleted.

  • platform/audio/PlatformMediaSessionManager.cpp:

(WebCore::PlatformMediaSessionManager::sessionCanLoadMedia const): Deleted.

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

(WebCore::MediaSessionManageriOS::sessionCanLoadMedia const): Deleted.

  • rendering/RenderVideo.cpp:

(WebCore::RenderVideo::willBeDestroyed):

  • testing/Internals.cpp:

(WebCore::Internals::elementShouldBufferData):

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

LayoutTests:

  • media/video-buffering-allowed-expected.txt: Added.
  • media/video-buffering-allowed.html: Added.
  • media/video-test.js:

(compare):
(testExpected):
(sleepFor):
(testArraysEqual): Deleted.

Location:
trunk
Files:
2 added
18 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified trunk/LayoutTests/ChangeLog

    r231813 r231817  
     12018-05-15  Jer Noble  <jer.noble@apple.com>
     2
     3        Media continues loading after rendered invisible (removed from DOM; scrolled off screen)
     4        https://bugs.webkit.org/show_bug.cgi?id=185487
     5
     6        Reviewed by Eric Carlson.
     7
     8        * media/video-buffering-allowed-expected.txt: Added.
     9        * media/video-buffering-allowed.html: Added.
     10        * media/video-test.js:
     11        (compare):
     12        (testExpected):
     13        (sleepFor):
     14        (testArraysEqual): Deleted.
     15
    1162018-05-15  Charles Vazac  <cvazac@gmail.com>
    217
  • TabularUnified trunk/LayoutTests/media/media-source/only-bcp47-language-tags-accepted-as-valid-expected.txt

    r210280 r231817  
    1 CONSOLE MESSAGE: line 176: The language 'a' is not a valid BCP 47 language tag.
     1CONSOLE MESSAGE: line 221: The language 'a' is not a valid BCP 47 language tag.
    22CONSOLE MESSAGE: line 106: The language 'a' is not a valid BCP 47 language tag.
    3 CONSOLE MESSAGE: line 176: The language 'a' is not a valid BCP 47 language tag.
    4 CONSOLE MESSAGE: line 176: The language '1' is not a valid BCP 47 language tag.
     3CONSOLE MESSAGE: line 221: The language 'a' is not a valid BCP 47 language tag.
     4CONSOLE MESSAGE: line 221: The language '1' is not a valid BCP 47 language tag.
    55CONSOLE MESSAGE: line 106: The language '1' is not a valid BCP 47 language tag.
    6 CONSOLE MESSAGE: line 176: The language '1' is not a valid BCP 47 language tag.
    7 CONSOLE MESSAGE: line 176: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
     6CONSOLE MESSAGE: line 221: The language '1' is not a valid BCP 47 language tag.
     7CONSOLE MESSAGE: line 221: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
    88CONSOLE MESSAGE: line 106: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
    9 CONSOLE MESSAGE: line 176: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
    10 CONSOLE MESSAGE: line 176: The language '1a' is not a valid BCP 47 language tag.
     9CONSOLE MESSAGE: line 221: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
     10CONSOLE MESSAGE: line 221: The language '1a' is not a valid BCP 47 language tag.
    1111CONSOLE MESSAGE: line 106: The language '1a' is not a valid BCP 47 language tag.
    12 CONSOLE MESSAGE: line 176: The language '1a' is not a valid BCP 47 language tag.
    13 CONSOLE MESSAGE: line 176: The language '-a' is not a valid BCP 47 language tag.
     12CONSOLE MESSAGE: line 221: The language '1a' is not a valid BCP 47 language tag.
     13CONSOLE MESSAGE: line 221: The language '-a' is not a valid BCP 47 language tag.
    1414CONSOLE MESSAGE: line 106: The language '-a' is not a valid BCP 47 language tag.
    15 CONSOLE MESSAGE: line 176: The language '-a' is not a valid BCP 47 language tag.
    16 CONSOLE MESSAGE: line 176: The language 'a-' is not a valid BCP 47 language tag.
     15CONSOLE MESSAGE: line 221: The language '-a' is not a valid BCP 47 language tag.
     16CONSOLE MESSAGE: line 221: The language 'a-' is not a valid BCP 47 language tag.
    1717CONSOLE MESSAGE: line 106: The language 'a-' is not a valid BCP 47 language tag.
    18 CONSOLE MESSAGE: line 176: The language 'a-' is not a valid BCP 47 language tag.
    19 CONSOLE MESSAGE: line 176: The language 'a1' is not a valid BCP 47 language tag.
     18CONSOLE MESSAGE: line 221: The language 'a-' is not a valid BCP 47 language tag.
     19CONSOLE MESSAGE: line 221: The language 'a1' is not a valid BCP 47 language tag.
    2020CONSOLE MESSAGE: line 106: The language 'a1' is not a valid BCP 47 language tag.
    21 CONSOLE MESSAGE: line 176: The language 'a1' is not a valid BCP 47 language tag.
    22 CONSOLE MESSAGE: line 176: The language 'aa1' is not a valid BCP 47 language tag.
     21CONSOLE MESSAGE: line 221: The language 'a1' is not a valid BCP 47 language tag.
     22CONSOLE MESSAGE: line 221: The language 'aa1' is not a valid BCP 47 language tag.
    2323CONSOLE MESSAGE: line 106: The language 'aa1' is not a valid BCP 47 language tag.
    24 CONSOLE MESSAGE: line 176: The language 'aa1' is not a valid BCP 47 language tag.
    25 CONSOLE MESSAGE: line 176: The language 'aaaa' is not a valid BCP 47 language tag.
     24CONSOLE MESSAGE: line 221: The language 'aa1' is not a valid BCP 47 language tag.
     25CONSOLE MESSAGE: line 221: The language 'aaaa' is not a valid BCP 47 language tag.
    2626CONSOLE MESSAGE: line 106: The language 'aaaa' is not a valid BCP 47 language tag.
    27 CONSOLE MESSAGE: line 176: The language 'aaaa' is not a valid BCP 47 language tag.
    28 CONSOLE MESSAGE: line 176: The language 'aaa1' is not a valid BCP 47 language tag.
     27CONSOLE MESSAGE: line 221: The language 'aaaa' is not a valid BCP 47 language tag.
     28CONSOLE MESSAGE: line 221: The language 'aaa1' is not a valid BCP 47 language tag.
    2929CONSOLE MESSAGE: line 106: The language 'aaa1' is not a valid BCP 47 language tag.
    30 CONSOLE MESSAGE: line 176: The language 'aaa1' is not a valid BCP 47 language tag.
    31 CONSOLE MESSAGE: line 176: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
     30CONSOLE MESSAGE: line 221: The language 'aaa1' is not a valid BCP 47 language tag.
     31CONSOLE MESSAGE: line 221: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
    3232CONSOLE MESSAGE: line 106: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
    33 CONSOLE MESSAGE: line 176: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
    34 CONSOLE MESSAGE: line 176: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
     33CONSOLE MESSAGE: line 221: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
     34CONSOLE MESSAGE: line 221: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
    3535CONSOLE MESSAGE: line 106: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
    36 CONSOLE MESSAGE: line 176: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
    37 CONSOLE MESSAGE: line 176: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
     36CONSOLE MESSAGE: line 221: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
     37CONSOLE MESSAGE: line 221: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
    3838CONSOLE MESSAGE: line 106: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
    39 CONSOLE MESSAGE: line 176: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
    40 CONSOLE MESSAGE: line 176: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
     39CONSOLE MESSAGE: line 221: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
     40CONSOLE MESSAGE: line 221: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
    4141CONSOLE MESSAGE: line 106: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
    42 CONSOLE MESSAGE: line 176: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
    43 CONSOLE MESSAGE: line 176: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
     42CONSOLE MESSAGE: line 221: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
     43CONSOLE MESSAGE: line 221: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
    4444CONSOLE MESSAGE: line 106: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
    45 CONSOLE MESSAGE: line 176: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
     45CONSOLE MESSAGE: line 221: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
    4646Test that only BCP47 language tags are accepted as valid but still reflected.
    4747
  • TabularUnified trunk/LayoutTests/media/video-test.js

    r225265 r231817  
    6363}
    6464
    65 function testExpected(testFuncString, expected, comparison)
    66 {
    67     try {
    68         var observed = eval(testFuncString);
    69     } catch (ex) {
    70         consoleWrite(ex);
    71         return;
    72     }
    73 
    74     if (comparison === undefined)
    75         comparison = '==';
     65function compare(testFuncString, expected, comparison)
     66{
     67    var observed = eval(testFuncString);
    7668
    7769    var success = false;
     
    8880    }
    8981
    90     reportExpected(success, testFuncString, comparison, expected, observed)
     82    return {success:success, observed:observed};
     83}
     84
     85function testExpected(testFuncString, expected, comparison)
     86{
     87    if (comparison === undefined)
     88        comparison = '==';
     89
     90    try {
     91        let {success, observed} = compare(testFuncString, expected, comparison);
     92        reportExpected(success, testFuncString, comparison, expected, observed)
     93    } catch (ex) {
     94        consoleWrite(ex);
     95    }
     96}
     97
     98function sleepFor(duration) {
     99    return new Promise(resolve => {
     100        setTimeout(resolve, duration);
     101    });
     102}
     103
     104function testExpectedEventually(testFuncString, expected, comparison)
     105{
     106    return new Promise(async resolve => {
     107        var success;
     108        var observed;
     109        if (comparison === undefined)
     110            comparison = '==';
     111        while (true) {
     112            try {
     113                let {success, observed} = compare(testFuncString, expected, comparison);
     114                if (success) {
     115                    reportExpected(success, testFuncString, comparison, expected, observed);
     116                    resolve();
     117                    return;
     118                }
     119                await sleepFor(1);
     120            } catch (ex) {
     121                consoleWrite(ex);
     122                resolve();
     123                return;
     124            }
     125        }
     126    });
    91127}
    92128
     
    149185        consoleWrite(ex);
    150186    }
     187}
     188
     189function waitFor(element, event) {
     190    return new Promise(resolve => {
     191        element.addEventListener(event, event => {
     192            consoleWrite(`EVENT(${event.type})`);
     193            resolve(event);
     194        }, { once: true });
     195    });
    151196}
    152197
  • TabularUnified trunk/Source/WebCore/ChangeLog

    r231813 r231817  
     12018-05-15  Jer Noble  <jer.noble@apple.com>
     2
     3        Media continues loading after rendered invisible (removed from DOM; scrolled off screen)
     4        https://bugs.webkit.org/show_bug.cgi?id=185487
     5
     6        Reviewed by Eric Carlson.
     7
     8        Test: media/video-buffering-allowed.html
     9
     10        When a media element is removed from the dom (e.g. through innerHTML=""), it doesn't
     11        necessarily stop loading media data; it will continue to do so until its destructor is
     12        called through garbage collection. Similarly, when a media element is rendered not-visible
     13        by being scrolled off-screen or being made display:none, media loading continues. There
     14        are legitimate use cases for out-of-DOM media loading, so only temporarily block loading
     15        when the element transitions out of the document. Similarly, only block loading for non-visible
     16        media elements when returning from the "page is hidden" state, and only until the media
     17        element is asked to play or is otherwise made visible.
     18
     19        Note: this refactors a lot of code out of PlatformMediaSession and into MediaElementSession,
     20        since this code is specific to "media elements".
     21
     22        * html/HTMLMediaElement.cpp:
     23        (WebCore::HTMLMediaElement::HTMLMediaElement):
     24        (WebCore::HTMLMediaElement::insertedIntoAncestor):
     25        (WebCore::HTMLMediaElement::removedFromAncestor):
     26        (WebCore::HTMLMediaElement::playInternal):
     27        (WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer):
     28        (WebCore::HTMLMediaElement::resume):
     29        (WebCore::HTMLMediaElement::visibilityStateChanged):
     30        (WebCore::HTMLMediaElement::createMediaPlayer):
     31        (WebCore::HTMLMediaElement::setShouldBufferData):
     32        (WebCore::HTMLMediaElement::purgeBufferedDataIfPossible):
     33        (WebCore::HTMLMediaElement::isVisibleInViewportChanged):
     34        (WebCore::HTMLMediaElement::fullscreenModeChanged):
     35        (WebCore::HTMLMediaElement::setInActiveDocument):
     36        * html/HTMLMediaElement.h:
     37        (WebCore::HTMLMediaElement::shouldBufferData const):
     38        (WebCore::HTMLMediaElement::elementIsHidden const):
     39        * html/MediaElementSession.cpp:
     40        (WebCore::MediaElementSession::MediaElementSession):
     41        (WebCore::MediaElementSession::clientWillBeginAutoplaying):
     42        (WebCore::MediaElementSession::clientWillBeginPlayback):
     43        (WebCore::MediaElementSession::clientWillPausePlayback):
     44        (WebCore::MediaElementSession::visibilityChanged):
     45        (WebCore::MediaElementSession::isVisibleInViewportChanged):
     46        (WebCore::MediaElementSession::inActiveDocumentChanged):
     47        (WebCore::MediaElementSession::scheduleClientDataBufferingCheck):
     48        (WebCore::MediaElementSession::clientDataBufferingTimerFired):
     49        (WebCore::MediaElementSession::updateClientDataBuffering):
     50        (WebCore::MediaElementSession::dataBufferingPermitted const):
     51        (WebCore::MediaElementSession::wantsToObserveViewportVisibilityForAutoplay const):
     52        * html/MediaElementSession.h:
     53        * platform/audio/PlatformMediaSession.cpp:
     54        (WebCore::PlatformMediaSession::PlatformMediaSession):
     55        (WebCore::PlatformMediaSession::clientWillBeginAutoplaying):
     56        (WebCore::PlatformMediaSession::clientWillBeginPlayback):
     57        (WebCore::PlatformMediaSession::clientWillPausePlayback):
     58        (): Deleted.
     59        (WebCore::PlatformMediaSession::visibilityChanged): Deleted.
     60        (WebCore::PlatformMediaSession::scheduleClientDataBufferingCheck): Deleted.
     61        (WebCore::PlatformMediaSession::clientDataBufferingTimerFired): Deleted.
     62        (WebCore::PlatformMediaSession::updateClientDataBuffering): Deleted.
     63        (WebCore::PlatformMediaSession::isHidden const): Deleted.
     64        * platform/audio/PlatformMediaSession.h:
     65        (WebCore::PlatformMediaSessionClient::setShouldBufferData): Deleted.
     66        (WebCore::PlatformMediaSessionClient::elementIsHidden const): Deleted.
     67        * platform/audio/PlatformMediaSessionManager.cpp:
     68        (WebCore::PlatformMediaSessionManager::sessionCanLoadMedia const): Deleted.
     69        * platform/audio/PlatformMediaSessionManager.h:
     70        * platform/audio/ios/MediaSessionManagerIOS.h:
     71        * platform/audio/ios/MediaSessionManagerIOS.mm:
     72        (WebCore::MediaSessionManageriOS::sessionCanLoadMedia const): Deleted.
     73        * rendering/RenderVideo.cpp:
     74        (WebCore::RenderVideo::willBeDestroyed):
     75        * testing/Internals.cpp:
     76        (WebCore::Internals::elementShouldBufferData):
     77        * testing/Internals.h:
     78        * testing/Internals.idl:
     79
    1802018-05-15  Charles Vazac  <cvazac@gmail.com>
    281
  • TabularUnified trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r231392 r231817  
    478478    , m_havePreparedToPlay(false)
    479479    , m_parsingInProgress(createdByParser)
     480    , m_shouldBufferData(true)
    480481    , m_elementIsHidden(document.hidden())
    481482    , m_creatingControls(false)
     
    927928    HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
    928929    if (insertionType.connectedToDocument)
    929         m_inActiveDocument = true;
     930        setInActiveDocument(true);
    930931
    931932    return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
     
    979980    INFO_LOG(LOGIDENTIFIER);
    980981
    981     m_inActiveDocument = false;
     982    setInActiveDocument(false);
    982983    if (removalType.disconnectedFromDocument) {
    983984        // Pause asynchronously to let the operation that removed us finish, in case we get inserted back into a document.
     
    34683469        return;
    34693470    }
    3470 
     3471   
    34713472    // 4.8.10.9. Playing the media resource
    34723473    if (!m_player || m_networkState == NETWORK_EMPTY)
     
    55215522
    55225523    updatePlaybackControlsManager();
    5523     m_inActiveDocument = false;
     5524    setInActiveDocument(false);
    55245525
    55255526    // Stop the playback without generating events
     
    56015602    INFO_LOG(LOGIDENTIFIER);
    56025603
    5603     m_inActiveDocument = true;
     5604    setInActiveDocument(true);
    56045605
    56055606    m_asyncEventQueue.resume();
     
    56395640void HTMLMediaElement::visibilityStateChanged()
    56405641{
    5641     m_elementIsHidden = document().hidden() && m_videoFullscreenMode != VideoFullscreenModePictureInPicture;
     5642    bool elementIsHidden = document().hidden() && m_videoFullscreenMode != VideoFullscreenModePictureInPicture;
     5643    if (elementIsHidden == m_elementIsHidden)
     5644        return;
     5645
     5646    m_elementIsHidden = elementIsHidden;
    56425647    INFO_LOG(LOGIDENTIFIER, "visible = ", !m_elementIsHidden);
     5648
    56435649    updateSleepDisabling();
    56445650    m_mediaSession->visibilityChanged();
     
    65006506#endif
    65016507    m_player = MediaPlayer::create(*this);
     6508    m_player->setShouldBufferData(m_shouldBufferData);
    65026509    scheduleUpdatePlaybackControlsManager();
    65036510
     
    76617668void HTMLMediaElement::setShouldBufferData(bool shouldBuffer)
    76627669{
     7670    if (shouldBuffer == m_shouldBufferData)
     7671        return;
     7672
     7673    m_shouldBufferData = shouldBuffer;
    76637674    if (m_player)
    76647675        m_player->setShouldBufferData(shouldBuffer);
     
    76687679{
    76697680#if PLATFORM(IOS)
    7670     if (!MemoryPressureHandler::singleton().isUnderMemoryPressure() && PlatformMediaSessionManager::sharedManager().sessionCanLoadMedia(*m_mediaSession))
     7681    if (!MemoryPressureHandler::singleton().isUnderMemoryPressure() && m_mediaSession->dataBufferingPermitted())
    76717682        return;
    76727683
     
    77767787{
    77777788    m_visibilityChangeTaskQueue.enqueueTask([this] {
     7789        m_mediaSession->isVisibleInViewportChanged();
    77787790        updateShouldAutoplay();
    77797791        scheduleUpdatePlaybackControlsManager();
     
    78757887    m_videoFullscreenMode = mode;
    78767888    visibilityStateChanged();
    7877     m_mediaSession->scheduleClientDataBufferingCheck();
    78787889    scheduleUpdatePlaybackControlsManager();
    78797890}
     
    79087919}
    79097920
    7910 }
    7911 
    7912 #endif
     7921void HTMLMediaElement::setInActiveDocument(bool inActiveDocument)
     7922{
     7923    if (inActiveDocument == m_inActiveDocument)
     7924        return;
     7925
     7926    m_inActiveDocument = inActiveDocument;
     7927    m_mediaSession->inActiveDocumentChanged();
     7928}
     7929
     7930}
     7931
     7932#endif
  • TabularUnified trunk/Source/WebCore/html/HTMLMediaElement.h

    r231604 r231817  
    266266    WEBCORE_EXPORT void play() override;
    267267    WEBCORE_EXPORT void pause() override;
    268     void setShouldBufferData(bool) override;
     268    void setShouldBufferData(bool);
     269    WEBCORE_EXPORT bool shouldBufferData() const { return m_shouldBufferData; }
    269270    WEBCORE_EXPORT void fastSeek(double);
    270271    double minFastReverseRate() const;
     
    278279    WEBCORE_EXPORT void setWebkitClosedCaptionsVisible(bool);
    279280
    280     bool elementIsHidden() const override { return m_elementIsHidden; }
     281    bool elementIsHidden() const { return m_elementIsHidden; }
    281282
    282283#if ENABLE(MEDIA_STATISTICS)
     
    913914    void applicationDidBecomeActive() final;
    914915
     916    void setInActiveDocument(bool);
     917
    915918#if !RELEASE_LOG_DISABLED
    916919    const char* logClassName() const final { return "HTMLMediaElement"; }
     
    10651068    bool m_havePreparedToPlay : 1;
    10661069    bool m_parsingInProgress : 1;
     1070    bool m_shouldBufferData : 1;
    10671071    bool m_elementIsHidden : 1;
     1072    bool m_elementWasRemovedFromDOM : 1;
    10681073    bool m_creatingControls : 1;
    10691074    bool m_receivedLayoutSizeChanged : 1;
  • TabularUnified trunk/Source/WebCore/html/MediaElementSession.cpp

    r231604 r231817  
    5757namespace WebCore {
    5858
     59static const Seconds clientDataBufferingTimerThrottleDelay { 100_ms };
    5960static const Seconds elementMainContentCheckInterval { 250_ms };
    6061
     
    110111#endif
    111112    , m_mainContentCheckTimer(*this, &MediaElementSession::mainContentCheckTimerFired)
     113    , m_clientDataBufferingTimer(*this, &MediaElementSession::clientDataBufferingTimerFired)
    112114#if !RELEASE_LOG_DISABLED
    113115    , m_logIdentifier(element.logIdentifier())
     
    132134    UNUSED_PARAM(document);
    133135#endif
     136}
     137
     138void MediaElementSession::clientWillBeginAutoplaying()
     139{
     140    PlatformMediaSession::clientWillBeginAutoplaying();
     141    m_elementIsHiddenBecauseItWasRemovedFromDOM = false;
     142    updateClientDataBuffering();
     143}
     144
     145bool MediaElementSession::clientWillBeginPlayback()
     146{
     147    if (!PlatformMediaSession::clientWillBeginPlayback())
     148        return false;
     149
     150    m_elementIsHiddenBecauseItWasRemovedFromDOM = false;
     151    updateClientDataBuffering();
     152    return true;
     153}
     154
     155bool MediaElementSession::clientWillPausePlayback()
     156{
     157    if (!PlatformMediaSession::clientWillPausePlayback())
     158        return false;
     159
     160    updateClientDataBuffering();
     161    return true;
     162}
     163
     164void MediaElementSession::visibilityChanged()
     165{
     166    scheduleClientDataBufferingCheck();
     167
     168    if (m_element.elementIsHidden() && !m_element.isFullscreen())
     169        m_elementIsHiddenUntilVisibleInViewport = true;
     170}
     171
     172void MediaElementSession::isVisibleInViewportChanged()
     173{
     174    scheduleClientDataBufferingCheck();
     175
     176    if (m_element.isFullscreen() || m_element.isVisibleInViewport())
     177        m_elementIsHiddenUntilVisibleInViewport = false;
     178}
     179
     180void MediaElementSession::inActiveDocumentChanged()
     181{
     182    m_elementIsHiddenBecauseItWasRemovedFromDOM = !m_element.inActiveDocument();
     183    scheduleClientDataBufferingCheck();
     184}
     185
     186void MediaElementSession::scheduleClientDataBufferingCheck()
     187{
     188    if (!m_clientDataBufferingTimer.isActive())
     189        m_clientDataBufferingTimer.startOneShot(clientDataBufferingTimerThrottleDelay);
     190}
     191
     192void MediaElementSession::clientDataBufferingTimerFired()
     193{
     194    INFO_LOG(LOGIDENTIFIER, "visible = ", m_element.elementIsHidden());
     195
     196    updateClientDataBuffering();
     197
     198#if PLATFORM(IOS)
     199    PlatformMediaSessionManager::sharedManager().configureWireLessTargetMonitoring();
     200#endif
     201
     202    if (state() != Playing || !m_element.elementIsHidden())
     203        return;
     204
     205    PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType());
     206    if ((restrictions & PlatformMediaSessionManager::BackgroundTabPlaybackRestricted) == PlatformMediaSessionManager::BackgroundTabPlaybackRestricted)
     207        pauseSession();
     208}
     209
     210void MediaElementSession::updateClientDataBuffering()
     211{
     212    if (m_clientDataBufferingTimer.isActive())
     213        m_clientDataBufferingTimer.stop();
     214
     215    m_element.setShouldBufferData(dataBufferingPermitted());
    134216}
    135217
     
    276358}
    277359
     360bool MediaElementSession::dataBufferingPermitted() const
     361{
     362    if (isSuspended())
     363        return false;
     364
     365    if (state() == PlatformMediaSession::Playing)
     366        return true;
     367
     368    if (shouldOverrideBackgroundLoadingRestriction())
     369        return true;
     370
     371    if (m_elementIsHiddenUntilVisibleInViewport || m_elementIsHiddenBecauseItWasRemovedFromDOM || m_element.elementIsHidden())
     372        return false;
     373
     374    return true;
     375}
     376
    278377bool MediaElementSession::fullscreenPermitted() const
    279378{
     
    419518bool MediaElementSession::wantsToObserveViewportVisibilityForAutoplay() const
    420519{
    421     if (!m_element.isVideo())
    422         return false;
    423     return hasBehaviorRestriction(InvisibleAutoplayNotPermitted) || hasBehaviorRestriction(OverrideUserGestureRequirementForMainContent);
     520    return m_element.isVideo();
    424521}
    425522
     
    675772bool MediaElementSession::requiresPlaybackTargetRouteMonitoring() const
    676773{
    677     return m_hasPlaybackTargetAvailabilityListeners && !client().elementIsHidden();
     774    return m_hasPlaybackTargetAvailabilityListeners && !m_element.elementIsHidden();
    678775}
    679776#endif
  • TabularUnified trunk/Source/WebCore/html/MediaElementSession.h

    r231604 r231817  
    6262    void unregisterWithDocument(Document&);
    6363
     64    void clientWillBeginAutoplaying() final;
     65    bool clientWillBeginPlayback() final;
     66    bool clientWillPausePlayback() final;
     67
     68    void visibilityChanged();
     69    void isVisibleInViewportChanged();
     70    void inActiveDocumentChanged();
     71
    6472    SuccessOr<MediaPlaybackDenialReason> playbackPermitted() const;
    6573    bool autoplayPermitted() const;
    6674    bool dataLoadingPermitted() const;
     75    bool dataBufferingPermitted() const;
    6776    bool fullscreenPermitted() const;
    6877    bool pageAllowsDataLoading() const;
     
    166175    void mainContentCheckTimerFired();
    167176
     177    void scheduleClientDataBufferingCheck();
     178    void clientDataBufferingTimerFired();
     179    void updateClientDataBuffering();
     180
    168181    HTMLMediaElement& m_element;
    169182    BehaviorRestrictions m_restrictions;
     183
     184    bool m_elementIsHiddenUntilVisibleInViewport { false };
     185    bool m_elementIsHiddenBecauseItWasRemovedFromDOM { false };
    170186
    171187#if ENABLE(WIRELESS_PLAYBACK_TARGET)
     
    183199    mutable bool m_isMainContent { false };
    184200    Timer m_mainContentCheckTimer;
     201    Timer m_clientDataBufferingTimer;
    185202
    186203#if !RELEASE_LOG_DISABLED
  • TabularUnified trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp

    r231604 r231817  
    9494PlatformMediaSession::PlatformMediaSession(PlatformMediaSessionClient& client)
    9595    : m_client(client)
    96     , m_clientDataBufferingTimer(*this, &PlatformMediaSession::clientDataBufferingTimerFired)
    9796    , m_state(Idle)
    9897    , m_stateToRestore(Idle)
     
    177176
    178177    setState(Autoplaying);
    179     updateClientDataBuffering();
    180178}
    181179
     
    192190
    193191    setState(Playing);
    194     updateClientDataBuffering();
    195192    return true;
    196193}
     
    210207    setState(Paused);
    211208    PlatformMediaSessionManager::sharedManager().sessionWillEndPlayback(*this);
    212     scheduleClientDataBufferingCheck();
    213209    return true;
    214210}
     
    274270}
    275271
    276 void PlatformMediaSession::visibilityChanged()
    277 {
    278     scheduleClientDataBufferingCheck();
    279 }
    280 
    281 void PlatformMediaSession::scheduleClientDataBufferingCheck()
    282 {
    283     if (!m_clientDataBufferingTimer.isActive())
    284         m_clientDataBufferingTimer.startOneShot(clientDataBufferingTimerThrottleDelay);
    285 }
    286 
    287 void PlatformMediaSession::clientDataBufferingTimerFired()
    288 {
    289     INFO_LOG(LOGIDENTIFIER, "visible = ", m_client.elementIsHidden());
    290 
    291     updateClientDataBuffering();
    292 
    293 #if PLATFORM(IOS)
    294     PlatformMediaSessionManager::sharedManager().configureWireLessTargetMonitoring();
    295 #endif
    296 
    297     if (m_state != Playing || !m_client.elementIsHidden())
    298         return;
    299 
    300     PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType());
    301     if ((restrictions & PlatformMediaSessionManager::BackgroundTabPlaybackRestricted) == PlatformMediaSessionManager::BackgroundTabPlaybackRestricted)
    302         pauseSession();
    303 }
    304 
    305 void PlatformMediaSession::updateClientDataBuffering()
    306 {
    307     if (m_clientDataBufferingTimer.isActive())
    308         m_clientDataBufferingTimer.stop();
    309 
    310     m_client.setShouldBufferData(PlatformMediaSessionManager::sharedManager().sessionCanLoadMedia(*this));
    311 }
    312 
    313272String PlatformMediaSession::sourceApplicationIdentifier() const
    314273{
    315274    return m_client.sourceApplicationIdentifier();
    316 }
    317 
    318 bool PlatformMediaSession::isHidden() const
    319 {
    320     return m_client.elementIsHidden();
    321275}
    322276
  • TabularUnified trunk/Source/WebCore/platform/audio/PlatformMediaSession.h

    r231604 r231817  
    106106    void endInterruption(EndInterruptionFlags);
    107107
    108     void clientWillBeginAutoplaying();
    109     bool clientWillBeginPlayback();
    110     bool clientWillPausePlayback();
     108    virtual void clientWillBeginAutoplaying();
     109    virtual bool clientWillBeginPlayback();
     110    virtual bool clientWillPausePlayback();
    111111
    112112    void pauseSession();
    113113    void stopSession();
    114114   
    115     void visibilityChanged();
    116 
    117115#if ENABLE(VIDEO)
    118116    String title() const;
     
    172170    void canProduceAudioChanged();
    173171
    174     void scheduleClientDataBufferingCheck();
    175172    virtual void resetPlaybackSessionState() { }
    176173    String sourceApplicationIdentifier() const;
     
    189186
    190187private:
    191     void clientDataBufferingTimerFired();
    192     void updateClientDataBuffering();
    193 
    194188    PlatformMediaSessionClient& m_client;
    195     Timer m_clientDataBufferingTimer;
    196189    State m_state;
    197190    State m_stateToRestore;
     
    233226    virtual bool supportsSeeking() const = 0;
    234227
    235     virtual void setShouldBufferData(bool) { }
    236     virtual bool elementIsHidden() const { return false; }
    237228    virtual bool canProduceAudio() const { return false; }
    238229    virtual bool isSuspended() const { return false; };
  • TabularUnified trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp

    r228043 r231817  
    288288}
    289289   
    290 bool PlatformMediaSessionManager::sessionCanLoadMedia(const PlatformMediaSession& session) const
    291 {
    292     if (session.isSuspended())
    293         return false;
    294     return session.state() == PlatformMediaSession::Playing || !session.isHidden() || session.shouldOverrideBackgroundLoadingRestriction();
    295 }
    296 
    297290void PlatformMediaSessionManager::applicationWillBecomeInactive() const
    298291{
  • TabularUnified trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h

    r229893 r231817  
    9595    virtual bool sessionWillBeginPlayback(PlatformMediaSession&);
    9696    virtual void sessionWillEndPlayback(PlatformMediaSession&);
    97     virtual bool sessionCanLoadMedia(const PlatformMediaSession&) const;
    9897    virtual void sessionDidEndRemoteScrubbing(const PlatformMediaSession&) { };
    9998    virtual void clientCharacteristicsChanged(PlatformMediaSession&) { }
  • TabularUnified trunk/Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.h

    r228531 r231817  
    6666    void configureWireLessTargetMonitoring() override;
    6767
    68     bool sessionCanLoadMedia(const PlatformMediaSession&) const override;
    69 
    7068    bool hasActiveNowPlayingSession() const final { return m_nowPlayingActive; }
    7169    String lastUpdatedNowPlayingTitle() const final { return m_reportedTitle; }
  • TabularUnified trunk/Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.mm

    r230490 r231817  
    302302}
    303303
    304 bool MediaSessionManageriOS::sessionCanLoadMedia(const PlatformMediaSession& session) const
    305 {
    306     if (session.displayType() == PlatformMediaSession::Optimized)
    307         return true;
    308 
    309     return PlatformMediaSessionManager::sessionCanLoadMedia(session);
    310 }
    311 
    312304void MediaSessionManageriOS::externalOutputDeviceAvailableDidChange()
    313305{
  • TabularUnified trunk/Source/WebCore/rendering/RenderVideo.cpp

    r228908 r231817  
    6565void RenderVideo::willBeDestroyed()
    6666{
     67    visibleInViewportStateChanged();
    6768    if (auto player = videoElement().player())
    6869        player->setVisible(false);
  • TabularUnified trunk/Source/WebCore/testing/Internals.cpp

    r231798 r231817  
    32333233}
    32343234
     3235bool Internals::elementShouldBufferData(HTMLMediaElement& element)
     3236{
     3237    return element.shouldBufferData();
     3238}
     3239
    32353240#endif
    32363241
  • TabularUnified trunk/Source/WebCore/testing/Internals.h

    r231779 r231817  
    474474    void beginSimulatedHDCPError(HTMLMediaElement&);
    475475    void endSimulatedHDCPError(HTMLMediaElement&);
     476
     477    bool elementShouldBufferData(HTMLMediaElement&);
    476478#endif
    477479
  • TabularUnified trunk/Source/WebCore/testing/Internals.idl

    r231779 r231817  
    430430    [Conditional=VIDEO] void endSimulatedHDCPError(HTMLMediaElement media);
    431431
     432    [Conditional=VIDEO] boolean elementShouldBufferData(HTMLMediaElement media);
     433
    432434    [Conditional=LEGACY_ENCRYPTED_MEDIA] void initializeMockCDM();
    433435    [Conditional=ENCRYPTED_MEDIA] MockCDMFactory registerMockCDM();
Note: See TracChangeset for help on using the changeset viewer.