eyevinn-channel-engine 4.2.2 → 4.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine/server.d.ts +1 -1
- package/dist/engine/session.d.ts +1 -0
- package/dist/engine/session.js +339 -287
- package/dist/examples/truncate.d.ts +1 -0
- package/dist/examples/truncate.js +92 -0
- package/dist/package.json +1 -1
- package/engine/server.ts +1 -1
- package/engine/session.js +44 -2
- package/examples/truncate.ts +104 -0
- package/package.json +1 -1
package/dist/engine/server.d.ts
CHANGED
package/dist/engine/session.d.ts
CHANGED
|
@@ -107,6 +107,7 @@ declare class Session {
|
|
|
107
107
|
_tickAsync(): Promise<void>;
|
|
108
108
|
_getNextVod(): Promise<any>;
|
|
109
109
|
_loadSlate(afterVod: any, reps: any): Promise<any>;
|
|
110
|
+
_truncateVod(vodResponse: any): Promise<any>;
|
|
110
111
|
_truncateSlate(afterVod: any, requestedDuration: any, vodUri: any): Promise<any>;
|
|
111
112
|
_fillGap(afterVod: any, desiredDuration: any): Promise<any>;
|
|
112
113
|
_getNextVodById(id: any): Promise<any>;
|
package/dist/engine/session.js
CHANGED
|
@@ -1768,19 +1768,19 @@ var Session = /** @class */ (function () {
|
|
|
1768
1768
|
};
|
|
1769
1769
|
Session.prototype._tickAsync = function () {
|
|
1770
1770
|
return __awaiter(this, void 0, void 0, function () {
|
|
1771
|
-
var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts,
|
|
1771
|
+
var newVod, sessionState, isLeader, currentVod, vodResponse, _a, nextVodPromise, nextVodStart, _b, loadPromise, hlsOpts, _c, mediaManifestLoader, audioManifestLoader, loadStart, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, err_7, _s, length_1, endMseqValue, endMseqValueAudio, endMseqValueSubtitle, lastDiscontinuity, lastDiscontinuityAudio, lastDiscontinuitySubtitle, _t, vodPromise, gracePeriod, nextVodStart, _u, loadPromise, hlsOpts, _v, mediaManifestLoader, audioManifestLoader, loadStart, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, diffMs, err_8, startTS, _8, mSeq, currentVod_2, dSeq, mSeqOffset, reloadBehind, segments, playheadState, nextMseq, _9, err_9;
|
|
1772
1772
|
var _this = this;
|
|
1773
|
-
return __generator(this, function (
|
|
1774
|
-
switch (
|
|
1773
|
+
return __generator(this, function (_10) {
|
|
1774
|
+
switch (_10.label) {
|
|
1775
1775
|
case 0: return [4 /*yield*/, this._sessionState.getValues(["state", "assetId", "vodMediaSeqVideo", "vodMediaSeqAudio", "vodMediaSeqSubtitle", "mediaSeq", "mediaSeqAudio", "mediaSeqSubtitle", "discSeq", "discSeqAudio", "discSeqSubtitle", "nextVod"])];
|
|
1776
1776
|
case 1:
|
|
1777
|
-
sessionState =
|
|
1777
|
+
sessionState = _10.sent();
|
|
1778
1778
|
return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
|
|
1779
1779
|
case 2:
|
|
1780
|
-
isLeader =
|
|
1780
|
+
isLeader = _10.sent();
|
|
1781
1781
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1782
1782
|
case 3:
|
|
1783
|
-
currentVod =
|
|
1783
|
+
currentVod = _10.sent();
|
|
1784
1784
|
if (!sessionState.state) {
|
|
1785
1785
|
sessionState.state = SessionState.VOD_INIT;
|
|
1786
1786
|
}
|
|
@@ -1788,23 +1788,23 @@ var Session = /** @class */ (function () {
|
|
|
1788
1788
|
switch (_a) {
|
|
1789
1789
|
case SessionState.VOD_INIT: return [3 /*break*/, 4];
|
|
1790
1790
|
case SessionState.VOD_INIT_BY_ID: return [3 /*break*/, 4];
|
|
1791
|
-
case SessionState.VOD_PLAYING: return [3 /*break*/,
|
|
1792
|
-
case SessionState.VOD_NEXT_INITIATING: return [3 /*break*/,
|
|
1793
|
-
case SessionState.VOD_NEXT_INIT: return [3 /*break*/,
|
|
1794
|
-
case SessionState.VOD_RELOAD_INIT: return [3 /*break*/,
|
|
1795
|
-
case SessionState.VOD_RELOAD_INITIATING: return [3 /*break*/,
|
|
1791
|
+
case SessionState.VOD_PLAYING: return [3 /*break*/, 35];
|
|
1792
|
+
case SessionState.VOD_NEXT_INITIATING: return [3 /*break*/, 41];
|
|
1793
|
+
case SessionState.VOD_NEXT_INIT: return [3 /*break*/, 42];
|
|
1794
|
+
case SessionState.VOD_RELOAD_INIT: return [3 /*break*/, 78];
|
|
1795
|
+
case SessionState.VOD_RELOAD_INITIATING: return [3 /*break*/, 100];
|
|
1796
1796
|
}
|
|
1797
|
-
return [3 /*break*/,
|
|
1797
|
+
return [3 /*break*/, 104];
|
|
1798
1798
|
case 4:
|
|
1799
|
-
|
|
1799
|
+
_10.trys.push([4, 32, , 35]);
|
|
1800
1800
|
// Needed if store was reset
|
|
1801
1801
|
return [4 /*yield*/, this._sessionStateStore.clearLeaderCache()];
|
|
1802
1802
|
case 5:
|
|
1803
1803
|
// Needed if store was reset
|
|
1804
|
-
|
|
1804
|
+
_10.sent();
|
|
1805
1805
|
return [4 /*yield*/, this._sessionStateStore.isLeader(this._instanceId)];
|
|
1806
1806
|
case 6:
|
|
1807
|
-
isLeader =
|
|
1807
|
+
isLeader = _10.sent();
|
|
1808
1808
|
nextVodPromise = void 0;
|
|
1809
1809
|
if (sessionState.state === SessionState.VOD_INIT) {
|
|
1810
1810
|
debug("[".concat(this._sessionId, "]: state=VOD_INIT"));
|
|
@@ -1814,96 +1814,105 @@ var Session = /** @class */ (function () {
|
|
|
1814
1814
|
debug("[".concat(this._sessionId, "]: state=VOD_INIT_BY_ID ").concat(sessionState.assetId));
|
|
1815
1815
|
nextVodPromise = this._getNextVodById(sessionState.assetId);
|
|
1816
1816
|
}
|
|
1817
|
-
if (!isLeader) return [3 /*break*/,
|
|
1817
|
+
if (!isLeader) return [3 /*break*/, 28];
|
|
1818
1818
|
nextVodStart = Date.now();
|
|
1819
1819
|
return [4 /*yield*/, nextVodPromise];
|
|
1820
1820
|
case 7:
|
|
1821
|
-
vodResponse =
|
|
1821
|
+
vodResponse = _10.sent();
|
|
1822
1822
|
_b = sessionState;
|
|
1823
1823
|
return [4 /*yield*/, this._sessionState.set("nextVod", vodResponse)];
|
|
1824
1824
|
case 8:
|
|
1825
|
-
_b.nextVod =
|
|
1825
|
+
_b.nextVod = _10.sent();
|
|
1826
1826
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'nextVod', channel: this._sessionId, reqTimeMs: Date.now() - nextVodStart });
|
|
1827
1827
|
loadPromise = void 0;
|
|
1828
|
-
if (
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
}
|
|
1843
|
-
currentVod = newVod;
|
|
1844
|
-
loadPromise = currentVod.load();
|
|
1828
|
+
if (!!vodResponse.type) return [3 /*break*/, 12];
|
|
1829
|
+
debug("[".concat(this._sessionId, "]: got first VOD uri=").concat(vodResponse.uri, ":").concat(vodResponse.offset || 0));
|
|
1830
|
+
hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
|
|
1831
|
+
forcedDemuxMode: this.use_demuxed_audio,
|
|
1832
|
+
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
|
|
1833
|
+
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
1834
|
+
shouldContainSubtitles: this.use_vtt_subtitles,
|
|
1835
|
+
expectedSubtitleTracks: this._subtitleTracks
|
|
1836
|
+
};
|
|
1837
|
+
newVod = new HLSVod(vodResponse.uri, [], vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
1838
|
+
if (vodResponse.timedMetadata) {
|
|
1839
|
+
Object.keys(vodResponse.timedMetadata).map(function (k) {
|
|
1840
|
+
newVod.addMetadata(k, vodResponse.timedMetadata[k]);
|
|
1841
|
+
});
|
|
1845
1842
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1843
|
+
currentVod = newVod;
|
|
1844
|
+
if (!vodResponse.desiredDuration) return [3 /*break*/, 10];
|
|
1845
|
+
return [4 /*yield*/, this._truncateVod(vodResponse)];
|
|
1846
|
+
case 9:
|
|
1847
|
+
_c = _10.sent(), mediaManifestLoader = _c.mediaManifestLoader, audioManifestLoader = _c.audioManifestLoader;
|
|
1848
|
+
loadPromise = currentVod.load(null, mediaManifestLoader, audioManifestLoader);
|
|
1849
|
+
return [3 /*break*/, 11];
|
|
1850
|
+
case 10:
|
|
1851
|
+
loadPromise = currentVod.load();
|
|
1852
|
+
_10.label = 11;
|
|
1853
|
+
case 11: return [3 /*break*/, 13];
|
|
1854
|
+
case 12:
|
|
1855
|
+
if (vodResponse.type === 'gap') {
|
|
1856
|
+
loadPromise = new Promise(function (resolve, reject) {
|
|
1857
|
+
_this._fillGap(null, vodResponse.desiredDuration)
|
|
1858
|
+
.then(function (gapVod) {
|
|
1859
|
+
currentVod = gapVod;
|
|
1860
|
+
resolve(gapVod);
|
|
1861
|
+
}).catch(reject);
|
|
1862
|
+
});
|
|
1856
1863
|
}
|
|
1864
|
+
_10.label = 13;
|
|
1865
|
+
case 13:
|
|
1857
1866
|
loadStart = Date.now();
|
|
1858
1867
|
return [4 /*yield*/, loadPromise];
|
|
1859
|
-
case
|
|
1860
|
-
|
|
1868
|
+
case 14:
|
|
1869
|
+
_10.sent();
|
|
1861
1870
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'loadVod', channel: this._sessionId, loadTimeMs: Date.now() - loadStart });
|
|
1862
1871
|
debug("[".concat(this._sessionId, "]: first VOD loaded"));
|
|
1863
1872
|
debug("[".concat(this._sessionId, "]: ").concat(currentVod.getDeltaTimes()));
|
|
1864
1873
|
debug("[".concat(this._sessionId, "]: playhead positions [V]=").concat(currentVod.getPlayheadPositions("video")));
|
|
1865
1874
|
debug("[".concat(this._sessionId, "]: playhead positions [A]=").concat(currentVod.getPlayheadPositions("audio")));
|
|
1866
1875
|
//debug(newVod);
|
|
1867
|
-
|
|
1876
|
+
_d = sessionState;
|
|
1868
1877
|
return [4 /*yield*/, this._sessionState.set("mediaSeq", 0)];
|
|
1869
|
-
case
|
|
1878
|
+
case 15:
|
|
1870
1879
|
//debug(newVod);
|
|
1871
|
-
|
|
1872
|
-
_d = sessionState;
|
|
1873
|
-
return [4 /*yield*/, this._sessionState.set("mediaSeqAudio", 0)];
|
|
1874
|
-
case 11:
|
|
1875
|
-
_d.mediaSeqAudio = _8.sent();
|
|
1880
|
+
_d.mediaSeq = _10.sent();
|
|
1876
1881
|
_e = sessionState;
|
|
1877
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
1878
|
-
case
|
|
1879
|
-
_e.
|
|
1882
|
+
return [4 /*yield*/, this._sessionState.set("mediaSeqAudio", 0)];
|
|
1883
|
+
case 16:
|
|
1884
|
+
_e.mediaSeqAudio = _10.sent();
|
|
1880
1885
|
_f = sessionState;
|
|
1881
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
1882
|
-
case
|
|
1883
|
-
_f.
|
|
1886
|
+
return [4 /*yield*/, this._sessionState.set("mediaSeqSubtitle", 0)];
|
|
1887
|
+
case 17:
|
|
1888
|
+
_f.mediaSeqSubtitle = _10.sent();
|
|
1884
1889
|
_g = sessionState;
|
|
1885
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
1886
|
-
case
|
|
1887
|
-
_g.
|
|
1890
|
+
return [4 /*yield*/, this._sessionState.set("discSeq", 0)];
|
|
1891
|
+
case 18:
|
|
1892
|
+
_g.discSeq = _10.sent();
|
|
1888
1893
|
_h = sessionState;
|
|
1889
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
1890
|
-
case
|
|
1891
|
-
_h.
|
|
1894
|
+
return [4 /*yield*/, this._sessionState.set("discSeqAudio", 0)];
|
|
1895
|
+
case 19:
|
|
1896
|
+
_h.discSeqAudio = _10.sent();
|
|
1892
1897
|
_j = sessionState;
|
|
1893
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
1894
|
-
case
|
|
1895
|
-
_j.
|
|
1898
|
+
return [4 /*yield*/, this._sessionState.set("discSeqSubtitle", 0)];
|
|
1899
|
+
case 20:
|
|
1900
|
+
_j.discSeqSubtitle = _10.sent();
|
|
1896
1901
|
_k = sessionState;
|
|
1897
|
-
return [4 /*yield*/, this._sessionState.set("
|
|
1898
|
-
case
|
|
1899
|
-
_k.
|
|
1902
|
+
return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
|
|
1903
|
+
case 21:
|
|
1904
|
+
_k.vodMediaSeqVideo = _10.sent();
|
|
1900
1905
|
_l = sessionState;
|
|
1906
|
+
return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
|
|
1907
|
+
case 22:
|
|
1908
|
+
_l.vodMediaSeqAudio = _10.sent();
|
|
1909
|
+
_m = sessionState;
|
|
1901
1910
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqSubtitle", 0)];
|
|
1902
|
-
case
|
|
1903
|
-
|
|
1911
|
+
case 23:
|
|
1912
|
+
_m.vodMediaSeqSubtitle = _10.sent();
|
|
1904
1913
|
return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now(), isLeader)];
|
|
1905
|
-
case
|
|
1906
|
-
|
|
1914
|
+
case 24:
|
|
1915
|
+
_10.sent();
|
|
1907
1916
|
this.produceEvent({
|
|
1908
1917
|
type: 'NOW_PLAYING',
|
|
1909
1918
|
data: {
|
|
@@ -1911,32 +1920,32 @@ var Session = /** @class */ (function () {
|
|
|
1911
1920
|
title: this.currentMetadata.title,
|
|
1912
1921
|
}
|
|
1913
1922
|
});
|
|
1914
|
-
_m = sessionState;
|
|
1915
|
-
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
|
|
1916
|
-
case 20:
|
|
1917
|
-
_m.state = _8.sent();
|
|
1918
1923
|
_o = sessionState;
|
|
1924
|
+
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
|
|
1925
|
+
case 25:
|
|
1926
|
+
_o.state = _10.sent();
|
|
1927
|
+
_p = sessionState;
|
|
1919
1928
|
return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 })];
|
|
1920
|
-
case
|
|
1921
|
-
|
|
1929
|
+
case 26:
|
|
1930
|
+
_p.currentVod = _10.sent();
|
|
1922
1931
|
return [4 /*yield*/, this._sessionState.remove("nextVod")];
|
|
1923
|
-
case
|
|
1924
|
-
|
|
1932
|
+
case 27:
|
|
1933
|
+
_10.sent();
|
|
1925
1934
|
return [2 /*return*/];
|
|
1926
|
-
case
|
|
1935
|
+
case 28:
|
|
1927
1936
|
debug("[".concat(this._sessionId, "]: not a leader so will go directly to state VOD_PLAYING"));
|
|
1928
|
-
_p = sessionState;
|
|
1929
|
-
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
|
|
1930
|
-
case 24:
|
|
1931
|
-
_p.state = _8.sent();
|
|
1932
1937
|
_q = sessionState;
|
|
1938
|
+
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_PLAYING)];
|
|
1939
|
+
case 29:
|
|
1940
|
+
_q.state = _10.sent();
|
|
1941
|
+
_r = sessionState;
|
|
1933
1942
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1934
|
-
case
|
|
1935
|
-
|
|
1943
|
+
case 30:
|
|
1944
|
+
_r.currentVod = _10.sent();
|
|
1936
1945
|
return [2 /*return*/];
|
|
1937
|
-
case
|
|
1938
|
-
case
|
|
1939
|
-
err_7 =
|
|
1946
|
+
case 31: return [3 /*break*/, 35];
|
|
1947
|
+
case 32:
|
|
1948
|
+
err_7 = _10.sent();
|
|
1940
1949
|
console.error("[".concat(this._sessionId, "]: Failed to init first VOD"));
|
|
1941
1950
|
if (this._assetManager.handleError) {
|
|
1942
1951
|
this._assetManager.handleError(new Error("Failed to init first VOD"), vodResponse);
|
|
@@ -1944,18 +1953,18 @@ var Session = /** @class */ (function () {
|
|
|
1944
1953
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'firstvod', channel: this._sessionId, err: err_7, vod: vodResponse });
|
|
1945
1954
|
debug(err_7);
|
|
1946
1955
|
return [4 /*yield*/, this._sessionState.remove("nextVod")];
|
|
1947
|
-
case
|
|
1948
|
-
|
|
1956
|
+
case 33:
|
|
1957
|
+
_10.sent();
|
|
1949
1958
|
return [4 /*yield*/, this._insertSlate(currentVod)];
|
|
1950
|
-
case
|
|
1951
|
-
currentVod =
|
|
1959
|
+
case 34:
|
|
1960
|
+
currentVod = _10.sent();
|
|
1952
1961
|
if (!currentVod) {
|
|
1953
1962
|
debug("No slate to load");
|
|
1954
1963
|
throw err_7;
|
|
1955
1964
|
}
|
|
1956
|
-
return [3 /*break*/,
|
|
1957
|
-
case
|
|
1958
|
-
if (!isLeader) return [3 /*break*/,
|
|
1965
|
+
return [3 /*break*/, 35];
|
|
1966
|
+
case 35:
|
|
1967
|
+
if (!isLeader) return [3 /*break*/, 39];
|
|
1959
1968
|
// Handle edge case where store has been reset, but leader has not cleared cache.
|
|
1960
1969
|
if (this.prevVodMediaSeq.video === null) {
|
|
1961
1970
|
this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
|
|
@@ -1979,20 +1988,20 @@ var Session = /** @class */ (function () {
|
|
|
1979
1988
|
this.prevMediaSeqOffset.subtitle = sessionState.mediaSeqSubtitle;
|
|
1980
1989
|
}
|
|
1981
1990
|
}
|
|
1982
|
-
if (!(sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video)) return [3 /*break*/,
|
|
1991
|
+
if (!(sessionState.vodMediaSeqVideo < this.prevVodMediaSeq.video)) return [3 /*break*/, 38];
|
|
1983
1992
|
debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
|
|
1984
1993
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
1985
|
-
case
|
|
1986
|
-
|
|
1994
|
+
case 36:
|
|
1995
|
+
_10.sent();
|
|
1987
1996
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
1988
|
-
case
|
|
1989
|
-
currentVod =
|
|
1997
|
+
case 37:
|
|
1998
|
+
currentVod = _10.sent();
|
|
1990
1999
|
this.prevVodMediaSeq.video = sessionState.vodMediaSeqVideo;
|
|
1991
2000
|
this.prevVodMediaSeq.audio = sessionState.vodMediaSeqAudio;
|
|
1992
2001
|
this.prevVodMediaSeq.subtitle = sessionState.vodMediaSeqSubtitle;
|
|
1993
|
-
|
|
1994
|
-
case
|
|
1995
|
-
case
|
|
2002
|
+
_10.label = 38;
|
|
2003
|
+
case 38: return [3 /*break*/, 40];
|
|
2004
|
+
case 39:
|
|
1996
2005
|
// Handle edge case where Leader loaded next vod but Follower remained in state=VOD_PLAYING
|
|
1997
2006
|
if ((this.prevMediaSeqOffset.video !== null) & (sessionState.mediaSeq !== this.prevMediaSeqOffset.video)) {
|
|
1998
2007
|
debug("[".concat(this._sessionId, "]: state=VOD_PLAYING, current[").concat(sessionState.vodMediaSeqVideo, "], prev[").concat(this.prevVodMediaSeq.video, "], total[").concat(currentVod.getLiveMediaSequencesCount(), "]"));
|
|
@@ -2000,11 +2009,11 @@ var Session = /** @class */ (function () {
|
|
|
2000
2009
|
// Allow Follower to clear VodCache...
|
|
2001
2010
|
this.isAllowedToClearVodCache = true;
|
|
2002
2011
|
}
|
|
2003
|
-
|
|
2004
|
-
case
|
|
2012
|
+
_10.label = 40;
|
|
2013
|
+
case 40:
|
|
2005
2014
|
debug("[".concat(this._sessionId, "]: state=VOD_PLAYING (").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, "_").concat(sessionState.vodMediaSeqSubtitle, ", ").concat(currentVod.getLiveMediaSequencesCount(), "_").concat(currentVod.getLiveMediaSequencesCount("audio"), "_").concat(currentVod.getLiveMediaSequencesCount("subtitle"), ")"));
|
|
2006
2015
|
return [2 /*return*/];
|
|
2007
|
-
case
|
|
2016
|
+
case 41:
|
|
2008
2017
|
debug("[".concat(this._sessionId, "]: state=VOD_NEXT_INITIATING (").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, "_").concat(sessionState.vodMediaSeqSubtitle, ", ").concat(currentVod.getLiveMediaSequencesCount(), "_").concat(currentVod.getLiveMediaSequencesCount("audio"), "_").concat(currentVod.getLiveMediaSequencesCount("subtitle"), ")"));
|
|
2009
2018
|
if (!isLeader) {
|
|
2010
2019
|
debug("[".concat(this._sessionId, "]: not the leader so just waiting for the VOD to be initiated"));
|
|
@@ -2012,18 +2021,18 @@ var Session = /** @class */ (function () {
|
|
|
2012
2021
|
// Allow Leader|Follower to clear vodCache...
|
|
2013
2022
|
this.isAllowedToClearVodCache = true;
|
|
2014
2023
|
return [2 /*return*/];
|
|
2015
|
-
case
|
|
2016
|
-
|
|
2024
|
+
case 42:
|
|
2025
|
+
_10.trys.push([42, 74, , 77]);
|
|
2017
2026
|
debug("[".concat(this._sessionId, "]: state=VOD_NEXT_INIT"));
|
|
2018
|
-
if (!isLeader) return [3 /*break*/,
|
|
2019
|
-
if (!!currentVod) return [3 /*break*/,
|
|
2027
|
+
if (!isLeader) return [3 /*break*/, 69];
|
|
2028
|
+
if (!!currentVod) return [3 /*break*/, 44];
|
|
2020
2029
|
debug("[".concat(this._sessionId, "]: no VOD to append to, assume first VOD to init"));
|
|
2021
|
-
|
|
2030
|
+
_s = sessionState;
|
|
2022
2031
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_INIT)];
|
|
2023
|
-
case
|
|
2024
|
-
|
|
2032
|
+
case 43:
|
|
2033
|
+
_s.state = _10.sent();
|
|
2025
2034
|
return [2 /*return*/];
|
|
2026
|
-
case
|
|
2035
|
+
case 44:
|
|
2027
2036
|
length_1 = currentVod.getLiveMediaSequencesCount();
|
|
2028
2037
|
endMseqValue = void 0;
|
|
2029
2038
|
endMseqValueAudio = void 0;
|
|
@@ -2041,77 +2050,87 @@ var Session = /** @class */ (function () {
|
|
|
2041
2050
|
lastDiscontinuity = currentVod.getLastDiscontinuity();
|
|
2042
2051
|
lastDiscontinuityAudio = currentVod.getLastDiscontinuityAudio();
|
|
2043
2052
|
lastDiscontinuitySubtitle = currentVod.getLastDiscontinuitySubtitle();
|
|
2044
|
-
|
|
2053
|
+
_t = sessionState;
|
|
2045
2054
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INITIATING)];
|
|
2046
|
-
case
|
|
2047
|
-
|
|
2055
|
+
case 45:
|
|
2056
|
+
_t.state = _10.sent();
|
|
2048
2057
|
vodPromise = this._getNextVod();
|
|
2049
|
-
if (!(length_1 === 1)) return [3 /*break*/,
|
|
2058
|
+
if (!(length_1 === 1)) return [3 /*break*/, 47];
|
|
2050
2059
|
gracePeriod = (this.averageSegmentDuration / 2);
|
|
2051
2060
|
debug("[".concat(this._sessionId, "]: adding a grace period before calling nextVod: ").concat(gracePeriod, "ms"));
|
|
2052
2061
|
return [4 /*yield*/, timer(gracePeriod)];
|
|
2053
|
-
case
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
case
|
|
2062
|
+
case 46:
|
|
2063
|
+
_10.sent();
|
|
2064
|
+
_10.label = 47;
|
|
2065
|
+
case 47:
|
|
2057
2066
|
nextVodStart = Date.now();
|
|
2058
2067
|
return [4 /*yield*/, vodPromise];
|
|
2059
|
-
case
|
|
2060
|
-
vodResponse =
|
|
2061
|
-
|
|
2068
|
+
case 48:
|
|
2069
|
+
vodResponse = _10.sent();
|
|
2070
|
+
_u = sessionState;
|
|
2062
2071
|
return [4 /*yield*/, this._sessionState.set("nextVod", vodResponse)];
|
|
2063
|
-
case
|
|
2064
|
-
|
|
2072
|
+
case 49:
|
|
2073
|
+
_u.nextVod = _10.sent();
|
|
2065
2074
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'nextVod', channel: this._sessionId, reqTimeMs: Date.now() - nextVodStart });
|
|
2066
2075
|
loadPromise = void 0;
|
|
2067
|
-
if (
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
});
|
|
2081
|
-
}
|
|
2082
|
-
this.produceEvent({
|
|
2083
|
-
type: 'NEXT_VOD_SELECTED',
|
|
2084
|
-
data: {
|
|
2085
|
-
id: this.currentMetadata.id,
|
|
2086
|
-
uri: vodResponse.uri,
|
|
2087
|
-
title: this.currentMetadata.title || '',
|
|
2088
|
-
}
|
|
2076
|
+
if (!!vodResponse.type) return [3 /*break*/, 53];
|
|
2077
|
+
debug("[".concat(this._sessionId, "]: got next VOD uri=").concat(vodResponse.uri, ":").concat(vodResponse.offset));
|
|
2078
|
+
hlsOpts = { sequenceAlwaysContainNewSegments: this.alwaysNewSegments,
|
|
2079
|
+
forcedDemuxMode: this.use_demuxed_audio,
|
|
2080
|
+
dummySubtitleEndpoint: this.dummySubtitleEndpoint,
|
|
2081
|
+
subtitleSliceEndpoint: this.subtitleSliceEndpoint,
|
|
2082
|
+
shouldContainSubtitles: this.use_vtt_subtitles,
|
|
2083
|
+
expectedSubtitleTracks: this._subtitleTracks
|
|
2084
|
+
};
|
|
2085
|
+
newVod = new HLSVod(vodResponse.uri, null, vodResponse.unixTs, vodResponse.offset * 1000, m3u8Header(this._instanceId), hlsOpts);
|
|
2086
|
+
if (vodResponse.timedMetadata) {
|
|
2087
|
+
Object.keys(vodResponse.timedMetadata).map(function (k) {
|
|
2088
|
+
newVod.addMetadata(k, vodResponse.timedMetadata[k]);
|
|
2089
2089
|
});
|
|
2090
|
-
loadPromise = newVod.loadAfter(currentVod);
|
|
2091
|
-
if (vodResponse.diffMs) {
|
|
2092
|
-
this.diffCompensation = vodResponse.diffMs;
|
|
2093
|
-
if (this.diffCompensation) {
|
|
2094
|
-
this.timePositionOffset = this.diffCompensation;
|
|
2095
|
-
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
|
|
2096
|
-
}
|
|
2097
|
-
else {
|
|
2098
|
-
this.timePositionOffset = 0;
|
|
2099
|
-
}
|
|
2100
|
-
}
|
|
2101
2090
|
}
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2091
|
+
this.produceEvent({
|
|
2092
|
+
type: 'NEXT_VOD_SELECTED',
|
|
2093
|
+
data: {
|
|
2094
|
+
id: this.currentMetadata.id,
|
|
2095
|
+
uri: vodResponse.uri,
|
|
2096
|
+
title: this.currentMetadata.title || '',
|
|
2097
|
+
}
|
|
2098
|
+
});
|
|
2099
|
+
if (!vodResponse.desiredDuration) return [3 /*break*/, 51];
|
|
2100
|
+
return [4 /*yield*/, this._truncateVod(vodResponse)];
|
|
2101
|
+
case 50:
|
|
2102
|
+
_v = _10.sent(), mediaManifestLoader = _v.mediaManifestLoader, audioManifestLoader = _v.audioManifestLoader;
|
|
2103
|
+
loadPromise = newVod.loadAfter(currentVod, null, mediaManifestLoader, audioManifestLoader);
|
|
2104
|
+
return [3 /*break*/, 52];
|
|
2105
|
+
case 51:
|
|
2106
|
+
loadPromise = newVod.loadAfter(currentVod);
|
|
2107
|
+
_10.label = 52;
|
|
2108
|
+
case 52:
|
|
2109
|
+
if (vodResponse.diffMs) {
|
|
2110
|
+
this.diffCompensation = vodResponse.diffMs;
|
|
2111
|
+
if (this.diffCompensation) {
|
|
2112
|
+
this.timePositionOffset = this.diffCompensation;
|
|
2113
|
+
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'timePositionOffsetUpdated', channel: this._sessionId, offsetMs: this.timePositionOffset });
|
|
2114
|
+
}
|
|
2115
|
+
else {
|
|
2116
|
+
this.timePositionOffset = 0;
|
|
2117
|
+
}
|
|
2110
2118
|
}
|
|
2119
|
+
return [3 /*break*/, 54];
|
|
2120
|
+
case 53:
|
|
2121
|
+
loadPromise = new Promise(function (resolve, reject) {
|
|
2122
|
+
_this._fillGap(currentVod, vodResponse.desiredDuration)
|
|
2123
|
+
.then(function (gapVod) {
|
|
2124
|
+
newVod = gapVod;
|
|
2125
|
+
resolve(newVod);
|
|
2126
|
+
}).catch(reject);
|
|
2127
|
+
});
|
|
2128
|
+
_10.label = 54;
|
|
2129
|
+
case 54:
|
|
2111
2130
|
loadStart = Date.now();
|
|
2112
2131
|
return [4 /*yield*/, ChaosMonkey.loadVod(loadPromise)];
|
|
2113
|
-
case
|
|
2114
|
-
|
|
2132
|
+
case 55:
|
|
2133
|
+
_10.sent();
|
|
2115
2134
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'loadVod', channel: this._sessionId, loadTimeMs: Date.now() - loadStart });
|
|
2116
2135
|
this.leaderIsSettingNextVod = true;
|
|
2117
2136
|
debug("[".concat(this._sessionId, "]: next VOD loaded (").concat(newVod.getDeltaTimes(), ")"));
|
|
@@ -2119,57 +2138,57 @@ var Session = /** @class */ (function () {
|
|
|
2119
2138
|
debug("[".concat(this._sessionId, "]: playhead positions [A]=").concat(newVod.getPlayheadPositions("audio")));
|
|
2120
2139
|
currentVod = newVod;
|
|
2121
2140
|
debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod.getLiveMediaSequencesCount(), "; audio msequences=").concat(currentVod.getLiveMediaSequencesCount("audio"), "; subtitle msequences=").concat(currentVod.getLiveMediaSequencesCount("subtitle")));
|
|
2122
|
-
|
|
2141
|
+
_w = sessionState;
|
|
2123
2142
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
|
|
2124
|
-
case
|
|
2125
|
-
|
|
2126
|
-
|
|
2143
|
+
case 56:
|
|
2144
|
+
_w.vodMediaSeqVideo = _10.sent();
|
|
2145
|
+
_x = sessionState;
|
|
2127
2146
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
|
|
2128
|
-
case
|
|
2129
|
-
|
|
2130
|
-
|
|
2147
|
+
case 57:
|
|
2148
|
+
_x.vodMediaSeqAudio = _10.sent();
|
|
2149
|
+
_y = sessionState;
|
|
2131
2150
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqSubtitle", 0)];
|
|
2132
|
-
case
|
|
2133
|
-
|
|
2134
|
-
|
|
2151
|
+
case 58:
|
|
2152
|
+
_y.vodMediaSeqSubtitle = _10.sent();
|
|
2153
|
+
_z = sessionState;
|
|
2135
2154
|
return [4 /*yield*/, this._sessionState.set("mediaSeq", sessionState.mediaSeq + endMseqValue)];
|
|
2136
|
-
case
|
|
2137
|
-
|
|
2138
|
-
|
|
2155
|
+
case 59:
|
|
2156
|
+
_z.mediaSeq = _10.sent();
|
|
2157
|
+
_0 = sessionState;
|
|
2139
2158
|
return [4 /*yield*/, this._sessionState.set("mediaSeqAudio", sessionState.mediaSeqAudio + endMseqValueAudio)];
|
|
2140
|
-
case
|
|
2141
|
-
|
|
2142
|
-
|
|
2159
|
+
case 60:
|
|
2160
|
+
_0.mediaSeqAudio = _10.sent();
|
|
2161
|
+
_1 = sessionState;
|
|
2143
2162
|
return [4 /*yield*/, this._sessionState.set("mediaSeqSubtitle", sessionState.mediaSeqSubtitle + endMseqValueSubtitle)];
|
|
2144
|
-
case
|
|
2145
|
-
|
|
2146
|
-
|
|
2163
|
+
case 61:
|
|
2164
|
+
_1.mediaSeqSubtitle = _10.sent();
|
|
2165
|
+
_2 = sessionState;
|
|
2147
2166
|
return [4 /*yield*/, this._sessionState.set("discSeq", sessionState.discSeq + lastDiscontinuity)];
|
|
2148
|
-
case
|
|
2149
|
-
|
|
2150
|
-
|
|
2167
|
+
case 62:
|
|
2168
|
+
_2.discSeq = _10.sent();
|
|
2169
|
+
_3 = sessionState;
|
|
2151
2170
|
return [4 /*yield*/, this._sessionState.set("discSeqAudio", sessionState.discSeqAudio + lastDiscontinuityAudio)];
|
|
2152
|
-
case
|
|
2153
|
-
|
|
2154
|
-
|
|
2171
|
+
case 63:
|
|
2172
|
+
_3.discSeqAudio = _10.sent();
|
|
2173
|
+
_4 = sessionState;
|
|
2155
2174
|
return [4 /*yield*/, this._sessionState.set("discSeqSubtitle", sessionState.discSeqSubtitle + lastDiscontinuitySubtitle)];
|
|
2156
|
-
case
|
|
2157
|
-
|
|
2175
|
+
case 64:
|
|
2176
|
+
_4.discSeqSubtitle = _10.sent();
|
|
2158
2177
|
debug("[".concat(this._sessionId, "]: new sequence data set in store V[").concat(sessionState.mediaSeq, "][").concat(sessionState.discSeq, "]_A[").concat(sessionState.mediaSeqAudio, "][").concat(sessionState.discSeqAudio, "]_S[").concat(sessionState.mediaSeqSubtitle, "][").concat(sessionState.discSeqSubtitle, "]"));
|
|
2159
2178
|
return [4 /*yield*/, this._sessionState.remove("nextVod")];
|
|
2160
|
-
case
|
|
2161
|
-
|
|
2162
|
-
|
|
2179
|
+
case 65:
|
|
2180
|
+
_10.sent();
|
|
2181
|
+
_5 = sessionState;
|
|
2163
2182
|
return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod, { ttl: currentVod.getDuration() * 1000 })];
|
|
2164
|
-
case
|
|
2165
|
-
|
|
2183
|
+
case 66:
|
|
2184
|
+
_5.currentVod = _10.sent();
|
|
2166
2185
|
this.leaderIsSettingNextVod = false;
|
|
2167
2186
|
return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now(), isLeader)];
|
|
2168
|
-
case
|
|
2169
|
-
|
|
2187
|
+
case 67:
|
|
2188
|
+
_10.sent();
|
|
2170
2189
|
return [4 /*yield*/, this._playheadState.set("diffCompensation", this.diffCompensation, isLeader)];
|
|
2171
|
-
case
|
|
2172
|
-
|
|
2190
|
+
case 68:
|
|
2191
|
+
_10.sent();
|
|
2173
2192
|
debug("[".concat(this._sessionId, "]: sharing durrent vods diffCompensation=").concat(this.diffCompensation));
|
|
2174
2193
|
this.produceEvent({
|
|
2175
2194
|
type: 'NOW_PLAYING',
|
|
@@ -2179,22 +2198,22 @@ var Session = /** @class */ (function () {
|
|
|
2179
2198
|
}
|
|
2180
2199
|
});
|
|
2181
2200
|
return [2 /*return*/];
|
|
2182
|
-
case
|
|
2201
|
+
case 69:
|
|
2183
2202
|
debug("[".concat(this._sessionId, "]: not a leader so will go directly to state VOD_NEXT_INITIATING"));
|
|
2184
2203
|
this.waitingForNextVod = true;
|
|
2185
|
-
|
|
2204
|
+
_6 = sessionState;
|
|
2186
2205
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_NEXT_INITIATING)];
|
|
2187
|
-
case
|
|
2188
|
-
|
|
2206
|
+
case 70:
|
|
2207
|
+
_6.state = _10.sent();
|
|
2189
2208
|
// Allow Leader|Follower to clear vodCache...
|
|
2190
2209
|
this.isAllowedToClearVodCache = true;
|
|
2191
|
-
|
|
2210
|
+
_7 = sessionState;
|
|
2192
2211
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
2193
|
-
case
|
|
2194
|
-
|
|
2212
|
+
case 71:
|
|
2213
|
+
_7.currentVod = _10.sent();
|
|
2195
2214
|
return [4 /*yield*/, this._playheadState.get("diffCompensation")];
|
|
2196
|
-
case
|
|
2197
|
-
diffMs =
|
|
2215
|
+
case 72:
|
|
2216
|
+
diffMs = _10.sent();
|
|
2198
2217
|
if (diffMs) {
|
|
2199
2218
|
this.diffCompensation = diffMs;
|
|
2200
2219
|
debug("[".concat(this._sessionId, "]: Setting diffCompensation=").concat(this.diffCompensation));
|
|
@@ -2206,10 +2225,10 @@ var Session = /** @class */ (function () {
|
|
|
2206
2225
|
this.timePositionOffset = 0;
|
|
2207
2226
|
}
|
|
2208
2227
|
}
|
|
2209
|
-
|
|
2210
|
-
case
|
|
2211
|
-
case
|
|
2212
|
-
err_8 =
|
|
2228
|
+
_10.label = 73;
|
|
2229
|
+
case 73: return [3 /*break*/, 77];
|
|
2230
|
+
case 74:
|
|
2231
|
+
err_8 = _10.sent();
|
|
2213
2232
|
console.error("[".concat(this._sessionId, "]: Failed to init next VOD"));
|
|
2214
2233
|
debug("[".concat(this._sessionId, "]: ").concat(err_8));
|
|
2215
2234
|
if (this._assetManager.handleError) {
|
|
@@ -2217,34 +2236,34 @@ var Session = /** @class */ (function () {
|
|
|
2217
2236
|
}
|
|
2218
2237
|
cloudWatchLog(!this.cloudWatchLogging, 'engine-session', { event: 'error', on: 'nextvod', channel: this._sessionId, err: err_8, vod: vodResponse });
|
|
2219
2238
|
return [4 /*yield*/, this._sessionState.remove("nextVod")];
|
|
2220
|
-
case
|
|
2221
|
-
|
|
2239
|
+
case 75:
|
|
2240
|
+
_10.sent();
|
|
2222
2241
|
return [4 /*yield*/, this._insertSlate(currentVod)];
|
|
2223
|
-
case
|
|
2224
|
-
currentVod =
|
|
2242
|
+
case 76:
|
|
2243
|
+
currentVod = _10.sent();
|
|
2225
2244
|
if (!currentVod) {
|
|
2226
2245
|
debug("No slate to load");
|
|
2227
2246
|
throw err_8;
|
|
2228
2247
|
}
|
|
2229
2248
|
// Allow Leader|Follower to clear vodCache...
|
|
2230
2249
|
this.isAllowedToClearVodCache = true;
|
|
2231
|
-
return [3 /*break*/,
|
|
2232
|
-
case
|
|
2233
|
-
case
|
|
2234
|
-
|
|
2250
|
+
return [3 /*break*/, 77];
|
|
2251
|
+
case 77: return [3 /*break*/, 105];
|
|
2252
|
+
case 78:
|
|
2253
|
+
_10.trys.push([78, 98, , 99]);
|
|
2235
2254
|
debug("[".concat(this._sessionId, "]: state=VOD_RELOAD_INIT"));
|
|
2236
|
-
if (!isLeader) return [3 /*break*/,
|
|
2255
|
+
if (!isLeader) return [3 /*break*/, 95];
|
|
2237
2256
|
startTS = Date.now();
|
|
2238
2257
|
// 1) To tell Follower that, Leader is working on it!
|
|
2239
|
-
|
|
2258
|
+
_8 = sessionState;
|
|
2240
2259
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING)];
|
|
2241
|
-
case
|
|
2260
|
+
case 79:
|
|
2242
2261
|
// 1) To tell Follower that, Leader is working on it!
|
|
2243
|
-
|
|
2262
|
+
_8.state = _10.sent();
|
|
2244
2263
|
mSeq = this.switchDataForSession.mediaSeq;
|
|
2245
2264
|
return [4 /*yield*/, this._sessionState.getCurrentVod()];
|
|
2246
|
-
case
|
|
2247
|
-
currentVod_2 =
|
|
2265
|
+
case 80:
|
|
2266
|
+
currentVod_2 = _10.sent();
|
|
2248
2267
|
if (currentVod_2.sequenceAlwaysContainNewSegments) {
|
|
2249
2268
|
// (!) will need to compensate if using this setting on HLSVod Object.
|
|
2250
2269
|
Object.keys(this.switchDataForSession.transitionSegments).forEach(function (bw) {
|
|
@@ -2263,21 +2282,21 @@ var Session = /** @class */ (function () {
|
|
|
2263
2282
|
return [2 /*return*/];
|
|
2264
2283
|
}
|
|
2265
2284
|
return [4 /*yield*/, this._sessionState.set("mediaSeq", mSeq)];
|
|
2266
|
-
case
|
|
2267
|
-
|
|
2285
|
+
case 81:
|
|
2286
|
+
_10.sent();
|
|
2268
2287
|
return [4 /*yield*/, this._playheadState.set("mediaSeq", mSeq, isLeader)];
|
|
2269
|
-
case
|
|
2270
|
-
|
|
2288
|
+
case 82:
|
|
2289
|
+
_10.sent();
|
|
2271
2290
|
return [4 /*yield*/, this._sessionState.set("discSeq", dSeq)];
|
|
2272
|
-
case
|
|
2273
|
-
|
|
2291
|
+
case 83:
|
|
2292
|
+
_10.sent();
|
|
2274
2293
|
// TODO: support demux^
|
|
2275
2294
|
debug("[".concat(this._sessionId, "]: Setting current media and discontinuity count -> [").concat(mSeq, "]:[").concat(dSeq, "]"));
|
|
2276
2295
|
// 3) Set new media segments/currentVod, to carry on the continuity from session-live
|
|
2277
2296
|
debug("[".concat(this._sessionId, "]: LEADER: making changes to current VOD. I will also update currentVod in store."));
|
|
2278
2297
|
return [4 /*yield*/, this._playheadState.getValues(["vodMediaSeqVideo"])];
|
|
2279
|
-
case
|
|
2280
|
-
playheadState =
|
|
2298
|
+
case 84:
|
|
2299
|
+
playheadState = _10.sent();
|
|
2281
2300
|
nextMseq = playheadState.vodMediaSeqVideo + 1;
|
|
2282
2301
|
if (nextMseq > currentVod_2.getLiveMediaSequencesCount() - 1) {
|
|
2283
2302
|
nextMseq = currentVod_2.getLiveMediaSequencesCount() - 1;
|
|
@@ -2286,38 +2305,38 @@ var Session = /** @class */ (function () {
|
|
|
2286
2305
|
// TODO: Support reloading with audioSegments and SubtitleSegments as well |
|
|
2287
2306
|
// ---------------------------------------------------'
|
|
2288
2307
|
return [4 /*yield*/, currentVod_2.reload(nextMseq, segments, null, reloadBehind)];
|
|
2289
|
-
case
|
|
2308
|
+
case 85:
|
|
2290
2309
|
// ---------------------------------------------------.
|
|
2291
2310
|
// TODO: Support reloading with audioSegments and SubtitleSegments as well |
|
|
2292
2311
|
// ---------------------------------------------------'
|
|
2293
|
-
|
|
2312
|
+
_10.sent();
|
|
2294
2313
|
return [4 /*yield*/, this._sessionState.setCurrentVod(currentVod_2, { ttl: currentVod_2.getDuration() * 1000 })];
|
|
2295
|
-
case
|
|
2296
|
-
|
|
2314
|
+
case 86:
|
|
2315
|
+
_10.sent();
|
|
2297
2316
|
return [4 /*yield*/, this._sessionState.set("vodReloaded", 1)];
|
|
2298
|
-
case
|
|
2299
|
-
|
|
2317
|
+
case 87:
|
|
2318
|
+
_10.sent();
|
|
2300
2319
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqVideo", 0)];
|
|
2301
|
-
case
|
|
2302
|
-
|
|
2320
|
+
case 88:
|
|
2321
|
+
_10.sent();
|
|
2303
2322
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqAudio", 0)];
|
|
2304
|
-
case
|
|
2305
|
-
|
|
2323
|
+
case 89:
|
|
2324
|
+
_10.sent();
|
|
2306
2325
|
return [4 /*yield*/, this._sessionState.set("vodMediaSeqSubtitle", 0)];
|
|
2307
|
-
case
|
|
2308
|
-
|
|
2326
|
+
case 90:
|
|
2327
|
+
_10.sent();
|
|
2309
2328
|
return [4 /*yield*/, this._playheadState.set("vodMediaSeqVideo", 0, isLeader)];
|
|
2310
|
-
case
|
|
2311
|
-
|
|
2329
|
+
case 91:
|
|
2330
|
+
_10.sent();
|
|
2312
2331
|
return [4 /*yield*/, this._playheadState.set("vodMediaSeqAudio", 0, isLeader)];
|
|
2313
|
-
case
|
|
2314
|
-
|
|
2332
|
+
case 92:
|
|
2333
|
+
_10.sent();
|
|
2315
2334
|
return [4 /*yield*/, this._playheadState.set("vodMediaSeqSubtitle", 0, isLeader)];
|
|
2316
|
-
case
|
|
2317
|
-
|
|
2335
|
+
case 93:
|
|
2336
|
+
_10.sent();
|
|
2318
2337
|
return [4 /*yield*/, this._playheadState.set("playheadRef", Date.now(), isLeader)];
|
|
2319
|
-
case
|
|
2320
|
-
|
|
2338
|
+
case 94:
|
|
2339
|
+
_10.sent();
|
|
2321
2340
|
// 4) Log to debug and cloudwatch
|
|
2322
2341
|
debug("[".concat(this._sessionId, "]: LEADER: Set new Reloaded VOD and vodMediaSeq counts in store."));
|
|
2323
2342
|
debug("[".concat(this._sessionId, "]: next VOD Reloaded (").concat(currentVod_2.getDeltaTimes(), ")"));
|
|
@@ -2325,38 +2344,38 @@ var Session = /** @class */ (function () {
|
|
|
2325
2344
|
debug("[".concat(this._sessionId, "]: msequences=").concat(currentVod_2.getLiveMediaSequencesCount()));
|
|
2326
2345
|
cloudWatchLog(!this.cloudWatchLogging, "engine-session", { event: "switchback", channel: this._sessionId, reqTimeMs: Date.now() - startTS });
|
|
2327
2346
|
return [2 /*return*/];
|
|
2328
|
-
case
|
|
2347
|
+
case 95:
|
|
2329
2348
|
debug("[".concat(this._sessionId, "]: not a leader so will go directly to state VOD_RELOAD_INITIATING"));
|
|
2330
|
-
|
|
2349
|
+
_9 = sessionState;
|
|
2331
2350
|
return [4 /*yield*/, this._sessionState.set("state", SessionState.VOD_RELOAD_INITIATING)];
|
|
2332
|
-
case
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
case
|
|
2336
|
-
case
|
|
2337
|
-
err_9 =
|
|
2351
|
+
case 96:
|
|
2352
|
+
_9.state = _10.sent();
|
|
2353
|
+
_10.label = 97;
|
|
2354
|
+
case 97: return [3 /*break*/, 99];
|
|
2355
|
+
case 98:
|
|
2356
|
+
err_9 = _10.sent();
|
|
2338
2357
|
debug("Failed to init reload vod");
|
|
2339
2358
|
throw err_9;
|
|
2340
|
-
case
|
|
2341
|
-
case
|
|
2359
|
+
case 99: return [3 /*break*/, 105];
|
|
2360
|
+
case 100:
|
|
2342
2361
|
debug("[".concat(this._sessionId, "]: state=VOD_RELOAD_INITIATING (").concat(sessionState.vodMediaSeqVideo, "_").concat(sessionState.vodMediaSeqAudio, "_").concat(sessionState.vodMediaSeqSubtitle, ", ").concat(currentVod.getLiveMediaSequencesCount(), "_").concat(currentVod.getLiveMediaSequencesCount("audio"), "_").concat(currentVod.getLiveMediaSequencesCount("subtitle"), ")"));
|
|
2343
|
-
if (!!isLeader) return [3 /*break*/,
|
|
2362
|
+
if (!!isLeader) return [3 /*break*/, 103];
|
|
2344
2363
|
debug("[".concat(this._sessionId, "]: not the leader so just waiting for the VOD to be reloaded"));
|
|
2345
|
-
if (!(sessionState.vodMediaSeqVideo === 0 || this.waitingForNextVod)) return [3 /*break*/,
|
|
2364
|
+
if (!(sessionState.vodMediaSeqVideo === 0 || this.waitingForNextVod)) return [3 /*break*/, 102];
|
|
2346
2365
|
debug("[".concat(this._sessionId, "]: First mediasequence in VOD and I am not the leader so invalidate current VOD cache and fetch the new one from the leader"));
|
|
2347
2366
|
return [4 /*yield*/, this._sessionState.clearCurrentVodCache()];
|
|
2348
|
-
case
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
case
|
|
2367
|
+
case 101:
|
|
2368
|
+
_10.sent();
|
|
2369
|
+
_10.label = 102;
|
|
2370
|
+
case 102:
|
|
2352
2371
|
this.waitingForNextVod = true;
|
|
2353
|
-
|
|
2354
|
-
case
|
|
2372
|
+
_10.label = 103;
|
|
2373
|
+
case 103:
|
|
2355
2374
|
// Allow Leader|Follower to clear vodCache...
|
|
2356
2375
|
this.isAllowedToClearVodCache = true;
|
|
2357
2376
|
return [2 /*return*/];
|
|
2358
|
-
case
|
|
2359
|
-
case
|
|
2377
|
+
case 104: throw new Error("Invalid state: " + sessionState.state);
|
|
2378
|
+
case 105: return [2 /*return*/];
|
|
2360
2379
|
}
|
|
2361
2380
|
});
|
|
2362
2381
|
});
|
|
@@ -2455,6 +2474,39 @@ var Session = /** @class */ (function () {
|
|
|
2455
2474
|
}
|
|
2456
2475
|
});
|
|
2457
2476
|
};
|
|
2477
|
+
Session.prototype._truncateVod = function (vodResponse) {
|
|
2478
|
+
var _this = this;
|
|
2479
|
+
return new Promise(function (resolve, reject) {
|
|
2480
|
+
try {
|
|
2481
|
+
var truncatedVod_1 = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000);
|
|
2482
|
+
truncatedVod_1.load()
|
|
2483
|
+
.then(function () {
|
|
2484
|
+
var audioManifestLoader;
|
|
2485
|
+
var mediaManifestLoader = function (bw) {
|
|
2486
|
+
var mediaManifestStream = new Readable();
|
|
2487
|
+
mediaManifestStream.push(truncatedVod_1.getMediaManifest(bw));
|
|
2488
|
+
mediaManifestStream.push(null);
|
|
2489
|
+
return mediaManifestStream;
|
|
2490
|
+
};
|
|
2491
|
+
if (_this.use_demuxed_audio) {
|
|
2492
|
+
audioManifestLoader = function (audioGroupId, audioLanguage) {
|
|
2493
|
+
var mediaManifestStream = new Readable();
|
|
2494
|
+
mediaManifestStream.push(truncatedVod_1.getAudioManifest(audioGroupId, audioLanguage));
|
|
2495
|
+
mediaManifestStream.push(null);
|
|
2496
|
+
return mediaManifestStream;
|
|
2497
|
+
};
|
|
2498
|
+
}
|
|
2499
|
+
resolve({ mediaManifestLoader: mediaManifestLoader, audioManifestLoader: audioManifestLoader });
|
|
2500
|
+
}).catch(function (err) {
|
|
2501
|
+
debug(err);
|
|
2502
|
+
reject(err);
|
|
2503
|
+
});
|
|
2504
|
+
}
|
|
2505
|
+
catch (err) {
|
|
2506
|
+
reject(err);
|
|
2507
|
+
}
|
|
2508
|
+
});
|
|
2509
|
+
};
|
|
2458
2510
|
Session.prototype._truncateSlate = function (afterVod, requestedDuration, vodUri) {
|
|
2459
2511
|
var _this = this;
|
|
2460
2512
|
return new Promise(function (resolve, reject) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Reference implementation of Channel Engine library
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
var index_1 = require("../index");
|
|
7
|
+
var DEFAULT_ASSETS = [
|
|
8
|
+
{
|
|
9
|
+
id: 1,
|
|
10
|
+
title: "Tears of Steel",
|
|
11
|
+
uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: 2,
|
|
15
|
+
title: "VINN",
|
|
16
|
+
uri: "https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8",
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
var RefAssetManager = /** @class */ (function () {
|
|
20
|
+
function RefAssetManager(opts) {
|
|
21
|
+
this.assets = {};
|
|
22
|
+
this.assets['1'] = DEFAULT_ASSETS;
|
|
23
|
+
this.pos = {
|
|
24
|
+
'1': 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} vodRequest
|
|
30
|
+
* {
|
|
31
|
+
* sessionId,
|
|
32
|
+
* category,
|
|
33
|
+
* playlistId
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
RefAssetManager.prototype.getNextVod = function (vodRequest) {
|
|
37
|
+
var _this = this;
|
|
38
|
+
return new Promise(function (resolve, reject) {
|
|
39
|
+
var channelId = vodRequest.playlistId;
|
|
40
|
+
if (_this.pos[channelId] === undefined) {
|
|
41
|
+
_this.pos[channelId] = 0;
|
|
42
|
+
_this.assets[channelId] = DEFAULT_ASSETS;
|
|
43
|
+
}
|
|
44
|
+
if (_this.assets[channelId]) {
|
|
45
|
+
var vod = _this.assets[channelId][_this.pos[channelId]++];
|
|
46
|
+
if (_this.pos[channelId] > _this.assets[channelId].length - 1) {
|
|
47
|
+
_this.pos[channelId] = 0;
|
|
48
|
+
}
|
|
49
|
+
var vodResponse = {
|
|
50
|
+
id: vod.id,
|
|
51
|
+
title: vod.title,
|
|
52
|
+
uri: vod.uri,
|
|
53
|
+
desiredDuration: 50000
|
|
54
|
+
};
|
|
55
|
+
resolve(vodResponse);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
reject("Invalid channelId provided");
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
return RefAssetManager;
|
|
63
|
+
}());
|
|
64
|
+
var RefChannelManager = /** @class */ (function () {
|
|
65
|
+
function RefChannelManager() {
|
|
66
|
+
this.channels = [];
|
|
67
|
+
this.channels.push({ id: "1", profile: this._getProfile() });
|
|
68
|
+
}
|
|
69
|
+
RefChannelManager.prototype.getChannels = function () {
|
|
70
|
+
return this.channels;
|
|
71
|
+
};
|
|
72
|
+
RefChannelManager.prototype._getProfile = function () {
|
|
73
|
+
return [
|
|
74
|
+
{ bw: 6134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1024, 458] },
|
|
75
|
+
{ bw: 2323000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [640, 286] },
|
|
76
|
+
{ bw: 1313000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [480, 214] },
|
|
77
|
+
];
|
|
78
|
+
};
|
|
79
|
+
return RefChannelManager;
|
|
80
|
+
}());
|
|
81
|
+
var refAssetManager = new RefAssetManager();
|
|
82
|
+
var refChannelManager = new RefChannelManager();
|
|
83
|
+
var engineOptions = {
|
|
84
|
+
heartbeat: "/",
|
|
85
|
+
averageSegmentDuration: 2000,
|
|
86
|
+
channelManager: refChannelManager,
|
|
87
|
+
defaultSlateUri: "https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
|
|
88
|
+
slateRepetitions: 10,
|
|
89
|
+
};
|
|
90
|
+
var engine = new index_1.ChannelEngine(refAssetManager, engineOptions);
|
|
91
|
+
engine.start();
|
|
92
|
+
engine.listen(process.env.PORT || 8000);
|
package/dist/package.json
CHANGED
package/engine/server.ts
CHANGED
package/engine/session.js
CHANGED
|
@@ -1331,7 +1331,12 @@ class Session {
|
|
|
1331
1331
|
})
|
|
1332
1332
|
}
|
|
1333
1333
|
currentVod = newVod;
|
|
1334
|
-
|
|
1334
|
+
if (vodResponse.desiredDuration) {
|
|
1335
|
+
const { mediaManifestLoader, audioManifestLoader} = await this._truncateVod(vodResponse);
|
|
1336
|
+
loadPromise = currentVod.load(null, mediaManifestLoader, audioManifestLoader);
|
|
1337
|
+
} else {
|
|
1338
|
+
loadPromise = currentVod.load();
|
|
1339
|
+
}
|
|
1335
1340
|
} else {
|
|
1336
1341
|
if (vodResponse.type === 'gap') {
|
|
1337
1342
|
loadPromise = new Promise((resolve, reject) => {
|
|
@@ -1509,7 +1514,12 @@ class Session {
|
|
|
1509
1514
|
title: this.currentMetadata.title || '',
|
|
1510
1515
|
}
|
|
1511
1516
|
});
|
|
1512
|
-
|
|
1517
|
+
if (vodResponse.desiredDuration) {
|
|
1518
|
+
const { mediaManifestLoader, audioManifestLoader} = await this._truncateVod(vodResponse);
|
|
1519
|
+
loadPromise = newVod.loadAfter(currentVod, null, mediaManifestLoader, audioManifestLoader);
|
|
1520
|
+
} else {
|
|
1521
|
+
loadPromise = newVod.loadAfter(currentVod);
|
|
1522
|
+
}
|
|
1513
1523
|
if (vodResponse.diffMs) {
|
|
1514
1524
|
this.diffCompensation = vodResponse.diffMs;
|
|
1515
1525
|
if (this.diffCompensation) {
|
|
@@ -1782,6 +1792,38 @@ class Session {
|
|
|
1782
1792
|
});
|
|
1783
1793
|
}
|
|
1784
1794
|
|
|
1795
|
+
_truncateVod(vodResponse) {
|
|
1796
|
+
return new Promise((resolve, reject) => {
|
|
1797
|
+
try {
|
|
1798
|
+
const truncatedVod = new HLSTruncateVod(vodResponse.uri, vodResponse.desiredDuration / 1000);
|
|
1799
|
+
truncatedVod.load()
|
|
1800
|
+
.then(() => {
|
|
1801
|
+
let audioManifestLoader;
|
|
1802
|
+
const mediaManifestLoader = (bw) => {
|
|
1803
|
+
let mediaManifestStream = new Readable();
|
|
1804
|
+
mediaManifestStream.push(truncatedVod.getMediaManifest(bw));
|
|
1805
|
+
mediaManifestStream.push(null);
|
|
1806
|
+
return mediaManifestStream;
|
|
1807
|
+
};
|
|
1808
|
+
if (this.use_demuxed_audio) {
|
|
1809
|
+
audioManifestLoader = (audioGroupId, audioLanguage) => {
|
|
1810
|
+
let mediaManifestStream = new Readable();
|
|
1811
|
+
mediaManifestStream.push(truncatedVod.getAudioManifest(audioGroupId, audioLanguage));
|
|
1812
|
+
mediaManifestStream.push(null);
|
|
1813
|
+
return mediaManifestStream;
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
resolve({ mediaManifestLoader, audioManifestLoader });
|
|
1817
|
+
}).catch(err => {
|
|
1818
|
+
debug(err);
|
|
1819
|
+
reject(err);
|
|
1820
|
+
});
|
|
1821
|
+
} catch (err) {
|
|
1822
|
+
reject(err);
|
|
1823
|
+
}
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1785
1827
|
_truncateSlate(afterVod, requestedDuration, vodUri) {
|
|
1786
1828
|
return new Promise((resolve, reject) => {
|
|
1787
1829
|
let nexVodUri = null;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Reference implementation of Channel Engine library
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ChannelEngine, ChannelEngineOpts,
|
|
6
|
+
IAssetManager, IChannelManager,
|
|
7
|
+
VodRequest, VodResponse, Channel, ChannelProfile
|
|
8
|
+
} from "../index";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_ASSETS = [
|
|
11
|
+
{
|
|
12
|
+
id: 1,
|
|
13
|
+
title: "Tears of Steel",
|
|
14
|
+
uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: 2,
|
|
18
|
+
title: "VINN",
|
|
19
|
+
uri: "https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8",
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
class RefAssetManager implements IAssetManager {
|
|
24
|
+
private assets;
|
|
25
|
+
private pos;
|
|
26
|
+
|
|
27
|
+
constructor(opts?) {
|
|
28
|
+
this.assets = {};
|
|
29
|
+
this.assets['1'] = DEFAULT_ASSETS;
|
|
30
|
+
this.pos = {
|
|
31
|
+
'1': 0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} vodRequest
|
|
38
|
+
* {
|
|
39
|
+
* sessionId,
|
|
40
|
+
* category,
|
|
41
|
+
* playlistId
|
|
42
|
+
* }
|
|
43
|
+
*/
|
|
44
|
+
getNextVod(vodRequest: VodRequest): Promise<VodResponse> {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const channelId = vodRequest.playlistId;
|
|
47
|
+
if (this.pos[channelId] === undefined) {
|
|
48
|
+
this.pos[channelId] = 0;
|
|
49
|
+
this.assets[channelId] = DEFAULT_ASSETS;
|
|
50
|
+
}
|
|
51
|
+
if (this.assets[channelId]) {
|
|
52
|
+
let vod = this.assets[channelId][this.pos[channelId]++];
|
|
53
|
+
if (this.pos[channelId] > this.assets[channelId].length - 1) {
|
|
54
|
+
this.pos[channelId] = 0;
|
|
55
|
+
}
|
|
56
|
+
const vodResponse = {
|
|
57
|
+
id: vod.id,
|
|
58
|
+
title: vod.title,
|
|
59
|
+
uri: vod.uri,
|
|
60
|
+
desiredDuration: 50000
|
|
61
|
+
};
|
|
62
|
+
resolve(vodResponse);
|
|
63
|
+
} else {
|
|
64
|
+
reject("Invalid channelId provided");
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class RefChannelManager implements IChannelManager {
|
|
71
|
+
private channels: Channel[] = [];
|
|
72
|
+
|
|
73
|
+
constructor() {
|
|
74
|
+
this.channels.push({ id: "1", profile: this._getProfile() });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getChannels(): Channel[] {
|
|
78
|
+
return this.channels;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_getProfile(): ChannelProfile[] {
|
|
82
|
+
return [
|
|
83
|
+
{ bw: 6134000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [1024, 458] },
|
|
84
|
+
{ bw: 2323000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [640, 286] },
|
|
85
|
+
{ bw: 1313000, codecs: "avc1.4d001f,mp4a.40.2", resolution: [480, 214] },
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const refAssetManager = new RefAssetManager();
|
|
91
|
+
const refChannelManager = new RefChannelManager();
|
|
92
|
+
|
|
93
|
+
const engineOptions: ChannelEngineOpts = {
|
|
94
|
+
heartbeat: "/",
|
|
95
|
+
averageSegmentDuration: 2000,
|
|
96
|
+
channelManager: refChannelManager,
|
|
97
|
+
defaultSlateUri:
|
|
98
|
+
"https://maitv-vod.lab.eyevinn.technology/slate-consuo.mp4/master.m3u8",
|
|
99
|
+
slateRepetitions: 10,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const engine = new ChannelEngine(refAssetManager, engineOptions);
|
|
103
|
+
engine.start();
|
|
104
|
+
engine.listen(process.env.PORT || 8000);
|