Skip to content

Commit

Permalink
Merge pull request #263 from fmtvp/sentinel-trust-zero-spike
Browse files Browse the repository at this point in the history
LG/Amazon Spinner During Playback Bug
  • Loading branch information
tsadler1988 committed Jun 15, 2015
2 parents ad17c6d + 6466267 commit c35e64b
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 7 deletions.
157 changes: 157 additions & 0 deletions static/script-tests/tests/devices/mediaplayer/html5commontests.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,17 @@ window.commonTests.mediaPlayer.html5.mixinTests = function (testCase, mediaPlaye
assert(self._eventCallback.notCalled);
};

var assertEventTypeHasBeenFiredASpecificNumberOfTimes = function (self, eventType, expectedNumberOfCalls) {
var numberOfCalls = 0;

for( i = 0; i < self._eventCallback.args.length; i++) {
if(eventType === self._eventCallback.args[i][0].type) {
numberOfCalls++;
}
}
assertEquals(expectedNumberOfCalls, numberOfCalls);
};

var clearEvents = function(self) {
self._eventCallback.reset();
};
Expand Down Expand Up @@ -1124,6 +1135,7 @@ window.commonTests.mediaPlayer.html5.mixinTests = function (testCase, mediaPlaye
clearEvents(self);
fireSentinels(self);
fireSentinels(self);
fireSentinels(self);

assertEvent(self, MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING);
assertEvent(self, MediaPlayer.EVENT.BUFFERING);
Expand Down Expand Up @@ -1254,6 +1266,136 @@ window.commonTests.mediaPlayer.html5.mixinTests = function (testCase, mediaPlaye
});
};

var ensureEnterBufferingSentinelIsNotCalledWhenZeroesCannotBeTrusted = function(self, MediaPlayer) {
var i;
for (i = 0; i<3; i++) {
advancePlayTime(self);
fireSentinels(self);
}

for (i=0; i<2; i++) {
stubCreateElementResults.video.currentTime = 0;
fireSentinels(self);
}
assertNoEvent(self, MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING);
assertState(self, MediaPlayer.STATE.PLAYING);
};

var ensureEnterBufferingSentinelIsCalledWhenZeroesCanBeTrusted = function(self, MediaPlayer) {
for (var i=0; i<2; i++) {
stubCreateElementResults.video.currentTime = 0;
fireSentinels(self);
}
assertEvent(self, MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING);
assertState(self, MediaPlayer.STATE.BUFFERING);
};

var testForThreeIntervalsOfNormalPlaybackTwoIntervalsOfZeroesAndOneIntervalOfTimeIncreaseBelowSentinelTolerance = function(self, MediaPlayer) {
var i;

for (i = 0; i<3; i++) {
advancePlayTime(self);
fireSentinels(self);
}

for (i=0; i<2; i++) {
stubCreateElementResults.video.currentTime = 0;
fireSentinels(self);
}

assertNoEvent(self, MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING);

stubCreateElementResults.video.currentTime = 0.01;
fireSentinels(self);

assertNoEvent(self, MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING);
};

mixins.testEnterBufferingSentinelDoesNothingWhenDeviceTimeIsReportedAsZeroDuringPlayback = function(queue) {
expectAsserts(2);
var self = this;
runMediaPlayerTest(this, queue, function (MediaPlayer) {
getToPlaying(self, MediaPlayer, 0);
clearEvents(self);
ensureEnterBufferingSentinelIsNotCalledWhenZeroesCannotBeTrusted(self, MediaPlayer);
});
};

mixins.testEnterBufferingSentinelDoesNothingWhenBeginPlaybackIsCalledAndDeviceTimeIsReportedAsZeroForAtLeastTwoIntervals = function (queue) {
expectAsserts(2);
var self = this;
runMediaPlayerTest(this, queue, function (MediaPlayer) {
getToPlayingWithBeginPlayback(self, MediaPlayer, 20);
clearEvents(self);
ensureEnterBufferingSentinelIsNotCalledWhenZeroesCannotBeTrusted(self, MediaPlayer);
});
};

mixins.testEnterBufferingSentinelFiresWhenBeginPlaybackFromZeroIsCalledAndDeviceTimeDoesNotAdvance = function(queue) {
expectAsserts(2);
var self = this;
runMediaPlayerTest(this, queue, function (MediaPlayer) {
getToPlaying(self, MediaPlayer, 0);
clearEvents(self);
ensureEnterBufferingSentinelIsCalledWhenZeroesCanBeTrusted(self, MediaPlayer);
});
};

mixins.testEnterBufferingSentinelFiresWhenBeginPlaybackIsCalledAndDeviceTimeDoesNotAdvance = function(queue) {
expectAsserts(2);
var self = this;
runMediaPlayerTest(this, queue, function (MediaPlayer) {
getToPlayingWithBeginPlayback(self, MediaPlayer, 0);
clearEvents(self);
ensureEnterBufferingSentinelIsCalledWhenZeroesCanBeTrusted(self, MediaPlayer);
});
};

mixins.testEnterBufferingSentinelFiresWhenSeekedToZeroAndDeviceTimeIsReportedAsZeroForAtLeastTwoIntervals = function(queue) {
expectAsserts(1);
var self = this;
runMediaPlayerTest(this, queue, function (MediaPlayer) {
getToPlaying(self, MediaPlayer, 20);
clearEvents(self);

self._mediaPlayer.playFrom(0);
deviceMockingHooks.finishBuffering(self._mediaPlayer);
fireSentinels(self);
fireSentinels(self);

assertEvent(self, MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING);
});
};

mixins.testEnterBufferingSentinelOnlyFiresOnSecondAttemptWhenDeviceReportsTimeAsNotChangingWithinTolerance = function(queue) {
expectAsserts(3);
runMediaPlayerTest(this, queue, function (MediaPlayer) {
getToPlaying(this, MediaPlayer, 0);
clearEvents(this);

testForThreeIntervalsOfNormalPlaybackTwoIntervalsOfZeroesAndOneIntervalOfTimeIncreaseBelowSentinelTolerance(this, MediaPlayer);

stubCreateElementResults.video.currentTime = 0.01;
fireSentinels(this);

stubCreateElementResults.video.currentTime = 0.01;
fireSentinels(this);

assertEventTypeHasBeenFiredASpecificNumberOfTimes(this, MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING, 1);
});
};

mixins.testEnterBufferingSentinelDoesNotFireOnTwoNonConsecutiveOccurrencesOfDeviceReportingTimeAsNotChangingWithinTolerance = function(queue) {
expectAsserts(4);
runMediaPlayerTest(this, queue, function (MediaPlayer) {
getToPlaying(this, MediaPlayer, 0);
clearEvents(this);

testForThreeIntervalsOfNormalPlaybackTwoIntervalsOfZeroesAndOneIntervalOfTimeIncreaseBelowSentinelTolerance(this, MediaPlayer);
testForThreeIntervalsOfNormalPlaybackTwoIntervalsOfZeroesAndOneIntervalOfTimeIncreaseBelowSentinelTolerance(this, MediaPlayer);
});
};

mixins.testExitBufferingSentinelCausesTransitionToPlayingWhenPlaybackStarts = function(queue) {
expectAsserts(3);
var self = this;
Expand Down Expand Up @@ -1880,6 +2022,21 @@ window.commonTests.mediaPlayer.html5.mixinTests = function (testCase, mediaPlaye
});
};

mixins.testPauseSentinelDoesNotFireWhenDeviceTimeAdvancesByLessThanSentinelTolerance = function(queue) {
expectAsserts(1);
var self = this;
runMediaPlayerTest(this, queue, function(MediaPlayer) {
getToPlaying(self, MediaPlayer, 20);
clearEvents(self);

self._mediaPlayer.pause();
stubCreateElementResults.video.currentTime += 0.01;
fireSentinels(self);

assertNoEvent(self, MediaPlayer.EVENT.SENTINEL_PAUSE);
});
};

mixins.testPlayFromNearCurrentTimeWillNotCauseFinishBufferingToPerformSeekLater = function(queue) {
expectAsserts(1);
runMediaPlayerTest(this, queue, function (MediaPlayer) {
Expand Down
55 changes: 48 additions & 7 deletions static/script/devices/mediaplayer/html5.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ require.def(
this._super();
this._setSentinelLimits();
this._state = MediaPlayer.STATE.EMPTY;

},

/**
* @inheritDoc
*/
setSource: function(mediaType, url, mimeType) {
if (this.getState() === MediaPlayer.STATE.EMPTY) {
this._trustZeroes = false;
this._type = mediaType;
this._source = url;
this._mimeType = mimeType;
Expand Down Expand Up @@ -119,6 +121,7 @@ require.def(
switch (this.getState()) {
case MediaPlayer.STATE.PAUSED:
case MediaPlayer.STATE.COMPLETE:
this._trustZeroes = true;
this._toBuffering();
this._playFromIfReady();
break;
Expand All @@ -128,6 +131,7 @@ require.def(
break;

case MediaPlayer.STATE.PLAYING:
this._trustZeroes = true;
this._toBuffering();
this._targetSeekTime = this._getClampedTimeForPlayFrom(seconds);
if (this._isNearToCurrentTime(this._targetSeekTime)) {
Expand All @@ -152,6 +156,7 @@ require.def(
this._sentinelSeekTime = undefined;
switch (this.getState()) {
case MediaPlayer.STATE.STOPPED:
this._trustZeroes = true;
this._toBuffering();
this._mediaElement.play();
break;
Expand All @@ -172,6 +177,7 @@ require.def(

switch (this.getState()) {
case MediaPlayer.STATE.STOPPED:
this._trustZeroes = true;
this._toBuffering();
this._playFromIfReady();
break;
Expand Down Expand Up @@ -411,7 +417,6 @@ require.def(

} else if (this._postBufferingState === MediaPlayer.STATE.PAUSED) {
this._toPaused();

} else {
this._toPlaying();
}
Expand Down Expand Up @@ -577,12 +582,39 @@ require.def(
},

_enterBufferingSentinel: function() {
var notFirstSentinelActivationSinceStateChange = this._sentinelIntervalNumber > 1;
if(!this._hasSentinelTimeChanged && !this._nearEndOfMedia && notFirstSentinelActivationSinceStateChange) {
var sentinelShouldFire = !this._hasSentinelTimeChangedWithinTolerance && !this._nearEndOfMedia ;

if (this.getCurrentTime() === 0) {
sentinelShouldFire = this._trustZeroes && sentinelShouldFire;
}

if (this._enterBufferingSentinelAttemptCount === undefined) {
this._enterBufferingSentinelAttemptCount = 0;
}

if(sentinelShouldFire) {
this._enterBufferingSentinelAttemptCount++;
} else {
this._enterBufferingSentinelAttemptCount = 0;
}

if (this._enterBufferingSentinelAttemptCount === 1) {
sentinelShouldFire = false;
}

if(sentinelShouldFire) {
this._emitEvent(MediaPlayer.EVENT.SENTINEL_ENTER_BUFFERING);
this._toBuffering();
/* Resetting the sentinel attempt count to zero means that the sentinel will only fire once
even if multiple iterations result in the same conditions.
This should not be needed as the second iteration, when the enter buffering sentinel is fired
will cause the media player to go into the buffering state. The enter buffering sentinel is not fired
when in buffering state
*/
this._enterBufferingSentinelAttemptCount = 0;
return true;
}

return false;
},

Expand All @@ -597,7 +629,7 @@ require.def(
return fireExitBufferingSentinel(this);
}

if (this._hasSentinelTimeChanged) {
if (this._hasSentinelTimeChangedWithinTolerance) {
return fireExitBufferingSentinel(this);
}
return false;
Expand Down Expand Up @@ -627,7 +659,7 @@ require.def(

_shouldBePausedSentinel: function() {
var sentinelActionTaken = false;
if (this._hasSentinelTimeChanged) {
if (this._hasSentinelTimeChangedWithinTolerance) {
var mediaElement = this._mediaElement;
sentinelActionTaken = this._nextSentinelAttempt(this._sentinelLimits.pause, function() {
mediaElement.pause();
Expand Down Expand Up @@ -658,7 +690,7 @@ require.def(
},

_endOfMediaSentinel: function() {
if (!this._hasSentinelTimeChanged && this._nearEndOfMedia) {
if (!this._hasSentinelTimeChangedWithinTolerance && this._nearEndOfMedia) {
this._emitEvent(MediaPlayer.EVENT.SENTINEL_COMPLETE);
this._onEndOfMedia();
return true;
Expand All @@ -678,16 +710,25 @@ require.def(
this._sentinelInterval = setInterval(function() {
self._sentinelIntervalNumber += 1;
var newTime = self.getCurrentTime();
self._hasSentinelTimeChanged = (Math.abs(newTime - self._lastSentinelTime) > 0.2);

self._hasSentinelTimeChangedWithinTolerance = (Math.abs(newTime - self._lastSentinelTime) > 0.2);
self._nearEndOfMedia = (self.getDuration() - (newTime || self._lastSentinelTime)) <= 1;
self._lastSentinelTime = newTime;

for (var i = 0; i < sentinels.length; i++) {
var sentinelActivated = sentinels[i].call(self);

if (self.getCurrentTime() > 0) {
self._trustZeroes = false;
}

if(sentinelActivated) {
break;
}
}
}, 1100);


},

_isReadyToPlayFrom: function() {
Expand Down

0 comments on commit c35e64b

Please sign in to comment.