精华内容
下载资源
问答
  • 本Demo使用Nodejs +socket.io搭建webRTC信令服务器, 实现了局域网的音视频聊天,可在局域网下两台电脑浏览器互相视频通话
  • 示例webrtc信令服务器实现(android客户端)服务器端//github.com/nkming2/webrtc-signaling-server浏览器的客户端//github.com/nkming2/webrtc-signaling-client
  • 会议 基于WebRTC的会议媒体服务器。 执照 源代码是根据条款提供。
  • WebRTC信令

    2019-09-16 22:14:24
    WebRTC的世界中,信令是web浏览器与web服务器之间的一种事物,用于需要进行通信的端(web浏览器)之间在建立媒体信道之前,作为端(浏览器)与端交换必要信息的中继。 1.1 WebRTC世界没有统一的标准信令 在...

    1 信令


    在WebRTC的世界中,信令是web浏览器与web服务器之间的一种事物,用于需要进行通信的端(web浏览器)之间在建立媒体信道之前,作为端(浏览器)与端交换必要信息的中继。

    1.1 WebRTC世界没有统一的标准信令


    在WebRTC中,信令发挥着举足轻重的作用,但是并没有实现标准化。之所以没有进行标准化,一方面是要让两个浏览器能够进行互操作,并不需要建立信令标准;另一方面,可以让开发人员根据自己的业务形态,设计自己的信令来满足不同类型的应用。

    web服务器可以确保需要进行点对点通信的两个浏览器通过下载同样的JavaScript代码来使用相同的信令协议,如下图所示:

    如果端不是web浏览器的情况,比如常规的VoIP或者视频系统中,信令服务器无法向终端设备推送信令代码。那么,就只能让两个终端使用同一标准化信令协议,比如SIP或者Jingle。

    1.2 WebRTC信令的作用


    由于端(浏览器)一般情况下都是位于NAT或防火墙之后,其IP地址是私有地址,相互之间无法发现(非同一局域网的情况),因此也无法直接建立P2P信道。那么要实现P2P的媒体通信,首先需要端各自与信令服务器建立连接之后,通过服务器的转发来实现端与端的信息交换,其中就包含用于P2P打洞的候选网络地址信息。当然,信令的作用并不止于此,一般WebRTC通信中,信令的主要作用有以下四个方面:

    1. 媒体协商(交换媒体信息,候选地址信息,媒体加密信息);
    2. 标识和验证会话参与者身份;
    3. 控制媒体会话的发起,进度,更改,终止;
    4. 解决双占用问题(通信双方同时发起或者更改会话)。

    1.2.1 媒体协商


    媒体协商是信令最重要的功能,即在对等连接的两个浏览器之间交换会话描述协议对象(Session Description Protocol, SDP)中包含的信息。SDP一般包含了如下信息:供浏览器的RTP媒体栈配置媒体会话所需的全部信息,包括媒体类型(音频,视频,数据),所用的编解码器(Opus,VP8,G.711等),用于编解码器的各个参数或者设置,以及有关带宽的信息。信令通道还用于交换候选地址(candidate address),以便进行ICE(Interactive Connective Establishment,交互式连接建立)打洞,建立P2P连接。候选地址表示浏览器可以从中接受潜在媒体数据包的IP地址和UDP端口,候选地址可以不包含在SDP对象中,通过信令通道另外发送。另外,还必须在信令通道中交换用于SRTP的密钥。

    1.2.2 标识和身份验证


     

     

     

    1.2.3 控制媒体会话


     传统多媒体信令协议(SIP或Jingle)会提供完整的会话呼叫控制。但是WebRTC中,信令只需要提供发起会话和更改会话的作用,不需要信令提供会话进度控制和会话终止控制:会话建立过程中,检查候选项地址时,端上的ICE状态机提供了会话进度信息;会话建立后,ICE持续检查失败,表明会话已终止。

    1.2.4 双占用分解


     

    展开全文
  • #webrtc-example Signaling with Big Bang 和 WebRTC 在下面画一条下划线:这就是你如何使用存在,一个大爆炸功能 #谁会读这个 以前不一定使用过 WebRTC 曾使用 WebRTC 并遇到运行后端组件的挑战 对点对点实时通信...
  • WebRTC是没有将信令服务纳入到整个的规范中,更多的是规范了客户端这边的所有的过程,那为什么没有将信令服务器放到规范中,各个公司它的业务模型都是不一样的,很难将每个公司的信令都统一订成一套规范。...

    WebRTC是没有将信令服务纳入到整个的规范中,更多的是规范了客户端这边的所有的过程,那为什么没有将信令服务器放到规范中,各个公司它的业务模型都是不一样的,很难将每个公司的信令都统一订成一套规范。所有与其这个不如让他们各自自己去定义。

    只有是我必须的这些信息的交换可以实现,其他的业务你可以自己去定义,这个比较灵活,各个公司也比较容易接受这套方案。

    其实这个对整个WebRTC的推广其实是有好处的。

    下面我看看 信令服务器的作用。

    如果我们没有信令服务器,WebRTC之间是肯定不能通信的,这个大家是一定要清楚的,我们来看上图,这张图就表达了信令服务器在整个通话过程中它起到的作用。

    首先我们先看下面蓝色的发起端和接受端,这个发起端和接受端如果想传递媒体数据的时候 ,它有两个信息是必须要经过信令服务器交换之后才能进行通信的,这个两个信息。第一个就是媒体信息,它是通过SDP来表述。可以简单的理解,我们双方要通信,你的编解码的器是什么,比如说我现在可以进行视频传输,我的编码是H264,那么对方也要告诉我你的编解码器能不能支持H264的码,比如我们给你传过去H264的码,你说只能解H265的,那肯定双方之间就没法通信了。所有这个信息是必须要传递的。

    此外你是否支持视频是否支持音频,你们的编码方式是什么,这些信息是通过SDP给它描述出来,通过信令服务器,首先客户端要将这个SDP信息发送到服务端 ,服务端再中转,中转到另一端,大家已经知道了为什么要通过信令服务器进行中转,因为这个时候相互之间还没有进行连接,相互之间还不知道对方的存在。那这是第一个要传递的信息,第二个要传递的信息是网络信息,大家知道WebRTC最终之间尽可能通过P2P进行传输,那在他们连接之前,他们如何发现对方呢?也是通过信令服务器,首先你要将所有网络相关的信息传到服务器,那么这个服务器在帮你交换到对端,那对端拿到你的信息之后,才知道我们是在同一个局域网内,那就直接通过P2P就传输好了。那如果不在同一个网络内,那我要通过P2P穿越 ,看看之间能不能打通,这里面又分了好几种类型,对于对称是肯定打通不了,对于非对称的那就可以尝试打通,打通之后,他们之间才能进行通信。如果打通不了,还要通过服务端进行中转。所以这个信令服务器最基础的要传输媒体相关的信息进行交换,第二个是网络相关的信息要进行交换,再有第三个就是你的具体的业务,加入房间,离开房间,禁言,将对方禁止发言,或者给对方权限让他发言等等有很多信令,可以根据自己的业务模型去设置。

    这个就是信令服务器在整个WebRTC在整个WebRTC通讯中的作用,所以这是WebRTC中必须要有的信令服务器。

    为什么要使用socket.io

    我们这里要实现一个信令服务器,我们这里使用的是socket.io,主要是因为它有几个优点

    socket.io是WebSocket超集,它本身就有WebSocket功能,我们都知道在整个音视频传输的时候,一般有两种协议,TCP和UDP,底层协议里面UDP主要用于流媒体的传输,比如音频、视频、文本可以通过 UDP进行传输,UDP的问题在于它是不可靠的传输,也就是说我是可以丢包的,对于音频视频来说这是没有任何问题的。当我网络不好的时候,我丢了音频数据,它顶多就卡一下,它还能继续运行,不太影响我们正常的通话。

    但是如果对于信令来说就不一样了,信令一般就使用TCP,叫做可靠性连接,我的包是要必须保证到达的,否则我就断开连接了,因为网络就不能支持我的整个业务运转。所以它要么就必须达到,我们就甭玩了。就这两种状况,所以我们的信令在传输的过程中是必须要到达的。

    如果我们的媒体信息和网络信息不能交换的话,那肯定就是不能工作的,所以对于 信令来说我们一般使用TCP,websocket底层使用的就是TCP,所以socket.io底层使用的也是 TCP。

     

    socket.io有房间的概念,socket.io两个人或者多个人进行通讯的时候,首先我要进入到 一个房间里,这是很自然的一个逻辑,我们 要上课 或者开会,首先大家要聚集在一起,有一个虚拟的逻辑的概念,就是大家要在一个房间里,大家在这个房间大家就可以相互通信了。

    我们可以看webrtc官方提供的例子,实际上他有三种服务器,分别是房间服务器,信令服务器,流媒体中转服务器,我们这里用了socket.io我们这里就不用单独写一个房间服务器了,也就是说房间服务器和信令服务器是在同一个服务器上。

     

    socket.io跨平台、跨终端、跨语言,这样就方便我们在各个端上去实现信令的各个端,去与我们的服务端进行连接,所以特别方便,这就是使用socket来实现socket.io来实现信令服务器的根本原因。

     

    socket.io工作原理

    其实非常简单,socket.io其他它是一个js库,它是基于node.js 的Server的,这个和我们的技术选项有关,我们之前选择web服务器的时候选择的是nodeJS,在这个nodeJS的服务器上 我们在增加这个socket.io,那么我们整个服务器端就完成了,非常简单,但是如果我们单独写一套的话,那要花很长很长时间,在我们现有的nodeJS  web服务器上我们只有增加了socket.io,简简单单的修改几行代码,我们就实现了一个服务器端,其实光有服务器它还是不能工作的,所以还有客户端。

    在网页 也好,在安卓或者IOS也好,在任何终端都可以引入socket.io这个client lib客户端的库,那么客户端这个库我们就可以连接到NodeJS 的socket.io的这个服务上,那么这样就建立了连接,建立了连接之后,我们才可以创建房间或者加入到房间里,那么在整个房间内的用户就可以相互通信了,这块的逻辑非常的简单。

    这个socket.io它是可以横向扩展的,还可以级联部署很多个socket.io服务,还可以串到一起,这时当我去发送信息的时候,它是可以在各个socket.io上传输的,比如有两个用户,第一个用户在北京那个节点上,有一个 用户是上海这个节点上,没关系在它上层也就是它服务端可以串在一起的,那么北京的用户首先将你的信息发送到北京的服务端,北京的服务端通过整个网络曾然后传到上海的节点,上海的节点最终找到上海的用户,最后发送出去,这样他们之间就实现了通信。

    当然这是一个非常宏大的场景了,我们真实的部署中可以这样设置。

    以上就是WebRTC信令服务器的基本内容。

     

    展开全文
  • ws中继 一个简单的WebSocket中继服务器。 可用于WebRTC信令,或直接在浏览器之间发送数据。
  • 本论文研究了SIP与WebRTC间的融合通讯, 以及实现融合通讯终端的设计。
  • webrtc 信令理解

    2021-07-08 10:56:17
    借助WebRTC源码快速构建自己的音视频对聊功能。都是需要通过信令进行交互一些相关信息,需要借助信令服务器做一个消息中转,所以客户端A和客户端B进行发送音视频之前,客户端A先要去连接信令服务器,客户端B也需要先...

    p2p信令交互过程

    借助WebRTC源码快速构建自己的音视频对聊功能。都是需要通过信令进行交互一些相关信息,需要借助信令服务器做一个消息中转,所以客户端A和客户端B进行发送音视频之前,客户端A先要去连接信令服务器,客户端B也需要先连接服务器。当客户端B连接服务器之后,就会通知客户端A对端已经上线。此时客户端A就会创建对端连接对象,发送握手请求,请求turn服务器获取自己的ip地址和发送canditate给客户B。客户端B也需要类似的流程。

    P2P的交互时序图如下所示:

    环境安装

    nodejs 安装

    此过程网上教程比较多,在此不再过多描述。

    注意:安装io模块的是,最好放到nodejs 安装目录下

    turn / stun服务器的安装和测试

    不在本篇文章中描述,后续可能会有单独的篇章进行操作

    代码编写

    当前代码只是一些我认为重要的代码,并不是一个完整的信令服务器代码。我目前的要求是,只要我的webrtc能在两个页面上能正确执行就可以了,因此只能是一个参考。

    信令服务器代码,因为在网上进行查询,看到大部分的资料都是使用nodejs,因此本次代码也是使用nodejs进行编写。此代码肯定不是良好的代码,但是对于我自己的目的是已经达到。所以记录下来,希望对webrtc新手有所帮助(我自身也是刚入坑的新人)。代码连接地址:127.0.0.1:8081

    var os = require('os');
    const static = require('node-static');
    const http = require('http');
    const { Socket } = require('dgram');
    const file = new static.Server();
    
    var clientsInRoom = {}
    
    const app = http.createServer(function(req, res) {
        file.serve(req, res);
    }).listen(8081);
    
    const io = require('socket.io')(app);
    
    
    io.on('connection', (socket) => {
        function log() {
            const array = ['>>> Message form server: '];
            for (var i = 0; i < arguments.length; ++i) {
                array.push(arguments[i]);
            }
            socket.emit('log', array);
        }
    
        socket.on('message', function (message) {
            log('client said', message);
    
            socket.broadcast.emit('message', message);
        });
    
        socket.on('create or join', function(room) {
            log('Received request to create or join room' + room);
            
            curRoom = clientsInRoom[room] = clientsInRoom[room] || [];
            log('room ' + room + " number is " + curRoom.length);
            if (curRoom.length === 0) {
                socket.join(room);
                log('Client ID ' + socket.id + ' create room ' + room);
                curRoom.push(socket);
                socket.emit('created', room, socket.id);
            } else {
                var current_room = curRoom;
                var num = current_room.length;
                log('room num' + num);
                if (num == 1) {
                    log('Client ID ' + socket.id + ' create room ' + room);
                    io.sockets.in(room).emit('join', room, socket.id);
                    socket.join(room);
                    
                    var peer_id = "";
                    for (var i = 0; i < current_room.length; ++i) {
                        log('server socket:' + current_room[i].id);
                        if (current_room[i].id !== socket.id) {
                            log('notify peer_join' + current_room[i].id);
                            current_room[i].emit('peer_join', room, socket.id);
                            peer_id = current_room[i].id;
                        }
                    }
    
                    current_room.push(socket);
                    socket.emit('joined', room, socket.id, peer_id);
                    
                   // io.sockets.in(room).emit('ready');
                    
                }
                else {
                    socket.emit('full', room);
                }
            }
            
        });
    
        socket.on('ice_candidata', function(data, room) {
            var current_room = clientsInRoom[room] = clientsInRoom[room] || [];
            if (current_room.length !== 2) {
                log('room: ' + room + ' is empty');
                return;
            }
    
            var other_socket = current_room[0];
            if (socket.id === other_socket.id) {
                other_socket = current_room[1];
            }
            
            other_socket.emit('ice_candidata', data, socket.id);
        });
    
        socket.on('ipaddr',function(){
            var iface = os.networkInterfaces();
            for (var dev in iface) {
                iface[dev].forEach(function(details) {
                    if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
                        socket.emit('ipaddr', details.address);
                    }
                });
            }
        }) ;
    
        socket.on('offer', function(sdp, room) {
            log('offer')
            var current_room = clientsInRoom[room] = clientsInRoom[room] || [];
            if (current_room.length !== 2) {
                log('room: ' + room + ' is empty');
                return;
            }
    
            for (var i = 0; i < current_room.length; ++i) {
                var other_socket = current_room[i];
                if (other_socket.id !== socket.id) {
                    other_socket.emit('offer', sdp);
                }
            }
        });
    
        socket.on('answer', function(sdp, room) {
            log('answer');
            var current_room = clientsInRoom[room] = clientsInRoom[room] || [];
            if (current_room.length !== 2) {
                log('room: ' + room + ' is empty');
                return;
            }
    
            for (var i = 0; i < current_room.length; ++i) {
                var other_socket = current_room[i];
                if (other_socket.id !== socket.id) {
                    other_socket.emit('answer', sdp);
                }
            }
        });
    });

    客户端的代码分成两个部分,一个部分是html代码,一个部分是main.js代码,在main.js代码中,配置ice server 地址,我会在代码中注释说明。

    首先是html代码:

    <html> 
        <head>
            <title>webrtc client -- 20210527</title>
        </head>
    
        <body>
            <div style="float: left; width: 480;">
                <text>webrtc client -- 20210527</text>
                <div id="room_div">
                    <input id="room_input" type="text" />
                    <button onclick="add_room()"> join room</button>
                </div>
    
                <div id="rtc_content">
                    <div>
                        <input id="msg_input" type="text" />
                        <button onclick="send()"> send message</button>
                    </div>
    
                    <div>chat info</div>
                    <div>
                        <textarea id="msg_content" style="width: 450; height: 280px;"></textarea>
                    </div>
                </div>
            </div>
            <div id="videos" style="float: right;">
                <video id="self" style="width: 320; height: 240;" autoplay> </video>
                <video id="remoteVideo" style="width: 320; height: 240;" muted="muted" autoplay playsinline></video>
            </div>
            
           
            <script type="text/javascript" src='/socket.io/socket.io.js'></script>
            <script type="text/javascript" src='js/client.js'></script>
            <script>
                var rtcSdk = RtcSdk();
                var videos= document.getElementById('videos');
                function add_room() {
                    var room = document.getElementById("room_input").value;
                    console.log('room is ' + room);
                    rtcSdk.connect('ws://127.0.0.0:8081', room);
                }
    
                function send() {
                    var msg = document.getElementById('msg_input');
                    
                    var chat_info = document.getElementById('msg_content');
                    chat_info.value += "you: " + msg.value +"\r\n";
    
                    rtcSdk.sendMessage(msg.value);
                    msg.value = "";
                }
    
                rtcSdk.on('message', function(message){
                    var chat_info = document.getElementById('msg_content');
                    chat_info.value += "other: " + message +"\r\n";
                });
    
                rtcSdk.on('connected', function(room, socket) {
                    console.log('join room:' + room + " socket: "+ socket);
                    rtcSdk.createStream({"video":true});
                });
    
                rtcSdk.on('stream_created', function(stream) {
                    try {
                        document.getElementById('self').srcObject = stream;
                    } catch (error) {
                        document.getElementById('self').src = window.URL.createObjectURL(stream);
                    }
                    document.getElementById('self').play();
                });
                rtcSdk.on("stream_create_error", function(err) {
                    alert("create stream failed!");
                });
    
                rtcSdk.on('pc_add_stream', function(stream, pc) {
                    rtcSdk.attachStream(stream, "remoteVideo");
                });
    
            </script>
    
           
        </body>
    </html>

    接下来是main.j代码

    var RtcSdk = function() {
        var PeerConnection = (window.PeerConnection || window.webkitPeerConnection00 || window.webkitRTCPeerConnection || window.mozRTCPeerConnection);
        var getUserMedia = (navigator.getUserMedia || navigator.webkitUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMeida)
        var nativeRTCIceCandidate = (window.mozRTCIceCandidate || window.RTCIceCandidate);
        var nativeRTCSessionDescription = (window.mozRTCSessionDescription || window.RTCSessionDescription);
        var iceServer = {
            "iceServers": [{
                "url": "stun:xxx.xxx.xxx.xxx:3478", // ip 地址,可以配置在阿里云或者其他的地方
                "username": "xxx", // stun 服务器上配置的用户名
                "password": "xxx", // stun 服务器上配置的密码
            }]
            
        };
    
        function EventEmitter() {
            this.events = {};
        };
    
        EventEmitter.prototype.on = function(eventName, callback) {
            this.events[eventName] = this.events[eventName] || [];
            this.events[eventName].push(callback);
        };
    
        EventEmitter.prototype.emit = function(eventName, _){
            var events = this.events[eventName];
            if (!events) {
                return;
            }
    
            var args = Array.prototype.slice.call(arguments, 1);
            var i, m;
            for (i = 0, m = events.length; i < m; i++) {
                events[i].apply(null, args);
            }
        };
    
        function rtc() {
            this.localMediaStream = null;
            this.room = null;
            this.socket = null;
            this.isInitiator = false;
            this.numStreams = 0;
            this.initializedStreams = 0;
            this.peerSocketId = "";
            this.peerConnection = null;
        }
    
        rtc.prototype = new EventEmitter();
    
        rtc.prototype.connect = function(server, room) {
            if (room === "") {
                console.log('room is empty');
                return;
            }
    
            this.room = room;
            var socket;
            var self = this;
            socket = this.socket = io.connect();
            console.log('joining room:' + room);
            socket.emit('create or join', room);
    
            socket.on('created', function(room, clientId) {
                self.isInitiator = true;
                self.emit('connected', room, clientId);
            });
            socket.on('joined', function(room, self_id, peer_id) {
                self.isInitiator = false;
                self.peerSocketId = peer_id;
                self.emit('connected', room, self_id);
            });
            socket.on('join', function(room, peerId){
                console.log('clinet ' + peerId + ' joining room:' + room);
            });
            socket.on('peer_join', function(room, peerId) {
                console.log('peer_join, peer Id:' + peerId + ' joind room:' + room);
                self.peerSocketId = peerId;
                var pc = self.createPeerConnection();
               // pc.addStream(self.localMediaStream);
            });
            socket.on('full', function(room){
                alert(room + 'is full');
            });
            socket.on('log', (array) => {
                console.log.apply(console, array);
            });
    
            socket.on('message', function(message) {
                self.emit('message', message);
            });
    
            socket.on('ice_candidata', function(data, socket_id) {
                var candidate = new nativeRTCIceCandidate({
                    sdpMLineIndex: data.label,
                    candidate: data.candidate
                });
                var pc = self.peerConnection;
                pc.addIceCandidate(candidate);
            });
    
            socket.on('offer', function(sdp) {
                self.emit('answer_offer', sdp);
            });
    
            socket.on('answer', function(sdp) {
                self.reciveAnswer(sdp);
            });
    
            this.on('ready', function() {
                console.log('ready to perr');
                self.createPeerConnection();
                self.addStreams();
                self.sendOffer();
            });
    
            this.on('answer_offer', function(sdp) {
                console.log('answer offer');
                self.answerOffer(sdp);
            });
        };
    
        
    
        rtc.prototype.iceCandidate = function(data, socket_id) {
            var candidate = nativeRTCIceCandidate({
                sdpMLineIndex: data.label,
                candidate: data.candidate
            });
            var pc = self.peerConnection;
            pc.addIceCandidate(candidate);
        };
    
        rtc.prototype.sendMessage = function(message) {
            var self = this;
            self.socket.emit('message', message);
        };
    
        rtc.prototype.createStream = function(options) {
            var self  = this;
    
            options.video = !!options.video;
            options.audio = !!options.audio;
    
            if (getUserMedia) {
                this.numStreams++;
    
                getUserMedia.call(navigator, options, function(stream) {
                    self.localMediaStream = stream;
                    self.initializedStreams++;
                    self.emit("stream_created", stream);
                    if (self.initializedStreams == self.numStreams) {
                        self.emit("ready");
                    }
                },
                function(error) {
                    self.emit("stream_create_error", error);
                });
            } else {
                self.emit("stream_create_error", new Error('WebRTC is not yet supported in this browser.'));
            }
        };
    
        rtc.prototype.createPeerConnection = function() {
            var self = this;
            if (this.peerConnection !== null) {
                return this.peerConnection;
            }
            console.log("create peer connection");
            var pc = new PeerConnection(iceServer);
            this.peerConnection = pc;
            pc.onicecandidate = function(evt) {
                if (evt.candidate) {
                    console.log("send ice candidata");
                    self.socket.emit('ice_candidata',
                    {
                        "label": evt.candidate.sdpMLineIndex,
                        "candidate": evt.candidate.candidate
                    },
                    self.room);
                }
            };
            pc.onopen = function(evt) {
                console.log('pc opened');
            };
            pc.onaddstream = function(evt) {
                self.emit('pc_add_stream', evt.stream, pc);
            }
            return pc;
        };
    
        rtc.prototype.addStreams = function () {
            if (null == this.localMediaStream) {
                return;
            }
            this.peerConnection.addStream(this.localMediaStream);
        };
    
        rtc.prototype.attachStream = function(stream, domId) {
            try {
                document.getElementById(domId).srcObject = stream;
            } catch (error) {
                document.getElementById(domId).src = window.URL.createObjectURL(stream);
            }
            document.getElementById(domId).play();
        };
    
        rtc.prototype.sendOffer = function() {
            var self = this;
            if (this.peerSocketId === '') {
                return;
            }
    
            var pcCreateOfferCbGen = function(pc, room) {
                return function(session_desc) {
                    pc.setLocalDescription(session_desc);
                    self.socket.emit('offer', session_desc, room);
                };
            };
    
            var pcCreateOfferErrorCb = function(err) {
                console.log(err);
            };
            var pc = this.peerConnection;
            console.log("create offer");
            pc.createOffer(pcCreateOfferCbGen(pc, this.room), pcCreateOfferErrorCb);
        };
    
        rtc.prototype.answerOffer = function(sdp) {
            var self = this;
            var pc = this.peerConnection;
            pc.setRemoteDescription(new nativeRTCSessionDescription(sdp));
            console.log("crate answer");
            pc.createAnswer(function(session_desc) {
                console.log("set local description");
                pc.setLocalDescription(session_desc);
                console.log("send answer");
                self.socket.emit('answer', session_desc, self.room);
            }, function(err) {
                console.log("err:" + err);
            });
        };
    
        rtc.prototype.reciveAnswer = function(sdp) {
            console.log('reciveAnswer');
            var pc = this.peerConnection;
            pc.setRemoteDescription(new nativeRTCSessionDescription(sdp));
        }
    
        return new rtc();
    };
    

    最后放置一个效果图:

    demo下载地址:https://download.csdn.net/download/jiejieaiai/20082808(如果有更改,后续发布评论区)

    存在问题

    目前只能是127.0.0.0 地址访问,其他地址会提示打不开设摄像头(是不是因为不是https的缘故,具体没有再去考察,如果后续有时间,我会去研究一下具体原因),如果哪位大佬了解原因,欢迎在评论区告知,在此非常感谢!!!

    展开全文
  • webRTC(六):webrtc信令服务器实现

    千次阅读 2020-03-03 22:52:43
    信令服务器实现 引入socketIo和log4js //命令服务器 var socketIo =require('socket.io'); var log4js = require('log4js'); 安装 socketIo和日志log4js插件 /home/huangxiaoguo/RTCWorkSpace/samples/webserver...

    信令服务器实现

    • 引入socketIo和log4js
    //命令服务器
    var socketIo =require('socket.io');
    var log4js = require('log4js');
    
    安装 socketIo和日志log4js插件
    
    /home/huangxiaoguo/RTCWorkSpace/samples/webserver 
    
    npm install socket.io 
    
    npm install  log4js 
    
    • 命令服务器绑定https
    var io = socketIo.listen(https_server);
    
    • 建立信令监听
    io.sockets.on('connection',(socket)=>{
    	logger.debug("connection");
    	
    	//转发信息
    	socket.on('message', (room, data)=>{
    		logger.debug("message data "+socket.id+" "+room,data);
    		socket.to(room).emit('message', room, socket.id, data)//房间内所有人,除自己外
    	});
    	
    	//用户加入
    	socket.on('join',(room)=>{
    		logger.debug("join",",room = ", room,",socket.id = ", socket.id);
    		socket.join(room);
    		var myRoom = io.sockets.adapter.rooms[room];
    		var users =(myRoom)?Object.keys(myRoom.sockets).length:0;
    		logger.debug('the number of user in room is:'+users)
    		
    		//处理一对一通信
    		if (users<USERCOUNT) {
    			//给本人回信息
    			socket.emit('joined',room,socket.id);
    			if(users>1){
    				socket.to(room).emit('otherjoin',room,socket.id);
    			}
    		}else{
    			socket.leave(room);
    			socket.emit('full',room,socket.id);
    		}
    		
    		//给本人回信息
    		//socket.emit('joined',room,socket.id);
    		//给房间除自己以外所有人回
    		// socket.to(room).emit('joined',room,socket.id);
    		//给房间所有人回
    		// io.in(room).emit('joined',room,socket.id);
    		//除自己所有站点回
    		// socket.broadcast.emit('joined',room,socket.id)
    	});
    
    	//用户离开
    	socket.on('leave',(room)=>{
    		var myRoom = io.sockets.adapter.rooms[room];
    		var users =(myRoom)?Object.keys(myRoom.sockets).length:0;
    		//users-1
    		logger.debug('the number of user in room is:'+(users-1));
    		
    		socket.to(room).emit('bye',room,socket.id);
    		socket.emit('leaved',room,socket.id);
    		
    		//给本人回信息
    		//socket.emit('leaved',room,socket.id);
    		//给房间除自己以外所有人回
    		//socket.to(room).emit('leaved',room,socket.id)
    		//给房间所有人回
    		//io.in(room).emit('leaved',room,socket.id);
    		//除自己所有站点回
    		//socket.broadcast.emit('leaved',room,socket.id)
    	});
    });
    

    • 服务器全部代码
    
    
    'use strict'
    
    var http = require('http');
    var https = require('https');
    var fs = require('fs');
    
    var express= require('express');
    
    var serveIndex=require('serve-index');
    
    var USERCOUNT=3;
    
    
    //命令服务器
    var socketIo =require('socket.io');
    var log4js = require('log4js');
    
    log4js.configure({
    	appenders:{
    		file:{
    			type:'file',
    			filename:'app.log',
    			layout:{
    				type:'pattern',
    				pattern:'%r %p - %m',
    			}
    		}
    	},
    	categories:{
    		default:{
    			appenders:['file'],
    			level:'debug'
    		}
    	}
    });
    var logger = log4js.getLogger();
    
    
    
    var app=express();
    app.use(serveIndex('./public'));
    app.use(express.static('./public'));
    
    //http  server
    var http_server=http.createServer(app);
    
    //-----------------------------------------------------------------------//
    
    var options={
    	key:fs.readFileSync('./cert/3435783_huangxiaoguo.club.key'),
    	cert:fs.readFileSync('./cert/3435783_huangxiaoguo.club.pem')
    }
    
    //https server
    var https_server=https.createServer(options,app);
    
    //命令服务器绑定https
    var io = socketIo.listen(https_server);
    
    io.sockets.on('connection',(socket)=>{
    	logger.debug("connection");
    	
    	//转发信息
    	socket.on('message', (room, data)=>{
    		logger.debug("message data "+socket.id+" "+room,data);
    		socket.to(room).emit('message', room, socket.id, data)//房间内所有人,除自己外
    	});
    	
    	//用户加入
    	socket.on('join',(room)=>{
    		logger.debug("join",",room = ", room,",socket.id = ", socket.id);
    		socket.join(room);
    		var myRoom = io.sockets.adapter.rooms[room];
    		var users =(myRoom)?Object.keys(myRoom.sockets).length:0;
    		logger.debug('the number of user in room is:'+users)
    		
    		//处理一对一通信
    		if (users<USERCOUNT) {
    			//给本人回信息
    			socket.emit('joined',room,socket.id);
    			if(users>1){
    				socket.to(room).emit('otherjoin',room,socket.id);
    			}
    		}else{
    			socket.leave(room);
    			socket.emit('full',room,socket.id);
    		}
    		
    		//给本人回信息
    		//socket.emit('joined',room,socket.id);
    		//给房间除自己以外所有人回
    		// socket.to(room).emit('joined',room,socket.id);
    		//给房间所有人回
    		// io.in(room).emit('joined',room,socket.id);
    		//除自己所有站点回
    		// socket.broadcast.emit('joined',room,socket.id)
    	});
    
    	//用户离开
    	socket.on('leave',(room)=>{
    		var myRoom = io.sockets.adapter.rooms[room];
    		var users =(myRoom)?Object.keys(myRoom.sockets).length:0;
    		//users-1
    		logger.debug('the number of user in room is:'+(users-1));
    		
    		socket.to(room).emit('bye',room,socket.id);
    		socket.emit('leaved',room,socket.id);
    		
    		//给本人回信息
    		//socket.emit('leaved',room,socket.id);
    		//给房间除自己以外所有人回
    		//socket.to(room).emit('leaved',room,socket.id)
    		//给房间所有人回
    		//io.in(room).emit('leaved',room,socket.id);
    		//除自己所有站点回
    		//socket.broadcast.emit('leaved',room,socket.id)
    	});
    });
    
    https_server.listen(443, '0.0.0.0');
    http_server.listen(80,'0.0.0.0');
    
    

    利用socketio实现简单聊天室

    • 页面
    <html>
    	<head>
    		<title>
    			Chat Room
    		</title>
    	</head>
    	<body>
    		<table align="center">
    			<tr>
    				<td>
    					<label>UserName:</label>
    					<input type="text" id="uesrname"/>
    				</td>	
    			</tr>
    			<tr>
    				<td>
    					<label>room:</label>
    					<input type="text" id="room"/>
    					<button id="connect">connect</button>
    				</td>
    			</tr>
    			<tr>
    				<td>
    					<label>Content:</label><br>
    					<textarea disabled  id="output" rows="10" cols="50"></textarea>
    				</td>
    			</tr>
    			<tr>
    				<td>
    					<label>Input:</label><br>
    					<textarea disabled  id="input" rows="3" cols="50"></textarea>
    				</td>
    			</tr>
    			<tr>
    				<td>
    					<button id="send">Send</button>
    				</td>
    			</tr>
    		</table>
    		<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
    		<script src="./js/client.js"></script>
    	</body>
    </html>
    
    • js
    'use strict'
    
    var userName= document.querySelector('input#uesrname');
    var inputRoom= document.querySelector('input#room');
    var btnConnect= document.querySelector('button#connect');
    var outputArea= document.querySelector('textarea#output');
    var inputArea= document.querySelector('textarea#input');
    var btnSend= document.querySelector('button#send');
    
    
    var socket ;
    var room;
    btnConnect.onclick=()=>{
    	
    	//链接服务器
    	socket = io.connect();
    	//断开服务器
    	socket.on('disconnect', socket=> {
    		console.log("disconnect===>"+socket);
    	})
    	//消息
    	socket.on('joined',(room,id)=>{
    		btnConnect.disabled=true;
    		inputArea.disabled=false;
    		btnSend.disabled=false;
    	});
    	socket.on('leaved',(room,id)=>{
    		btnConnect.disabled=false;
    		inputArea.disabled=true;
    		btnSend.disabled=true;
    	});
    	socket.on('message',(room,id,data)=>{
    		console.log("data====>"+data);
    		outputArea.scrollTop = outputArea.scrollHeight;//窗口总是显示最后的内容
    		outputArea.value=outputArea.value+data+'\r';
    	});
    	//发送消息
    	room =inputRoom.value;
    	socket.emit('join',room);
    }
    
    btnSend.onclick=()=>{
    	if (inputArea.value==='') {
    		return;
    	} 
    	var data=inputArea.value;
    	data=userName.value+':'+data;
    	socket.emit('message',room,data);
    	outputArea.scrollTop = outputArea.scrollHeight;//窗口总是显示最后的内容
    	outputArea.value=outputArea.value+data+'\r';
    	inputArea.value='';
    }
    

    测试地址:https://www.huangxiaoguo.club/chatroom/index.html

    展开全文
  • webrtc 信令传输过程

    千次阅读 2019-05-30 17:13:04
    下面这篇介绍webrtc的文章不错,我花了大半天翻译了一下. 翻译的时候不是逐字逐句的,而是按照自己的理解翻译的,同时...本文主要介绍webrtc信令,stun,turn,转载请说明出处(博客园RTC.Blacker). 英文来自:ht...
  • 文章目录WebRTC源码研究(20)WebRTC信令服务器原理 WebRTC源码研究(20)WebRTC信令服务器原理
  • 文档gitbook地址 文档github地址
  • WebRTC信令服务器Ayame 关于Shiguredo的开源软件 我们不会回应PR或在Discord上尚未讨论的问题。 另外,Discord仅提供日语。 使用前请阅读 。 时雨堂のオープンソースソフトウェアについて 利用前にをお読みください...
  • 前言 我们在学习 WebRTC 时,首先要把实验环境搭建好,这样我们就可以在上面做各种实验了。 对于 WebRTC 来说,它有一整套...除此之外,WebRTC还需要房间服务器将多端聚集到一起管理,以及信令服务器进行信令数...
  • 使用Node.js WebSocket的WebRTC信令 该库使用Node.js WebSocket服务器为WebRTC实现信令客户端和服务器。 用法 您在信令服务器中的ID是通过从您在客户端构造函数中传递的电子邮件+秘密令牌中获取SHA256哈希来创建的。...
  • Webrtc 信令交换过程

    2021-08-27 16:25:33
    开发Webrtc程序,首先需要知道其连接的建立过程,现记录如下: 1、A向服务器发出init请求 2、服务器将A的init请求转发给连接上服务器的其他端 3、B收到init请求后,调用peerConnection.createOffer()方法创建一个...
  • WebRTC[33]-WebRTC信令服务器的选择

    千次阅读 2018-07-19 10:14:13
    众所周知,webrtc1.0是没有提供信令协议标准的,这样一方面增加webrtc的灵活性,另一方也让一些小伙伴不知所措。那么我们应该怎么选择webrtc信令服务器呢,一般有如下三种情况。 一、大师级用户,完全自己搭一套...
  • 搭建 webrtc 信令服务器

    千次阅读 2017-11-13 21:03:26
    发现demo代码里的服务器地址指向了https://appr.tc, webrtc是google推出,在中国就意味着需要翻墙,为何不在自己的linux 虚拟机上自己搭建一个https://appr.tc 服务来测试,webrtc已经开源了这个信令服务器,参考...
  • PalavaMachine是WebRTC信令服务器。 信令描述了寻找其他对等点并交换有关如何建立媒体连接的信息的过程。 它与一起工作。 该服务器在和实现,并且通过WebSockets与客户端进行通信。 该应用程序当前不属于palava....
  • DWRTC-分布式WebRTC信令 DWRTC通过分散的连接设置(信号发送)​​扩展了WebRTC。 用户连接到Internet上的不同节点。 这些节点通过存储路由信息的P2P网络连接。 连接设置消息通过此网络路由。 然后,可以使用WebRTC...
  • 该项目是一个概念证明,旨在了解我们是否可以使用IPFS进行WebRTC信令,从而无需使用单独的服务器。 目标1-浏览器到浏览器信令 状态:已完成 我目前已打开调试功能,因此控制台日志确实显示了一些详细信息。 脚步: ...
  • 什么是无服务器WebRTC信令服务器? 无服务器WebRTC Signaling Server是使用WebSocket并在AWS上运行的WebRTC的Signaling Server。 该信令服务器仅适用于WebRTC P2P。 该信令服务器实现了与兼容的会议室功能。 房间...
  • webrtc 信令demo

    2021-07-08 11:32:16
    webrtc 信令新入坑学习
  • Signal-Fire Server是为node.js构建的WebRTC信令服务器。 WebRTC信令服务器在对等方之间进行通信,以建立对等音频/视频和/或数据通道。 这使您的客户可以直接相互交流。 特征 WebSockets支持的信令服务器 使用简单...
  • WebRTC信令服务器在对等方之间进行通信,以建立对等音频/视频和/或数据通道。 这使您的客户可以直接相互交流。 特征 包括以实现浏览器兼容性 与无缝 消除建立对等连接的麻烦 使用基于JSON的简单 没有依赖林 安装 ...
  • 信令服务器 该项目使用项目(不再维护)。 我添加了自定义信号、房间最大参与者限制和其他约束,以在两个客户端之间提供完整的视频通话解决方案。 它通过使用由Hazelcast支持的分布式事件总线和节点自动发现来感知...
  • 一个简单的信令服务器,供客户端连接并为WebRTC信令。 #URL ## Deploying您可以使用以下命令在本地运行 $ npm start 您可能还想在Heroku上运行它 ##注意已将其配置为通过HTTP。 如果您想通过HTTPS进行相同的...
  • 用于 WebRTC 缓存共享系统的 WebRTC 信令服务器 开发环境 JavaScript Node.js (v0.10.x) MongoDB 使用的库 (v0.11.x) 跑步 $ npm install $ npm start 测试 $ npm test 应用程序接口 [文件路径] 采用 URL 的 ...
  • 这是一个简单的 WebRTC 信令服务器。 用法 信息: $ curl -X GET http://localhost:7665/ { "name": "smoke-signals", "description": "A simple WebRTC signaling server", "version":"0.0.1", "endpoint":...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,987
精华内容 1,194
关键字:

webrtc信令