mirror of
https://github.com/datarhei/restreamer.git
synced 2025-12-12 06:24:08 +01:00
RC4
This commit is contained in:
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,3 +1,21 @@
|
||||
## Changes from 0.1.0-RC3 to 0.1.0-RC4
|
||||
|
||||
* added https sources to Dockerfiles (thx @ [nodiscc](https://github.com/nodiscc))
|
||||
* fixed visualisation problem of new RTMP/RTSP endpoint (JSONDB processing)
|
||||
* optimized input-process (removed generateOutputRTMPPath)
|
||||
* cleaned up NPM packages
|
||||
* added ESLint insteed of JSHint+ first ruleset
|
||||
* first code optimizations (ecma5 -> ecma6)
|
||||
* optimized RaspiCam-Hack for Raspberry Pi 1
|
||||
* updated NPM packages and node
|
||||
* refactored FFmpeg-Fluent integration by own fork (reduces process-output)
|
||||
* fixed output-process (generated high CPU load on arm)
|
||||
* fixed preview player (no play-icon, didn't stop when the modalbox is closed)
|
||||
|
||||
##### Merged pull requests:
|
||||
|
||||
* Fixed ARM typo @ [Vyacheslav Shevchenko](https://github.com/bliz937)
|
||||
|
||||
## Changes from 0.1.0-RC2 to 0.1.0-RC3
|
||||
|
||||
* fixed links to docs
|
||||
|
||||
38
Dockerfile
38
Dockerfile
@@ -1,17 +1,18 @@
|
||||
FROM node:4.2.3-slim
|
||||
FROM node:4.2.6-slim
|
||||
|
||||
MAINTAINER datarhei <info@datarhei.org>
|
||||
|
||||
ENV FFMPEG_VERSION 2.8.1
|
||||
ENV YASM_VERSION 1.3.0
|
||||
ENV LAME_VERSION 3.99.5
|
||||
ENV LAME_VERSION 3_99_5
|
||||
ENV NGINX_VERSION 1.8.0
|
||||
ENV NGINX_RTMP_VERSION 1.1.7
|
||||
|
||||
ENV SRC /usr/local
|
||||
ENV LD_LIBRARY_PATH ${SRC}/lib
|
||||
ENV PKG_CONFIG_PATH ${SRC}/lib/pkgconfig
|
||||
|
||||
ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev unzip"
|
||||
ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev"
|
||||
|
||||
RUN rm -rf /var/lib/apt/lists/* && \
|
||||
apt-get update && \
|
||||
@@ -19,8 +20,8 @@ RUN rm -rf /var/lib/apt/lists/* && \
|
||||
|
||||
# yasm
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -Os http://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \
|
||||
tar xzvf yasm-${YASM_VERSION}.tar.gz && \
|
||||
curl -LOks https://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \
|
||||
tar xzvf yasm-${YASM_VERSION}.tar.gz && \
|
||||
cd yasm-${YASM_VERSION} && \
|
||||
./configure --prefix="$SRC" --bindir="${SRC}/bin" && \
|
||||
make && \
|
||||
@@ -40,9 +41,9 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# libmp3lame
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -L -Os http://downloads.sourceforge.net/project/lame/lame/${LAME_VERSION%.*}/lame-${LAME_VERSION}.tar.gz && \
|
||||
tar xzvf lame-${LAME_VERSION}.tar.gz && \
|
||||
cd lame-${LAME_VERSION} && \
|
||||
curl -LOks https://github.com/rbrito/lame/archive/RELEASE__${LAME_VERSION}.tar.gz && \
|
||||
tar xzvf RELEASE__${LAME_VERSION}.tar.gz && \
|
||||
cd lame-RELEASE__${LAME_VERSION} && \
|
||||
./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-shared --enable-nasm && \
|
||||
make && \
|
||||
make install && \
|
||||
@@ -51,12 +52,12 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# ffmpeg
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -Os http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
curl -LOks https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
cd ffmpeg-${FFMPEG_VERSION} && \
|
||||
./configure --prefix="${SRC}" --extra-cflags="-I${SRC}/include" --extra-ldflags="-L${SRC}/lib" --bindir="${SRC}/bin" \
|
||||
--extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \
|
||||
--enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \
|
||||
--extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \
|
||||
--enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \
|
||||
make && \
|
||||
make install && \
|
||||
make distclean && \
|
||||
@@ -70,13 +71,12 @@ RUN ffmpeg -buildconf
|
||||
|
||||
# nginx-rtmp
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -LOks http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
|
||||
tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \
|
||||
curl -LOks https://github.com/arut/nginx-rtmp-module/archive/master.zip && \
|
||||
unzip master.zip && \
|
||||
rm master.zip && \
|
||||
cd nginx-${NGINX_VERSION} && \
|
||||
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master && \
|
||||
curl -LOks https://github.com/nginx/nginx/archive/release-${NGINX_VERSION}.tar.gz && \
|
||||
tar xzvf release-${NGINX_VERSION}.tar.gz && \
|
||||
curl -LOks https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_VERSION}.tar.gz && \
|
||||
tar xzvf v${NGINX_RTMP_VERSION}.tar.gz && \
|
||||
cd nginx-release-${NGINX_VERSION} && \
|
||||
auto/configure --with-http_ssl_module --add-module=../nginx-rtmp-module-${NGINX_RTMP_VERSION} && \
|
||||
make && \
|
||||
make install && \
|
||||
rm -rf ${DIR}
|
||||
|
||||
@@ -2,30 +2,30 @@ FROM resin/rpi-raspbian:jessie
|
||||
|
||||
MAINTAINER datarhei <info@datarhei.org>
|
||||
|
||||
ENV NODE_VERSION 4.2.3
|
||||
ENV NPM_VERSION 2.14.7
|
||||
ENV NODE_VERSION 4.2.6
|
||||
ENV NPM_VERSION 2.14.12
|
||||
|
||||
ENV FFMPEG_VERSION 2.8.1
|
||||
ENV YASM_VERSION 1.3.0
|
||||
ENV LAME_VERSION 3.99.5
|
||||
ENV LAME_VERSION 3_99_5
|
||||
ENV NGINX_VERSION 1.8.0
|
||||
ENV NGINX_RTMP_VERSION 1.1.7
|
||||
|
||||
ENV SRC /usr/local
|
||||
ENV LD_LIBRARY_PATH ${SRC}/lib
|
||||
ENV PKG_CONFIG_PATH ${SRC}/lib/pkgconfig
|
||||
|
||||
ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev unzip"
|
||||
ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev"
|
||||
|
||||
RUN rm -rf /var/lib/apt/lists/* && \
|
||||
apt-get update && \
|
||||
apt-get install -y curl wget git libpcre3 tar ${BUILDDEPS}
|
||||
apt-get install -y curl git libpcre3 tar ${BUILDDEPS}
|
||||
|
||||
# node
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
set -x && \
|
||||
wget "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv6l.tar.gz" && \
|
||||
tar -xzf "node-v$NODE_VERSION-linux-armv6l.tar.gz" -C /usr/local --strip-components=1 && \
|
||||
rm "node-v$NODE_VERSION-linux-armv6l.tar.gz" && \
|
||||
curl -LOks https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv6l.tar.gz && \
|
||||
tar -xzf "node-v$NODE_VERSION-linux-armv6l.tar.gz" -C /usr/local --strip-components=1 && \
|
||||
npm install -g npm@"$NPM_VERSION" --unsafe-perm && \
|
||||
npm cache clear && \
|
||||
npm config set unsafe-perm true -g --unsafe-perm && \
|
||||
@@ -33,8 +33,8 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# yasm
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -Os http://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \
|
||||
tar xzvf yasm-${YASM_VERSION}.tar.gz && \
|
||||
curl -LOks https://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \
|
||||
tar xzvf yasm-${YASM_VERSION}.tar.gz && \
|
||||
cd yasm-${YASM_VERSION} && \
|
||||
./configure --prefix="$SRC" --bindir="${SRC}/bin" && \
|
||||
make && \
|
||||
@@ -54,9 +54,9 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# libmp3lame
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -L -Os http://downloads.sourceforge.net/project/lame/lame/${LAME_VERSION%.*}/lame-${LAME_VERSION}.tar.gz && \
|
||||
tar xzvf lame-${LAME_VERSION}.tar.gz && \
|
||||
cd lame-${LAME_VERSION} && \
|
||||
curl -LOks https://github.com/rbrito/lame/archive/RELEASE__${LAME_VERSION}.tar.gz && \
|
||||
tar xzvf RELEASE__${LAME_VERSION}.tar.gz && \
|
||||
cd lame-RELEASE__${LAME_VERSION} && \
|
||||
./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-shared --enable-nasm && \
|
||||
make && \
|
||||
make install && \
|
||||
@@ -65,12 +65,12 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# ffmpeg
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -Os http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
curl -LOks https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
cd ffmpeg-${FFMPEG_VERSION} && \
|
||||
./configure --prefix="${SRC}" --extra-cflags="-I${SRC}/include" --extra-ldflags="-L${SRC}/lib" --bindir="${SRC}/bin" \
|
||||
--extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \
|
||||
--enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \
|
||||
--extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \
|
||||
--enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \
|
||||
make && \
|
||||
make install && \
|
||||
make distclean && \
|
||||
@@ -84,21 +84,22 @@ RUN ffmpeg -buildconf
|
||||
|
||||
# nginx-rtmp
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -LOks http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
|
||||
tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \
|
||||
curl -LOks https://github.com/arut/nginx-rtmp-module/archive/master.zip && \
|
||||
unzip master.zip && \
|
||||
rm master.zip && \
|
||||
cd nginx-${NGINX_VERSION} && \
|
||||
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master && \
|
||||
curl -LOks https://github.com/nginx/nginx/archive/release-${NGINX_VERSION}.tar.gz && \
|
||||
tar xzvf release-${NGINX_VERSION}.tar.gz && \
|
||||
curl -LOks https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_VERSION}.tar.gz && \
|
||||
tar xzvf v${NGINX_RTMP_VERSION}.tar.gz && \
|
||||
cd nginx-release-${NGINX_VERSION} && \
|
||||
auto/configure --with-http_ssl_module --add-module=../nginx-rtmp-module-${NGINX_RTMP_VERSION} && \
|
||||
make && \
|
||||
make install && \
|
||||
rm -rf ${DIR}
|
||||
|
||||
RUN apt-get purge -y --auto-remove ${BUILDDEPS} && \
|
||||
apt-get install -y --force-yes git && \
|
||||
rm -rf /tmp/*
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --force-yes git
|
||||
|
||||
COPY . /restreamer
|
||||
WORKDIR /restreamer
|
||||
|
||||
|
||||
@@ -2,30 +2,30 @@ FROM armbuild/debian:jessie
|
||||
|
||||
MAINTAINER datarhei <info@datarhei.org>
|
||||
|
||||
ENV NODE_VERSION 4.2.3
|
||||
ENV NPM_VERSION 2.14.7
|
||||
ENV NODE_VERSION 4.2.6
|
||||
ENV NPM_VERSION 2.14.12
|
||||
|
||||
ENV FFMPEG_VERSION 2.8.1
|
||||
ENV YASM_VERSION 1.3.0
|
||||
ENV LAME_VERSION 3.99.5
|
||||
ENV LAME_VERSION 3_99_5
|
||||
ENV NGINX_VERSION 1.8.0
|
||||
ENV NGINX_RTMP_VERSION 1.1.7
|
||||
|
||||
ENV SRC /usr/local
|
||||
ENV LD_LIBRARY_PATH ${SRC}/lib
|
||||
ENV PKG_CONFIG_PATH ${SRC}/lib/pkgconfig
|
||||
|
||||
ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev unzip"
|
||||
ENV BUILDDEPS "autoconf automake gcc g++ libtool make nasm zlib1g-dev libssl-dev xz-utils cmake perl build-essential libpcre3-dev"
|
||||
|
||||
RUN rm -rf /var/lib/apt/lists/* && \
|
||||
apt-get update && \
|
||||
apt-get install -y curl wget git libpcre3 tar ${BUILDDEPS}
|
||||
apt-get install -y curl git libpcre3 tar ${BUILDDEPS}
|
||||
|
||||
# node
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
set -x && \
|
||||
wget "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv7l.tar.gz" && \
|
||||
tar -xzf "node-v$NODE_VERSION-linux-armv7l.tar.gz" -C /usr/local --strip-components=1 && \
|
||||
rm "node-v$NODE_VERSION-linux-armv7l.tar.gz" && \
|
||||
curl -LOks https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-armv7l.tar.gz && \
|
||||
tar -xzf "node-v$NODE_VERSION-linux-armv7l.tar.gz" -C /usr/local --strip-components=1 && \
|
||||
npm install -g npm@"$NPM_VERSION" --unsafe-perm && \
|
||||
npm cache clear && \
|
||||
npm config set unsafe-perm true -g --unsafe-perm && \
|
||||
@@ -33,8 +33,8 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# yasm
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -Os http://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \
|
||||
tar xzvf yasm-${YASM_VERSION}.tar.gz && \
|
||||
curl -LOks https://www.tortall.net/projects/yasm/releases/yasm-${YASM_VERSION}.tar.gz && \
|
||||
tar xzvf yasm-${YASM_VERSION}.tar.gz && \
|
||||
cd yasm-${YASM_VERSION} && \
|
||||
./configure --prefix="$SRC" --bindir="${SRC}/bin" && \
|
||||
make && \
|
||||
@@ -54,9 +54,9 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# libmp3lame
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -L -Os http://downloads.sourceforge.net/project/lame/lame/${LAME_VERSION%.*}/lame-${LAME_VERSION}.tar.gz && \
|
||||
tar xzvf lame-${LAME_VERSION}.tar.gz && \
|
||||
cd lame-${LAME_VERSION} && \
|
||||
curl -LOks https://github.com/rbrito/lame/archive/RELEASE__${LAME_VERSION}.tar.gz && \
|
||||
tar xzvf RELEASE__${LAME_VERSION}.tar.gz && \
|
||||
cd lame-RELEASE__${LAME_VERSION} && \
|
||||
./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-shared --enable-nasm && \
|
||||
make && \
|
||||
make install && \
|
||||
@@ -65,12 +65,12 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
|
||||
# ffmpeg
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -Os http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
curl -LOks https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
tar xzvf ffmpeg-${FFMPEG_VERSION}.tar.gz && \
|
||||
cd ffmpeg-${FFMPEG_VERSION} && \
|
||||
./configure --prefix="${SRC}" --extra-cflags="-I${SRC}/include" --extra-ldflags="-L${SRC}/lib" --bindir="${SRC}/bin" \
|
||||
--extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \
|
||||
--enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \
|
||||
--extra-libs=-ldl --enable-version3 --enable-libmp3lame --enable-libx264 --enable-gpl \
|
||||
--enable-postproc --enable-nonfree --enable-avresample --disable-debug --enable-small --enable-openssl && \
|
||||
make && \
|
||||
make install && \
|
||||
make distclean && \
|
||||
@@ -84,13 +84,12 @@ RUN ffmpeg -buildconf
|
||||
|
||||
# nginx-rtmp
|
||||
RUN DIR=$(mktemp -d) && cd ${DIR} && \
|
||||
curl -LOks http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
|
||||
tar -zxvf nginx-${NGINX_VERSION}.tar.gz && \
|
||||
curl -LOks https://github.com/arut/nginx-rtmp-module/archive/master.zip && \
|
||||
unzip master.zip && \
|
||||
rm master.zip && \
|
||||
cd nginx-${NGINX_VERSION} && \
|
||||
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master && \
|
||||
curl -LOks https://github.com/nginx/nginx/archive/release-${NGINX_VERSION}.tar.gz && \
|
||||
tar xzvf release-${NGINX_VERSION}.tar.gz && \
|
||||
curl -LOks https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_VERSION}.tar.gz && \
|
||||
tar xzvf v${NGINX_RTMP_VERSION}.tar.gz && \
|
||||
cd nginx-release-${NGINX_VERSION} && \
|
||||
auto/configure --with-http_ssl_module --add-module=../nginx-rtmp-module-${NGINX_RTMP_VERSION} && \
|
||||
make && \
|
||||
make install && \
|
||||
rm -rf ${DIR}
|
||||
|
||||
12
README.md
12
README.md
@@ -10,14 +10,14 @@ Datarhei/Restreamer offers smart free video streaming in real time. Stream H.264
|
||||
- <a target= "_blank" href="https://www.docker.com/">Docker</a> and <a target= "_blank" href="https://kitematic.com/">Kitematic (Docker-Toolbox)</a> optimizations and very easy installation
|
||||
|
||||
##Roadmap
|
||||
- RC4 (planned 1.25.2016)
|
||||
- refactoring ffmpeg-fluent integration
|
||||
- nginx process monitor
|
||||
- cleanup packages
|
||||
- optimizing ui (jsonDB processing, input-validation, clappr-integration)
|
||||
- RC5 (planned 2.1.2016)
|
||||
- code optimizations (full ecma6, lint, jsdocs)
|
||||
- start writing tests
|
||||
- input-validation
|
||||
- optimizing scope of stats
|
||||
- cleanup JSONDB
|
||||
- start restructuring code
|
||||
- cleanup packages
|
||||
- NGINX process monitor
|
||||
|
||||
##Documentation
|
||||
Documentation is available on [Datarhei/Restreamer GitHub pages](https://datarhei.github.io/restreamer/).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Restreamer",
|
||||
"version": "0.1.0-RC3",
|
||||
"version": "0.1.0-RC4",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bootstrap": "3.3.6",
|
||||
|
||||
132
gruntfile.js
132
gruntfile.js
@@ -6,7 +6,7 @@ module.exports = function(grunt) {
|
||||
compiledFrontendJS: ['bin/webserver/public/scripts/**/*.js', 'bin/executors/**/gui/js/*.js'],
|
||||
es6Src: ['**/*.js'],
|
||||
stylesheets: ['static/webserver/public/css/*.css']
|
||||
};
|
||||
};
|
||||
// find all node modules
|
||||
var modules = [];
|
||||
var pck = require('./package.json')
|
||||
@@ -19,8 +19,8 @@ module.exports = function(grunt) {
|
||||
return './node_modules/' + m + '/**/*'
|
||||
});
|
||||
}
|
||||
// Project Configuration
|
||||
grunt.initConfig({
|
||||
// Project Configuration
|
||||
grunt.initConfig({
|
||||
watch: {
|
||||
scripts: {
|
||||
files: ['src/**/*.js'],
|
||||
@@ -63,7 +63,7 @@ module.exports = function(grunt) {
|
||||
},
|
||||
//temp workaround - https://github.com/clappr/clappr/issues/709
|
||||
clappr: {
|
||||
command: 'git clone https://github.com/clappr/clappr.git bin/webserver/public/libs/clappr'
|
||||
command: 'git clone https://github.com/clappr/clappr bin/webserver/public/libs/clappr'
|
||||
}
|
||||
},
|
||||
babel: {
|
||||
@@ -82,101 +82,85 @@ module.exports = function(grunt) {
|
||||
]
|
||||
}
|
||||
},
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
jshint: {
|
||||
all: {
|
||||
src: [
|
||||
'src/*.js',
|
||||
'src/classes/*.js',
|
||||
'src/webserver/*.js',
|
||||
'src/webserver/**/*.js',
|
||||
'src/webserver/**/**/*.js',
|
||||
'src/webserver/**/**/**/*.js'
|
||||
],
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
eslint: {
|
||||
all: ['src/**/*.js'],
|
||||
options: {
|
||||
configFile: '.eslintrc.json'
|
||||
}
|
||||
},
|
||||
csslint: {
|
||||
options: {
|
||||
csslintrc: '.csslintrc'
|
||||
},
|
||||
all: {
|
||||
src: ['static/webserver/public/css/*.css']
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
production: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
mangle: true
|
||||
},
|
||||
files: {
|
||||
'bin/webserver/public/dist/application.min.js': 'bin/webserver/public/dist/application.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
csslint: {
|
||||
options: {
|
||||
csslintrc: '.csslintrc'
|
||||
},
|
||||
all: {
|
||||
src: ['static/webserver/public/css/*.css']
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
production: {
|
||||
options: {
|
||||
mangle: true
|
||||
},
|
||||
files: {
|
||||
'bin/webserver/public/dist/application.min.js': 'bin/webserver/public/dist/application.js'
|
||||
}
|
||||
}
|
||||
},
|
||||
cssmin: {
|
||||
combine: {
|
||||
files: {
|
||||
'bin/webserver/public/css/restreamer.min.css': '<%= stylesheets %>'
|
||||
}
|
||||
}
|
||||
},
|
||||
ngAnnotate: {
|
||||
production: {
|
||||
files: {
|
||||
'bin/webserver/public/dist/application.js': '<%= compiledFrontendJS %>'
|
||||
}
|
||||
}
|
||||
},
|
||||
env: {
|
||||
test: {
|
||||
NODE_ENV: 'test'
|
||||
},
|
||||
secure: {
|
||||
NODE_ENV: 'secure'
|
||||
}
|
||||
}
|
||||
});
|
||||
cssmin: {
|
||||
combine: {
|
||||
files: {
|
||||
'bin/webserver/public/css/restreamer.min.css': '<%= stylesheets %>'
|
||||
}
|
||||
}
|
||||
},
|
||||
ngAnnotate: {
|
||||
production: {
|
||||
files: {
|
||||
'bin/webserver/public/dist/application.js': '<%= compiledFrontendJS %>'
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Load NPM tasks
|
||||
require('load-grunt-tasks')(grunt);
|
||||
/*
|
||||
Load NPM tasks
|
||||
*/
|
||||
require('load-grunt-tasks')(grunt);
|
||||
grunt.task.registerTask('loadConfig', 'Task that loads the config into a grunt option.', function() {
|
||||
grunt.config.set('es6Src', files.es6Src);
|
||||
grunt.config.set('compiledFrontendJS', files.compiledFrontendJS);
|
||||
grunt.config.set('stylesheets', files.stylesheets);
|
||||
});
|
||||
grunt.loadNpmTasks('grunt-shell');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy')
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('gruntify-eslint');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
/*
|
||||
Helper tasks to keep overview
|
||||
*/
|
||||
//css lint
|
||||
grunt.registerTask('lint', ['csslint', 'jshint']);
|
||||
//clear old bin folder and create new one
|
||||
*/
|
||||
// lint
|
||||
grunt.registerTask('lint', ['csslint', 'eslint']);
|
||||
// clear old bin folder and create new one
|
||||
grunt.registerTask('clearOldBuild', ['shell:removeOldBinFolder', 'shell:createBinFolder']);
|
||||
//install frontendlibraries (atm through bower)
|
||||
// install frontendlibraries (atm through bower)
|
||||
grunt.registerTask('installFrontendLibraries', ['shell:bower', 'shell:clappr']);
|
||||
//minify the frontend files
|
||||
// minify the frontend files
|
||||
grunt.registerTask('minifyFrontendFiles', ['cssmin', 'ngAnnotate', 'uglify']);
|
||||
|
||||
/*
|
||||
Build Tasks
|
||||
*/
|
||||
/*
|
||||
Build Tasks
|
||||
*/
|
||||
grunt.registerTask('build', ['loadConfig','clearOldBuild', 'shell:copyStatics', 'babel', 'minifyFrontendFiles', 'installFrontendLibraries']);
|
||||
grunt.registerTask('build-code', ['loadConfig', 'shell:copyStatics', 'babel', 'minifyFrontendFiles']);
|
||||
|
||||
/*
|
||||
Run Tasks
|
||||
*/
|
||||
//run current build in /bin
|
||||
// run current build in /bin
|
||||
grunt.registerTask('run', ['shell:start']);
|
||||
//rebuild and run
|
||||
// rebuild and run
|
||||
grunt.registerTask('run-clean', ['build', 'run']);
|
||||
//update code and run
|
||||
grunt.registerTask("run-update-code", ['loadConfig','babel','shell:copyStatics', 'minifyFrontendFiles', 'run'])
|
||||
// update code and run
|
||||
grunt.registerTask('run-update-code', ['loadConfig','babel','shell:copyStatics', 'minifyFrontendFiles', 'run'])
|
||||
};
|
||||
|
||||
25
package.json
25
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Restreamer",
|
||||
"version": "0.1.0-RC3",
|
||||
"version": "0.1.0-RC4",
|
||||
"description": "Allows you to do h.264 real-time video streaming on your website without a streaming provider",
|
||||
"author": "datarhei.org",
|
||||
"license": "Apache-2.0",
|
||||
@@ -8,54 +8,35 @@
|
||||
"start": "node ./bin/start"
|
||||
},
|
||||
"dependencies": {
|
||||
"app-root-path": "1.0.0",
|
||||
"async": "~1.5.0",
|
||||
"body-parser": "1.14.2",
|
||||
"bytes": "^2.1.0",
|
||||
"colors": "^1.1.2",
|
||||
"compression": "~1.6.0",
|
||||
"connect-flash": "^0.1.1",
|
||||
"cookie-parser": "1.4.0",
|
||||
"debug": "2.2.0",
|
||||
"dockerode": "2.2.8",
|
||||
"ejs": "2.3.4",
|
||||
"exec": "^0.2.1",
|
||||
"express": "4.13.3",
|
||||
"express-session": "^1.12.1",
|
||||
"fluent-ffmpeg": "git://github.com/christophjohannsdotter/node-fluent-ffmpeg#FIX_stderr-variable_of_infinite_growth",
|
||||
"i18n": "0.5.0",
|
||||
"fluent-ffmpeg": "git://github.com/datarhei/node-fluent-ffmpeg",
|
||||
"jsonschema": "^1.0.2",
|
||||
"moment-timezone": "^0.5.0",
|
||||
"morgan": "1.6.1",
|
||||
"node-json-db": "^0.5.1",
|
||||
"passport": "^0.3.2",
|
||||
"passport-local": "^1.0.0",
|
||||
"q": "1.4.1",
|
||||
"q-io": "~1.13.1",
|
||||
"request": "2.67.0",
|
||||
"sequent": "0.1.2",
|
||||
"serve-favicon": "2.3.0",
|
||||
"shortid": "2.2.4",
|
||||
"socket.io": "1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-preset-es2015": "^6.1.2",
|
||||
"chai": "^3.3.0",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-babel": "^6.0.0",
|
||||
"grunt-concurrent": "~2.1.0",
|
||||
"grunt-contrib-copy": "0.8",
|
||||
"grunt-contrib-csslint": "^0.5.0",
|
||||
"grunt-contrib-cssmin": "~0.14.0",
|
||||
"grunt-contrib-jshint": "~0.11.3",
|
||||
"grunt-contrib-uglify": "~0.11.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-env": "~0.4.1",
|
||||
"grunt-ng-annotate": "~1.0.1",
|
||||
"grunt-nodemon": "~0.4.1",
|
||||
"grunt-nw-builder": "^2.0.0",
|
||||
"grunt-shell": "^1.1.2",
|
||||
"jshint-stylish": "^2.0.0",
|
||||
"gruntify-eslint": "^1.3.0",
|
||||
"load-grunt-tasks": "~3.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
30
run.sh
30
run.sh
@@ -1,12 +1,36 @@
|
||||
#!/bin/bash
|
||||
cpu=$(uname -m | cut -c 1-3)
|
||||
if [ "${MODE}" == "RASPICAM" ] && [ "$cpu" == "arm" ];
|
||||
CPU_TYPE=$(uname -m | cut -c 1-3)
|
||||
if [ "${MODE}" == "RASPICAM" ] && [ "$CPU_TYPE" == "arm" ];
|
||||
then
|
||||
echo "/opt/vc/lib" > /etc/ld.so.conf.d/00-vmcs.conf
|
||||
ldconfig
|
||||
npm start &
|
||||
sleep 20
|
||||
NGINX_RUNNING=0
|
||||
until [ "$NGINX_RUNNING" = "1" ]; do
|
||||
if pgrep "nginx" > /dev/null
|
||||
then
|
||||
NGINX_RUNNING=1
|
||||
else
|
||||
NGINX_RUNNING=0
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
/opt/vc/bin/raspivid -t 0 -w 1280 -h 720 -fps 25 -b 500000 -o - | ffmpeg -i - -c copy -f flv rtmp://127.0.0.1:1935/live/raspicam.stream
|
||||
elif [ "${MODE}" == "USBCAM" ];
|
||||
then
|
||||
apt-get update && apt-get install -y v4l-utils libv4l-0
|
||||
npm start &
|
||||
NGINX_RUNNING=0
|
||||
until [ "$NGINX_RUNNING" = "1" ]; do
|
||||
if pgrep "nginx" > /dev/null
|
||||
then
|
||||
NGINX_RUNNING=1
|
||||
else
|
||||
NGINX_RUNNING=0
|
||||
sleep 5
|
||||
fi
|
||||
done
|
||||
ffmpeg -f v4l2 -r 25 -s 1280x720 -i /dev/video0 -f flv rtmp://127.0.0.1:1935/live/usb.stream
|
||||
else
|
||||
npm start
|
||||
fi
|
||||
|
||||
@@ -7,16 +7,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const moment = require("moment-timezone");
|
||||
require("colors");
|
||||
|
||||
const moment = require('moment-timezone');
|
||||
const LEVEL_ERROR = 1;
|
||||
const LEVEL_WARN = 2;
|
||||
const LEVEL_INFO = 3;
|
||||
const LEVEL_DEBUG = 4;
|
||||
|
||||
//set default timezone to use the timezone before the default values are
|
||||
process.env.TIMEZONE = process.env.TIMEZONE ? process.env.TIMEZONE : "Europe/Berlin";
|
||||
process.env.TIMEZONE = process.env.TIMEZONE ? process.env.TIMEZONE : 'Europe/Berlin';
|
||||
|
||||
/**
|
||||
* Class for logger
|
||||
@@ -51,11 +49,11 @@ class Logger {
|
||||
return;
|
||||
}
|
||||
if (context === false){
|
||||
context = "";
|
||||
context = '';
|
||||
}else{
|
||||
context = "(" + context + ")";
|
||||
context = '(' + context + ')';
|
||||
}
|
||||
var str = "[" + (moment().tz(process.env.TIMEZONE).format('DD-MM-YYYY HH:mm:ss.SSS')) + "] [" + type + "] " + message + " " + context;
|
||||
var str = '[' + (moment().tz(process.env.TIMEZONE).format('DD-MM-YYYY HH:mm:ss.SSS')) + '] [' + type + '] ' + message + ' ' + context;
|
||||
if (process.env.LOGGER_LEVEL === '4') {
|
||||
console.log(str[color]);
|
||||
} else {
|
||||
@@ -76,7 +74,7 @@ class Logger {
|
||||
alertGui = false;
|
||||
}
|
||||
if (process.env.LOGGER_LEVEL >= LEVEL_INFO) {
|
||||
return this.stdout(message, context, "INFO", "blue");
|
||||
return this.stdout(message, context, 'INFO', 'blue');
|
||||
}
|
||||
if (alertGui){
|
||||
//todo: if alertGui is activated on frontend and websocketcontroller, insert emit here
|
||||
@@ -96,9 +94,9 @@ class Logger {
|
||||
alertGui = false;
|
||||
}
|
||||
if (process.env.LOGGER_LEVEL >= LEVEL_WARN) {
|
||||
return this.stdout(message, context, "WARN", "orange");
|
||||
return this.stdout(message, context, 'WARN', 'orange');
|
||||
}
|
||||
if (alertGui){
|
||||
if (alertGui) {
|
||||
//todo: if alertGui is activated on frontend and websocketcontroller, insert emit here
|
||||
}
|
||||
}
|
||||
@@ -116,7 +114,7 @@ class Logger {
|
||||
alertGui = false;
|
||||
}
|
||||
if (process.env.LOGGER_LEVEL >= LEVEL_DEBUG) {
|
||||
return this.stdout(message, context, "DEBUG", "yellow");
|
||||
return this.stdout(message, context, 'DEBUG', 'yellow');
|
||||
}
|
||||
if (alertGui){
|
||||
//todo: if alertGui is activated on frontend and websocketcontroller, insert emit here
|
||||
@@ -137,7 +135,7 @@ class Logger {
|
||||
alertGui = false;
|
||||
}
|
||||
if (process.env.LOGGER_LEVEL >= LEVEL_ERROR) {
|
||||
return this.stdout(message, context, "ERROR", "red");
|
||||
return this.stdout(message, context, 'ERROR', 'red');
|
||||
}
|
||||
if (alertGui){
|
||||
//todo: if alertGui is activated on frontend and websocketcontroller, insert emit here
|
||||
|
||||
@@ -5,34 +5,25 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
const config = require("../../conf/live.json");
|
||||
const Logger = require("./Logger");
|
||||
const logger = new Logger("Restreamer");
|
||||
const WebsocketsController = require("./WebsocketController");
|
||||
const config = require('../../conf/live.json');
|
||||
const Logger = require('./Logger');
|
||||
const logger = new Logger('Restreamer');
|
||||
const WebsocketsController = require('./WebsocketController');
|
||||
const FfmpegCommand = require('fluent-ffmpeg');
|
||||
const Q = require("q");
|
||||
const Q = require('q');
|
||||
|
||||
/**
|
||||
* class Restreamer creates and manages streams through ffmpeg
|
||||
*/
|
||||
class Restreamer{
|
||||
|
||||
/**
|
||||
* generate output rtmp-path from config-file
|
||||
* @returns {string}
|
||||
*/
|
||||
static generateOutputRTMPPath (){
|
||||
var nginx = config.nginx.streaming;
|
||||
return "rtmp://" + nginx.ip + ":" + nginx.rtmp_port + nginx.rtmp_path + "live.stream";
|
||||
}
|
||||
|
||||
/**
|
||||
* generate output hls-path from config-file
|
||||
* @returns {string}
|
||||
*/
|
||||
static generateOutputHLSPath (){
|
||||
var nginx = config.nginx.streaming;
|
||||
return "rtmp://" + nginx.ip + ":" + nginx.rtmp_port + nginx.hls_path + "live.stream";
|
||||
return 'rtmp://' + nginx.ip + ':' + nginx.rtmp_port + nginx.rtmp_hls_path + 'live.stream';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,8 +31,8 @@ class Restreamer{
|
||||
* @returns {string}
|
||||
*/
|
||||
static generateSnapshotPath (){
|
||||
const path = require("path");
|
||||
return path.join(__dirname, "..", "webserver", "public", "images", "live.jpg");
|
||||
const path = require('path');
|
||||
return path.join(__dirname, '..', 'webserver', 'public', 'images', 'live.jpg');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,14 +42,14 @@ class Restreamer{
|
||||
static fetchSnapshot(firstSnapshot){
|
||||
|
||||
if (Restreamer.data.states.repeatToLocalNginx.type === 'connected' || firstSnapshot){
|
||||
var command = new FfmpegCommand(Restreamer.generateOutputRTMPPath());
|
||||
var command = new FfmpegCommand(Restreamer.generateOutputHLSPath());
|
||||
command.output(Restreamer.generateSnapshotPath());
|
||||
command.outputOption(config.ffmpeg.options.snapshot);
|
||||
command.on('error', (error)=> {
|
||||
logger.error("Error on fetching snapshot: " + error.toString());
|
||||
logger.error('Error on fetching snapshot: ' + error.toString());
|
||||
});
|
||||
command.on("end", () =>{
|
||||
logger.info("updated snapshot");
|
||||
command.on('end', () =>{
|
||||
logger.info('updated snapshot');
|
||||
Q.delay(process.env.SNAPSHOT_REFRESH_INTERVAL).then(function(){
|
||||
Restreamer.fetchSnapshot(false);
|
||||
});
|
||||
@@ -72,13 +63,13 @@ class Restreamer{
|
||||
* @param {string} processName
|
||||
*/
|
||||
static stopStream(processName){
|
||||
logger.info("stopStream " + processName);
|
||||
Restreamer.updateState(processName, "stopped");
|
||||
logger.info('stopStream ' + processName);
|
||||
Restreamer.updateState(processName, 'stopped');
|
||||
var processHasBeenSpawned = typeof Restreamer.data.processes[processName].kill === 'function';
|
||||
if(processHasBeenSpawned){
|
||||
Restreamer.data.processes[processName].kill();
|
||||
Restreamer.data.processes[processName] = {
|
||||
state: "not_connected"
|
||||
state: 'not_connected'
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -88,26 +79,26 @@ class Restreamer{
|
||||
* after the applicatoin has been killed or stuff
|
||||
*/
|
||||
static restoreFFMpegProcesses(){
|
||||
var JsonDB = require("node-json-db");
|
||||
var JsonDB = require('node-json-db');
|
||||
var db = new JsonDB(config.jsondb, true, false);
|
||||
try {
|
||||
Restreamer.data.addresses = db.getData("/addresses");
|
||||
Restreamer.data.states = db.getData("/states");
|
||||
Restreamer.data.userActions = db.getData("/userActions");
|
||||
Restreamer.data.addresses = db.getData('/addresses');
|
||||
Restreamer.data.states = db.getData('/states');
|
||||
Restreamer.data.userActions = db.getData('/userActions');
|
||||
//check if the srcAddress has been repeated to Local Nginx
|
||||
var repeatToLocalNginxIsConnected = Restreamer.data.states.repeatToLocalNginx.type === 'connected';
|
||||
var repeatToLocalNginxIsConnecting = Restreamer.data.states.repeatToLocalNginx.type === 'connecting';
|
||||
var repeatToOptionalOutputIsConnected = Restreamer.data.states.repeatToOptionalOutput.type === 'connected';
|
||||
var repeatToOptionalOutputIsConnecting = Restreamer.data.states.repeatToOptionalOutput.type === 'connecting';
|
||||
if (Restreamer.data.addresses.srcAddress && (!!repeatToLocalNginxIsConnected || !!repeatToLocalNginxIsConnecting)) {
|
||||
Restreamer.startStream(Restreamer.data.addresses.srcAddress, "repeatToLocalNginx");
|
||||
Restreamer.startStream(Restreamer.data.addresses.srcAddress, 'repeatToLocalNginx');
|
||||
}
|
||||
if (Restreamer.data.addresses.optionalOutputAddress && (!!repeatToOptionalOutputIsConnected || !!repeatToOptionalOutputIsConnecting)) {
|
||||
Restreamer.startStream(Restreamer.data.addresses.srcAddress, "repeatToOptionalOutput", Restreamer.data.addresses.optionalOutputAddress);
|
||||
Restreamer.startStream(Restreamer.data.addresses.srcAddress, 'repeatToOptionalOutput', Restreamer.data.addresses.optionalOutputAddress);
|
||||
}
|
||||
}
|
||||
catch(error){
|
||||
logger.error("error restoring ffmpeg process: " + error);
|
||||
logger.error('error restoring ffmpeg process: ' + error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,23 +106,23 @@ class Restreamer{
|
||||
* write JSON file for persistency
|
||||
*/
|
||||
static writeToDB(){
|
||||
var JsonDB = require("node-json-db");
|
||||
var JsonDB = require('node-json-db');
|
||||
var db = new JsonDB(config.jsondb, true, false);
|
||||
db.push("/", Restreamer.extractDataOfStreams());
|
||||
db.push('/', Restreamer.extractDataOfStreams());
|
||||
}
|
||||
|
||||
/**
|
||||
* send websocket event to GUI to update the state of the streams
|
||||
*/
|
||||
static updateStreamDataOnGui(){
|
||||
WebsocketsController.emitToNamespace("/", "updateStreamData", Restreamer.extractDataOfStreams());
|
||||
WebsocketsController.emitToNamespace('/', 'updateStreamData', Restreamer.extractDataOfStreams());
|
||||
}
|
||||
|
||||
/**
|
||||
* send websocket event to GUI to update the state of the streams
|
||||
*/
|
||||
static updateProgressOnGui(){
|
||||
WebsocketsController.emitToNamespace("/", "updateProgress", Restreamer.data.progresses);
|
||||
WebsocketsController.emitToNamespace('/', 'updateProgress', Restreamer.data.progresses);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,10 +150,10 @@ class Restreamer{
|
||||
var ffmpegOptions;
|
||||
if(data.streams.length > 1) {
|
||||
ffmpegOptions = config.ffmpeg.options.native_h264;
|
||||
logger.debug("Selected ffmpeg.option: native_h264");
|
||||
logger.debug(`Selected ffmpeg.option: native_h264`);
|
||||
}else{
|
||||
ffmpegOptions = config.ffmpeg.options.native_h264_soundless_aac;
|
||||
logger.debug("Selected ffmpeg.option: native_h264_soundless_aac");
|
||||
logger.debug(`Selected ffmpeg.option: native_h264_soundless_aac`);
|
||||
}
|
||||
for (let option of ffmpegOptions){
|
||||
ffmpegCommand.outputOption(option);
|
||||
@@ -181,7 +172,7 @@ class Restreamer{
|
||||
* @return {string} name of the new state
|
||||
*/
|
||||
static updateState(processName, state, message){
|
||||
logger.debug("Update state of '" + processName + "' from state '" + Restreamer.data.states[processName].type + "' to state '" + state + "'");
|
||||
logger.debug(`Update state of "${processName}" from state "${Restreamer.data.states[processName].type}" to state "${state}"`);
|
||||
Restreamer.data.states[processName] = {
|
||||
type: state,
|
||||
message: message
|
||||
@@ -198,7 +189,7 @@ class Restreamer{
|
||||
* @return {string} name of the new user action
|
||||
*/
|
||||
static updateUserAction(processName, action){
|
||||
logger.debug("Set useraction of '" + processName + "' from '" + Restreamer.data.userActions[processName] + "' to '" + action + "'");
|
||||
logger.debug(`Set useraction of "${processName}" from "${Restreamer.data.userActions[processName]}" to "${action}"`);
|
||||
Restreamer.data.userActions[processName] = action;
|
||||
Restreamer.writeToDB();
|
||||
Restreamer.updateStreamDataOnGui();
|
||||
@@ -214,7 +205,7 @@ class Restreamer{
|
||||
* @param {string} retryCounter current value of the retry counter (startStream retries automatically if anything fails)
|
||||
*/
|
||||
static startStream(src, streamType, optionalOutput, retryCounter){
|
||||
logger.info("start stream " + streamType);
|
||||
logger.info(`Start stream "${streamType}"`);
|
||||
|
||||
//update the retry counter for the streamType
|
||||
Restreamer.data.retryCounter[streamType] = typeof retryCounter === 'undefined' ? 0 : retryCounter;
|
||||
@@ -233,34 +224,32 @@ class Restreamer{
|
||||
|
||||
// check if the user has clicked 'stop' meanwhile, so the startStream process has to be skipped
|
||||
if (Restreamer.data.userActions[streamType] === 'stop'){
|
||||
logger.debug("skipping 'startStream' since 'stopped' has been clicked");
|
||||
logger.debug(`Skipping "startStream" since "stopped" has been clicked`);
|
||||
return;
|
||||
}
|
||||
|
||||
// update the state on the frontend
|
||||
Restreamer.updateState(streamType, "connecting");
|
||||
// update the state and src address on the frontend
|
||||
Restreamer.data.addresses.srcAddress = src;
|
||||
Restreamer.updateState(streamType, 'connecting');
|
||||
|
||||
|
||||
//repeat to local nginx server
|
||||
if (repeatToLocalNginx){
|
||||
command = new FfmpegCommand(src, {
|
||||
outputLineLimit: 50
|
||||
outputLineLimit: 1
|
||||
});
|
||||
|
||||
//add outputs to the ffmpeg stream
|
||||
addOutputPromise = Restreamer.addOutput(command, Restreamer.generateOutputRTMPPath())
|
||||
.then(function(){
|
||||
return Restreamer.addOutput(command, Restreamer.generateOutputHLSPath());
|
||||
})
|
||||
addOutputPromise = Restreamer.addOutput(command, Restreamer.generateOutputHLSPath())
|
||||
.catch(function(error){
|
||||
logger.error("error adding one or more outputs: " + error.toString);
|
||||
logger.error(`Error adding one or more outputs: ${error.toString}`);
|
||||
});
|
||||
|
||||
//repeat to optional output
|
||||
}else if (repeatToOptionalOutput){
|
||||
command = new FfmpegCommand(Restreamer.generateOutputRTMPPath(src, {
|
||||
outputLineLimit: 50
|
||||
}));
|
||||
command = new FfmpegCommand(Restreamer.generateOutputHLSPath(), {
|
||||
outputLineLimit: 1
|
||||
});
|
||||
Restreamer.data.addresses.optionalOutputAddress = optionalOutput;
|
||||
addOutputPromise = Restreamer.addOutput(command, optionalOutput);
|
||||
}
|
||||
@@ -273,12 +262,11 @@ class Restreamer{
|
||||
*/
|
||||
.on('start', function(commandLine){
|
||||
if (Restreamer.data.userActions[streamType] === 'stop'){
|
||||
logger.debug("skipping on 'start' event of ffmpeg command since 'stopped' has been clicked");
|
||||
logger.debug(`Skipping on "start" event of FFmpeg command since "stopped" has been clicked`);
|
||||
return;
|
||||
}else{
|
||||
logger.debug("FFMPEG spawned: " + commandLine);
|
||||
logger.debug(`FFmpeg spawned: ${commandLine}`);
|
||||
Restreamer.data.processes[streamType] = command;
|
||||
Restreamer.data.addresses.srcAddress = src;
|
||||
//fetch snapshot only, if repeated to local nginx
|
||||
if (repeatToLocalNginx){
|
||||
Restreamer.fetchSnapshot(true);
|
||||
@@ -290,20 +278,20 @@ class Restreamer{
|
||||
ERROR HANDLER
|
||||
*/
|
||||
.on('error', (error)=>{
|
||||
if (error.toString().indexOf("SIGKILL") > -1) {
|
||||
Restreamer.updateState(streamType, "disconnected");
|
||||
logger.info("FFMPEG streaming stopped for " + streamType);
|
||||
if (error.toString().indexOf('SIGKILL') > -1) {
|
||||
Restreamer.updateState(streamType, 'disconnected');
|
||||
logger.info(`FFmpeg streaming stopped for "${streamType}"`);
|
||||
}else{
|
||||
Restreamer.data.retryCounter[streamType]++;
|
||||
if (Restreamer.data.retryCounter[streamType] <= config.ffmpeg.monitor.retries) {
|
||||
if (Restreamer.data.userActions[streamType] === 'stop'){
|
||||
logger.debug("skipping retry since 'stopped' has been clicked");
|
||||
logger.debug(`Skipping retry since "stopped" has been clicked`);
|
||||
return;
|
||||
}else{
|
||||
Restreamer.updateState(streamType, "error", error.toString());
|
||||
logger.info("Retrying ffmpeg connection to " + src + " after " + config.ffmpeg.monitor.restart_wait + "ms");
|
||||
Restreamer.updateState(streamType, 'error', error.toString());
|
||||
logger.info(`Retrying FFmpeg connection to "${src}" after "${config.ffmpeg.monitor.restart_wait} ms`);
|
||||
Q.delay(config.ffmpeg.monitor.restart_wait).then(function () {
|
||||
logger.info("Retry ffmpeg connection to " + src + " retrycounter:" + Restreamer.data.retryCounter[streamType]);
|
||||
logger.info(`Retry FFmpeg connection to "${src}" retrycounter: ${Restreamer.data.retryCounter[streamType]}`);
|
||||
Restreamer.startStream(src, streamType, optionalOutput, Restreamer.data.retryCounter[streamType]);
|
||||
});
|
||||
}
|
||||
@@ -315,16 +303,16 @@ class Restreamer{
|
||||
STREAMING ENDED
|
||||
*/
|
||||
.on('end',()=>{
|
||||
Restreamer.updateState(streamType, "disconnected");
|
||||
Restreamer.updateState(streamType, 'disconnected');
|
||||
Restreamer.data.retryCounter[streamType]++;
|
||||
if (Restreamer.data.retryCounter[streamType] <= config.ffmpeg.monitor.retries) {
|
||||
if (Restreamer.data.userActions[streamType] === 'stop'){
|
||||
logger.debug("skipping retry since 'stopped' has been clicked");
|
||||
logger.debug(`Skipping retry since "stopped" has been clicked`);
|
||||
return;
|
||||
}else{
|
||||
logger.info("Retrying ffmpeg connection to " + src + " after " + config.ffmpeg.monitor.restart_wait + "ms");
|
||||
logger.info(`Retrying FFmpeg connection to "${src}" after "${config.ffmpeg.monitor.restart_wait}" ms`);
|
||||
Q.delay(config.ffmpeg.monitor.restart_wait).then(function () {
|
||||
logger.info("Retry ffmpeg connection to " + src + " retrycounter:" + Restreamer.data.retryCounter[streamType]);
|
||||
logger.info(`Retry FFmpeg connection to "${src}" retrycounter: ${Restreamer.data.retryCounter[streamType]}`);
|
||||
Restreamer.startStream(src, streamType, optionalOutput, Restreamer.data.retryCounter[streamType]);
|
||||
});
|
||||
}
|
||||
@@ -336,21 +324,21 @@ class Restreamer{
|
||||
*/
|
||||
var progressMethod = function (progress){
|
||||
if (Restreamer.data.states[streamType].type === 'connecting'){
|
||||
Restreamer.updateState(streamType, "connected");
|
||||
Restreamer.updateState(streamType, 'connected');
|
||||
}
|
||||
Restreamer.data.progresses[streamType] = progress;
|
||||
Restreamer.updateProgressOnGui();
|
||||
command.removeAllListeners("progress");
|
||||
command.removeAllListeners('progress');
|
||||
};
|
||||
command.on('progress', progressMethod);
|
||||
setInterval(()=>{
|
||||
if(command.listeners("progress").length === 0) {
|
||||
if(command.listeners('progress').length === 0) {
|
||||
command.on('progress', progressMethod);
|
||||
}
|
||||
}, 1000);
|
||||
command.exec();
|
||||
}).catch(function(error){
|
||||
logger.error("Error starting ffmpeg command: " + error.toString());
|
||||
logger.error(`Error starting FFmpeg command: ${error.toString()}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -358,20 +346,20 @@ class Restreamer{
|
||||
* binded on app-start to bind websocketevents of Restreamer
|
||||
*/
|
||||
static bindWebsocketEvents(){
|
||||
WebsocketsController.addOnConnectionEventToNamespace("/", function(socket){
|
||||
socket.on("startStream", (options)=> {
|
||||
Restreamer.updateUserAction(options.streamType, "start");
|
||||
WebsocketsController.addOnConnectionEventToNamespace('/', function(socket){
|
||||
socket.on('startStream', (options)=> {
|
||||
Restreamer.updateUserAction(options.streamType, 'start');
|
||||
Restreamer.startStream(options.src, options.streamType, options.optionalOutput);
|
||||
});
|
||||
socket.on("stopStream", (streamType)=>{
|
||||
Restreamer.updateUserAction(streamType, "stop");
|
||||
socket.on('stopStream', (streamType)=>{
|
||||
Restreamer.updateUserAction(streamType, 'stop');
|
||||
Restreamer.stopStream(streamType);
|
||||
});
|
||||
socket.on("checkForAppUpdates", ()=>{
|
||||
const app = require("../webserver/app");
|
||||
socket.emit("checkForAppUpdatesResult", app.get("updateAvailable"));
|
||||
socket.on('checkForAppUpdates', ()=>{
|
||||
const app = require('../webserver/app');
|
||||
socket.emit('checkForAppUpdatesResult', app.get('updateAvailable'));
|
||||
});
|
||||
socket.on("checkStates", Restreamer.updateStreamDataOnGui);
|
||||
socket.on('checkStates', Restreamer.updateStreamDataOnGui);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -400,26 +388,26 @@ Restreamer.data = {
|
||||
},
|
||||
states: {
|
||||
repeatToLocalNginx: {
|
||||
type: "disconnected",
|
||||
message: ""
|
||||
type: 'disconnected',
|
||||
message: ''
|
||||
},
|
||||
repeatToOptionalOutput: {
|
||||
type: "disconnected",
|
||||
message: ""
|
||||
type: 'disconnected',
|
||||
message: ''
|
||||
}
|
||||
},
|
||||
userActions: {
|
||||
repeatToLocalNginx: "start",
|
||||
repeatToOptionalOutput: "start"
|
||||
userActions: {
|
||||
repeatToLocalNginx: 'start',
|
||||
repeatToOptionalOutput: 'start'
|
||||
},
|
||||
processes: {
|
||||
//overwritten with ffmpeg process if stream has been started
|
||||
repeatToLocalNginx: {
|
||||
state: "not_connected"
|
||||
state: 'not_connected'
|
||||
},
|
||||
//overwritten with ffmpeg process if stream has been started
|
||||
repeatToOptionalOutput: {
|
||||
state: "not_connected"
|
||||
state: 'not_connected'
|
||||
}
|
||||
},
|
||||
progresses: {
|
||||
@@ -429,8 +417,8 @@ Restreamer.data = {
|
||||
repeatToOptionalOutput: {}
|
||||
},
|
||||
addresses: {
|
||||
srcAddress: "",
|
||||
optionalOutputAddress: ""
|
||||
srcAddress: '',
|
||||
optionalOutputAddress: ''
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const async = require("async");
|
||||
const Logger = require("../classes/Logger");
|
||||
const logger = new Logger("WebsocketsController");
|
||||
const Logger = require('../classes/Logger');
|
||||
const logger = new Logger('WebsocketsController');
|
||||
|
||||
|
||||
/**
|
||||
@@ -26,9 +24,9 @@ class WebsocketsController {
|
||||
* @param {object} data data to emit to the client event listener
|
||||
*/
|
||||
static emitToNamespace(namespace, event, data) {
|
||||
var app = require("../webserver/app");
|
||||
app.get("websocketsReady").promise.then(function (io) {
|
||||
logger.debug("websocket got event " + event + " to namespace " + namespace + "","Websockets");
|
||||
var app = require('../webserver/app');
|
||||
app.get('websocketsReady').promise.then(function (io) {
|
||||
logger.debug('websocket got event ' + event + ' to namespace ' + namespace + '','Websockets');
|
||||
io.of(namespace).emit(event, data);
|
||||
});
|
||||
}
|
||||
@@ -39,10 +37,10 @@ class WebsocketsController {
|
||||
* @param {function} callback
|
||||
*/
|
||||
static addOnConnectionEventToNamespace(namespace, callback) {
|
||||
var app = require("../webserver/app");
|
||||
app.get("websocketsReady").promise.then(function (io) {
|
||||
var app = require('../webserver/app');
|
||||
app.get('websocketsReady').promise.then(function (io) {
|
||||
var nsp = io.of(namespace);
|
||||
nsp.on("connection", function (socket) {
|
||||
nsp.on('connection', function (socket) {
|
||||
callback(socket);
|
||||
});
|
||||
});
|
||||
@@ -52,15 +50,15 @@ class WebsocketsController {
|
||||
* bind default events of all classes that are using websocketevents
|
||||
*/
|
||||
static bindDefaultEvents() {
|
||||
WebsocketsController.addOnConnectionEventToNamespace("/", function (socket) {
|
||||
socket.on("testConnection", (options)=> {
|
||||
var packageJson = require("../../package.json");
|
||||
socket.emit("connection", packageJson.version);
|
||||
WebsocketsController.addOnConnectionEventToNamespace('/', function (socket) {
|
||||
socket.on('getVersion', (options)=> {
|
||||
var packageJson = require('../../package.json');
|
||||
socket.emit('version', packageJson.version);
|
||||
});
|
||||
var app = require("../webserver/app");
|
||||
socket.emit("publicIp", app.get("publicIp"));
|
||||
var app = require('../webserver/app');
|
||||
socket.emit('publicIp', app.get('publicIp'));
|
||||
});
|
||||
require("./Restreamer").bindWebsocketEvents();
|
||||
require('./Restreamer').bindWebsocketEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
141
src/start.js
141
src/start.js
@@ -10,59 +10,60 @@
|
||||
/*
|
||||
requirements
|
||||
*/
|
||||
const Logger = require("./classes/Logger");
|
||||
const logger = new Logger("start");
|
||||
const EnvVar = require("./classes/EnvVar");
|
||||
const packageJson = require("../package.json");
|
||||
const Logger = require('./classes/Logger');
|
||||
const logger = new Logger('start');
|
||||
const EnvVar = require('./classes/EnvVar');
|
||||
const packageJson = require('../package.json');
|
||||
const app = require('./webserver/app');
|
||||
const config = require('../conf/live.json');
|
||||
const Q = require("q");
|
||||
const Q = require('q');
|
||||
|
||||
if(process.env.CREATE_HEAPDUMPS === 'true'){
|
||||
const heapdump = require('heapdump');
|
||||
setInterval(function(){
|
||||
heapdump.writeSnapshot('heapdump/' + Date.now() + '.heapsnapshot');
|
||||
logger.info(`CREATE HEAPDUMP`);
|
||||
heapdump.writeSnapshot('/restreamer/heapdump/' + Date.now() + '.heapsnapshot');
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
if (typeof process.env.LOGGER_LEVEL === 'undefined'){
|
||||
process.env.LOGGER_LEVEL = "3";
|
||||
process.env.LOGGER_LEVEL = '3';
|
||||
}
|
||||
|
||||
/*
|
||||
init simple_streamer with environments
|
||||
*/
|
||||
logger.info(" _ _ _ _ ", false);
|
||||
logger.info(" __| | __ _| |_ __ _ _ __| |___ ___(_)", false);
|
||||
logger.info(" / _ |/ _ | __/ _ | __| _ |/ _ | |", false);
|
||||
logger.info("| (_| | (_| | || (_| | | | | | | __/| |", false);
|
||||
logger.info("|_____|_____|_||_____|_| |_| |_|____||_|", false);
|
||||
logger.info("", false);
|
||||
logger.info("Restreamer v" + packageJson.version, false);
|
||||
logger.info("", false);
|
||||
logger.info("ENVIRONMENTS", false);
|
||||
logger.info("More informations in our Docs", false);
|
||||
logger.info("", false);
|
||||
logger.info(' _ _ _ _ ', false);
|
||||
logger.info(' __| | __ _| |_ __ _ _ __| |___ ___(_)', false);
|
||||
logger.info(' / _ |/ _ | __/ _ | __| _ |/ _ | |', false);
|
||||
logger.info('| (_| | (_| | || (_| | | | | | | __/| |', false);
|
||||
logger.info('|_____|_____|_||_____|_| |_| |_|____||_|', false);
|
||||
logger.info('', false);
|
||||
logger.info('Restreamer v' + packageJson.version, false);
|
||||
logger.info('', false);
|
||||
logger.info('ENVIRONMENTS', false);
|
||||
logger.info('More informations in our Docs', false);
|
||||
logger.info('', false);
|
||||
|
||||
// define environment variables
|
||||
var env_vars = [];
|
||||
env_vars.push(new EnvVar("NODEJS_PORT", false, 3000, "Webserver port of application"));
|
||||
env_vars.push(new EnvVar("LOGGER_LEVEL", true, "3", "Logger level to defined, what should be logged"));
|
||||
env_vars.push(new EnvVar("TIMEZONE", true, "Europe/Berlin", "Set the timezone"));
|
||||
env_vars.push(new EnvVar("SNAPSHOT_REFRESH_INTERVAL", false, 60000, "Interval to create a new Snapshot"));
|
||||
env_vars.push(new EnvVar("CREATE_HEAPDUMPS", false, "false", "Create Heapdumps of application"));
|
||||
env_vars.push(new EnvVar('NODEJS_PORT', false, 3000, 'Webserver port of application'));
|
||||
env_vars.push(new EnvVar('LOGGER_LEVEL', true, '3', 'Logger level to defined, what should be logged'));
|
||||
env_vars.push(new EnvVar('TIMEZONE', true, 'Europe/Berlin', 'Set the timezone'));
|
||||
env_vars.push(new EnvVar('SNAPSHOT_REFRESH_INTERVAL', false, 60000, 'Interval to create a new Snapshot'));
|
||||
env_vars.push(new EnvVar('CREATE_HEAPDUMPS', false, 'false', 'Create Heapdumps of application'));
|
||||
|
||||
// manage all environments
|
||||
var killProcess = false;
|
||||
for (let e of env_vars){
|
||||
if(typeof process.env[e.name] !== 'undefined'){
|
||||
logger.info("ENV \"" + e.name + "=" + process.env[e.name] + "\", " + e.description);
|
||||
logger.info(`ENV "${e.name}=${process.env[e.name]}"`, e.description);
|
||||
}else if(e.required === true){
|
||||
logger.error("No value set for env " + e.name + ", but it is required");
|
||||
logger.error(`No value set for env "${e.name}", but it is required`);
|
||||
killProcess = true;
|
||||
}else{
|
||||
process.env[e.name] = e.defaultValue;
|
||||
logger.info("ENV \"" + e.name + "=" + process.env[e.name] + "\", set to default-value!, " + e.description);
|
||||
logger.info(`ENV "${e.name}=${process.env[e.name]}", set to default-value!`, e.description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,68 +73,68 @@ if(killProcess === true){
|
||||
process.exit();
|
||||
}, 500);
|
||||
}
|
||||
logger.info("", false);
|
||||
logger.info('', false);
|
||||
|
||||
/**
|
||||
* check if the data from jsondb is valid against the Restreamer jsondb schema
|
||||
* @returns {promise}
|
||||
*/
|
||||
const checkJsonDb = function(){
|
||||
logger.info("checking jsondb file...");
|
||||
logger.info(`Checking jsondb file...`);
|
||||
var Validator = require('jsonschema').Validator;
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var schemadata;
|
||||
var dbdata;
|
||||
var deferred = Q.defer();
|
||||
|
||||
var readSchema = Q.nfcall(fs.readFile, path.join(__dirname, "../", "conf", "jsondb_v1_schema.json"));
|
||||
var readDBFile = Q.nfcall(fs.readFile, path.join(__dirname, "../", "db", "v1.json"));
|
||||
var readSchema = Q.nfcall(fs.readFile, path.join(__dirname, '../', 'conf', 'jsondb_v1_schema.json'));
|
||||
var readDBFile = Q.nfcall(fs.readFile, path.join(__dirname, '../', 'db', 'v1.json'));
|
||||
|
||||
readSchema
|
||||
.then(function(s){
|
||||
schemadata = JSON.parse(s.toString("utf8"));
|
||||
return readDBFile;
|
||||
})
|
||||
.then(function(d){
|
||||
dbdata = JSON.parse(d.toString("utf8"));
|
||||
var v = new Validator();
|
||||
var instance = dbdata;
|
||||
var schema = schemadata;
|
||||
var validateResult = v.validate(instance, schema);
|
||||
if (validateResult.errors.length > 0){
|
||||
logger.debug("validation error of v1.db: " + JSON.stringify(validateResult.errors));
|
||||
.then(function(s){
|
||||
schemadata = JSON.parse(s.toString('utf8'));
|
||||
return readDBFile;
|
||||
})
|
||||
.then(function(d){
|
||||
dbdata = JSON.parse(d.toString('utf8'));
|
||||
var v = new Validator();
|
||||
var instance = dbdata;
|
||||
var schema = schemadata;
|
||||
var validateResult = v.validate(instance, schema);
|
||||
if (validateResult.errors.length > 0){
|
||||
logger.debug(`Validation error of v1.db: ${JSON.stringify(validateResult.errors)}`);
|
||||
throw new Error(JSON.stringify(validateResult.errors));
|
||||
}else{
|
||||
logger.debug("v1.db is valid");
|
||||
}else{
|
||||
logger.debug(`"v1.db" is valid`);
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
}).catch(function(error){
|
||||
logger.debug("error reading v1.db:" + error.toString());
|
||||
logger.debug(`Error reading "v1.db": ${error.toString()}`);
|
||||
var defaultStructure = {
|
||||
addresses: {
|
||||
srcAddress: "",
|
||||
optionalOutputAddress: ""
|
||||
srcAddress: '',
|
||||
optionalOutputAddress: ''
|
||||
},
|
||||
states: {
|
||||
repeatToLocalNginx: {
|
||||
type: "stopped"
|
||||
type: 'stopped'
|
||||
},
|
||||
repeatToOptionalOutput: {
|
||||
type: "stopped"
|
||||
type: 'stopped'
|
||||
}
|
||||
},
|
||||
userActions:{
|
||||
repeatToLocalNginx: "stop",
|
||||
repeatToOptionalOutput: "stop"
|
||||
repeatToLocalNginx: 'stop',
|
||||
repeatToOptionalOutput: 'stop'
|
||||
},
|
||||
progresses: {
|
||||
repeatToLocalNginx: {},
|
||||
repeatToOptionalOutput: {}
|
||||
}
|
||||
};
|
||||
fs.writeFileSync(path.join(__dirname, "../", "db", "v1.json"), JSON.stringify(defaultStructure));
|
||||
fs.writeFileSync(path.join(__dirname, '../', 'db', 'v1.json'), JSON.stringify(defaultStructure));
|
||||
deferred.resolve();
|
||||
});
|
||||
return deferred.promise;
|
||||
@@ -144,7 +145,7 @@ const checkJsonDb = function(){
|
||||
* @returns {promise}
|
||||
*/
|
||||
const startNginxRTMPServer = function startNginxRTMPServer(){
|
||||
logger.info("starting nginx server....", "start.nginx");
|
||||
logger.info(`Starting nginx server...`, 'start.nginx');
|
||||
var deferred = Q.defer();
|
||||
const command = config.nginx.exec;
|
||||
const spawn = require('child_process').spawn;
|
||||
@@ -158,15 +159,15 @@ const startNginxRTMPServer = function startNginxRTMPServer(){
|
||||
* @returns {promise}
|
||||
*/
|
||||
const startWebserver = function startWebserver(){
|
||||
logger.info("starting webserver...");
|
||||
logger.info(`Starting webserver...`);
|
||||
var deferred = Q.defer();
|
||||
app.set('port', process.env.NODEJS_PORT);
|
||||
var server = app.listen(app.get('port'), function () {
|
||||
require("./classes/WebsocketController").bindDefaultEvents();
|
||||
app.set("io", require('socket.io')(server));
|
||||
app.set("server", server.address());
|
||||
app.get("websocketsReady").resolve(app.get("io")); //promise to determine if the webserver has been started to avoid ws binding before
|
||||
logger.info("Webserver running on port " + process.env.NODEJS_PORT, "start.webserver");
|
||||
require('./classes/WebsocketController').bindDefaultEvents();
|
||||
app.set('io', require('socket.io')(server));
|
||||
app.set('server', server.address());
|
||||
app.get('websocketsReady').resolve(app.get('io')); //promise to determine if the webserver has been started to avoid ws binding before
|
||||
logger.info(`Webserver running on port ${process.env.NODEJS_PORT}`, 'start.webserver');
|
||||
deferred.resolve(server.address().port);
|
||||
});
|
||||
return deferred.promise;
|
||||
@@ -176,13 +177,13 @@ const startWebserver = function startWebserver(){
|
||||
* get the public ip of the server, on that the Restreamer is running
|
||||
*/
|
||||
const getPublicIp = function(){
|
||||
logger.info("Getting public ip...", "start.publicip");
|
||||
var exec = require("child_process").exec;
|
||||
exec("public-ip", (err, stdout, stderr)=> {
|
||||
logger.info(`Getting public ip...`, 'start.publicip');
|
||||
var exec = require('child_process').exec;
|
||||
exec('public-ip', (err, stdout, stderr)=> {
|
||||
if (err){
|
||||
console.log(err);
|
||||
logger.error(err);
|
||||
}
|
||||
app.set("publicIp", stdout.split("\n")[0] );
|
||||
app.set('publicIp', stdout.split('\n')[0] );
|
||||
});
|
||||
};
|
||||
|
||||
@@ -191,9 +192,9 @@ const getPublicIp = function(){
|
||||
* @returns {promise}
|
||||
*/
|
||||
const restoreFFMPEGProcesses = function(){
|
||||
logger.info("Restoring ffmpeg processes...", "start.restore");
|
||||
logger.info(`Restoring FFmpeg processes...`, 'start.restore');
|
||||
var deferred = Q.defer();
|
||||
const Restreamer = require("./classes/Restreamer");
|
||||
const Restreamer = require('./classes/Restreamer');
|
||||
Restreamer.restoreFFMpegProcesses();
|
||||
deferred.resolve();
|
||||
return deferred.promise;
|
||||
@@ -209,7 +210,7 @@ startNginxRTMPServer()
|
||||
.then(restoreFFMPEGProcesses)
|
||||
.then(getPublicIp)
|
||||
.catch(function(error){
|
||||
logger.error("error starting webserver and nginx for application: " + error);
|
||||
logger.error(`Error starting webserver and nginx for application: ${error}`);
|
||||
setTimeout(()=> {
|
||||
process.exit();
|
||||
}, 500);
|
||||
|
||||
@@ -17,26 +17,25 @@ const flash = require('connect-flash');
|
||||
//express
|
||||
const express = require('express');
|
||||
const session = require('express-session');
|
||||
const i18n = require('i18n');
|
||||
const favicon = require('serve-favicon');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser');
|
||||
const compression = require("compression");
|
||||
const compression = require('compression');
|
||||
|
||||
//other
|
||||
const path = require('path');
|
||||
const Q = require("q");
|
||||
const request = require("request");
|
||||
const crypto = require("crypto");
|
||||
const Q = require('q');
|
||||
const request = require('request');
|
||||
const crypto = require('crypto');
|
||||
|
||||
/*
|
||||
modules
|
||||
*/
|
||||
const packageJson = require("../../package.json");
|
||||
const Logger = require("../classes/Logger");
|
||||
const logger = new Logger("Webserver");
|
||||
const packageJson = require('../../package.json');
|
||||
const Logger = require('../classes/Logger');
|
||||
const logger = new Logger('Webserver');
|
||||
//middlewares
|
||||
const expressLogger = require("./middlewares/expressLogger");
|
||||
const expressLogger = require('./middlewares/expressLogger');
|
||||
|
||||
//create express app
|
||||
const app = express();
|
||||
@@ -49,27 +48,17 @@ app.use(session({
|
||||
resave: false,
|
||||
saveUninitialized: true})); // session secret
|
||||
|
||||
//create promise for "websockets ready"
|
||||
app.set("websocketsReady", Q.defer());
|
||||
//create promise for 'websockets ready'
|
||||
app.set('websocketsReady', Q.defer());
|
||||
|
||||
//add passport auth
|
||||
app.use(passport.initialize());
|
||||
app.use(flash()); // use connect-flash for flash messages stored in session
|
||||
app.use(passport.session()); // persistent login sessions
|
||||
require("./config/passport")(passport);
|
||||
|
||||
//configure i18n
|
||||
i18n.configure({
|
||||
locales:['en','de'],
|
||||
directory: __dirname + '/locales',
|
||||
defaultLocale: 'en',
|
||||
cookie: 'locale',
|
||||
updateFiles: false
|
||||
});
|
||||
require('./config/passport')(passport);
|
||||
|
||||
//configure express app
|
||||
app.use(favicon(__dirname + '/public/images/favicon.ico'));
|
||||
app.use(i18n.init);
|
||||
app.use(bodyParser.json());
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
@@ -78,7 +67,7 @@ app.use(cookieParser());
|
||||
app.use(compression());
|
||||
app.set('json spaces', 4);
|
||||
|
||||
require("./controllers/index")(app, passport);
|
||||
require('./controllers/index')(app, passport);
|
||||
app.use('/', expressLogger);
|
||||
|
||||
// catch 404 and forward to error handler
|
||||
@@ -98,7 +87,7 @@ app.use(function(err, req, res, next) {
|
||||
});
|
||||
|
||||
var checkForAppUpdates = function(){
|
||||
logger.debug("checking app for updates...");
|
||||
logger.debug(`Checking app for updates...`);
|
||||
const url = 'http://datarhei.org/apps.json';
|
||||
request(url, function (error, response, body) {
|
||||
if (!error && response.statusCode === 200) {
|
||||
@@ -106,15 +95,15 @@ var checkForAppUpdates = function(){
|
||||
var updateAvailable = false;
|
||||
if (updateCheck.restreamer.version === packageJson.version){
|
||||
updateAvailable = false;
|
||||
logger.debug("checking app for updates successful. update is not available (remote: " + updateCheck.restreamer.version + ", local: " + packageJson.version + ")");
|
||||
logger.debug(`Checking app for updates successful. Update is not available (remote: ${updateCheck.restreamer.version}, local: ${packageJson.version})`);
|
||||
}else{
|
||||
updateAvailable = updateCheck.restreamer.version;
|
||||
logger.debug("checking app for updates successful. update is available (remote: " + updateCheck.restreamer.version + ", local: " + packageJson.version + ")");
|
||||
logger.debug(`Checking app for updates successful. Update is available (remote: ${updateCheck.restreamer.version}, local: ${packageJson.version})`);
|
||||
}
|
||||
logger.info("checking app for updates successful.");
|
||||
app.set("updateAvailable", updateAvailable);
|
||||
logger.info(`Checking app for updates successful`);
|
||||
app.set('updateAvailable', updateAvailable);
|
||||
} else {
|
||||
logger.info("Update check failed", false);
|
||||
logger.info(`Update check failed`, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
var LocalStrategy = require('passport-local').Strategy;
|
||||
var auth = require("../../../conf/live.json").auth;
|
||||
var auth = require('../../../conf/live.json').auth;
|
||||
|
||||
if (process.env.RESTREAMER_USERNAME) {
|
||||
var username = process.env.RESTREAMER_USERNAME;
|
||||
@@ -30,19 +30,19 @@ module.exports = (passport) => {
|
||||
done(null, user);
|
||||
});
|
||||
passport.use('local-login', new LocalStrategy({
|
||||
usernameField : 'user',
|
||||
passwordField : 'pass',
|
||||
passReqToCallback : true // allows us to pass back the entire request to the callback
|
||||
},
|
||||
function(req, user, pass, done) { // callback with user and pass from our form
|
||||
if (user === username && pass === password){
|
||||
//login success
|
||||
/*
|
||||
WEBSOCKET SECURITY HERE
|
||||
*/
|
||||
done(null, auth);
|
||||
}else{
|
||||
done(null, false, req.flash("wrong password or wrong user"));
|
||||
}
|
||||
}));
|
||||
usernameField: 'user',
|
||||
passwordField: 'pass',
|
||||
passReqToCallback: true // allows us to pass back the entire request to the callback
|
||||
},
|
||||
function(req, user, pass, done) { // callback with user and pass from our form
|
||||
if (user === username && pass === password){
|
||||
//login success
|
||||
/*
|
||||
WEBSOCKET SECURITY HERE
|
||||
*/
|
||||
done(null, auth);
|
||||
}else{
|
||||
done(null, false, req.flash('wrong password or wrong user'));
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -5,28 +5,28 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
const express = require("express");
|
||||
const path = require("path");
|
||||
const Restreamer = require("../../classes/Restreamer");
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
const Restreamer = require('../../classes/Restreamer');
|
||||
module.exports = (app, passport) => {
|
||||
|
||||
//static paths
|
||||
app.use("/css", express.static(path.join(__dirname, '../', 'public', 'css')));
|
||||
app.use("/libs", express.static(path.join(__dirname, '../', 'public', 'libs')));
|
||||
app.use("/dist", express.static(path.join(__dirname, '../', 'public', 'dist')));
|
||||
app.use("/help", express.static( path.join(__dirname, '../', 'public', 'help')));
|
||||
app.use("/images", express.static( path.join(__dirname, '../', 'public', 'images')));
|
||||
app.use("/locales", express.static(path.join(__dirname, '../', 'public', 'locales')));
|
||||
app.use("/crossdomain.xml",express.static( path.join(__dirname, '../', 'public', 'crossdomain.xml')));
|
||||
app.use("/player.html", express.static(path.join(__dirname, '../', 'public', 'player.html')));
|
||||
app.get("/main.html", (req, res)=>{
|
||||
app.use('/css', express.static(path.join(__dirname, '../', 'public', 'css')));
|
||||
app.use('/libs', express.static(path.join(__dirname, '../', 'public', 'libs')));
|
||||
app.use('/dist', express.static(path.join(__dirname, '../', 'public', 'dist')));
|
||||
app.use('/help', express.static( path.join(__dirname, '../', 'public', 'help')));
|
||||
app.use('/images', express.static( path.join(__dirname, '../', 'public', 'images')));
|
||||
app.use('/locales', express.static(path.join(__dirname, '../', 'public', 'locales')));
|
||||
app.use('/crossdomain.xml',express.static( path.join(__dirname, '../', 'public', 'crossdomain.xml')));
|
||||
app.use('/player.html', express.static(path.join(__dirname, '../', 'public', 'player.html')));
|
||||
app.get('/main.html', (req, res)=>{
|
||||
if (req.isAuthenticated()){
|
||||
res.sendFile(path.join(__dirname, '../', 'public', 'main.html'));
|
||||
} else {
|
||||
res.sendFile(path.join(__dirname, '../', 'public', 'login.html'));
|
||||
}
|
||||
});
|
||||
app.get("/", (req, res)=>{
|
||||
app.get('/', (req, res)=>{
|
||||
res.sendFile(path.join(__dirname, '../', 'public', 'index.html'));
|
||||
});
|
||||
/* Handle Login POST */
|
||||
@@ -37,19 +37,19 @@ module.exports = (app, passport) => {
|
||||
failureFlash : true
|
||||
})
|
||||
);
|
||||
app.get("/logout", (req, res)=>{
|
||||
app.get('/logout', (req, res)=>{
|
||||
req.logout();
|
||||
res.redirect("/");
|
||||
res.redirect('/');
|
||||
});
|
||||
//small get.api
|
||||
app.get("/v1/states", (req, res)=>{
|
||||
app.get('/v1/states', (req, res)=>{
|
||||
var states = Restreamer.data.states;
|
||||
res.json({
|
||||
repeat_to_local_nginx: states.repeatToLocalNginx,
|
||||
repeat_to_optional_output: states.repeatToOptionalOutput
|
||||
});
|
||||
});
|
||||
app.get("/v1/progresses", (req, res)=>{
|
||||
app.get('/v1/progresses', (req, res)=>{
|
||||
var progresses = Restreamer.data.progresses;
|
||||
res.json({
|
||||
repeat_to_local_nginx: {
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
'use strict';
|
||||
|
||||
const bytes = require('bytes');
|
||||
const Logger = require("../../classes/Logger");
|
||||
const logger = new Logger("webserver");
|
||||
const Logger = require('../../classes/Logger');
|
||||
const logger = new Logger('webserver');
|
||||
|
||||
module.exports = (req, res, next)=>{
|
||||
req._startTime = new Date();
|
||||
@@ -24,9 +24,9 @@ module.exports = (req, res, next)=>{
|
||||
var duration = ('new Date' - 'req._startTime');
|
||||
var url = (req.originalUrl || req.url);
|
||||
var method = req.method;
|
||||
logger.debug(method + " \"" + url + "\" " + code + " " + duration + " " + req.ip + " " + len, "Webserver");
|
||||
logger.debug(method + ' \'' + url + '\' ' + code + ' ' + duration + ' ' + req.ip + ' ' + len, 'Webserver');
|
||||
};
|
||||
res.on("finish", log);
|
||||
res.on("close", log);
|
||||
res.on('finish', log);
|
||||
res.on('close', log);
|
||||
next();
|
||||
};
|
||||
|
||||
@@ -17,12 +17,12 @@ datarheiApp.config(function ($translateProvider) {
|
||||
});
|
||||
|
||||
$translateProvider.useSanitizeValueStrategy('escape');
|
||||
$translateProvider.preferredLanguage("en_US");
|
||||
$translateProvider.preferredLanguage('en_US');
|
||||
});
|
||||
|
||||
datarheiApp.config(function($stateProvider, $urlRouterProvider){
|
||||
// For any unmatched url, redirect to /
|
||||
$urlRouterProvider.otherwise("/");
|
||||
$urlRouterProvider.otherwise('/');
|
||||
|
||||
$stateProvider
|
||||
.state('main',{
|
||||
@@ -43,7 +43,7 @@ datarheiApp.config(function($stateProvider, $urlRouterProvider){
|
||||
datarheiApp.filter('inArray', function($filter){
|
||||
return function(list, arrayFilter, element){
|
||||
if(arrayFilter){
|
||||
return $filter("filter")(list, function(listItem){
|
||||
return $filter('filter')(list, function(listItem){
|
||||
return arrayFilter.indexOf(listItem[element]) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ window.datarheiApp.controller('languageCtrl',['$scope','$translate', function($s
|
||||
$scope.switchLanguage = function(locale){
|
||||
$scope.currentLocale = locale;
|
||||
$translate.use(locale).then(function(){
|
||||
window.Logger.log("INFO", "Switched language to " + locale);
|
||||
window.Logger.log('INFO', 'Switched language to ' + locale);
|
||||
}, function(error){
|
||||
window.Logger.error("INFO", "Switching language to " + locale + " failed: " + error);
|
||||
window.Logger.error('INFO', 'Switching language to ' + locale + ' failed: ' + error);
|
||||
});
|
||||
};
|
||||
$scope.langIs = function(locale){
|
||||
|
||||
@@ -14,109 +14,133 @@
|
||||
window.datarheiApp.controller('mainCtrl',['ws', '$scope', '$location', '$rootScope', '$translate', function(ws, $scope, $location, $rootScope, $translate) {
|
||||
//binding just once
|
||||
var setup = false;
|
||||
$translate.use("en_US");
|
||||
var player = null;
|
||||
|
||||
const initClappr = function() {
|
||||
player = new Clappr.Player({
|
||||
source: "http://" + window.location.hostname + ":" + window.location.port + "/hls/live.stream.m3u8",
|
||||
parentId: "#player",
|
||||
baseUrl: '/libs/clappr/dist/',
|
||||
poster: "images/live.jpg",
|
||||
mediacontrol: {seekbar: "#3daa48", buttons: "#3daa48"},
|
||||
height: "100%",
|
||||
width: "100%"
|
||||
});
|
||||
};
|
||||
|
||||
$translate.use('en_US');
|
||||
|
||||
$scope.reStreamerData = {
|
||||
states: {
|
||||
repeatToLocalNginx: {
|
||||
type: ""
|
||||
},
|
||||
repeatToOptionalOutput: {
|
||||
type: ""
|
||||
}
|
||||
},
|
||||
userActions: {
|
||||
repeatToLocalNginx: "",
|
||||
repeatToOptionalOutput: ""
|
||||
},
|
||||
addresses: {
|
||||
optionalOutputAddress: "",
|
||||
srcAddress: ""
|
||||
}
|
||||
states: {
|
||||
repeatToLocalNginx: {
|
||||
type: ''
|
||||
},
|
||||
repeatToOptionalOutput: {
|
||||
type: ''
|
||||
}
|
||||
},
|
||||
userActions: {
|
||||
repeatToLocalNginx: '',
|
||||
repeatToOptionalOutput: ''
|
||||
},
|
||||
addresses: {
|
||||
optionalOutputAddress: '',
|
||||
srcAddress: ''
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.windowLocationPort = $location.port();
|
||||
|
||||
$scope.optionalOutput = "";
|
||||
$scope.optionalOutput = '';
|
||||
|
||||
$scope.showStopButton = function(streamType){
|
||||
return $scope.reStreamerData.userActions[streamType] === "start";
|
||||
return $scope.reStreamerData.userActions[streamType] === 'start';
|
||||
};
|
||||
|
||||
$scope.showStartButton = function(streamType){
|
||||
return $scope.reStreamerData.userActions[streamType] === "stop";
|
||||
return $scope.reStreamerData.userActions[streamType] === 'stop';
|
||||
};
|
||||
|
||||
$scope.nginxRepeatStreamConnecting = function(){
|
||||
return $scope.reStreamerData.states.repeatToLocalNginx.type === "connecting";
|
||||
return $scope.reStreamerData.states.repeatToLocalNginx.type === 'connecting';
|
||||
};
|
||||
|
||||
$scope.nginxRepeatStreamConnected = function(){
|
||||
return $scope.reStreamerData.states.repeatToLocalNginx.type === "connected";
|
||||
return $scope.reStreamerData.states.repeatToLocalNginx.type === 'connected';
|
||||
};
|
||||
|
||||
$scope.nginxRepeatStreamError = function(){
|
||||
return $scope.reStreamerData.states.repeatToLocalNginx.type === "error";
|
||||
return $scope.reStreamerData.states.repeatToLocalNginx.type === 'error';
|
||||
};
|
||||
|
||||
$scope.optionalOutputConnecting = function(){
|
||||
return $scope.reStreamerData.states.repeatToOptionalOutput.type === "connecting";
|
||||
return $scope.reStreamerData.states.repeatToOptionalOutput.type === 'connecting';
|
||||
};
|
||||
|
||||
$scope.optionalOutputConnected = function(){
|
||||
return $scope.reStreamerData.states.repeatToOptionalOutput.type === "connected";
|
||||
return $scope.reStreamerData.states.repeatToOptionalOutput.type === 'connected';
|
||||
};
|
||||
|
||||
$scope.optionalOutputError = function(){
|
||||
return $scope.reStreamerData.states.repeatToOptionalOutput.type === "error";
|
||||
return $scope.reStreamerData.states.repeatToOptionalOutput.type === 'error';
|
||||
};
|
||||
|
||||
$scope.openPlayer = function(){
|
||||
if (player === null) {
|
||||
initClappr();
|
||||
}
|
||||
$("#player-modal").modal("show");
|
||||
$('#player-modal').on('hide.bs.modal', function (e) {
|
||||
player.stop();
|
||||
$('#player-modal').off('hide.bs.modal');
|
||||
$("#player-modal").modal("hide");
|
||||
return e.preventDefault();
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Configure Websockets
|
||||
*/
|
||||
|
||||
//connect to namespace /
|
||||
ws = ws("/");
|
||||
ws = ws('/');
|
||||
|
||||
ws.emit('testConnection');
|
||||
ws.emit("getVersion");
|
||||
|
||||
//check states of hls and rtmp stream
|
||||
ws.emit('checkStates');
|
||||
|
||||
//check for app updates
|
||||
ws.emit('checkForAppUpdates');
|
||||
|
||||
//prohibit double binding of events
|
||||
if (!setup) {
|
||||
|
||||
/**
|
||||
* test websockets connection (should print below message to browser console if it works)
|
||||
*/
|
||||
ws.on("connection", function (version) {
|
||||
ws.on('version', function (version) {
|
||||
$rootScope.version = version;
|
||||
window.Logger.log("INFO", "Datarhei " + version + " websockets connected");
|
||||
var player = new Clappr.Player({
|
||||
source: "http://" + window.location.hostname + ":" + window.location.port + "/hls/live.stream.m3u8",
|
||||
parentId: "#player",
|
||||
baseUrl: '/libs/clappr/dist/',
|
||||
poster: "images/live.jpg",
|
||||
mediacontrol: {seekbar: "#3daa48", buttons: "#3daa48"},
|
||||
height: "100%",
|
||||
width: "100%"
|
||||
});
|
||||
window.Logger.log('INFO', 'Datarhei ' + version + ' websockets connected');
|
||||
});
|
||||
|
||||
ws.on("updateProgress", function(progresses){
|
||||
$scope.reStreamerData.progresses = progresses;
|
||||
|
||||
ws.on('updateProgress', function(progresses){
|
||||
$scope.reStreamerData.progresses = progresses;
|
||||
});
|
||||
ws.on("publicIp", function(publicIp){
|
||||
ws.on('publicIp', function(publicIp){
|
||||
$rootScope.publicIp = publicIp;
|
||||
});
|
||||
ws.on("updateStreamData", function(reStreamerData) {
|
||||
ws.on('updateStreamData', function(reStreamerData) {
|
||||
$scope.reStreamerData = reStreamerData;
|
||||
if ($scope.showStopButton('repeatToOptionalOutput')) {
|
||||
$scope.activateOptionalOutput = true; //checkbox;
|
||||
}
|
||||
});
|
||||
ws.on("checkForAppUpdatesResult", function(result){
|
||||
ws.on('checkForAppUpdatesResult', function(result){
|
||||
$rootScope.checkForAppUpdatesResult = result;
|
||||
});
|
||||
}
|
||||
@@ -126,14 +150,14 @@ window.datarheiApp.controller('mainCtrl',['ws', '$scope', '$location', '$rootSco
|
||||
if($scope.activateOptionalOutput === true){
|
||||
optionalOutput = $scope.reStreamerData.addresses.optionalOutputAddress;
|
||||
}
|
||||
ws.emit("startStream", {
|
||||
src: $scope.reStreamerData.addresses.srcAddress,
|
||||
streamType: streamType,
|
||||
optionalOutput: optionalOutput
|
||||
ws.emit('startStream', {
|
||||
src: $scope.reStreamerData.addresses.srcAddress,
|
||||
streamType: streamType,
|
||||
optionalOutput: optionalOutput
|
||||
});
|
||||
};
|
||||
|
||||
$scope.stopStream = function(streamType){
|
||||
ws.emit("stopStream", streamType);
|
||||
ws.emit('stopStream', streamType);
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -13,21 +13,21 @@ window.datarheiApp.factory('ws', [ '$rootScope', 'alertService', function ($root
|
||||
var ws = function(namespace){
|
||||
var wsHandler = {};
|
||||
|
||||
window.Logger.log ("WEBSOCKETS_NAMESPACE", "connect to namespace " + namespace);
|
||||
window.Logger.log ('WEBSOCKETS_NAMESPACE', `connect to namespace ${namespace}`);
|
||||
var socket;
|
||||
if (namespace === "/"){
|
||||
if (namespace === '/'){
|
||||
socket = io.connect();
|
||||
}else{
|
||||
socket = io.connect(namespace);
|
||||
}
|
||||
wsHandler.emit = function (event, data, callback) {
|
||||
window.Logger.log("WEBSOCKETS_OUT", "emit event '" + event + "'");
|
||||
window.Logger.log('WEBSOCKETS_OUT', `emit event "${event}"`);
|
||||
socket.emit(event, data);
|
||||
return wsHandler;
|
||||
};
|
||||
wsHandler.on = function (event, callback) {
|
||||
socket.on(event, function () {
|
||||
window.Logger.log("WEBSOCKETS_IN", "got event '" + event + "'");
|
||||
window.Logger.log('WEBSOCKETS_IN', `got event "${event}"`);
|
||||
var args = arguments;
|
||||
$rootScope.$apply(function () {
|
||||
callback.apply(null, args);
|
||||
@@ -39,7 +39,7 @@ window.datarheiApp.factory('ws', [ '$rootScope', 'alertService', function ($root
|
||||
socket.removeListener(event, callback);
|
||||
};
|
||||
wsHandler
|
||||
.on("alert", function(alert) {
|
||||
.on('alert', function(alert) {
|
||||
return alertService.add(alert);
|
||||
});
|
||||
return wsHandler;
|
||||
|
||||
@@ -16,6 +16,6 @@ window.Logger = {
|
||||
WEBSOCKETS_NAMESPACE: 'color: #00BF00; font-weight: bold'
|
||||
},
|
||||
log: function(level, message){
|
||||
console.log("%c " +"[" + level + "] " + message, this.level[level]);
|
||||
console.log('%c ' +'[' + level + '] ' + message, this.level[level]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Large modal -->
|
||||
<div class="modal fade player-modal" tabindex="-1" role="dialog">
|
||||
<div id="player-modal" class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Repeat to local nginxt
|
||||
Repeat to local nginx
|
||||
-->
|
||||
<div class="form-group">
|
||||
<label>{{'input_titel' | translate}} (<a href="https://datarhei.github.io/restreamer/docs/references-rtmp-rtsp-video-source.html", target="_blank">{{'help_titel' | translate}}</a>):</label>
|
||||
@@ -16,7 +16,11 @@
|
||||
</div>
|
||||
<div class="jumbotron progress-bar-danger progress-bar-striped" ng-if="nginxRepeatStreamError()">{{'process_failed' | translate}}</div>
|
||||
<div class="form group" >
|
||||
<p class="player-link" ng-if="nginxRepeatStreamConnected()"><a href="#" style="text-decoration:underline" data-toggle="modal" data-target=".player-modal">{{'player_link_titel' | translate}}</a></p>
|
||||
<p class="player-link" ng-if="nginxRepeatStreamConnected()">
|
||||
<a href="#" style="text-decoration:underline" ng-click="openPlayer()">
|
||||
{{'player_link_titel' | translate}}
|
||||
</a>
|
||||
</p>
|
||||
<div class="text-right">
|
||||
<button type="button" class="btn btn-success" ng-if="showStartButton('repeatToLocalNginx')" ng-click="startStream('repeatToLocalNginx')">{{'button_start' | translate}}</button>
|
||||
<button type="button" class="btn btn-danger" ng-if="showStopButton('repeatToLocalNginx')" ng-click="stopStream('repeatToLocalNginx')">{{'button_stop' | translate}}</button>
|
||||
|
||||
Reference in New Issue
Block a user