doccam-pi/out/src_commander.js.html

295 lines
7.4 KiB
HTML
Raw Normal View History

2017-04-27 17:43:06 +12:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: src/commander.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: src/commander.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @module Commander
* @description A Wrapper for Fluent-FFMPEG with a custom command.
*/
2017-04-18 17:23:59 +12:00
const ffmpeg = require('fluent-ffmpeg');
const http = require('http');
2017-04-22 12:12:16 +12:00
const logger = require('./logger');
2017-04-18 17:23:59 +12:00
///////////////////////////////////////////////////////////////////////////////
// Declarations //
///////////////////////////////////////////////////////////////////////////////
// Reference to itself. (Object oriented this. Only used to call public methods.)
let self = false;
2017-04-27 17:43:06 +12:00
/**
* The FFMPEG command.
* @member
*/
2017-04-18 17:23:59 +12:00
let cmd = ffmpeg({
stdoutLines: 20
});
// The Config, Logger and a handle for the kill timeout.
2017-04-22 12:12:16 +12:00
let _config, _stopHandle = false, _connectHandle = false;
2017-04-18 17:23:59 +12:00
2017-04-27 17:43:06 +12:00
// Error Texts //TODO put them into separate module
2017-04-18 17:23:59 +12:00
let errorDescriptions = ['Camera Disconnected',
'YoutTube Disconnected',
'Wrong ffmpeg executable.',
'Unknown Error - Restarting'];
// The stream source url. Yet to be set.
let source = "";
///////////////////////////////////////////////////////////////////////////////
// Code //
///////////////////////////////////////////////////////////////////////////////
/**
* Interface to the ffmpeg process. Uses fluent-ffmpeg.
2017-04-27 17:43:06 +12:00
* @constructor
2017-04-18 17:23:59 +12:00
*/
2017-04-27 17:43:06 +12:00
let Commander = function(){
2017-04-18 17:23:59 +12:00
// singleton
if(self)
return self;
2017-04-22 12:12:16 +12:00
// Make `new` optional.
if(!(this instanceof Commander))
2017-04-27 17:43:06 +12:00
return new Commander();
2017-04-18 17:23:59 +12:00
self = this;
2017-04-27 17:43:06 +12:00
/**
* (Re)Create the ffmpeg command and configure it.
* @param { Object } config The configuration for the stream.
* @returns { Object } The fluent-ffmpeg command object.
*/
let createCommand = function(config) {
2017-04-18 17:23:59 +12:00
// Clear inputs
cmd._inputs = [];
// TODO: Multi Protocol
source = 'rtsp://' + config.camIP + ':' + config.camPort + '/' + config.camProfile;
cmd.input(source);
// Custom config if any.
if (config.customOutputOptions !== "")
cmd.outputOptions(config.customOutputOptions.replace(/\s+\,\s+/g, ',').replace(/\s+\-/g, ',-').split(','));
if (config.customAudioOptions !== "")
cmd.outputOptions(config.customAudioOptions.replace(/\s+\,\s+/g, ',').replace(/\s+\-/g, ',-').split(','));
else
cmd.AudioCodec('copy');
if (config.customVideoOptions !== "")
cmd.outputOptions(config.customVideoOptions.replace(/\s+\,\s+/g, ',').replace(/\s+\-/g, ',-').split(','));
else
cmd.videoCodec('copy');
// Output Options.
cmd.outputFormat('flv')
.outputOptions(['-bufsize 50000k', '-tune film'])
.output('rtmp://a.rtmp.youtube.com/live2/' + config.key);
// Register events.
cmd.on('start', started);
cmd.on('end', stopped);
cmd.on('error', crashed);
2017-04-22 12:12:16 +12:00
return cmd;
2017-04-18 17:23:59 +12:00
};
let ffmpegCommand = function() {
return cmd;
};
// NOTE: Maybe better error resolving strategy.
// Start streaming.
let start = function() {
// Ignore if we try to reconnect.
2017-04-22 12:12:16 +12:00
if(_connectHandle)
2017-04-18 17:23:59 +12:00
return;
cmd.run();
};
// Restart the stream;
let restart = function() {
if(status.streaming) {
restart = true; // NOTE: not very nice
this.stop();
} else
this.start();
};
// Stop streaming.
let stop = function() {
cmd.kill('SIGINT');
2017-04-22 12:12:16 +12:00
_stopHandle = setTimeout(() => {
2017-04-18 17:23:59 +12:00
logger.log(logger.importance[3], "Force Stop!");
cmd.kill();
}, 3000);
};
};
/**
* Utilities
*/
// Handle Stop and Restart
function stopped() {
status.streaming = false;
// Clear force kill Timeout
if(stopTimeout) {
clearTimeout(stopTimeout);
stopTimeout = false;
}
// Restart the stream;
if (restart) {
self.start();
}
cmd.emit('stopped');
}
// TODO: Restart = false in stopped?
// Hande Stat
function started() {
cmd.emit(restart ? 'restarted' : 'started');
restart = false;
status.error = false;
status.streaming = true;
}
/**
* Error Handling
*/
/**
* Log and handle crashes. Notify the main module.
* @param { Object } error - Error object from the crash.
* @param { String } stdout
* @param { String } stderr
*/
function crashed(error, stdout, stderr){
// Can't connect to the
if (err.message.indexOf(source) > -1)
status.error = 0;
// Can't connect to the Internet / YouTube
2017-04-22 12:12:16 +12:00
else if (err.message.indexOf(source + 'Input/output error') > -1 || err.message.indexOf('rtmp://a.rtmp.youtube.com/live2/' + _config.key) > -1)
2017-04-18 17:23:59 +12:00
status.error = 1;
// Wrong FFMPEG Executable
else if (err.message.indexOf('spawn') > -1 || err.message.indexOf('niceness') > -1)
status.error = 2;
// Stopped by us - SIGINT Shouldn't lead to a crash.
else if (err.message.indexOf('SIGINT') > -1 || err.message.indexOf('SIGKILL') > -1){
stopped();
return;
}
// Some unknown Problem, just try to restart.
else {
status.error = 3;
// Just restart in a Second
setTimeout(function(){
self.start();
}, 1000);
}
logger.log(logger.importance[2], `Crashed: ${erro}\nSTDERR: ${stderr}`);
}
/**
* Probe the connection to the host on the port and restart the stream afterwards.
* @param { string } host
* @param { number } port
*/
function tryReconnect( host, port ){
if (!host || !port)
return;
http.get({
host: host.split('/')[0],
port: port
}, function(res) {
// We have a response! Connection works.
setTimeout(function() {
// NOTE: Ugly!
// We have a response! Connection works.
2017-04-22 12:12:16 +12:00
_connectHandle = false;
2017-04-18 17:23:59 +12:00
self.start();
}, 1000);
}).on("error", function(e) {
if (e.message == "socket hang up") {
setTimeout(function() {
// NOTE: Ugly!
// We have a response! Connection works.
2017-04-22 12:12:16 +12:00
_connectHandle = false;
2017-04-18 17:23:59 +12:00
self.start();
}, 1000);
} else {
// try again
2017-04-22 12:12:16 +12:00
_connectHandle = setTimeout(function(){
2017-04-18 17:23:59 +12:00
tryReconnect(host, port);
}, 1000);
}
});
}
2017-04-27 17:43:06 +12:00
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-Actions.html">Actions</a></li><li><a href="module-Commander.html">Commander</a></li><li><a href="module-Main.html">Main</a></li><li><a href="module-Reducers.html">Reducers</a></li><li><a href="module-Streamer.html">Streamer</a></li><li><a href="module-Utilities_Config.html">Utilities/Config</a></li></ul><h3>Classes</h3><ul><li><a href="module-Commander-Commander.html">Commander</a></li><li><a href="module-Streamer-Streamer.html">Streamer</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Mon Apr 24 2017 18:52:45 GMT+1200 (NZST)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>