精华内容
下载资源
问答
  • Webrtc WebSocket实现音视频通讯

    万次阅读 2017-06-01 15:44:31
    本文主要利用websocket进行通讯,支持个google浏览器,无法兼容Firefox浏览器,同时对于Tomcat要求8.0以上,同时由于最新的webrtc要么用localhost访问,如果要用IP访问,则只能用https协议进行访问,因此这些都是...

    一般的浏览器都集成了webrtc的功能,因此是不需要webrtc服务器就可以在局域网内进行点对点的音视频通讯。

    本文主要利用websocket进行通讯,支持个google浏览器,无法兼容Firefox浏览器,同时对于Tomcat要求8.0以上,同时由于最新的webrtc要么用localhost访问,如果要用IP访问,则只能用https协议进行访问,因此这些都是需要解决的问题,本文只是一个demon程序。


    <%@ page language="java" pageEncoding="UTF-8" %>
    <!DOCTYPE html>
    <html>
    <head>
        <title>Java后端WebSocket的Tomcat实现</title>
    </head>
    <body>
        Welcome<br/><input id="text" type="text"/>
        <button οnclick="send()">发送消息</button>
        <hr/>
        <button οnclick="closeWebSocket()">关闭WebSocket连接</button>
        <hr/>
        <div id="message"></div>
        
        <video id="vid1" width="640" height="480" autoplay></video>
    	<video id="vid2" width="640" height="480" autoplay></video><br>
    	<a id="create" href="/Websocket/#true" οnclick="init()">点击此链接新建聊天室</a><br>
    	<p id="tips" style="background-color:red">请在其他浏览器中打开:http://此电脑   加入此视频聊天</p>
    </body>
    
    <script type="text/javascript">
    	var isCaller = window.location.href.split('#')[1];
        var websocket = null;
        //判断当前浏览器是否支持WebSocket
        if ('WebSocket' in window) {
            websocket = new WebSocket("ws://localhost:8080/Websocket/websocket");
        }
        else {
            alert('当前浏览器 Not support websocket')
        }
    
        //连接发生错误的回调方法
        websocket.onerror = function () {
            setMessageInnerHTML("WebSocket连接发生错误");
        };
    
        //连接成功建立的回调方法
        websocket.onopen = function () {
            setMessageInnerHTML("WebSocket连接成功");
        }
    
     // 创建PeerConnection实例 (参数为null则没有iceserver,即使没有stunserver和turnserver,仍可在局域网下通讯)
    	var pc = new webkitRTCPeerConnection(null);
    
    	// 发送ICE候选到其他客户端
    	pc.onicecandidate = function(event) {
    		setMessageInnerHTML("我看看 1");
    		if (event.candidate !== null) {
    			setMessageInnerHTML("我看看 2");
    			websocket.send(JSON.stringify({
    				"event" : "_ice_candidate",
    				"data" : {
    					"candidate" : event.candidate
    				}
    			}));
    		}
    	};
    	
        //接收到消息的回调方法
        websocket.onmessage = function (event) {
        	setMessageInnerHTML("接收到的信息");
            setMessageInnerHTML(event.data);
            if(event.data=="new user") {
    			console.log("new user");
    			location.reload();
    		} else {
    			var json = JSON.parse(event.data);
    			console.log('onmessage: ', json);
    			//如果是一个ICE的候选,则将其加入到PeerConnection中,否则设定对方的session描述为传递过来的描述
    			if (json.event === "_ice_candidate") {
    				pc.addIceCandidate(new RTCIceCandidate(json.data.candidate));
    			} else {
    				pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp));
    				// 如果是一个offer,那么需要回复一个answer
    				if (json.event === "_offer") {
    					pc.createAnswer(sendAnswerFn, function(error) {
    						console.log('Failure callback: ' + error);
    					});
    				}
    			}
    		}
        }
    
        //连接关闭的回调方法
        websocket.onclose = function () {
            setMessageInnerHTML("WebSocket连接关闭");
        }
    
        //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
        window.onbeforeunload = function () {
            closeWebSocket();
        }
    
        //将消息显示在网页上
        function setMessageInnerHTML(innerHTML) {
            document.getElementById('message').innerHTML += innerHTML + '<br/>';
        }
    
        //关闭WebSocket连接
        function closeWebSocket() {
            websocket.close();
        }
    
        //发送消息
        function send() {
            var message = document.getElementById('text').value;
            websocket.send(message);
        }
        
     // stun和turn服务器
    	var iceServer = {
    		"iceServers" : [ {
    			"url" : "stun:stun.l.google.com:19302"
    		}, {
    			"url" : "turn:numb.viagenie.ca",
    			"username" : "webrtc@live.com",
    			"credential" : "muazkh"
    		} ]
    	};
    
    	
    
    	// 如果检测到媒体流连接到本地,将其绑定到一个video标签上输出
    	pc.onaddstream = function(event) {
    		document.getElementById('vid2').src = URL
    				.createObjectURL(event.stream);
    	};
    
    	// 发送offer和answer的函数,发送本地session描述
    	var sendOfferFn = function(desc) {
    		pc.setLocalDescription(desc);
    		websocket.send(JSON.stringify({
    			"event" : "_offer",
    			"data" : {
    				"sdp" : desc
    			}
    		}));
    	}, sendAnswerFn = function(desc) {
    		pc.setLocalDescription(desc);
    		websocket.send(JSON.stringify({
    			"event" : "_answer",
    			"data" : {
    				"sdp" : desc
    			}
    		}));
    	};
    
    	// 获取本地音频和视频流
    	navigator.webkitGetUserMedia({
    		"audio" : true,
    		"video" : true
    	},
    			function(stream) {
    				//绑定本地媒体流到video标签用于输出
    				document.getElementById('vid1').src = URL
    						.createObjectURL(stream);
    				//向PeerConnection中加入需要发送的流
    				pc.addStream(stream);
    				//如果是发起方则发送一个offer信令
    				if (isCaller) {
    					pc.createOffer(sendOfferFn, function(error) {
    						console.log('Failure callback: ' + error);
    					});
    				} 
    			}, function(error) {
    				//处理媒体流创建失败错误
    				console.log('getUserMedia error: ' + error);
    			});
    	
    	window.οnlοad=function(){ 
    		if(isCaller==null||isCaller==undefined) {
    			var tips = document.getElementById("tips");
    			tips.remove();
    		} else {
    			var create = document.getElementById("create");
    			create.remove();
    		}
    	};
    	function init() {
    		location.reload();
    	}
    </script>
    </html>

    package me.gacl.websocket;
    
    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    
    /**
     * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
     * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
     */
    @ServerEndpoint("/websocket")
    public class WebSocketTest {
        //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
        private static int onlineCount = 0;
    
        //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
        private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();
    
        //与某个客户端的连接会话,需要通过它来给客户端发送数据
        private Session session;
    
        /**
         * 连接建立成功调用的方法
         * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
         */
        @OnOpen
        public void onOpen(Session session){
            this.session = session;
            webSocketSet.add(this);     //加入set中
            addOnlineCount();           //在线数加1
            System.out.println(session.getId()+"有新连接加入!当前在线人数为" + getOnlineCount());
        }
    
        /**
         * 连接关闭调用的方法
         */
        @OnClose
        public void onClose(){
            webSocketSet.remove(this);  //从set中删除
            subOnlineCount();           //在线数减1
            System.out.println(session.getId()+"有一连接关闭!当前在线人数为" + getOnlineCount());
        }
    
        /**
         * 收到客户端消息后调用的方法
         * @param message 客户端发送过来的消息
         * @param session 可选的参数
         */
        @OnMessage
        public void onMessage(String message, Session session) {
            System.out.println(session.getId()+"来自客户端的消息:" + message);
            //群发消息
            for(WebSocketTest item: webSocketSet){
                try {
                    item.sendMessage(message);
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    
        /**
         * 发生错误时调用
         * @param session
         * @param error
         */
        @OnError
        public void onError(Session session, Throwable error){
            System.out.println("发生错误");
            error.printStackTrace();
        }
    
        /**
         * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
         * @param message
         * @throws IOException
         */
        public void sendMessage(String message) throws IOException{
            this.session.getBasicRemote().sendText(message);
            //this.session.getAsyncRemote().sendText(message);
        }
    
        public static synchronized int getOnlineCount() {
            return onlineCount;
        }
    
        public static synchronized void addOnlineCount() {
            WebSocketTest.onlineCount++;
        }
    
        public static synchronized void subOnlineCount() {
            WebSocketTest.onlineCount--;
        }
    }


    展开全文
  • webrtc-websocket-源码

    2021-02-13 12:37:35
    webrtc-websocket
  • WebRTC+websocket

    2017-08-22 10:26:04
    WebRTC开发的视频通话,修改了之前的一个小例子,可以正常运行,后台java的websocket,用于学习交流
  • WebRTC-WebSocket demo

    2021-01-20 17:09:57
    webrtc简单的demo http://localhost:9000/index.html?room=XX&name=BB
  • WebRTCwebRTCwebSocket的区别

    千次阅读 2018-02-11 16:05:52
    区别 WebSockets允许浏览器和Web服务器之间的全双工通信 WebRTC的PeerConnection允许两个浏览器之间的全双工通信

    区别

    • WebSockets允许浏览器和Web服务器之间的全双工通信
    • WebRTC的PeerConnection允许两个浏览器之间的全双工通信
    展开全文
  • 最近空闲时间较多,于是写了...webRTCwebsocket 2.实现思路: 两个浏览器打开同一页面,连接到同一个socket。 此时由一端点击建立连接,发起建立连接的一端就是offer(携带信号源信息),发给另外一个端,另外一个端收

    最近空闲时间较多,于是写了一个个人博客,其中实现了实时通话,但是感觉功能比较无趣,前两天突发奇想,觉得如果可以视频通话就有意思了,于是从网上搜索了相关资料,发现webRTC可以实现该功能,但是网上关于webRTC的资料甚少,经过三天的研究,终于简单的实现了视频通话的功能,具体实现过程如下:

    1.技术点:

    webRTC、websocket

    2.实现思路:

    两个浏览器打开同一页面,连接到同一个socket。
    此时由一端点击建立连接,发起建立连接的一端就是offer(携带信号源信息),发给另外一个端,另外一个端收到offer之后,发出响应answer(携带信号源信息),offer端收到answer端信息进行存储;这样每个端都有了自己的信息和对方的信息,offer发出answer发出后设置了localDescription和remoteDescription后就会触发onicecandidate,如此一来,双方都有了对方的localDescription、remoteDescription和candidata;有了这三种数据之后,就可以触发Connection.onaddstream函数,然后通过theirVideo.srcObject = e.stream这个方法,把流写到video标签内,然后video标签里就会有对方的视频画面了。

    注意:这样实现之后不能直接调用navigator.getUserMedia()函数,浏览器会默认getUserMedia为undifined,如果是互联网模式这里需要设置浏览(如果只是本地测试则不需要)(谷歌浏览器配置方法);webrtc如只是p2p不需要特别服务器,自已开发信令服务就可以啦,当要安装turn server 国内常有打洞不成功需要转发。

    下面是实现代码:

    1.前端页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>webrtc</title>
        <style>
            #yours{
                width:300px;
                position:absolute;
                top:200px;
                left:100px;
            }
            #theirs{
                width:300px;
                position:absolute;
                top:200px;
                left:400px;
            }
        </style>
    </head>
    <body>
    <button onclick="createOffer()">开始视频</button>
    <video id="yours" autoplay></video>
    <video id="theirs" autoplay></video>
    
    </body>
    
    <script type="text/javascript" src="../blog/plugin/jquery/1.9.1/jquery.min.js"></script>
    <script src="webtrc.js"></script>
    <script>
        $(function () {
            f()
        })
    </script>
    </html>
    

    2.js、webRTC实现方法

    var websocket;
    
    function randomNum(minNum,maxNum){
        switch(arguments.length){
            case 1:
                return parseInt(Math.random()*minNum+1,10);
                break;
            case 2:
                return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
                break;
            default:
                return 0;
                break;
        }
    }
    const userid = 'user' + randomNum(0,100000);
    
    function hasUserMedia() {
        navigator.getUserMedia = navigator.getUserMedia || navigator.msGetUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
        return !!navigator.getUserMedia;
    }
    function hasRTCPeerConnection() {
        window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection;
        return !!window.RTCPeerConnection;
    }
    
    var yourVideo = document.getElementById("yours");
    var theirVideo = document.getElementById("theirs");
    var Connection;
    
    
    function startPeerConnection() {
        //return;
        var config = {
            'iceServers': [
                //{ 'urls': 'stun:stun.xten.com:3478' },
                //{ 'urls': 'stun:stun.voxgratia.org:3478' },
                { 'url': 'stun:stun.l.google.com:19302' }
            ]
        };
        config = {
            iceServers: [
                { urls: 'stun:stun.l.google.com:19302' },
                { urls: 'stun:global.stun.twilio.com:3478?transport=udp' }
            ],
            //sdpSemantics: 'unified-plan'
        };
        // {
        //     "iceServers": [{
        //         "url": "stun:stun.1.google.com:19302"
        //     }]
        // };
        Connection = new RTCPeerConnection(config);
        Connection.onicecandidate = function(e) {
            console.log('onicecandidate');
            if (e.candidate) {
                websocket.send(JSON.stringify({
                    "userid":userid,
                    "event": "_ice_candidate",
                    "data": {
                        "candidate": e.candidate
                    }
                }));
            }
        }
        Connection.onaddstream = function(e) {
            console.log('onaddstream');
    
            //theirVideo.src = window.URL.createObjectURL(e.stream);
            theirVideo.srcObject = e.stream;
        }
    }
    
    
    createSocket();
    startPeerConnection();
    
    function f() {
        navigator.getUserMedia({ video: true, audio: true },
            stream => {
                yourVideo.srcObject = stream;
                window.stream = stream;
                Connection.addStream(stream)
            },
            err => {
                console.log(err);
            })
    }
    
    
    function createOffer(){
        //发送offer和answer的函数,发送本地session描述
        Connection.createOffer().then(offer => {
            Connection.setLocalDescription(offer);
            websocket.send(JSON.stringify({
                "userid":userid,
                "event": "offer",
                "data": {
                    "sdp": offer
                }
            }));
        });
    }
    
    
    
    function createSocket(){
        var user = Math.round(Math.random()*1000) + ""
        websocket = new WebSocket("ws://127.0.0.1:8080/msgServer/"+user);
        eventBind();
    };
    function eventBind() {
        //连接成功
        websocket.onopen = function(e) {
            console.log('连接成功')
        };
        //server端请求关闭
        websocket.onclose = function(e) {
            console.log('close')
        };
        //error
        websocket.onerror = function(e) {
    
        };
        //收到消息
        websocket.onmessage = (event)=> {
            if(event.data == "new user") {
                location.reload();
            } else {
                var json = JSON.parse(event.data);
                console.log('onmessage: ', json);
                if(json.userid !=userid){
                    //如果是一个ICE的候选,则将其加入到PeerConnection中,否则设定对方的session描述为传递过来的描述
                    if(json.event === "_ice_candidate"&&json.data.candidate) {
                        Connection.addIceCandidate(new RTCIceCandidate(json.data.candidate));
                    }else if(json.event ==='offer'){
                        Connection.setRemoteDescription(json.data.sdp);
                        Connection.createAnswer().then(answer => {
                            Connection.setLocalDescription(answer);
                            console.log(window.stream)
                            websocket.send(JSON.stringify({
                                "userid":userid,
                                "event": "answer",
                                "data": {
                                    "sdp": answer
                                }
                            }));
                        })
                    }else if(json.event ==='answer'){
                        Connection.setRemoteDescription(json.data.sdp);
                        console.log(window.stream)
                    }
                }
            }
        };
    }
    

    websocket

    package com.chat.api.web.restctrl;
    
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    
    import javax.websocket.*;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.concurrent.ConcurrentHashMap;
    
    
    @ServerEndpoint("/msgServer/{userId}")
    @Component
    @Scope("prototype")
    public class WebSocketServer {
    
        /**
         * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
         */
        private static int onlineCount = 0;
        /**
         * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
         */
        private static ConcurrentHashMap<String, Session> webSocketMap = new ConcurrentHashMap<>();
        /**
         * 与某个客户端的连接会话,需要通过它来给客户端发送数据
         */
        private Session session;
        /**
         * 接收userId
         */
        private String userId = "";
    
        @OnOpen
        public void onOpen(Session session, @PathParam("userId") String userId) {
            this.session = session;
            this.userId = userId;
            /**
             * 连接被打开:向socket-map中添加session
             */
            webSocketMap.put(userId, session);
            System.out.println(userId + " - 连接建立成功...");
        }
    
        @OnMessage
        public void onMessage(String message, Session session) {
            try {
                this.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @OnError
        public void onError(Session session, Throwable error) {
            System.out.println("连接异常...");
            error.printStackTrace();
        }
    
        @OnClose
        public void onClose() {
            System.out.println("连接关闭");
        }
    
        /**
         * 实现服务器主动推送
         */
        public void sendMessage(String message) throws IOException {
            if (message.equals("心跳")){
                this.session.getBasicRemote().sendText(message);
            }
            Enumeration<String> keys = webSocketMap.keys();
            while (keys.hasMoreElements()){
                String key = keys.nextElement();
                if (key.equals(this.userId)){
                    System.err.println("my id " + key);
                    continue;
                }
                if (webSocketMap.get(key) == null){
                    webSocketMap.remove(key);
                    System.err.println(key + " : null");
                    continue;
                }
                Session sessionValue = webSocketMap.get(key);
                if (sessionValue.isOpen()){
                    System.out.println("发消息给: " + key + " ,message: " + message);
                    sessionValue.getBasicRemote().sendText(message);
                }else {
                    System.err.println(key + ": not open");
                    sessionValue.close();
                    webSocketMap.remove(key);
                }
            }
        }
    
        /**
         * 发送自定义消息
         */
        public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
            System.out.println("发送消息到:" + userId + ",内容:" + message);
            if (!StringUtils.isEmpty(userId) && webSocketMap.containsKey(userId)) {
                webSocketMap.get(userId).getBasicRemote().sendText(message);
                //webSocketServer.sendMessage(message);
            } else {
                System.out.println("用户" + userId + ",不在线!");
            }
        }
    
        public static synchronized int getOnlineCount() {
            return onlineCount;
        }
    
        public static synchronized void addOnlineCount() {
            WebSocketServer.onlineCount++;
        }
    
        public static synchronized void subOnlineCount() {
            WebSocketServer.onlineCount--;
        }
    }
    
    

    最终的实现效果如下(为了避免我的帅气伤人,这里打码( ̄ェ ̄;))

    在这里插入图片描述

    自己尝试的搭建了信令服务器,但是没有成功,已经购买了域名,备案成功后,想通过域名来实现跨网的视频通话。

    展开全文
  • webRtc+websocket多人视频通话

    万次阅读 2016-08-10 17:50:32
    webRTc+ websocket实现多人视频通话,目前此demo只支持crome浏览器, 版本仅仅支持:ChromeStandalone_46.0.2490.80_Setup.1445829883 tomcat要8,jdk要1.7,不需要数据库 192.168.1.118是我的ip地址,在所以jsp页面...

    webRTc+ websocket实现多人视频通话,目前此demo只支持crome浏览器,

    版本仅仅支持:ChromeStandalone_46.0.2490.80_Setup.1445829883

    tomcat要8,jdk要1.7,不需要数据库

    192.168.1.118是我的ip地址,在所有jsp页面中,要修改成自己的服务器的ip地址

    多人视频通话启动后访问地址:

    http://192.168.1.118:8080/WebRTC/manyrtcclientA

    http://192.168.1.118:8080/WebRTC/manyrtcclientC

    最后打开http://192.168.1.118:8080/WebRTC/manyrtcclientB

    因为B是触发者,B会先发消息给A和C


    一对一视频通话访问地址

    http://192.168.1.118:8080/WebRTC/rtcclientA

    之后访问:http://192.168.1.118:8080/WebRTC/rtcclientB


    websocket测试地址:

    http://192.168.1.118:8080/WebRTC/clientA

    http://192.168.1.118:8080/WebRTC/clientB

    没有顺序,可以直接测试


    csdn下载源码下载地址:http://download.csdn.net/detail/heqinghua217/9600085


    看代码之前,建议大家看看webrtc通信原理,来自:http://www.cnblogs.com/fangkm/p/4364553.html

    这段文字和图片虽然很简短,但是很清楚,要多看几遍,反正我看了很多遍

    --这篇文章有些文字也是很好的参考

    http://www.cnblogs.com/lingyunhu/p/4058182.html?utm_source=tuicool


    一对一的通信网上有demo,其实很简单,关键是多人视频通信,我也是想了很久,看了这个图,自己也在本子上画了几个图,

    我多人视频通话思路:饶了很多弯路,最后终于可以了,以下是我的心里路程:

    视频通话websokit和webRTC视频监控端调试,发现问题。
    C端数据可以接收到,但是无法显示。


    解决1:后面考虑C必须也要和AB建立链接,于是修改成C也发送响应消息给A和B结果,导致A和B通信混乱,
    解决2、考虑可能服务器只是解决了信令服务的消息传送,但是视频端的服务stun并没有区分接受到的是谁的消息,考虑client创建多个视频链接connection。然后每一端都和相应的peerconnction通信。这里消息是固定,需要拿到消息,重新编辑,加入消息发送人,否则无法知道用哪个peerconnection保持通信。
    测试1、怀疑是未建立链接导致,测试,A和B的正常通信,吧A的消息不传入给B,A是否可以看到B的视频?修改代码后测试,发现看不到,所以必须要建立链接
    测试2、先测试A和B通信的情况下,建立多个peerconnection,建立链接,转发消息,看看是否可行?因为担心,candidate消息格式不允许修改,怕stun服务无法识别,发现不可行
    测试3、A和B通信建立后,可以继续发送文本消息,不会断开
    疑问1、还是需要先确定A和B通信,一共发起几次请求,请求内容分别是什么,否则不是仅仅修
    改canidate就可以解决的。分析数据后发现
    (场景:A和B通信,B请求A的过程:
    1、B先发送offer和sdp(音频相关参数)给A,结束后继续发送candidate(ip和端口以及是video还是audio)给A,这里video和audio发送了4遍
    2、A接收到请求,发送answer和sdp,结束后继续发送candidate的audio和video也是多遍给B
    然后再发送一个offer,sdp给B
    3、B接收到信息,发送一个answer,sdp给A,最后连接成功后,websoket就没有再传递消息,感觉是他们自己直接通信了。
    有点类似,我打电话给你(不确定你是谁),先发个短信问确认下你是谁?(当然要把自己的一些基本信息发送过去,否则别人也不理我) ,对方看到短息,发现是朋友,然后回复我,他张三,性别男、年龄88,然后张三回复可以打电话了,,我收到信息,打电话过去。

     

    1、创建多个peerconnection之后,B和A之间的通信也显示不
    了,B给A发送请求,A可以收到的请求,但是A无法响应给B


    2、怀疑多个peerconncetion会发送多条数据给别人,如B到A,B会发多条给A,那么A的两个消息冲断,导致混乱。原来这是考虑接受到消息,用发送方来判断是B发过来的,用connection接受,是C发过来的用connect2接受,但是A也有两个peerconnection,它会发送两边消息给B和C,其实应该是A的connetion发送给B,connection1发送给C,然后B和C接受到消息,判断是来自A还是B。
    最后方法可行



    上述序列中,WebRTC并不提供Stun服务器和Signal服务器,服务器端需要自己实现。Stun服务器可以用google提供的实现stun协议的测试服务器(stun:stun.l.google.com:19302),Signal服务器则完全需要自己实现了,它需要在ClientA和ClientB之间传送彼此的SDP信息和candidate信息,ClientA和ClientB通过这些信息建立P2P连接来传送音视频数据。由于网络环境的复杂性,并不是所有的客户端之间都能够建立P2P连接,这种情况下就需要有个relay服务器做音视频数据的中转,本文本着源码剖析的态度,这种情况就不考虑了。这里说明一下, stun/turn、relay服务器的实现在WebRTC源码中都有示例,真是个名副其实的大宝库。

    上述序列中,标注的场景是ClientA向ClientB发起对聊请求,调用描述如下:

    • ClientA首先创建PeerConnection对象,然后打开本地音视频设备,将音视频数据封装成MediaStream添加到PeerConnection中。
    • ClientA调用PeerConnection的CreateOffer方法创建一个用于offer的SDP对象,SDP对象中保存当前音视频的相关参数。ClientA通过PeerConnection的SetLocalDescription方法将该SDP对象保存起来,并通过Signal服务器发送给ClientB。
    • ClientB接收到ClientA发送过的offer SDP对象,通过PeerConnection的SetRemoteDescription方法将其保存起来,并调用PeerConnection的CreateAnswer方法创建一个应答的SDP对象,通过PeerConnection的SetLocalDescription的方法保存该应答SDP对象并将它通过Signal服务器发送给ClientA。
    • ClientA接收到ClientB发送过来的应答SDP对象,将其通过PeerConnection的SetRemoteDescription方法保存起来。
    • 在SDP信息的offer/answer流程中,ClientA和ClientB已经根据SDP信息创建好相应的音频Channel和视频Channel并开启Candidate数据的收集,Candidate数据可以简单地理解成Client端的IP地址信息(本地IP地址、公网IP地址、Relay服务端分配的地址)。
    • 当ClientA收集到Candidate信息后,PeerConnection会通过OnIceCandidate接口给ClientA发送通知,ClientA将收到的Candidate信息通过Signal服务器发送给ClientB,ClientB通过PeerConnection的AddIceCandidate方法保存起来。同样的操作ClientB对ClientA再来一次。
    • 这样ClientA和ClientB就已经建立了音视频传输的P2P通道,ClientB接收到ClientA传送过来的音视频流,会通过PeerConnection的OnAddStream回调接口返回一个标识ClientA端音视频流的MediaStream对象,在ClientB端渲染出来即可。同样操作也适应ClientB到ClientA的音视频流的传输。



    展开全文
  • W3 WebRTCWebSocket官网API

    千次阅读 2013-12-20 15:23:22
    http://www.w3.org/TR/webrtc/ http://dev.w3.org/html5/websockets/
  • 前言 上一次进行了手动交换sdp成功进行了ice连接,但是正常情况下,不可能是让你手动交换,因为你能手动交换,说明你们之间已经有了传输通道,不然怎么获取对方的sdp。...const wss = new webSocket.Server
  • 这篇文章主要参考了Webrtc WebSocket实现音视频通讯,非常感谢提供代码 前端部分完全是从这篇文章复制过来的,只是修改了webscket的url,还有加入了webrtc-adapterjs,至于做什么,可以点击链接进行了解 前端...
  • freeswitch websocket webrtc

    2018-11-16 09:46:00
    因为webRTC需要https,所以对应的FreeSWITCH提供WebSocket服务也要wss   conf/var.xml中有两个开关,要设置true   conf/sip_profiles/internal.xml 中确保wss配置打开(SIP 服务的端口是 5060...
  • websocket autobahn webrtc

    千次阅读 2015-11-10 14:28:59
    最近分析webrtc android 的交互流程(房间服务器、信令、穿透等),发现webrtc是使用的是autohahn 的 websocket,初步看了下发现这个库封装的很不错,就分享出来,下面的 内容是来自网上。。 Autobahn ...
  • WebSocketwebrtc结合

    2013-03-12 09:41:02
    websocket发送信令消息,用WebRtc传输音视频消息。测试通过,对需要的人妖帮助
  • websocket连通本地webrtc

    2019-09-30 12:57:52
    发现了有个东西叫webrtc,有人分析过他不适合做流量大,人数多的直播。但是我也只是玩一下,感受一下视频连通的感觉。 一开始在github上面看到了一个,比较全大部分的API都做了demo,还有canva 3d融合webrtc的例子...
  • 基于Chrome、Java、WebSocketWebRTC实现浏览器视频通话

    千次下载 热门讨论 2013-03-07 13:03:46
    基于Chrome、Java、WebSocketWebRTC实现浏览器视频通话

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 468
精华内容 187
关键字:

webrtcwebsocket