Skip to content
Permalink
Browse files
[Mac][MSE] Stalled YouTube playback does not allow display to sleep.
https://bugs.webkit.org/show_bug.cgi?id=140468
rdar://problem/19171162

Reviewed by Eric Carlson.

Source/WebCore:

Test: media/media-source/media-source-stalled-holds-sleep-assertion.html

The unstated convention of MediaPlayerPrivate::paused() is that implementations should
return 'true' if the playback rate is 0. However, MediaPlayerPrivateMediaSourceAVFObjC
was returning 'false' if it was supposed to be playing, regardless of the actual rate.
This caused a check in HTMLMediaElement of whether to release the sleep assertion token
to fail, thinking the media engine was still playing.

Add some testing infrastructure to allow us to test whether the media element is disabling
display sleep from within layout tests.

* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::isDisablingSleep):
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::paused):
* testing/Internals.cpp:
(WebCore::Internals::elementIsBlockingDisplaySleep):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* media/media-source/content/test-fragmented-manifest.json: Added.
* media/media-source/content/test-fragmented.mp4: Added.
* media/media-source/media-source-loader.js: Added.
(MediaSourceLoader):
(MediaSourceLoader.prototype.loadManifest):
(MediaSourceLoader.prototype.loadManifestSucceeded):
(MediaSourceLoader.prototype.loadManifestFailed):
(MediaSourceLoader.prototype.loadMediaData):
(MediaSourceLoader.prototype.loadMediaDataSucceeded):
(MediaSourceLoader.prototype.loadMediaDataFailed):
(MediaSourceLoader.prototype.type):
(MediaSourceLoader.prototype.duration):
(MediaSourceLoader.prototype.initSegment):
(MediaSourceLoader.prototype.mediaSegmentsLength):
(MediaSourceLoader.prototype.mediaSegment):
* media/media-source/media-source-stalled-holds-sleep-assertion-expected.txt: Added.
* media/media-source/media-source-stalled-holds-sleep-assertion.html: Added.


Canonical link: https://commits.webkit.org/158460@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@178486 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
jernoble committed Jan 15, 2015
1 parent 6bc00a8 commit 31e995929e6f0359a5726d4ac99b67398989e213
@@ -1,3 +1,29 @@
2015-01-14 Jer Noble <jer.noble@apple.com>

[Mac][MSE] Stalled YouTube playback does not allow display to sleep.
https://bugs.webkit.org/show_bug.cgi?id=140468
rdar://problem/19171162

Reviewed by Eric Carlson.

* media/media-source/content/test-fragmented-manifest.json: Added.
* media/media-source/content/test-fragmented.mp4: Added.
* media/media-source/media-source-loader.js: Added.
(MediaSourceLoader):
(MediaSourceLoader.prototype.loadManifest):
(MediaSourceLoader.prototype.loadManifestSucceeded):
(MediaSourceLoader.prototype.loadManifestFailed):
(MediaSourceLoader.prototype.loadMediaData):
(MediaSourceLoader.prototype.loadMediaDataSucceeded):
(MediaSourceLoader.prototype.loadMediaDataFailed):
(MediaSourceLoader.prototype.type):
(MediaSourceLoader.prototype.duration):
(MediaSourceLoader.prototype.initSegment):
(MediaSourceLoader.prototype.mediaSegmentsLength):
(MediaSourceLoader.prototype.mediaSegment):
* media/media-source/media-source-stalled-holds-sleep-assertion-expected.txt: Added.
* media/media-source/media-source-stalled-holds-sleep-assertion.html: Added.

2015-01-14 Andrzej Badowski <a.badowski@samsung.com>

[EFL] Change expectations for two layout tests.
@@ -0,0 +1,18 @@
{
"url": "content/test-fragmented.mp4",
"type": "video/mp4; codecs=\"mp4a.40.2,avc1.4d281e\"",
"init": { "offset": 0, "size": 1215 },
"duration": 10.327753,
"media": [
{ "offset": 1215, "size": 67526, "timecode": 0.000000, "duration": 1.041668 },
{ "offset": 68741, "size": 72683, "timecode": 1.016916, "duration": 1.024752 },
{ "offset": 141424, "size": 78499, "timecode": 2.015374, "duration": 1.026294 },
{ "offset": 219923, "size": 77358, "timecode": 3.013832, "duration": 1.027835 },
{ "offset": 297281, "size": 80748, "timecode": 4.012290, "duration": 1.029377 },
{ "offset": 378029, "size": 78038, "timecode": 5.010748, "duration": 1.030919 },
{ "offset": 456067, "size": 82223, "timecode": 6.009206, "duration": 1.032461 },
{ "offset": 538290, "size": 78331, "timecode": 7.007664, "duration": 1.034003 },
{ "offset": 616621, "size": 80736, "timecode": 8.006122, "duration": 1.035545 },
{ "offset": 697357, "size": 77752, "timecode": 9.004580, "duration": 1.044899 }
]
}
Binary file not shown.
@@ -15,7 +15,8 @@
if (window.internals)
internals.initializeMockMediaSource();

function runTest() {
function runTest()
{
findMediaElement();
source = new MediaSource();
source.addEventListener('sourceopen', startLoad);
@@ -26,7 +27,8 @@
run('video.src = URL.createObjectURL(source)');
}

function startLoad() {
function startLoad()
{
sourceBuffer = source.addSourceBuffer('video/mock; codecs="mock"');
sourceBuffer.addEventListener('update', sourceUpdated);
nextRequest = 0;
@@ -36,7 +38,8 @@
sourceBuffer.appendBuffer(init)
}

function sourceUpdated() {
function sourceUpdated()
{
source.activeSourceBuffers.length;
if (nextRequest < totalLength) {
sourceBuffer.appendBuffer(makeASample(nextRequest, nextRequest, 1, 1, SAMPLE_FLAG.SYNC));
@@ -0,0 +1,96 @@
function MediaSourceLoader(url)
{
this._url = url;
setTimeout(this.loadManifest.bind(this));

this.onload = null;
this.onerror = null;
}

MediaSourceLoader.prototype = {
loadManifest: function()
{
var request = new XMLHttpRequest();
request.open('GET', this._url, true);
request.responseType = 'json';
request.onload = this.loadManifestSucceeded.bind(this);
request.onerror = this.loadManifestFailed.bind(this);
request.send();
},

loadManifestSucceeded: function(e)
{
this._manifest = e.target.response;

if (!this._manifest || !this._manifest.url) {
if (this.onerror)
this.onerror();
return;
}

this.loadMediaData();
},

loadManifestFailed: function()
{
if (this.onerror)
this.onerror();
},

loadMediaData: function()
{
var request = new XMLHttpRequest();
request.open('GET', this._manifest.url, true);
request.responseType = 'arraybuffer';
request.onload = this.loadMediaDataSucceeded.bind(this);
request.onerror = this.loadMediaDataFailed.bind(this);
request.send();
},

loadMediaDataSucceeded: function(e)
{
this._mediaData = e.target.response;

if (this.onload)
this.onload();
},

loadMediaDataFailed: function()
{
if (this.onerror)
this.onerror();
},

type: function()
{
return this._manifest ? this._manifest.type : "";
},

duration: function()
{
return this._manifest ? this._manifest.duration : 0
},

initSegment: function()
{
if (!this._manifest || !this._manifest.init || !this._mediaData)
return null;
var init = this._manifest.init;
return this._mediaData.slice(init.offset, init.offset + init.size);
},

mediaSegmentsLength: function()
{
if (!this._manifest || !this._manifest.media)
return 0;
return this._manifest.media.length;
},

mediaSegment: function(segmentNumber)
{
if (!this._manifest || !this._manifest.media || !this._mediaData || segmentNumber >= this._manifest.media.length)
return null;
var media = this._manifest.media[segmentNumber];
return this._mediaData.slice(media.offset, media.offset + media.size);
},
};
@@ -0,0 +1,15 @@

RUN(video.src = URL.createObjectURL(source))
EVENT(sourceopen)
RUN(source.duration = loader.duration())
RUN(sourceBuffer = source.addSourceBuffer(loader.type()))
RUN(sourceBuffer.appendBuffer(loader.initSegment()))
EVENT(update)
RUN(sourceBuffer.appendBuffer(loader.mediaSegment(0)))
EVENT(update)
RUN(video.currentTime = video.buffered.end(0) - 0.1)
RUN(video.play())
EVENT(stalled)
EXPECTED (internals.elementIsBlockingDisplaySleep(video) == 'false') OK
END OF TEST

@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<title>media-source-stalled-holds-sleep-assertion</title>
<script src="media-source-loader.js"></script>
<script src="../video-test.js"></script>
<script>
var loader;
var source;
var sourceBuffer;

function runTest() {
findMediaElement();

loader = new MediaSourceLoader('content/test-fragmented-manifest.json');
loader.onload = mediaDataLoaded;
loader.onerror = mediaDataLoadingFailed;
}

function mediaDataLoadingFailed() {
failTest('Media data loading failed');
}

function mediaDataLoaded() {
source = new MediaSource();
waitForEvent('sourceopen', sourceOpen, false, false, source);
run('video.src = URL.createObjectURL(source)');
}

function sourceOpen() {
run('source.duration = loader.duration()');
run('sourceBuffer = source.addSourceBuffer(loader.type())');
waitForEventOn(sourceBuffer, 'update', sourceInitialized, false, true);
run('sourceBuffer.appendBuffer(loader.initSegment())');
}

function sourceInitialized() {
waitForEventOn(sourceBuffer, 'update', sourceUpdated, false, true);
run('sourceBuffer.appendBuffer(loader.mediaSegment(0))');
}

function sourceUpdated() {
run('video.currentTime = video.buffered.end(0) - 0.1');
run('video.play()');
waitForEvent('stalled', stalled);
}

function stalled() {
testExpected('internals.elementIsBlockingDisplaySleep(video)', false);
endTest();
}
</script>
</head>
<body onload="runTest()">
<video controls></video>
</body>
</html>
@@ -1,3 +1,31 @@
2015-01-14 Jer Noble <jer.noble@apple.com>

[Mac][MSE] Stalled YouTube playback does not allow display to sleep.
https://bugs.webkit.org/show_bug.cgi?id=140468
rdar://problem/19171162

Reviewed by Eric Carlson.

Test: media/media-source/media-source-stalled-holds-sleep-assertion.html

The unstated convention of MediaPlayerPrivate::paused() is that implementations should
return 'true' if the playback rate is 0. However, MediaPlayerPrivateMediaSourceAVFObjC
was returning 'false' if it was supposed to be playing, regardless of the actual rate.
This caused a check in HTMLMediaElement of whether to release the sleep assertion token
to fail, thinking the media engine was still playing.

Add some testing infrastructure to allow us to test whether the media element is disabling
display sleep from within layout tests.

* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::isDisablingSleep):
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::paused):
* testing/Internals.cpp:
(WebCore::Internals::elementIsBlockingDisplaySleep):
* testing/Internals.h:
* testing/Internals.idl:

2015-01-14 Zalan Bujtas <zalan@apple.com>

Move LayoutFragment and ClipRect to their own files.
@@ -465,6 +465,8 @@ class HTMLMediaElement

MediaControlsHost* mediaControlsHost() { return m_mediaControlsHost.get(); }

bool isDisablingSleep() const { return m_sleepDisabler.get(); }

protected:
HTMLMediaElement(const QualifiedName&, Document&, bool);
virtual ~HTMLMediaElement();
@@ -337,7 +337,7 @@ static void CMTimebaseEffectiveRateChangedCallback(CMNotificationCenterRef, cons

bool MediaPlayerPrivateMediaSourceAVFObjC::paused() const
{
return !m_playing;
return ![m_synchronizer rate];
}

void MediaPlayerPrivateMediaSourceAVFObjC::setVolume(float volume)
@@ -59,6 +59,7 @@
#include "HTMLPlugInElement.h"
#include "HTMLSelectElement.h"
#include "HTMLTextAreaElement.h"
#include "HTMLVideoElement.h"
#include "HistoryController.h"
#include "HistoryItem.h"
#include "InspectorClient.h"
@@ -2434,6 +2435,12 @@ void Internals::simulateSystemWake() const
#endif
}

bool Internals::elementIsBlockingDisplaySleep(Element* element) const
{
HTMLMediaElement* mediaElement = downcast<HTMLMediaElement>(element);
return mediaElement ? mediaElement->isDisablingSleep() : false;
}

void Internals::installMockPageOverlay(const String& overlayType, ExceptionCode& ec)
{
Document* document = contextDocument();
@@ -351,6 +351,7 @@ class Internals : public RefCounted<Internals>

void simulateSystemSleep() const;
void simulateSystemWake() const;
bool elementIsBlockingDisplaySleep(Element*) const;

void installMockPageOverlay(const String& overlayType, ExceptionCode&);
String pageOverlayLayerTreeAsText(ExceptionCode&) const;
@@ -307,6 +307,7 @@ enum PageOverlayType {

[Conditional=VIDEO] void simulateSystemSleep();
[Conditional=VIDEO] void simulateSystemWake();
[Conditional=VIDEO] boolean elementIsBlockingDisplaySleep(Element element);

[RaisesException] void installMockPageOverlay(PageOverlayType type);
[RaisesException] DOMString pageOverlayLayerTreeAsText();

0 comments on commit 31e9959

Please sign in to comment.