Skip to content

Commit

Permalink
Merge pull request #3174 from Dash-Industry-Forum/development
Browse files Browse the repository at this point in the history
Create Release 3.0.2
  • Loading branch information
dsilhavy authored Feb 3, 2020
2 parents 3ff323e + 37ac86b commit ad7dd9e
Show file tree
Hide file tree
Showing 17 changed files with 186 additions and 54 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ For help, join our [Slack channel](https://dashif-slack.azurewebsites.net), our
## Reference players
The released [pre-built reference players](http://reference.dashif.org/dash.js/) are publicly accessible if you want direct access without writing any Javascript.

Multiple dash.js samples covering a wide set of common use cases can be found in the project's sample folder hosted [here](http://reference.dashif.org/dash.js/latest/samples/index.html).

The [nightly build of the /dev branch reference player](http://reference.dashif.org/dash.js/nightly/samples/dash-if-reference-player/index.html), is pre-release but contains the latest fixes. It is a good place to start if you are debugging playback problems.

A nightly build of the latest minified files are also available: [dash.all.min.js](http://reference.dashif.org/dash.js/nightly/dist/dash.all.min.js) and its debug version [dash.all.debug.js](http://reference.dashif.org/dash.js/nightly/dist/dash.all.debug.js).
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ declare namespace dashjs {
clearkeys?: { [key: string]: string };

/** Priority level of the key system to be selected (0 is the highest prority, -1 for undefined priority) */
priority?: number = -1;
priority?: number;
}

export interface KeySystem {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dashjs",
"version": "3.0.1",
"version": "3.0.2",
"description": "A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.",
"main": "build/es5/index.js",
"types": "build/typings/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion samples/dash-if-reference-player/app/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@
"url": "https://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)",
"protData": {
"com.microsoft.playready": {
"serverURL": "http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:true,sl:150)",
"serverURL": "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:true,sl:150)",
"sessionType": "persistent-license"
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/Version.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const VERSION = '3.0.1';
const VERSION = '3.0.2';
export function getVersionString() {
return VERSION;
}
2 changes: 1 addition & 1 deletion src/dash/DashHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ function DashHandler(config) {
}

if (segments.length > 0) {
representation.segmentAvailabilityRange = {start: segments[0].presentationStartTime, end: segments[len - 1].presentationStartTime};
representation.segmentAvailabilityRange = {start: segments[0].presentationStartTime, end: segments[segments.length - 1].presentationStartTime};
representation.availableSegmentsNumber = segments.length;
representation.segments = segments;

Expand Down
12 changes: 6 additions & 6 deletions src/dash/parser/matchers/DurationMatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ class DurationMatcher extends BaseMatcher {
str => {
//str = "P10Y10M10DT10H10M10.1S";
const match = durationRegex.exec(str);
let result = (parseFloat(match[2] || 0) * SECONDS_IN_YEAR +
parseFloat(match[4] || 0) * SECONDS_IN_MONTH +
parseFloat(match[6] || 0) * SECONDS_IN_DAY +
parseFloat(match[8] || 0) * SECONDS_IN_HOUR +
parseFloat(match[10] || 0) * SECONDS_IN_MIN +
parseFloat(match[12] || 0));
let result = (parseFloat(match[3] || 0) * SECONDS_IN_YEAR +
parseFloat(match[5] || 0) * SECONDS_IN_MONTH +
parseFloat(match[7] || 0) * SECONDS_IN_DAY +
parseFloat(match[9] || 0) * SECONDS_IN_HOUR +
parseFloat(match[11] || 0) * SECONDS_IN_MIN +
parseFloat(match[13] || 0));

if (match[1] !== undefined) {
result = -result;
Expand Down
10 changes: 9 additions & 1 deletion src/dash/utils/SegmentsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,15 @@ function isSegmentAvailable(timelineConverter, representation, segment, isDynami

const segmentTime = timelineConverter.calcPeriodRelativeTimeFromMpdRelativeTime(representation, segment.presentationStartTime);
if (segmentTime >= periodRelativeEnd) {
return false;
if (isDynamic) {
// segment is not available in current period, but it may be segment available in another period that current one (in DVR window)
// if not (time > segmentAvailabilityRange.end), then return false
if ( representation.segmentAvailabilityRange && segment.presentationStartTime >= representation.segmentAvailabilityRange.end) {
return false;
}
} else {
return false;
}
}

return true;
Expand Down
2 changes: 1 addition & 1 deletion src/streaming/ManifestUpdater.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function ManifestUpdater() {

function stopManifestRefreshTimer() {
if (refreshTimer !== null) {
clearInterval(refreshTimer);
clearTimeout(refreshTimer);
refreshTimer = null;
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/streaming/MediaPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1373,14 +1373,13 @@ function MediaPlayer() {

/**
* This method allows to set media settings that will be used to pick the initial track. Format of the settings
* is following:
* {lang: langValue,
* is following: <br />
* {lang: langValue (can be either a string or a regex to match),
* viewpoint: viewpointValue,
* audioChannelConfiguration: audioChannelConfigurationValue,
* accessibility: accessibilityValue,
* role: roleValue}
*
*
* @param {string} type
* @param {Object} value
* @memberof module:MediaPlayer
Expand Down
1 change: 1 addition & 0 deletions src/streaming/controllers/BufferController.js
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ function BufferController(config) {
if (!bufferResetInProgress) {
logger.debug('onRemoved : call updateBufferLevel');
updateBufferLevel();
addBufferMetrics();
} else {
bufferResetInProgress = false;
if (mediaChunk) {
Expand Down
2 changes: 1 addition & 1 deletion src/streaming/controllers/MediaController.js
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ function MediaController() {
}

function matchSettings(settings, track) {
const matchLang = !settings.lang || (settings.lang === track.lang);
const matchLang = !settings.lang || (track.lang.match(settings.lang));
const matchViewPoint = !settings.viewpoint || (settings.viewpoint === track.viewpoint);
const matchRole = !settings.role || !!track.roles.filter(function (item) {
return item === settings.role;
Expand Down
93 changes: 59 additions & 34 deletions src/streaming/controllers/PlaybackController.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function PlaybackController() {
timelineConverter,
liveStartTime,
wallclockTimeIntervalId,
commonEarliestTime,
earliestTime,
liveDelay,
bufferedRange,
streamInfo,
Expand Down Expand Up @@ -90,6 +90,7 @@ function PlaybackController() {

eventBus.on(Events.DATA_UPDATE_COMPLETED, onDataUpdateCompleted, this);
eventBus.on(Events.BYTES_APPENDED_END_FRAGMENT, onBytesAppended, this);
eventBus.on(Events.BUFFER_CLEARED, onBufferCleared, this);
eventBus.on(Events.LOADING_PROGRESS, onFragmentLoadProgress, this);
eventBus.on(Events.BUFFER_LEVEL_STATE_CHANGED, onBufferLevelStateChanged, this);
eventBus.on(Events.PERIOD_SWITCH_STARTED, onPeriodSwitchStarted, this);
Expand All @@ -105,9 +106,9 @@ function PlaybackController() {
}

function onPeriodSwitchStarted(e) {
if (!isDynamic && e.fromStreamInfo && commonEarliestTime[e.fromStreamInfo.id] !== undefined) {
if (!isDynamic && e.fromStreamInfo && earliestTime[e.fromStreamInfo.id] !== undefined) {
delete bufferedRange[e.fromStreamInfo.id];
delete commonEarliestTime[e.fromStreamInfo.id];
delete earliestTime[e.fromStreamInfo.id];
}
}

Expand Down Expand Up @@ -150,15 +151,11 @@ function PlaybackController() {
// Internal seek = seek video model only (disable 'seeking' listener),
// buffer(s) are already appended at given time (see onBytesAppended())
videoModel.removeEventListener('seeking', onPlaybackSeeking);
logger.info('Requesting seek to time: ' + time);
logger.info('Requesting internal seek to time: ' + time);
videoModel.setCurrentTime(time, stickToBuffered);
}
} else {
eventBus.trigger(Events.PLAYBACK_SEEK_ASKED);
if (streamInfo) {
delete bufferedRange[streamInfo.id];
delete commonEarliestTime[streamInfo.id];
}
logger.info('Requesting seek to time: ' + time);
videoModel.setCurrentTime(time, stickToBuffered);
}
Expand Down Expand Up @@ -228,9 +225,16 @@ function PlaybackController() {
function computeLiveDelay(fragmentDuration, dvrWindowSize) {
let delay,
ret,
r,
startTime;
const END_OF_PLAYLIST_PADDING = 10;

let uriParameters = uriFragmentModel.getURIFragmentData();

if (uriParameters) {
r = parseInt(uriParameters.r, 10);
}

let suggestedPresentationDelay = adapter.getSuggestedPresentationDelay();

if (settings.get().streaming.useSuggestedPresentationDelay && suggestedPresentationDelay !== null) {
Expand All @@ -239,7 +243,10 @@ function PlaybackController() {
delay = 0;
} else if (mediaPlayerModel.getLiveDelay()) {
delay = mediaPlayerModel.getLiveDelay(); // If set by user, this value takes precedence
} else if (!isNaN(fragmentDuration)) {
} else if (r) {
delay = r;
}
else if (!isNaN(fragmentDuration)) {
delay = fragmentDuration * settings.get().streaming.liveDelayFragmentCount;
} else {
delay = streamInfo.manifestInfo.minBufferTime * 2;
Expand Down Expand Up @@ -284,7 +291,7 @@ function PlaybackController() {
function reset() {
liveStartTime = NaN;
playOnceInitialized = false;
commonEarliestTime = {};
earliestTime = {};
liveDelay = 0;
availabilityStartTime = 0;
bufferedRange = {};
Expand All @@ -298,6 +305,7 @@ function PlaybackController() {
eventBus.off(Events.PLAYBACK_TIME_UPDATED, onPlaybackProgression, this);
eventBus.off(Events.PLAYBACK_ENDED, onPlaybackEnded, this);
eventBus.off(Events.STREAM_INITIALIZING, onStreamInitializing, this);
eventBus.off(Events.BUFFER_CLEARED, onBufferCleared, this);
stopUpdatingWallclockTime();
removeAllListeners();
}
Expand Down Expand Up @@ -388,8 +396,8 @@ function PlaybackController() {
if (!isNaN(startTimeOffset) && startTimeOffset < Math.max(streamInfo.manifestInfo.duration, streamInfo.duration) && startTimeOffset >= 0) {
presentationStartTime = startTimeOffset;
} else {
let earliestTime = commonEarliestTime[streamInfo.id]; //set by ready bufferStart after first onBytesAppended
presentationStartTime = earliestTime !== undefined ? Math.max(earliestTime.audio !== undefined ? earliestTime.audio : 0, earliestTime.video !== undefined ? earliestTime.video : 0, streamInfo.start) : streamInfo.start;
let currentEarliestTime = earliestTime[streamInfo.id]; //set by ready bufferStart after first onBytesAppended
presentationStartTime = currentEarliestTime !== undefined ? Math.max(currentEarliestTime.audio !== undefined ? currentEarliestTime.audio : 0, currentEarliestTime.video !== undefined ? currentEarliestTime.video : 0, streamInfo.start) : streamInfo.start;
}
}
}
Expand All @@ -402,10 +410,14 @@ function PlaybackController() {
const DVRWindow = DVRMetrics ? DVRMetrics.range : null;
let actualTime;

if (!DVRWindow) return NaN;
if (!DVRWindow) {
return NaN;
}
if (currentTime > DVRWindow.end) {
actualTime = Math.max(DVRWindow.end - streamInfo.manifestInfo.minBufferTime * 2, DVRWindow.start);
} else if (currentTime + 0.250 < DVRWindow.start && DVRWindow.start - currentTime > DVRWindow.start - 315360000) {

} else if (currentTime > 0 && currentTime + 0.250 < DVRWindow.start && Math.abs(currentTime - DVRWindow.start) < 315360000) {

// Checking currentTime plus 250ms as the 'timeupdate' is fired with a frequency between 4Hz and 66Hz
// https://developer.mozilla.org/en-US/docs/Web/Events/timeupdate
// http://w3c.github.io/html/single-page.html#offsets-into-the-media-resource
Expand Down Expand Up @@ -671,12 +683,25 @@ function PlaybackController() {
}
}

function onBufferCleared(e) {
const type = e.sender.getType();

if (streamInfo && earliestTime[streamInfo.id] && (earliestTime[streamInfo.id][type] >= e.from && earliestTime[streamInfo.id][type] <= e.to)) {
logger.info('Reset commonEarliestTime and bufferedRange for ' + type);
bufferedRange[streamInfo.id][type] = undefined;
earliestTime[streamInfo.id][type] = undefined;
earliestTime[streamInfo.id].started = false;
} else {
logger.info('No need to reset commonEarliestTime and bufferedRange for ' + type);
}
}

function onBytesAppended(e) {
let earliestTime,
let commonEarliestTime,
initialStartTime;
let ranges = e.bufferedRanges;
if (!ranges || !ranges.length) return;
if (commonEarliestTime[streamInfo.id] && commonEarliestTime[streamInfo.id].started === true) {
if (earliestTime[streamInfo.id] && earliestTime[streamInfo.id].started === true) {
//stream has already been started.
return;
}
Expand All @@ -689,51 +714,51 @@ function PlaybackController() {

bufferedRange[streamInfo.id][type] = ranges;

if (commonEarliestTime[streamInfo.id] === undefined) {
commonEarliestTime[streamInfo.id] = [];
commonEarliestTime[streamInfo.id].started = false;
if (earliestTime[streamInfo.id] === undefined) {
earliestTime[streamInfo.id] = [];
earliestTime[streamInfo.id].started = false;
}

if (commonEarliestTime[streamInfo.id][type] === undefined) {
commonEarliestTime[streamInfo.id][type] = Math.max(ranges.start(0), streamInfo.start);
if (earliestTime[streamInfo.id][type] === undefined) {
earliestTime[streamInfo.id][type] = Math.max(ranges.start(0), streamInfo.start);
}

const hasVideoTrack = streamController.isTrackTypePresent(Constants.VIDEO);
const hasAudioTrack = streamController.isTrackTypePresent(Constants.AUDIO);

initialStartTime = getStreamStartTime(true);
initialStartTime = getStreamStartTime(false);
if (hasAudioTrack && hasVideoTrack) {
//current stream has audio and video contents
if (!isNaN(commonEarliestTime[streamInfo.id].audio) && !isNaN(commonEarliestTime[streamInfo.id].video)) {
if (!isNaN(earliestTime[streamInfo.id].audio) && !isNaN(earliestTime[streamInfo.id].video)) {

if (commonEarliestTime[streamInfo.id].audio < commonEarliestTime[streamInfo.id].video) {
if (earliestTime[streamInfo.id].audio < earliestTime[streamInfo.id].video) {
// common earliest is video time
// check buffered audio range has video time, if ok, we seek, otherwise, we wait some other data
earliestTime = commonEarliestTime[streamInfo.id].video > initialStartTime ? commonEarliestTime[streamInfo.id].video : initialStartTime;
commonEarliestTime = earliestTime[streamInfo.id].video > initialStartTime ? earliestTime[streamInfo.id].video : initialStartTime;
ranges = bufferedRange[streamInfo.id].audio;
} else {
// common earliest is audio time
// check buffered video range has audio time, if ok, we seek, otherwise, we wait some other data
earliestTime = commonEarliestTime[streamInfo.id].audio > initialStartTime ? commonEarliestTime[streamInfo.id].audio : initialStartTime;
commonEarliestTime = earliestTime[streamInfo.id].audio > initialStartTime ? earliestTime[streamInfo.id].audio : initialStartTime;
ranges = bufferedRange[streamInfo.id].video;
}
if (checkTimeInRanges(earliestTime, ranges)) {
if (checkTimeInRanges(commonEarliestTime, ranges)) {
if (!(checkTimeInRanges(getNormalizedTime(), bufferedRange[streamInfo.id].audio) && checkTimeInRanges(getNormalizedTime(), bufferedRange[streamInfo.id].video))) {
if (!compatibleWithPreviousStream && earliestTime !== 0) {
seek(earliestTime, true, true);
if (!compatibleWithPreviousStream && commonEarliestTime !== 0) {
seek(commonEarliestTime, true, true);
}
}
commonEarliestTime[streamInfo.id].started = true;
earliestTime[streamInfo.id].started = true;
}
}
} else {
//current stream has only audio or only video content
if (commonEarliestTime[streamInfo.id][type]) {
earliestTime = commonEarliestTime[streamInfo.id][type] > initialStartTime ? commonEarliestTime[streamInfo.id][type] : initialStartTime;
if (earliestTime[streamInfo.id][type]) {
commonEarliestTime = earliestTime[streamInfo.id][type] > initialStartTime ? earliestTime[streamInfo.id][type] : initialStartTime;
if (!compatibleWithPreviousStream) {
seek(earliestTime, false, true);
seek(commonEarliestTime, false, true);
}
commonEarliestTime[streamInfo.id].started = true;
earliestTime[streamInfo.id].started = true;
}
}
}
Expand Down
14 changes: 13 additions & 1 deletion src/streaming/protection/vo/ProtectionData.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ class ProtectionData {
* @param {Object} clearkeys defines a set of clear keys that are available to
* the key system. Object properties are base64-encoded keyIDs (with no padding).
* Corresponding property values are keys, base64-encoded (no padding).
* @param {number|undefined} priority priority order of the current ProtectionData
* @class
*/
constructor(serverURL, httpRequestHeaders, clearkeys) {
constructor(serverURL, httpRequestHeaders, clearkeys, priority) {
this.serverURL = serverURL;
this.httpRequestHeaders = httpRequestHeaders;
this.clearkeys = clearkeys;
this.priority = priority === undefined ? -1 : priority;
}
}

Expand Down Expand Up @@ -87,4 +89,14 @@ class ProtectionData {
* @memberof ProtectionData
*/

/**
* priority
*
* @instance
* @type Object
* @name ProtectionData.priority
* @readonly
* @memberof ProtectionData
*/

export default ProtectionData;
7 changes: 6 additions & 1 deletion test/unit/mocks/URIFragmentModelMock.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
class URIFragmentModelMock {
constructor() {
this.uriFragmentData = null;
}

getURIFragmentData() {
return {t: 18.2};
return this.uriFragmentData;
}

setURIFragmentData(uri) {
this.uriFragmentData = uri;
}
}

Expand Down
Loading

0 comments on commit ad7dd9e

Please sign in to comment.