video-quality-tools
Advanced tools
Comparing version 2.0.0 to 3.0.0
# Changelog | ||
### 3.0.0 | ||
- `timeoutInSec` option was changed to `timeoutInMs` in the `FrameMonitor` and in the `StreamInfo` class. | ||
IMPROVEMENTS: | ||
- Added new option `analyzeDurationInMs` that specifies the maximum analyzing time of the input | ||
[[GH-97](https://github.com/LCMApps/video-quality-tools/issues/97)] | ||
BUG FIXES: | ||
- Fixed lack of support of the `timeout` for a `non-librtmp` builds of `ffmpeg` | ||
[[GH-92](https://github.com/LCMApps/video-quality-tools/issues/92)] | ||
### 2.0.0 | ||
@@ -4,0 +17,0 @@ |
const {FramesMonitor, processFrames} = require('../index'); | ||
// or | ||
// const {processFrames} = require('video-quality-tools'); | ||
// const {FramesMonitor, processFrames} = require('video-quality-tools'); | ||
// if you use it outside this repo | ||
@@ -11,3 +11,3 @@ | ||
ffprobePath: '/usr/local/bin/ffprobe', | ||
timeoutInSec: 5, | ||
timeoutInMs: 2000, | ||
bufferMaxLengthInBytes: 100000, | ||
@@ -14,0 +14,0 @@ errorLevel: 'error', |
{ | ||
"name": "video-quality-tools", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "Set of tools to evaluate video stream quality.", | ||
@@ -13,8 +13,8 @@ "main": "index.js", | ||
"scripts": { | ||
"lint": "./node_modules/.bin/eslint ./", | ||
"tests": "yarn run unit-tests", | ||
"test:coverage": "NODE_ENV=test istanbul cover ./node_modules/.bin/_mocha --print both -- --opts tests/mocha.opts -R spec ./tests/Unit", | ||
"unit-tests": "NODE_ENV=test ./node_modules/.bin/mocha --opts tests/mocha.opts -R spec './tests/Unit/**/*.js'", | ||
"func-tests": "NODE_ENV=test ./node_modules/.bin/mocha --opts tests/mocha.opts --timeout 30000 -R spec './tests/Functional/**/*.js'", | ||
"coveralls": "NODE_ENV=test istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- --opts tests/mocha.opts -R spec ./tests/Unit && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" | ||
"lint": "eslint .", | ||
"test": "yarn test:unit", | ||
"test:unit": "mocha --opts tests/mocha.opts -R spec './tests/Unit/**/*.js'", | ||
"test:func": "mocha --opts tests/mocha.opts -R spec './tests/Functional/**/*.js' --timeout 30000", | ||
"test:coverage": "nyc --reporter=text --reporter=text-summary mocha --opts tests/mocha.opts -R spec './tests/Unit/**/*.js'", | ||
"coveralls": "nyc --reporter=text-lcov mocha --opts tests/mocha.opts -R spec './tests/Unit/**/*.js' && nyc report --reporter=text-lcov | coveralls" | ||
}, | ||
@@ -25,19 +25,28 @@ "repository": { | ||
}, | ||
"keywords": ["ffmpeg", "ffprobe", "monitor", "livestream", "live", "rtmp", "hls", "dash", "monitoring"], | ||
"keywords": [ | ||
"ffmpeg", | ||
"ffprobe", | ||
"monitor", | ||
"livestream", | ||
"live", | ||
"rtmp", | ||
"hls", | ||
"dash", | ||
"monitoring" | ||
], | ||
"license": "MIT", | ||
"devDependencies": { | ||
"chai": "^4.1.0", | ||
"chai-as-promised": "^7.1.1", | ||
"coveralls": "^3.0.0", | ||
"data-driven": "^1.3.0", | ||
"eslint": "^5.6.1", | ||
"get-port": "^4.0.0", | ||
"istanbul": "v1.1.0-alpha.1", | ||
"mocha": "^5.2.0", | ||
"proxyquire": "^2.1.0", | ||
"sinon": "^6.3.5" | ||
"chai": "^4.2.0", | ||
"coveralls": "^3.0.7", | ||
"data-driven": "^1.4.0", | ||
"eslint": "^6.6.0", | ||
"get-port": "^5.0.0", | ||
"mocha": "^6.2.2", | ||
"nyc": "^14.1.1", | ||
"proxyquire": "^2.1.3", | ||
"sinon": "^7.5.0" | ||
}, | ||
"dependencies": { | ||
"app-module-path": "^2.2.0", | ||
"lodash": "^4.17.4" | ||
"lodash": "^4.17.15" | ||
}, | ||
@@ -44,0 +53,0 @@ "bugs": { |
@@ -11,2 +11,3 @@ # Video Quality Tools module - helps to measure live stream characteristics by RTMP/HLS/DASH streams | ||
[![NPM version](https://img.shields.io/npm/v/video-quality-tools.svg)](https://www.npmjs.com/package/video-quality-tools) | ||
[![Release Status](https://github.com/LCMApps/video-quality-tools/workflows/NPM%20Release/badge.svg)](https://github.com/LCMApps/video-quality-tools/releases) | ||
[![Build Status](https://travis-ci.org/LCMApps/video-quality-tools.svg?branch=master)](https://travis-ci.org/LCMApps/video-quality-tools) | ||
@@ -85,3 +86,3 @@ [![Coverage Status](https://coveralls.io/repos/github/LCMApps/video-quality-tools/badge.svg?branch=master)](https://coveralls.io/github/LCMApps/video-quality-tools?branch=master) | ||
ffprobePath: '/usr/local/bin/ffprobe', | ||
timeoutInSec: 5 | ||
timeoutInMs: 2000 | ||
}; | ||
@@ -184,6 +185,7 @@ const streamsInfo = new StreamsInfo(streamsInfoOptions, 'rtmp://host:port/appInstance/name'); | ||
ffprobePath: '/usr/local/bin/ffprobe', | ||
timeoutInSec: 5, | ||
timeoutInMs: 2000, | ||
bufferMaxLengthInBytes: 100000, | ||
errorLevel: 'error', | ||
exitProcessGuardTimeoutInMs: 1000 | ||
exitProcessGuardTimeoutInMs: 1000, | ||
analyzeDurationInMs: 9000 | ||
}; | ||
@@ -203,3 +205,4 @@ | ||
* `ffprobePath` - string, path to ffprobe executable; | ||
* `timeoutInSec` - integer, greater than 0, specifies the waiting time of a live stream’s first frame; | ||
* `timeoutInMs` - integer, greater than 0, specifies the maximum time to wait for (network) read/write operations | ||
to complete; | ||
* `bufferMaxLengthInBytes` - integer, greater than 0, specifies the buffer length for ffprobe frames. This setting | ||
@@ -216,2 +219,3 @@ prevents from hanging and receiving incorrect data from the stream, usually 1-2 KB is enough; | ||
`SIGKILL` signal and forces underlying ffprobe process to exit. | ||
* analyzeDurationInMs - integer, greater than 0, specifies the maximum analyzing time of the input. | ||
@@ -218,0 +222,0 @@ ## Listening of Frames |
@@ -36,7 +36,7 @@ 'use strict'; | ||
if (!_.isPlainObject(config)) { | ||
throw new TypeError('Config param should be a plain object, bastard.'); | ||
throw new TypeError('Config param should be a plain object.'); | ||
} | ||
if (!_.isString(url)) { | ||
throw new TypeError('You should provide a correct url, bastard.'); | ||
throw new TypeError('You should provide a correct url.'); | ||
} | ||
@@ -46,14 +46,15 @@ | ||
ffprobePath, | ||
timeoutInSec, | ||
timeoutInMs, | ||
bufferMaxLengthInBytes, | ||
errorLevel, | ||
exitProcessGuardTimeoutInMs | ||
exitProcessGuardTimeoutInMs, | ||
analyzeDurationInMs | ||
} = config; | ||
if (!_.isString(ffprobePath) || _.isEmpty(ffprobePath)) { | ||
throw new Errors.ConfigError('You should provide a correct path to ffprobe, bastard.'); | ||
throw new Errors.ConfigError('You should provide a correct path to ffprobe.'); | ||
} | ||
if (!_.isSafeInteger(timeoutInSec) || timeoutInSec <= 0) { | ||
throw new Errors.ConfigError('You should provide a correct timeout, bastard.'); | ||
if (!_.isSafeInteger(timeoutInMs) || timeoutInMs <= 0) { | ||
throw new Errors.ConfigError('You should provide a correct timeout.'); | ||
} | ||
@@ -67,3 +68,3 @@ | ||
throw new Errors.ConfigError( | ||
'You should provide correct error level, bastard. Check ffprobe documentation.' | ||
'You should provide correct error level. Check ffprobe documentation.' | ||
); | ||
@@ -76,7 +77,19 @@ } | ||
if (analyzeDurationInMs !== undefined && (!_.isSafeInteger(analyzeDurationInMs) || analyzeDurationInMs <= 0)) { | ||
throw new Errors.ConfigError('You should provide a correct analyze duration.'); | ||
} | ||
FramesMonitor._assertExecutable(ffprobePath); | ||
this._config = _.cloneDeep(config); | ||
this._url = url; | ||
this._config = { | ||
ffprobePath, | ||
bufferMaxLengthInBytes, | ||
errorLevel, | ||
exitProcessGuardTimeoutInMs, | ||
timeout: timeoutInMs * 1000, | ||
analyzeDuration: analyzeDurationInMs && analyzeDurationInMs * 1000 || undefined | ||
}; | ||
this._url = url; | ||
this._cp = null; | ||
@@ -267,22 +280,25 @@ this._chunkRemainder = ''; | ||
_runShowFramesProcess() { | ||
const {ffprobePath, timeoutInSec, errorLevel} = this._config; | ||
const {ffprobePath, timeout, analyzeDuration, errorLevel} = this._config; | ||
const args = [ | ||
'-hide_banner', | ||
'-v', | ||
errorLevel, | ||
'-fflags', | ||
'nobuffer', | ||
'-rw_timeout', | ||
timeout, | ||
'-show_frames', | ||
'-show_entries', | ||
'frame=pkt_size,pkt_pts_time,media_type,pict_type,key_frame,width,height', | ||
]; | ||
if (analyzeDuration) { | ||
args.push('-analyzeduration', analyzeDuration); | ||
} | ||
args.push('-i', this._url); | ||
try { | ||
const exec = spawn( | ||
ffprobePath, | ||
[ | ||
'-hide_banner', | ||
'-v', | ||
errorLevel, | ||
'-fflags', | ||
'nobuffer', | ||
'-show_frames', | ||
'-show_entries', | ||
'frame=pkt_size,pkt_pts_time,media_type,pict_type,key_frame,width,height', | ||
'-i', | ||
`${this._url} timeout=${timeoutInSec}` | ||
] | ||
); | ||
return exec; | ||
return spawn(ffprobePath, args); | ||
} catch (err) { | ||
@@ -289,0 +305,0 @@ if (err instanceof TypeError) { |
@@ -17,23 +17,32 @@ 'use strict'; | ||
if (!_.isObject(config) || _.isFunction(config)) { | ||
throw new TypeError('Config param should be an object, bastard.'); | ||
throw new TypeError('Config param should be an object.'); | ||
} | ||
if (!_.isString(url)) { | ||
throw new TypeError('You should provide a correct url, bastard.'); | ||
throw new TypeError('You should provide a correct url.'); | ||
} | ||
const {ffprobePath, timeoutInSec} = config; | ||
const {ffprobePath, timeoutInMs, analyzeDurationInMs} = config; | ||
if (!_.isString(ffprobePath) || _.isEmpty(ffprobePath)) { | ||
throw new Errors.ConfigError('You should provide a correct path to ffprobe, bastard.'); | ||
throw new Errors.ConfigError('You should provide a correct path to ffprobe.'); | ||
} | ||
if (!_.isInteger(timeoutInSec) || timeoutInSec <= 0) { | ||
throw new Errors.ConfigError('You should provide a correct timeout, bastard.'); | ||
if (!_.isInteger(timeoutInMs) || timeoutInMs <= 0) { | ||
throw new Errors.ConfigError('You should provide a correct timeout.'); | ||
} | ||
if (analyzeDurationInMs !== undefined && (!_.isInteger(analyzeDurationInMs) || analyzeDurationInMs <= 0)) { | ||
throw new Errors.ConfigError('You should provide a correct analyze duration.'); | ||
} | ||
this._assertExecutable(ffprobePath); | ||
this._config = config; | ||
this._url = url; | ||
this._config = { | ||
ffprobePath: config.ffprobePath, | ||
timeout: config.timeoutInMs * 1000, | ||
analyzeDuration: config.analyzeDurationInMs && config.analyzeDurationInMs * 1000 || 0 | ||
}; | ||
this._url = url; | ||
} | ||
@@ -83,14 +92,13 @@ | ||
_runShowStreamsProcess() { | ||
const {ffprobePath, timeoutInSec} = this._config; | ||
const {ffprobePath, timeout, analyzeDuration} = this._config; | ||
const command = ` | ||
${ffprobePath}\ | ||
-hide_banner\ | ||
-v error\ | ||
-show_streams\ | ||
-print_format json\ | ||
'${this._url} timeout=${timeoutInSec}' | ||
`; | ||
const commandArgs = [ffprobePath, '-hide_banner', '-v error']; | ||
return promisify(exec)(command); | ||
if (analyzeDuration) { | ||
commandArgs.push('-analyzeduration', analyzeDuration); | ||
} | ||
commandArgs.push('-rw_timeout', timeout, '-show_streams', '-print_format json', '-i', this._url); | ||
return promisify(exec)(commandArgs.join(' ')); | ||
} | ||
@@ -97,0 +105,0 @@ |
@@ -34,3 +34,3 @@ 'use strict'; | ||
ffprobePath : process.env.FFPROBE, | ||
timeoutInSec : 1, | ||
timeoutInMs : 1000, | ||
bufferMaxLengthInBytes : bufferMaxLengthInBytes, | ||
@@ -86,3 +86,3 @@ errorLevel : errorLevel, | ||
ffprobePath : process.env.FFPROBE, | ||
timeoutInSec : 1, | ||
timeoutInMs : 1000, | ||
bufferMaxLengthInBytes : bufferMaxLengthInBytes, | ||
@@ -107,3 +107,3 @@ errorLevel : errorLevel, | ||
it('must receive all stream frames', done => { | ||
const expectedReturnCode = 0; | ||
const expectedReturnCode = 0; | ||
@@ -152,3 +152,3 @@ const onFrame = {I: spyOnIFrame, P: spyOnPFrame}; | ||
ffprobePath : process.env.FFPROBE, | ||
timeoutInSec : 1, | ||
timeoutInMs : 1000, | ||
bufferMaxLengthInBytes : bufferMaxLengthInBytes, | ||
@@ -195,3 +195,3 @@ errorLevel : errorLevel, | ||
ffprobePath : process.env.FFPROBE, | ||
timeoutInSec : 1, | ||
timeoutInMs : 1000, | ||
bufferMaxLengthInBytes : bufferMaxLengthInBytes, | ||
@@ -198,0 +198,0 @@ errorLevel : errorLevel, |
@@ -26,4 +26,4 @@ 'use strict'; | ||
streamsInfo = new StreamsInfo({ | ||
ffprobePath : process.env.FFPROBE, | ||
timeoutInSec: 1, | ||
ffprobePath: process.env.FFPROBE, | ||
timeoutInMs: 1000, | ||
}, streamUrl); | ||
@@ -58,4 +58,4 @@ }); | ||
streamsInfo = new StreamsInfo({ | ||
ffprobePath : process.env.FFPROBE, | ||
timeoutInSec: 1, | ||
ffprobePath: process.env.FFPROBE, | ||
timeoutInMs: 1000, | ||
}, streamUrl); | ||
@@ -62,0 +62,0 @@ |
@@ -9,4 +9,4 @@ 'use strict'; | ||
function getSpawnArguments(url, timeoutInSec, errorLevel) { | ||
return [ | ||
function getSpawnArguments(url, timeoutInMs, analyzeDurationInMs, errorLevel) { | ||
const args = [ | ||
'-hide_banner', | ||
@@ -17,8 +17,16 @@ '-v', | ||
'nobuffer', | ||
'-rw_timeout', | ||
timeoutInMs * 1000, | ||
'-show_frames', | ||
'-show_entries', | ||
'frame=pkt_size,pkt_pts_time,media_type,pict_type,key_frame,width,height', | ||
'-i', | ||
`${url} timeout=${timeoutInSec}` | ||
]; | ||
if (analyzeDurationInMs) { | ||
args.push('-analyzeduration', analyzeDurationInMs * 1000); | ||
} | ||
args.push('-i', url); | ||
return args; | ||
} | ||
@@ -28,3 +36,5 @@ | ||
const expectedFfprobePath = config.ffprobePath; | ||
const expectedFfprobeArguments = getSpawnArguments(url, config.timeoutInSec, config.errorLevel); | ||
const expectedFfprobeArguments = getSpawnArguments( | ||
url, config.timeoutInMs, config.analyzeDurationInMs, config.errorLevel | ||
); | ||
@@ -66,2 +76,44 @@ it('must returns child process object just fine', () => { | ||
it('must returns child process object just fine with default analyze duration', () => { | ||
const analyzeDurationInMs = undefined; | ||
const expectedOutput = {cp: true}; | ||
const expectedFfprobeArguments = getSpawnArguments( | ||
url, config.timeoutInMs, analyzeDurationInMs, config.errorLevel | ||
); | ||
const spawn = () => expectedOutput; | ||
const spySpawn = sinon.spy(spawn); | ||
const FramesMonitor = proxyquire('src/FramesMonitor', { | ||
fs : { | ||
accessSync(filePath) { | ||
if (filePath !== config.ffprobePath) { | ||
throw new Error('no such file or directory'); | ||
} | ||
} | ||
}, | ||
child_process: { | ||
spawn: spySpawn | ||
} | ||
}); | ||
const options = Object.assign({}, config, {analyzeDurationInMs}); | ||
const framesMonitor = new FramesMonitor(options, url); | ||
const spyOnProcessStartError = sinon.spy(framesMonitor, '_onProcessStartError'); | ||
const result = framesMonitor._runShowFramesProcess(); | ||
assert.strictEqual(result, expectedOutput); | ||
assert.isTrue(spySpawn.calledOnce); | ||
assert.isTrue( | ||
spySpawn.calledWithExactly(expectedFfprobePath, expectedFfprobeArguments) | ||
); | ||
assert.isTrue(spyOnProcessStartError.notCalled); | ||
}); | ||
it('must re-thrown TypeError error from the spawn call', () => { | ||
@@ -68,0 +120,0 @@ const expectedError = new TypeError('some error'); |
@@ -13,3 +13,3 @@ 'use strict'; | ||
Buffer.alloc(1), | ||
new Error('bastard') | ||
new Error('error') | ||
]; | ||
@@ -27,3 +27,3 @@ | ||
Buffer.alloc(1), | ||
new Error('bastard') | ||
new Error('error') | ||
]; | ||
@@ -41,6 +41,6 @@ | ||
Buffer.alloc(1), | ||
new Error('bastard') | ||
new Error('error') | ||
]; | ||
const incorrectTimeoutInSec = [ | ||
const incorrectTimeoutInMs = [ | ||
undefined, | ||
@@ -55,3 +55,3 @@ null, | ||
Buffer.alloc(1), | ||
new Error('bastard') | ||
new Error('error') | ||
]; | ||
@@ -69,3 +69,3 @@ | ||
Buffer.alloc(1), | ||
new Error('bastard') | ||
new Error('error') | ||
]; | ||
@@ -83,3 +83,3 @@ | ||
Buffer.alloc(1), | ||
new Error('bastard') | ||
new Error('error') | ||
]; | ||
@@ -97,3 +97,3 @@ | ||
Buffer.alloc(1), | ||
new Error('bastard') | ||
new Error('error') | ||
]; | ||
@@ -103,10 +103,10 @@ | ||
{ | ||
description: 'config.timeoutInSec param must be a positive integer, float is passed', | ||
config : {timeoutInSec: 1.1}, | ||
errorMsg : 'You should provide a correct timeout, bastard.' | ||
description: 'config.timeoutInMs param must be a positive integer, float is passed', | ||
config : {timeoutInMs: 1.1}, | ||
errorMsg : 'You should provide a correct timeout.' | ||
}, | ||
{ | ||
description: 'config.timeoutInSec param must be a positive integer, negative is passed', | ||
config : {timeoutInSec: -1}, | ||
errorMsg : 'You should provide a correct timeout, bastard.' | ||
description: 'config.timeoutInMs param must be a positive integer, negative is passed', | ||
config : {timeoutInMs: -1}, | ||
errorMsg : 'You should provide a correct timeout.' | ||
}, | ||
@@ -126,3 +126,3 @@ { | ||
config : {errorLevel: 'error' + 'incorrect-part'}, | ||
errorMsg : 'You should provide correct error level, bastard. Check ffprobe documentation.' | ||
errorMsg : 'You should provide correct error level. Check ffprobe documentation.' | ||
}, | ||
@@ -139,2 +139,17 @@ { | ||
}, | ||
{ | ||
description: 'config.analyzeDurationInMs param must be a positive integer, float is passed', | ||
config : {analyzeDurationInMs: 1.1}, | ||
errorMsg : 'You should provide a correct analyze duration.' | ||
}, | ||
{ | ||
description: 'config.analyzeDurationInMs param must be a positive integer, negative is passed', | ||
config : {analyzeDurationInMs: -1}, | ||
errorMsg : 'You should provide a correct analyze duration.' | ||
}, | ||
{ | ||
description: 'config.analyzeDurationInMs param must be a positive integer, string is passed', | ||
config : {analyzeDurationInMs: '10'}, | ||
errorMsg : 'You should provide a correct analyze duration.' | ||
}, | ||
]; | ||
@@ -146,3 +161,3 @@ | ||
incorrectFfprobePath, | ||
incorrectTimeoutInSec, | ||
incorrectTimeoutInMs, | ||
incorrectBufferMaxLengthInBytes, | ||
@@ -149,0 +164,0 @@ incorrectErrorLevel, |
@@ -34,3 +34,3 @@ 'use strict'; | ||
new FramesMonitor(ctx.config, url); | ||
}, TypeError, 'Config param should be a plain object, bastard.'); | ||
}, TypeError, 'Config param should be a plain object.'); | ||
@@ -50,3 +50,3 @@ assert.isTrue(spyAssertExecutable.notCalled); | ||
new FramesMonitor(config, ctx.url); | ||
}, TypeError, 'You should provide a correct url, bastard.'); | ||
}, TypeError, 'You should provide a correct url.'); | ||
@@ -68,3 +68,3 @@ assert.isTrue(spyAssertExecutable.notCalled); | ||
new FramesMonitor(incorrectConfig, url); | ||
}, Error.ConfigError, 'You should provide a correct path to ffprobe, bastard.'); | ||
}, Error.ConfigError, 'You should provide a correct path to ffprobe.'); | ||
@@ -77,7 +77,7 @@ assert.isTrue(spyAssertExecutable.notCalled); | ||
dataDriven( | ||
testData.incorrectTimeoutInSec.map(item => ({type: typeOf(item), timeoutInSec: item})), | ||
testData.incorrectTimeoutInMs.map(item => ({type: typeOf(item), timeoutInMs: item})), | ||
() => { | ||
it('config.timeoutInSec param has invalid ({type}) type', ctx => { | ||
it('config.timeoutInMs param has invalid ({type}) type', ctx => { | ||
const incorrectConfig = Object.assign({}, config, { | ||
timeoutInSec: ctx.timeoutInSec | ||
timeoutInMs: ctx.timeoutInMs | ||
}); | ||
@@ -87,3 +87,3 @@ | ||
new FramesMonitor(incorrectConfig, url); | ||
}, Error.ConfigError, 'You should provide a correct timeout, bastard.'); | ||
}, Error.ConfigError, 'You should provide a correct timeout.'); | ||
@@ -122,3 +122,3 @@ assert.isTrue(spyAssertExecutable.notCalled); | ||
new FramesMonitor(incorrectConfig, url); | ||
}, Error.ConfigError, 'You should provide correct error level, bastard. Check ffprobe documentation.'); | ||
}, Error.ConfigError, 'You should provide correct error level. Check ffprobe documentation.'); | ||
@@ -181,2 +181,10 @@ assert.isTrue(spyAssertExecutable.notCalled); | ||
const expectedStderrOutputs = []; | ||
const expectedConfig = { | ||
ffprobePath : config.ffprobePath, | ||
bufferMaxLengthInBytes : config.bufferMaxLengthInBytes, | ||
errorLevel : config.errorLevel, | ||
exitProcessGuardTimeoutInMs: config.exitProcessGuardTimeoutInMs, | ||
timeout : config.timeoutInMs * 1000, | ||
analyzeDuration : config.analyzeDurationInMs * 1000 | ||
}; | ||
@@ -188,3 +196,4 @@ const framesMonitor = new FramesMonitor(config, url); | ||
assert.deepEqual(framesMonitor._config, config); | ||
assert.deepEqual(framesMonitor._config, expectedConfig); | ||
assert.strictEqual(framesMonitor._url, url); | ||
@@ -197,2 +206,31 @@ | ||
it('analyzeDurationInMs not setted in config', () => { | ||
const configLocal = Object.assign({}, config, {analyzeDurationInMs: undefined}); | ||
const expectedChildProcessDefaultValue = null; | ||
const expectedChunkRemainderDefaultValue = ''; | ||
const expectedStderrOutputs = []; | ||
const expectedConfig = { | ||
ffprobePath : configLocal.ffprobePath, | ||
bufferMaxLengthInBytes : configLocal.bufferMaxLengthInBytes, | ||
errorLevel : configLocal.errorLevel, | ||
exitProcessGuardTimeoutInMs: configLocal.exitProcessGuardTimeoutInMs, | ||
timeout : configLocal.timeoutInMs * 1000, | ||
analyzeDuration : undefined | ||
}; | ||
const framesMonitor = new FramesMonitor(configLocal, url); | ||
assert.isTrue(spyAssertExecutable.calledOnce); | ||
assert.isTrue(spyAssertExecutable.calledWithExactly(config.ffprobePath)); | ||
assert.deepEqual(framesMonitor._config, expectedConfig); | ||
assert.strictEqual(framesMonitor._url, url); | ||
assert.strictEqual(framesMonitor._cp, expectedChildProcessDefaultValue); | ||
assert.strictEqual(framesMonitor._chunkRemainder, expectedChunkRemainderDefaultValue); | ||
assert.deepEqual(framesMonitor._stderrOutputs, expectedStderrOutputs); | ||
}); | ||
}); |
@@ -9,6 +9,7 @@ 'use strict'; | ||
const bufferMaxLengthInBytes = 2 ** 20; | ||
const timeoutInSec = 1; | ||
const timeoutInMs = 1000; | ||
const url = 'rtmp://localhost:1935/myapp/mystream'; | ||
const errorLevel = 'fatal'; // https://ffmpeg.org/ffprobe.html | ||
const exitProcessGuardTimeoutInMs = 2000; | ||
const analyzeDurationInMs = 1000; | ||
@@ -42,6 +43,7 @@ | ||
ffprobePath, | ||
timeoutInSec, | ||
timeoutInMs, | ||
bufferMaxLengthInBytes, | ||
errorLevel, | ||
exitProcessGuardTimeoutInMs | ||
exitProcessGuardTimeoutInMs, | ||
analyzeDurationInMs | ||
}, | ||
@@ -48,0 +50,0 @@ url, |
@@ -16,4 +16,4 @@ 'use strict'; | ||
const streamsInfo = new StreamsInfo({ | ||
ffprobePath : correctPath, | ||
timeoutInSec: 1 | ||
ffprobePath: correctPath, | ||
timeoutInMs: 1 | ||
}, correctUrl); | ||
@@ -20,0 +20,0 @@ |
@@ -17,4 +17,4 @@ 'use strict'; | ||
const streamsInfo = new StreamsInfo({ | ||
ffprobePath : correctPath, | ||
timeoutInSec: 1 | ||
ffprobePath: correctPath, | ||
timeoutInMs: 1 | ||
}, correctUrl); | ||
@@ -21,0 +21,0 @@ |
@@ -71,24 +71,39 @@ const {correctPath} = require('./Helpers/'); | ||
'config' : {}, | ||
'errorMsg' : 'You should provide a correct path to ffprobe, bastard.' | ||
'errorMsg' : 'You should provide a correct path to ffprobe.' | ||
}, | ||
{ | ||
'description': 'config.timeout must be passed', | ||
'description': 'config.timeoutInMs must be passed', | ||
'config' : {ffprobePath: correctPath}, | ||
'errorMsg' : 'You should provide a correct timeout, bastard.' | ||
'errorMsg' : 'You should provide a correct timeout.' | ||
}, | ||
{ | ||
'description': 'config.timeout param must be a positive integer, float is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInSec: 1.1}, | ||
'errorMsg' : 'You should provide a correct timeout, bastard.' | ||
'description': 'config.timeoutInMs param must be a positive integer, float is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInMs: 1.1}, | ||
'errorMsg' : 'You should provide a correct timeout.' | ||
}, | ||
{ | ||
'description': 'config.timeout param must be a positive integer, negative is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInSec: -1}, | ||
'errorMsg' : 'You should provide a correct timeout, bastard.' | ||
'description': 'config.timeoutInMs param must be a positive integer, negative is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInMs: -1}, | ||
'errorMsg' : 'You should provide a correct timeout.' | ||
}, | ||
{ | ||
'description': 'config.timeout param must be a positive integer, string is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInSec: '10'}, | ||
'errorMsg' : 'You should provide a correct timeout, bastard.' | ||
'description': 'config.timeoutInMs param must be a positive integer, string is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInMs: '10'}, | ||
'errorMsg' : 'You should provide a correct timeout.' | ||
}, | ||
{ | ||
'description': 'config.analyzeDurationInMs param must be a positive integer, float is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInMs: 1, analyzeDurationInMs: 1.1}, | ||
'errorMsg' : 'You should provide a correct analyze duration.' | ||
}, | ||
{ | ||
'description': 'config.analyzeDurationInMs param must be a positive integer, negative is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInMs: 1, analyzeDurationInMs: -1}, | ||
'errorMsg' : 'You should provide a correct analyze duration.' | ||
}, | ||
{ | ||
'description': 'config.analyzeDurationInMs param must be a positive integer, string is passed', | ||
'config' : {ffprobePath: correctPath, timeoutInMs: 1, analyzeDurationInMs: '10'}, | ||
'errorMsg' : 'You should provide a correct analyze duration.' | ||
}, | ||
]; | ||
@@ -95,0 +110,0 @@ |
@@ -18,3 +18,3 @@ 'use strict'; | ||
new StreamsInfo(ctx.config, undefined); | ||
}, TypeError, 'Config param should be an object, bastard.'); | ||
}, TypeError, 'Config param should be an object.'); | ||
}); | ||
@@ -27,3 +27,3 @@ }); | ||
new StreamsInfo({}, ctx.url); | ||
}, TypeError, 'You should provide a correct url, bastard.'); | ||
}, TypeError, 'You should provide a correct url.'); | ||
}); | ||
@@ -43,4 +43,4 @@ }); | ||
new StreamsInfo({ | ||
ffprobePath : `/incorrect/path/${correctUrl}`, | ||
timeoutInSec: 1 | ||
ffprobePath: `/incorrect/path/${correctUrl}`, | ||
timeoutInMs: 1 | ||
}, correctUrl); | ||
@@ -53,4 +53,4 @@ }, Errors.ExecutablePathError); | ||
new StreamsInfo({ | ||
ffprobePath : correctPath, | ||
timeoutInSec: 1 | ||
ffprobePath: correctPath, | ||
timeoutInMs: 1 | ||
}, correctUrl); | ||
@@ -57,0 +57,0 @@ }); |
@@ -18,4 +18,4 @@ 'use strict'; | ||
let streamsInfo = new StreamsInfo({ | ||
ffprobePath : correctPath, | ||
timeoutInSec: 1 | ||
ffprobePath: correctPath, | ||
timeoutInMs: 1 | ||
}, correctUrl); | ||
@@ -22,0 +22,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9
4323
473
1589506
4
Updatedlodash@^4.17.15