forked from chenxiaoqino/getusermedia-to-rtmp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
123 lines (111 loc) · 3.4 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
//var ffmpeg = require('fluent-ffmpeg');
//var stream = require('stream');
var spawn = require('child_process').spawn;
//testing
spawn('ffmpeg',['-h']).on('error',function(m){
console.error("FFMpeg not found in system cli; please install ffmpeg properly or make a softlink to ./!");
process.exit(-1);
});
app.use(express.static('static'));
io.on('connection', function(socket){
socket.emit('message','Hello from mediarecorder-to-rtmp server!');
socket.emit('message','Please set rtmp destination before start streaming.');
var ffmpeg_process, feedStream=false;
socket.on('config_rtmpDestination',function(m){
if(typeof m != 'string'){
socket.emit('fatal','rtmp destination setup error.');
return;
}
var regexValidator=/^rtmp:\/\/[^\s]*$/;//TODO: should read config
if(!regexValidator.test(m)){
socket.emit('fatal','rtmp address rejected.');
return;
}
socket._rtmpDestination=m;
socket.emit('message','rtmp destination set to:'+m);
});
socket._vcodec='libvpx';//from firefox default encoder
socket.on('config_vcodec',function(m){
if(typeof m != 'string'){
socket.emit('fatal','input codec setup error.');
return;
}
if(!/^[0-9a-z]{2,}$/.test(m)){
socket.emit('fatal','input codec contains illegal character?.');
return;
}//for safety
socket._vcodec=m;
});
socket.on('start',function(m){
if(ffmpeg_process || feedStream){
socket.emit('fatal','stream already started.');
return;
}
if(!socket._rtmpDestination){
socket.emit('fatal','no destination given.');
return;
}
var ops=[
'-vcodec', socket._vcodec,'-i','-',
'-c:v', 'libx264', '-preset', 'veryfast', '-tune', 'zerolatency',
'-an', //TODO: give up audio for now...
//'-async', '1',
//'-filter_complex', 'aresample=44100', //necessary for trunked streaming?
//'-strict', 'experimental', '-c:a', 'aac', '-b:a', '128k',
'-bufsize', '1000',
'-f', 'flv', socket._rtmpDestination
];
ffmpeg_process=spawn('ffmpeg', ops);
feedStream=function(data){
ffmpeg_process.stdin.write(data);
//write exception cannot be caught here.
}
ffmpeg_process.stderr.on('data',function(d){
socket.emit('ffmpeg_stderr',''+d);
});
ffmpeg_process.on('error',function(e){
console.log('child process error'+e);
socket.emit('fatal','ffmpeg error!'+e);
feedStream=false;
socket.disconnect();
});
ffmpeg_process.on('exit',function(e){
console.log('child process exit'+e);
socket.emit('fatal','ffmpeg exit!'+e);
socket.disconnect();
});
});
socket.on('binarystream',function(m){
if(!feedStream){
socket.emit('fatal','rtmp not set yet.');
return;
}
feedStream(m);
});
socket.on('disconnect', function () {
feedStream=false;
if(ffmpeg_process)
try{
ffmpeg_process.stdin.end();
ffmpeg_process.kill('SIGINT');
}catch(e){console.warn('killing ffmoeg process attempt failed...');}
});
socket.on('error',function(e){
console.log('socket.io error:'+e);
});
});
io.on('error',function(e){
console.log('socket.io error:'+e);
});
http.listen(8888, function(){
console.log('http and websocket listening on *:8888');
});
process.on('uncaughtException', function(err) {
// handle the error safely
console.log(err)
// Note: after client disconnect, the subprocess will cause an Error EPIPE, which can only be caught this way.
})