【发布时间】:2016-04-04 21:02:01
【问题描述】:
我正在尝试设置一个基于网络的实时网络摄像头流媒体服务,用户可以通过网络摄像头进行现场直播(仅限网络),即:
用户 A 在以下位置开始直播
http://www.example.com/user-a
用户 B、C、D、E 和计数继续访问该网址,即:
http://www.example.com/user-a
并且将能够观看直播/流。我正在使用RTCPeerConnection 来创建点对点共享流以节省带宽和服务器负载,我可以通过发送OfferToReceiveAudio: true、@987654327 来使用以下代码与标准createOffer 和createAnswer 一起使用@ 约束。它一直运行良好。
现在我已经设法为每个连接的对等点(查看器)创建新的对等点连接。这样,任何人都可以从网络摄像头进行广播,而其他人(同行)将能够观看广播。如果这是一个可扩展的过程,我感到很困惑,这意味着如果用户 a 正在广播并且观众是 500+,而用户 b 正在广播并且观众是 1000 的话。这对于直播是否可靠。我不想设置媒体服务器,这就是我使用 webrtc 的原因。
客户
var
ws = new WebSocket('wss://www.example.com:443'),
isRemote = false,
iStream = null,
iDescription = null,
iAnswer = null,
video = document.querySelector('video'),
peerConnCfg = {'iceServers':
[{'url': 'stun:stun.services.mozilla.com'}, {'url': 'stun:stun.l.google.com:19302'}]
},
mediaConstraints = {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
},
peer;
ws.onmessage = function(message){
var json = JSON.parse(message.data);
if(isRemote==true){
if(json.result=="ok"){
StartWatch(json.sdp, json.ice);
}else{
console.log("Watch start failed...");
}
}else{
if(json.result=="ok" && json.action=="rsdp"){
peer.setRemoteDescription(new RTCSessionDescription(json.sdp), function () {
peer.addIceCandidate(new RTCIceCandidate(json.ice)).then(function(){
console.log("added remote ice");
}).catch(function(e){
console.log(e);
});
}, function(error){
console.log("Offer remote failed error : " + error);
});
}
console.log("Remote is false...");
}
};
function golive(){
peer = new RTCPeerConnection(peerConnCfg);
peer.onicecandidate = function(event){
console.log("Got candidate...");
if(event.candidate != null) {
ws.send(JSON.stringify({'mod' : 'golive', 'channel': 'channel-xyz', 'sdp' : iDescription, 'ice' : event.candidate}));
}
};
navigator.getUserMedia({ audio: true, video: { width: 1280, height: 720 } },
function(stream) {
iVideoStream = stream;
video.src = window.URL.createObjectURL(stream);
video.onloadedmetadata = function(e){
video.play();
};
peer.addStream(stream);
peer.createOffer(function(description){
//success
console.log("Got description...");
peer.setLocalDescription(description, function () {
iDescription = description;
}, function() {console.log('set description error')});
}, function(){
//error
});
},
function(err) {
console.log("The following error occurred: " + err.name);
}
);
}
function watch(){
ws.send(JSON.stringify({'mod' : 'watch', 'channel': 'channel-xyz'}));
}
function StartWatch(sdp, ice){
peer = new RTCPeerConnection(peerConnCfg);
peer.onicecandidate = function(event){
console.log("Got candidate...");
if(event.candidate != null) {
ws.send(JSON.stringify({'mod' : 'goliveupdate', 'channel': 'channel-xyz', 'sdp' : iAnswer, 'ice' : event.candidate}));
}
};
peer.onaddstream = function(event){
peer.addStream(event.stream);
video.src = window.URL.createObjectURL(event.stream);
video.onloadedmetadata = function(e){
video.play();
};
};
peer.setRemoteDescription(new RTCSessionDescription(sdp), function () {
peer.createAnswer(function(answer){
peer.setLocalDescription(answer, function() {
iAnswer = answer;
peer.addIceCandidate(new RTCIceCandidate(ice)).then(function(){
console.log("added");
}).catch(function(e){
console.log(e);
});
}, function (error) {
console.log("Local desc error: " + error);
});
}, function(error){
console.log("Answer Error: " + error);
});
}, function(error) { console.log('set description error: ' + error)});
}
//i.e waitForSocketConnection
function _init(){
setTimeout(function(){
if (ws.readyState === 1) {
console.log('Connected to WS');
<?php
if(!isset($_GET['v'])){
echo 'golive();';
}else{
echo 'isRemote = true; watch();';
}
?>
return;
}else{
_init();
}
}, 5);
}
_init();
用于信令的套接字服务器
"use strict";
var fs = require('fs');
var cfg = {
ssl: true,
port: 443,
ssl_key: '/home/csr/example_in.key',
ssl_cert: '/home/csr/example_in.crt'
};
var app = null;
var httpServ = ( cfg.ssl ) ? require('https') : require('http');
var processRequest = function( req, res ) {
res.writeHead(200);
res.end("All glory to WebSockets!\n");
};
if ( cfg.ssl ) {
app = httpServ.createServer({
// providing server with SSL key/cert
key: fs.readFileSync( cfg.ssl_key ),
cert: fs.readFileSync( cfg.ssl_cert )
}, processRequest ).listen( cfg.port );
} else {
app = httpServ.createServer( processRequest ).listen( cfg.port );
}
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({server: app, host:'www.example.in'}),
example = {
channels: [],
run: function(){
wss.on('connection', function(ws) {
//example.channels.push(ws);
ws.on('message', function(message) {
//example.respond(ws, message);
example.respond(ws, JSON.parse(message));
});
});
wss.on('close', function() {
example.closeChannel(ws);
});
},
closeChannel(ws){
for (var channel in example.channels) {
var _channel = example.channels[channel];
if (_channel[i] == ws){ delete _channel[i]; }
example.channels[channel] = example.swapArray(_channel);
if(example.channels && example.channels[channel] && !example.channels[channel].length)
delete example.channels[channel];
}
},
swapArray: function(arr) {
var swapped = [],
length = arr.length;
for (var i = 0; i < length; i++) {
if (arr[i])
swapped[swapped.length] = arr[i];
}
return swapped;
},
respond : function(ws, message){
//ws.send(message.mod); return;
switch(message.mod){
case "golive":
example.channels[message.channel] = {
name : message.channel,
socket : ws,
sdp : message.sdp,
rsdp: null,
ice: message.ice,
rice: null
};
ws.send(JSON.stringify({'result' : 'ok', 'action' : 'connected', 'channel': message.channel}));
break;
case "goliveupdate":
example.channels[message.channel].rsdp = message.sdp;
example.channels[message.channel].rice = message.ice;
example.channels[message.channel].socket.send(JSON.stringify({'result' : 'ok', 'action' : 'rsdp', 'sdp' : message.sdp, 'ice' : message.ice, 'message': 'A peer connected'}));
break;
case "watch":
if(example.channels[message.channel]){
example.channels[message.channel].socket.send(JSON.stringify({'result' : 'ok', 'message': 'A peer connected'}));
ws.send(JSON.stringify({
'result' : 'ok',
'action' : 'connected',
'message': 'Connected to ' + message.channel,
'sdp' : example.channels[message.channel].sdp,
'ice' : example.channels[message.channel].ice
}));
}else{
ws.send(JSON.stringify({'result' : 'ok', 'message': 'Unable to connect to ' + message.channel}));
}
break;
}
}
};
example.run();
【问题讨论】:
标签: node.js sockets websocket webrtc