Merge branch 'dev' of https://gitlab.com/Shinobi-Systems/Shinobi into dev
commit
ed4ead0269
|
@ -192,11 +192,20 @@ module.exports = (s,config,lang) => {
|
||||||
//`e` is the monitor object
|
//`e` is the monitor object
|
||||||
//`x` is an object used to contain temporary values.
|
//`x` is an object used to contain temporary values.
|
||||||
const channelStreamDirectory = !isNaN(parseInt(number)) ? `${e.sdir || s.getStreamsDirectory(e)}channel${number}/` : e.sdir
|
const channelStreamDirectory = !isNaN(parseInt(number)) ? `${e.sdir || s.getStreamsDirectory(e)}channel${number}/` : e.sdir
|
||||||
if(channelStreamDirectory !== e.sdir && !fs.existsSync(channelStreamDirectory)){
|
if(channelStreamDirectory !== e.sdir){
|
||||||
try{
|
if (fs.existsSync(channelStreamDirectory)) {
|
||||||
fs.mkdirSync(channelStreamDirectory)
|
try {
|
||||||
}catch(err){
|
fs.rmdirSync(channelStreamDirectory, { recursive: true, force: true })
|
||||||
// s.debugLog(err)
|
}catch(err){
|
||||||
|
// s.debugLog(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(channelStreamDirectory)) {
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(channelStreamDirectory)
|
||||||
|
}catch(err){
|
||||||
|
// s.debugLog(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const channelNumber = number - config.pipeAddition
|
const channelNumber = number - config.pipeAddition
|
||||||
|
|
|
@ -27,6 +27,7 @@ module.exports = function(s,config,lang){
|
||||||
getMonitorConfiguration,
|
getMonitorConfiguration,
|
||||||
copyMonitorConfiguration,
|
copyMonitorConfiguration,
|
||||||
checkObjectsInMonitorDetails,
|
checkObjectsInMonitorDetails,
|
||||||
|
spawnSubstreamProcess,
|
||||||
} = require('./monitor/utils.js')(s,config,lang)
|
} = require('./monitor/utils.js')(s,config,lang)
|
||||||
const {
|
const {
|
||||||
canAddMoreMonitors,
|
canAddMoreMonitors,
|
||||||
|
@ -664,6 +665,45 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
return endData
|
return endData
|
||||||
}
|
}
|
||||||
|
s.getStreamWaitTimeout = function (groupId, monitorId) {
|
||||||
|
const monitorConfig = s.group[groupId].rawMonitorConfigurations[monitorId];
|
||||||
|
var streamType = monitorConfig.details.stream_type;
|
||||||
|
var hls_time;
|
||||||
|
if (streamType === 'useSubstream') {
|
||||||
|
streamType = monitorConfig.details.substream.output.stream_type;
|
||||||
|
hls_time = monitorConfig.details.substream.output.hls_time;
|
||||||
|
} else {
|
||||||
|
hls_time = monitorConfig.details.hls_time;
|
||||||
|
}
|
||||||
|
return streamType == 'hls' && hls_time != ''
|
||||||
|
? (parseInt(hls_time) * 1000) + 10000
|
||||||
|
: 10000;
|
||||||
|
}
|
||||||
|
s.toggleSubstreamAndWaitForOutput = async function (groupId, monitorId) {
|
||||||
|
const monitorConfig = s.group[groupId].rawMonitorConfigurations[monitorId];
|
||||||
|
const streamType = monitorConfig.details.stream_type;
|
||||||
|
if (streamType === 'useSubstream') {
|
||||||
|
const activeMonitor = s.group[groupId].activeMonitors[monitorId];
|
||||||
|
if (!activeMonitor.subStreamProcess) {
|
||||||
|
spawnSubstreamProcess(monitorConfig);
|
||||||
|
}
|
||||||
|
if (!activeMonitor.subStreamOutputReady) {
|
||||||
|
const checkTime = 250;
|
||||||
|
var monitorTimeout = s.getStreamWaitTimeout(groupId, monitorId);
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
let totalTime = 0;
|
||||||
|
const timer = setInterval(function () {
|
||||||
|
totalTime += checkTime;
|
||||||
|
if (activeMonitor.subStreamOutputReady || totalTime >= monitorTimeout) {
|
||||||
|
clearInterval(timer);
|
||||||
|
resolve(activeMonitor.subStreamOutputReady);
|
||||||
|
}
|
||||||
|
}, checkTime);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
s.camera = async (selectedMode,e,cn) => {
|
s.camera = async (selectedMode,e,cn) => {
|
||||||
// e = monitor object
|
// e = monitor object
|
||||||
// cn = socket connection or callback or options (depends on function chosen)
|
// cn = socket connection or callback or options (depends on function chosen)
|
||||||
|
|
|
@ -287,6 +287,14 @@ module.exports = (s,config,lang) => {
|
||||||
channel: activeMonitor.subStreamChannel
|
channel: activeMonitor.subStreamChannel
|
||||||
},'GRP_'+groupKey);
|
},'GRP_'+groupKey);
|
||||||
}
|
}
|
||||||
|
const sendSubstreamEventActiveMonitor = function(activeMonitor, eventName = 'substream_start'){
|
||||||
|
s.tx({
|
||||||
|
f: eventName,
|
||||||
|
mid: activeMonitor.mid,
|
||||||
|
ke: activeMonitor.ke,
|
||||||
|
channel: activeMonitor.subStreamChannel
|
||||||
|
},'GRP_'+activeMonitor.mid);
|
||||||
|
}
|
||||||
const spawnSubstreamProcess = function(e){
|
const spawnSubstreamProcess = function(e){
|
||||||
// e = monitorConfig
|
// e = monitorConfig
|
||||||
try{
|
try{
|
||||||
|
@ -387,6 +395,26 @@ module.exports = (s,config,lang) => {
|
||||||
},2000)
|
},2000)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
activeMonitor.subStreamOutputReady = false;
|
||||||
|
if (outputFields.stream_type == 'hls') {
|
||||||
|
const channelStream = subStreamProcess.spawnargs.at(-1);
|
||||||
|
activeMonitor.subStreamOutputReadyCheck = setInterval(function () {
|
||||||
|
if (fs.existsSync(channelStream)) {
|
||||||
|
activeMonitor.subStreamOutputReady = true;
|
||||||
|
clearInterval(activeMonitor.subStreamOutputReadyCheck);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
} else if (outputFields.stream_type == 'mp4') {
|
||||||
|
const pipeNumber = activeMonitor.subStreamChannel + config.pipeAddition;
|
||||||
|
subStreamProcess.stdio[pipeNumber].once('data', (data) => {
|
||||||
|
activeMonitor.subStreamOutputReady = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const pipeNumber = activeMonitor.subStreamChannel + config.pipeAddition;
|
||||||
|
activeMonitor.emitterChannel[pipeNumber].once('data', (data) => {
|
||||||
|
activeMonitor.subStreamOutputReady = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
activeMonitor.subStreamProcess = subStreamProcess
|
activeMonitor.subStreamProcess = subStreamProcess
|
||||||
sendSubstreamEvent(groupKey, monitorId)
|
sendSubstreamEvent(groupKey, monitorId)
|
||||||
return subStreamProcess
|
return subStreamProcess
|
||||||
|
@ -407,11 +435,13 @@ module.exports = (s,config,lang) => {
|
||||||
}else if(activeMonitor.subStreamProcess){
|
}else if(activeMonitor.subStreamProcess){
|
||||||
activeMonitor.subStreamProcessClosing = true
|
activeMonitor.subStreamProcessClosing = true
|
||||||
activeMonitor.subStreamChannel = null;
|
activeMonitor.subStreamChannel = null;
|
||||||
|
activeMonitor.subStreamOutputReady = false;
|
||||||
|
clearInterval(activeMonitor.subStreamOutputReadyCheck);
|
||||||
const closeResponse = await processKill(activeMonitor.subStreamProcess)
|
const closeResponse = await processKill(activeMonitor.subStreamProcess)
|
||||||
response.hadSubStream = true
|
response.hadSubStream = true
|
||||||
response.closeResponse = closeResponse
|
response.closeResponse = closeResponse
|
||||||
delete(activeMonitor.subStreamProcess)
|
delete(activeMonitor.subStreamProcess)
|
||||||
sendSubstreamEvent(activeMonitor.mid, activeMonitor.ke, 'substream_end')
|
sendSubstreamEventActiveMonitor(activeMonitor, 'substream_end')
|
||||||
activeMonitor.subStreamProcessClosing = false
|
activeMonitor.subStreamProcessClosing = false
|
||||||
}
|
}
|
||||||
}catch(err){
|
}catch(err){
|
||||||
|
@ -462,7 +492,7 @@ module.exports = (s,config,lang) => {
|
||||||
function setActiveViewer(groupKey,monitorId,connectionId,isBeingAdded){
|
function setActiveViewer(groupKey,monitorId,connectionId,isBeingAdded){
|
||||||
const viewerList = s.group[groupKey].activeMonitors[monitorId].watch;
|
const viewerList = s.group[groupKey].activeMonitors[monitorId].watch;
|
||||||
if(isBeingAdded){
|
if(isBeingAdded){
|
||||||
if(viewerList.indexOf(connectionId) > -1)viewerList.push(connectionId);
|
if(viewerList.indexOf(connectionId) == -1)viewerList.push(connectionId);
|
||||||
}else{
|
}else{
|
||||||
viewerList.splice(viewerList.indexOf(connectionId), 1)
|
viewerList.splice(viewerList.indexOf(connectionId), 1)
|
||||||
}
|
}
|
||||||
|
@ -811,6 +841,13 @@ module.exports = (s,config,lang) => {
|
||||||
setActiveViewer(groupKey,monitorId,cn.id,true)
|
setActiveViewer(groupKey,monitorId,cn.id,true)
|
||||||
activeMonitor.allowDestroySubstream = false
|
activeMonitor.allowDestroySubstream = false
|
||||||
clearTimeout(activeMonitor.noViewerCountDisableSubstream)
|
clearTimeout(activeMonitor.noViewerCountDisableSubstream)
|
||||||
|
if (e.monitorTimeout) {
|
||||||
|
const uniqueId = cn.url + cn.id;
|
||||||
|
clearTimeout(streamViewerCountTimeouts[uniqueId])
|
||||||
|
streamViewerCountTimeouts[uniqueId] = setTimeout(() => {
|
||||||
|
monitorRemoveViewer(e,cn)
|
||||||
|
},e.monitorTimeout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function monitorRemoveViewer(e,cn){
|
function monitorRemoveViewer(e,cn){
|
||||||
const groupKey = e.ke
|
const groupKey = e.ke
|
||||||
|
@ -1861,5 +1898,6 @@ module.exports = (s,config,lang) => {
|
||||||
attachMainProcessHandlers: attachMainProcessHandlers,
|
attachMainProcessHandlers: attachMainProcessHandlers,
|
||||||
removeSenstiveInfoFromMonitorConfig,
|
removeSenstiveInfoFromMonitorConfig,
|
||||||
sendSubstreamEvent,
|
sendSubstreamEvent,
|
||||||
|
sendSubstreamEventActiveMonitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,10 +95,11 @@ module.exports = function(s,config,lang,app){
|
||||||
res.end('404 : Monitor not found');
|
res.end('404 : Monitor not found');
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.checkChildProxy(req.params,function(){
|
s.checkChildProxy(req.params,async function(){
|
||||||
var Channel = 'MAIN'
|
var Channel = 'MAIN'
|
||||||
if(req.params.channel){
|
if(req.params.channel){
|
||||||
Channel = parseInt(req.params.channel)+config.pipeAddition
|
Channel = parseInt(req.params.channel)+config.pipeAddition
|
||||||
|
await s.toggleSubstreamAndWaitForOutput(req.params.ke, monitorId);
|
||||||
}
|
}
|
||||||
var mp4frag = s.group[req.params.ke].activeMonitors[req.params.id].mp4frag[Channel];
|
var mp4frag = s.group[req.params.ke].activeMonitors[req.params.id].mp4frag[Channel];
|
||||||
var errorMessage = 'MP4 Stream is not enabled'
|
var errorMessage = 'MP4 Stream is not enabled'
|
||||||
|
@ -158,7 +159,7 @@ module.exports = function(s,config,lang,app){
|
||||||
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s.checkChildProxy(req.params,function(){
|
s.checkChildProxy(req.params,async function(){
|
||||||
if(s.group[req.params.ke]&&s.group[req.params.ke].activeMonitors&&s.group[req.params.ke].activeMonitors[req.params.id]){
|
if(s.group[req.params.ke]&&s.group[req.params.ke].activeMonitors&&s.group[req.params.ke].activeMonitors[req.params.id]){
|
||||||
if(user.permissions.watch_stream==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitors.indexOf(req.params.id)===-1){
|
if(user.permissions.watch_stream==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitors.indexOf(req.params.id)===-1){
|
||||||
res.end(user.lang['Not Permitted'])
|
res.end(user.lang['Not Permitted'])
|
||||||
|
@ -170,6 +171,7 @@ module.exports = function(s,config,lang,app){
|
||||||
if(!req.params.channel){
|
if(!req.params.channel){
|
||||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitter
|
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitter
|
||||||
}else{
|
}else{
|
||||||
|
await s.toggleSubstreamAndWaitForOutput(req.params.ke, monitorId);
|
||||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[chosenChannel]
|
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[chosenChannel]
|
||||||
}
|
}
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
|
@ -228,7 +230,7 @@ module.exports = function(s,config,lang,app){
|
||||||
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s.checkChildProxy(req.params,function(){
|
s.checkChildProxy(req.params,async function(){
|
||||||
noCache(res)
|
noCache(res)
|
||||||
if(user.permissions.watch_stream==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitors.indexOf(req.params.id)===-1){
|
if(user.permissions.watch_stream==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitors.indexOf(req.params.id)===-1){
|
||||||
res.end(user.lang['Not Permitted'])
|
res.end(user.lang['Not Permitted'])
|
||||||
|
@ -241,6 +243,19 @@ module.exports = function(s,config,lang,app){
|
||||||
req.dir+=req.params.file;
|
req.dir+=req.params.file;
|
||||||
}
|
}
|
||||||
res.on('finish',function(){res.end();});
|
res.on('finish',function(){res.end();});
|
||||||
|
if (req.params.file.endsWith('.m3u8')) {
|
||||||
|
await s.toggleSubstreamAndWaitForOutput(req.params.ke, monitorId);
|
||||||
|
const monitorTimeout = s.getStreamWaitTimeout(req.params.ke, monitorId);
|
||||||
|
var ip = s.getClientIp(req)
|
||||||
|
s.camera('watch_on',{
|
||||||
|
id : req.params.id,
|
||||||
|
ke: req.params.ke,
|
||||||
|
monitorTimeout: monitorTimeout
|
||||||
|
},{
|
||||||
|
id: req.params.auth + ip + req.headers['user-agent'],
|
||||||
|
url: req.originalUrl
|
||||||
|
})
|
||||||
|
}
|
||||||
if (fs.existsSync(req.dir)){
|
if (fs.existsSync(req.dir)){
|
||||||
fs.createReadStream(req.dir).pipe(res);
|
fs.createReadStream(req.dir).pipe(res);
|
||||||
}else{
|
}else{
|
||||||
|
@ -310,19 +325,21 @@ module.exports = function(s,config,lang,app){
|
||||||
*/
|
*/
|
||||||
app.get([config.webPaths.apiPrefix+':auth/flv/:ke/:id/s.flv',config.webPaths.apiPrefix+':auth/flv/:ke/:id/:channel/s.flv'], function(req,res) {
|
app.get([config.webPaths.apiPrefix+':auth/flv/:ke/:id/s.flv',config.webPaths.apiPrefix+':auth/flv/:ke/:id/:channel/s.flv'], function(req,res) {
|
||||||
s.auth(req.params,function(user){
|
s.auth(req.params,function(user){
|
||||||
|
const monitorId = req.params.id
|
||||||
if(cantLiveStreamPermission(user,monitorId,'watch_stream')){
|
if(cantLiveStreamPermission(user,monitorId,'watch_stream')){
|
||||||
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s.checkChildProxy(req.params,function(){
|
s.checkChildProxy(req.params, async function () {
|
||||||
noCache(res)
|
noCache(res)
|
||||||
var Emitter,chunkChannel
|
var Emitter,chunkChannel
|
||||||
if(!req.params.channel){
|
if(!req.params.channel){
|
||||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitter
|
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitter
|
||||||
chunkChannel = 'MAIN'
|
chunkChannel = 'MAIN'
|
||||||
}else{
|
}else{
|
||||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
|
await s.toggleSubstreamAndWaitForOutput(req.params.ke, monitorId);
|
||||||
chunkChannel = parseInt(req.params.channel)+config.pipeAddition
|
chunkChannel = parseInt(req.params.channel) + config.pipeAddition;
|
||||||
|
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[chunkChannel];
|
||||||
}
|
}
|
||||||
if(s.group[req.params.ke].activeMonitors[req.params.id].firstStreamChunk[chunkChannel]){
|
if(s.group[req.params.ke].activeMonitors[req.params.id].firstStreamChunk[chunkChannel]){
|
||||||
//variable name of contentWriter
|
//variable name of contentWriter
|
||||||
|
@ -370,17 +387,19 @@ module.exports = function(s,config,lang,app){
|
||||||
config.webPaths.apiPrefix+':auth/h264/:ke/:id'
|
config.webPaths.apiPrefix+':auth/h264/:ke/:id'
|
||||||
], function (req, res) {
|
], function (req, res) {
|
||||||
s.auth(req.params,function(user){
|
s.auth(req.params,function(user){
|
||||||
|
const monitorId = req.params.id;
|
||||||
if(cantLiveStreamPermission(user,monitorId,'watch_stream')){
|
if(cantLiveStreamPermission(user,monitorId,'watch_stream')){
|
||||||
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
s.closeJsonResponse(res,{ok: false, msg: lang['Not Authorized']});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s.checkChildProxy(req.params,function(){
|
s.checkChildProxy(req.params, async function(){
|
||||||
noCache(res)
|
noCache(res)
|
||||||
if(!req.query.feed){req.query.feed='1'}
|
if(!req.query.feed){req.query.feed='1'}
|
||||||
var Emitter
|
var Emitter
|
||||||
if(!req.params.feed){
|
if(!req.params.feed){
|
||||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].streamIn[req.query.feed]
|
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].streamIn[req.query.feed]
|
||||||
}else{
|
}else{
|
||||||
|
await s.toggleSubstreamAndWaitForOutput(req.params.ke, monitorId);
|
||||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[parseInt(req.params.feed)+config.pipeAddition]
|
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[parseInt(req.params.feed)+config.pipeAddition]
|
||||||
}
|
}
|
||||||
var contentWriter
|
var contentWriter
|
||||||
|
|
Loading…
Reference in New Issue