master
Moe 2024-10-21 17:31:12 -07:00
commit ed4ead0269
4 changed files with 120 additions and 14 deletions

View File

@ -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

View File

@ -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)

View File

@ -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
} }
} }

View File

@ -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