eyevinn-channel-engine
Advanced tools
Comparing version 2.2.4 to 2.3.0
@@ -55,2 +55,3 @@ const restify = require('restify'); | ||
this.server.get('/status/:sessionId', this._handleStatus.bind(this)); | ||
this.server.get('/health/:sessionId', this._handleSessionHealth.bind(this)); | ||
@@ -240,2 +241,19 @@ if (options && options.heartbeat) { | ||
_handleSessionHealth(req, res, next) { | ||
debug(`req.url=${req.url}`); | ||
const session = sessions[req.params.sessionId]; | ||
if (session) { | ||
session.getStatus().then(status => { | ||
if (status.playhead && status.playhead.state === "running") { | ||
res.send(200, { "health": "ok" }); | ||
} else { | ||
res.send(503, { "health": "unhealthy" }); | ||
} | ||
}); | ||
} else { | ||
const err = new errs.NotFoundError('Invalid session'); | ||
next(err); | ||
} | ||
} | ||
_gracefulErrorHandler(errMsg) { | ||
@@ -242,0 +260,0 @@ console.error(errMsg); |
@@ -6,2 +6,3 @@ const crypto = require('crypto'); | ||
const m3u8 = require('@eyevinn/m3u8'); | ||
const HLSRepeatVod = require('@eyevinn/hls-repeat'); | ||
const Readable = require('stream').Readable; | ||
@@ -81,2 +82,5 @@ | ||
} | ||
if (config.slateUri) { | ||
this.slateUri = config.slateUri; | ||
} | ||
} | ||
@@ -383,3 +387,19 @@ } | ||
resolve(); | ||
}).catch(reject); | ||
}).catch(e => { | ||
console.error("Failed to init first VOD, use slate instead"); | ||
if(this.slateUri) { | ||
this._loadSlate() | ||
.then(slateVod => { | ||
this.currentVod = slateVod; | ||
debug(`[${this._sessionId}]: slate loaded`); | ||
this._state.vodMediaSeq.video = 0; | ||
this._state.vodMediaSeq.audio = 0; | ||
this._state.state = SessionState.VOD_PLAYING; | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
} else { | ||
debug('No slate to load'); | ||
} | ||
}); | ||
break; | ||
@@ -433,3 +453,8 @@ case SessionState.VOD_PLAYING: | ||
return newVod.loadAfter(this.currentVod); | ||
}).then(() => { | ||
}) | ||
.catch(err => { | ||
console.error(err); | ||
console.error("Failed to init next VOD, will use slate instead"); | ||
}) | ||
.then(() => { | ||
debug(`[${this._sessionId}]: next VOD loaded`); | ||
@@ -451,6 +476,23 @@ //debug(newVod); | ||
resolve(); | ||
}).catch(err => { | ||
console.error("Failed to initiate next VOD: ", err); | ||
reject(err); | ||
}); | ||
}) | ||
.catch(err => { | ||
console.error("Failed to init next VOD, using slate instead"); | ||
if(this.slateUri) { | ||
this._loadSlate() | ||
.then(slateVod => { | ||
this.currentVod = slateVod; | ||
debug(`[${this._sessionId}]: slate loaded`); | ||
this._state.vodMediaSeq.video = 0; | ||
this._state.vodMediaSeq.audio = 0; | ||
this._state.mediaSeq += length; | ||
this._state.discSeq += lastDiscontinuity; | ||
this._state.state = SessionState.VOD_PLAYING; | ||
resolve(); | ||
}) | ||
.catch('No slate: ' + err); | ||
} else { | ||
debug('No slate to load'); | ||
reject(err); | ||
} | ||
}) | ||
break; | ||
@@ -460,3 +502,2 @@ default: | ||
} | ||
}); | ||
@@ -488,2 +529,31 @@ } | ||
_loadSlate() { | ||
return new Promise((resolve, reject) => { | ||
try { | ||
const slateVod = new HLSRepeatVod(this.slateUri, 3); | ||
slateVod.load() | ||
.then(() => { | ||
let hlsVod = new HLSVod(this.slateUri); | ||
if(!this.currentVod) { | ||
const slateMediaManifestLoader = (bw) => { | ||
let mediaManifestStream = new Readable(); | ||
mediaManifestStream.push(slateVod.getMediaManifest(bw)); | ||
mediaManifestStream.push(null); | ||
return mediaManifestStream; | ||
}; | ||
hlsVod.load(null, slateMediaManifestLoader) | ||
.then(() => { | ||
resolve(hlsVod); | ||
}) | ||
.catch(reject); | ||
} | ||
}) | ||
.catch(reject); | ||
} catch(err) { | ||
reject(err); | ||
} | ||
}); | ||
} | ||
_getNextVodById(id) { | ||
@@ -490,0 +560,0 @@ return new Promise((resolve, reject) => { |
{ | ||
"name": "eyevinn-channel-engine", | ||
"version": "2.2.4", | ||
"version": "2.3.0", | ||
"description": "OTT TV Channel Engine", | ||
@@ -20,3 +20,4 @@ "main": "index.js", | ||
"restify": ">=8.0.0", | ||
"@eyevinn/hls-vodtolive": "^1.0.1" | ||
"@eyevinn/hls-vodtolive": "^1.0.1", | ||
"@eyevinn/hls-repeat": "^0.1.1" | ||
}, | ||
@@ -23,0 +24,0 @@ "devDependencies": { |
@@ -32,7 +32,11 @@ /* | ||
const channelId = vodRequest.playlistId; | ||
let vod = this.assets[channelId][this.pos[channelId]++]; | ||
if (this.pos[channelId] > this.assets[channelId].length - 1) { | ||
this.pos[channelId] = 0; | ||
if (this.assets[channelId]) { | ||
let vod = this.assets[channelId][this.pos[channelId]++]; | ||
if (this.pos[channelId] > this.assets[channelId].length - 1) { | ||
this.pos[channelId] = 0; | ||
} | ||
resolve(vod); | ||
} else { | ||
reject("Invalid channelId provided"); | ||
} | ||
resolve(vod); | ||
}); | ||
@@ -39,0 +43,0 @@ } |
@@ -6,3 +6,3 @@ const Session = require('../../engine/session.js'); | ||
class TestAssetManager { | ||
constructor(assets) { | ||
constructor(opts, assets) { | ||
this.assets = [ | ||
@@ -16,10 +16,21 @@ { id: 1, title: "Tears of Steel", uri: "https://maitv-vod.lab.eyevinn.technology/tearsofsteel_4k.mov/master.m3u8" }, | ||
this.pos = 0; | ||
this.doFail = false; | ||
if (opts && opts.fail) { | ||
this.doFail = true; | ||
} | ||
if (opts && opts.failOnIndex) { | ||
this.failOnIndex = 1; | ||
} | ||
} | ||
getNextVod(vodRequest) { | ||
return new Promise((resolve, reject) => { | ||
const vod = this.assets[this.pos++]; | ||
if (this.pos > this.assets.length - 1) { | ||
this.pos = 0; | ||
if (this.doFail || this.pos === this.failOnIndex) { | ||
reject("should fail"); | ||
} else { | ||
const vod = this.assets[this.pos++]; | ||
if (this.pos > this.assets.length - 1) { | ||
this.pos = 0; | ||
} | ||
resolve(vod); | ||
} | ||
resolve(vod); | ||
}); | ||
@@ -128,3 +139,3 @@ | ||
it("can handle three short VODs in a row", async (done) => { | ||
const assetMgr = new TestAssetManager([{ id: 1, title: "Short", uri: "https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8" }]); | ||
const assetMgr = new TestAssetManager(null, [{ id: 1, title: "Short", uri: "https://maitv-vod.lab.eyevinn.technology/VINN.mp4/master.m3u8" }]); | ||
const session = new Session(assetMgr, { sessionId: '1' }); | ||
@@ -264,2 +275,72 @@ await verificationLoop(session, 10); | ||
}); | ||
it("inserts a slate when asset manager fails to return an initial VOD", async (done) => { | ||
const assetMgr = new TestAssetManager({ fail: true }); | ||
const session = new Session(assetMgr, { sessionId: '1', slateUri: 'http://testcontent.eyevinn.technology/slates/ottera/playlist.m3u8' }); | ||
let slateManifest; | ||
const loop = async (increments) => { | ||
let remain = increments; | ||
let verificationFns = []; | ||
while (remain > 0) { | ||
const verificationFn = () => { | ||
return new Promise((resolve, reject) => { | ||
session.increment() | ||
.then(async (manifest) => { | ||
return session.getCurrentMediaManifest(6134000); | ||
}) | ||
.then(manifest => { | ||
slateManifest = manifest; | ||
resolve(); | ||
}); | ||
}); | ||
}; | ||
verificationFns.push(verificationFn); | ||
remain--; | ||
} | ||
for (let verificationFn of verificationFns) { | ||
await verificationFn(); | ||
} | ||
}; | ||
await loop(1); | ||
let m = slateManifest.match('http://testcontent.eyevinn.technology/slates/ottera/1080p_000.ts\n'); | ||
expect(m).not.toBeNull; | ||
done(); | ||
}); | ||
it("inserts a slate when asset manager fails to return a next VOD", async (done) => { | ||
const assetMgr = new TestAssetManager({failOnIndex: 1}); | ||
const session = new Session(assetMgr, { sessionId: '1', slateUri: 'http://testcontent.eyevinn.technology/slates/ottera/playlist.m3u8' }); | ||
let slateManifest; | ||
const loop = async (increments) => { | ||
let remain = increments; | ||
let verificationFns = []; | ||
while (remain > 0) { | ||
const verificationFn = () => { | ||
return new Promise((resolve, reject) => { | ||
session.increment() | ||
.then(async (manifest) => { | ||
return session.getCurrentMediaManifest(6134000); | ||
}) | ||
.then(manifest => { | ||
slateManifest = manifest; | ||
resolve(); | ||
}) | ||
.catch(reject); | ||
}); | ||
}; | ||
verificationFns.push(verificationFn); | ||
remain--; | ||
} | ||
for (let verificationFn of verificationFns) { | ||
await verificationFn(); | ||
} | ||
}; | ||
await loop(85); | ||
// console.log('slateManifest', slateManifest); | ||
let m = slateManifest.match('http://testcontent.eyevinn.technology/slates/ottera/1080p_000.ts\n'); | ||
expect(m).not.toBeNull(); | ||
done(); | ||
}); | ||
}); |
3128146
1411
6
+ Added@eyevinn/hls-repeat@^0.1.1
+ Added@eyevinn/hls-repeat@0.1.6(transitive)