【问题标题】:Is RTCPeerConnection can be used for live cam services or i need a media server?RTCPeerConnection 可以用于实时摄像服务还是我需要媒体服务器?
【发布时间】: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 来使用以下代码与标准createOffercreateAnswer 一起使用@ 约束。它一直运行良好。

现在我已经设法为每个连接的对等点(查看器)创建新的对等点连接。这样,任何人都可以从网络摄像头进行广播,而其他人(同行)将能够观看广播。如果这是一个可扩展的过程,我感到很困惑,这意味着如果用户 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


    【解决方案1】:

    一对一的对等连接本质上不是“广播”。除非特定用户在 Google Fiber City 中拥有强大的盒子,否则从一个用户的上传链接提供 500 多个视频对等连接不会明显扩展。对于这样的流量,您需要一个媒体服务器。

    【讨论】:

    • 好的。我现在正在尝试设置 red5 媒体服务器,完成后会更新您。
    • @Appklony 我不是媒体服务器专家,但我注意到他们的网站说“目前正在构建对 WebRTC 的支持”...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多