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

    千次阅读 2018-03-14 13:31:30
    转载地址:http://blog.csdn.net/chenhande1990chenhan/article/details/72831782一般...本文主要利用websocket进行通讯,支持个google浏览器,无法兼容Firefox浏览器,同时对于Tomcat要求8.0以上,同时由于最新的w...

    转载地址:http://blog.csdn.net/chenhande1990chenhan/article/details/72831782


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

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



    [html]  view plain  copy
    1. <%@ page language="java" pageEncoding="UTF-8" %>  
    2. <!DOCTYPE html>  
    3. <html>  
    4. <head>  
    5.     <title>Java后端WebSocket的Tomcat实现</title>  
    6. </head>  
    7. <body>  
    8.     Welcome<br/><input id="text" type="text"/>  
    9.     <button onclick="send()">发送消息</button>  
    10.     <hr/>  
    11.     <button onclick="closeWebSocket()">关闭WebSocket连接</button>  
    12.     <hr/>  
    13.     <div id="message"></div>  
    14.       
    15.     <video id="vid1" width="640" height="480" autoplay></video>  
    16.     <video id="vid2" width="640" height="480" autoplay></video><br>  
    17.     <a id="create" href="/Websocket/#true" onclick="init()">点击此链接新建聊天室</a><br>  
    18.     <p id="tips" style="background-color:red">请在其他浏览器中打开:http://此电脑   加入此视频聊天</p>  
    19. </body>  
    20.   
    21. <script type="text/javascript">  
    22.     var isCaller = window.location.href.split('#')[1];  
    23.     var websocket = null;  
    24.     //判断当前浏览器是否支持WebSocket  
    25.     if ('WebSocket' in window) {  
    26.         websocket = new WebSocket("ws://localhost:8080/Websocket/websocket");  
    27.     }  
    28.     else {  
    29.         alert('当前浏览器 Not support websocket')  
    30.     }  
    31.   
    32.     //连接发生错误的回调方法  
    33.     websocket.onerror = function () {  
    34.         setMessageInnerHTML("WebSocket连接发生错误");  
    35.     };  
    36.   
    37.     //连接成功建立的回调方法  
    38.     websocket.onopen = function () {  
    39.         setMessageInnerHTML("WebSocket连接成功");  
    40.     }  
    41.   
    42.  // 创建PeerConnection实例 (参数为null则没有iceserver,即使没有stunserver和turnserver,仍可在局域网下通讯)  
    43.     var pc = new webkitRTCPeerConnection(null);  
    44.   
    45.     // 发送ICE候选到其他客户端  
    46.     pc.onicecandidate = function(event) {  
    47.         setMessageInnerHTML("我看看 1");  
    48.         if (event.candidate !== null) {  
    49.             setMessageInnerHTML("我看看 2");  
    50.             websocket.send(JSON.stringify({  
    51.                 "event" : "_ice_candidate",  
    52.                 "data" : {  
    53.                     "candidate" : event.candidate  
    54.                 }  
    55.             }));  
    56.         }  
    57.     };  
    58.       
    59.     //接收到消息的回调方法  
    60.     websocket.onmessage = function (event) {  
    61.         setMessageInnerHTML("接收到的信息");  
    62.         setMessageInnerHTML(event.data);  
    63.         if(event.data=="new user") {  
    64.             console.log("new user");  
    65.             location.reload();  
    66.         } else {  
    67.             var json = JSON.parse(event.data);  
    68.             console.log('onmessage: ', json);  
    69.             //如果是一个ICE的候选,则将其加入到PeerConnection中,否则设定对方的session描述为传递过来的描述  
    70.             if (json.event === "_ice_candidate") {  
    71.                 pc.addIceCandidate(new RTCIceCandidate(json.data.candidate));  
    72.             } else {  
    73.                 pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp));  
    74.                 // 如果是一个offer,那么需要回复一个answer  
    75.                 if (json.event === "_offer") {  
    76.                     pc.createAnswer(sendAnswerFn, function(error) {  
    77.                         console.log('Failure callback: ' + error);  
    78.                     });  
    79.                 }  
    80.             }  
    81.         }  
    82.     }  
    83.   
    84.     //连接关闭的回调方法  
    85.     websocket.onclose = function () {  
    86.         setMessageInnerHTML("WebSocket连接关闭");  
    87.     }  
    88.   
    89.     //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。  
    90.     window.onbeforeunload = function () {  
    91.         closeWebSocket();  
    92.     }  
    93.   
    94.     //将消息显示在网页上  
    95.     function setMessageInnerHTML(innerHTML) {  
    96.         document.getElementById('message').innerHTML += innerHTML + '<br/>';  
    97.     }  
    98.   
    99.     //关闭WebSocket连接  
    100.     function closeWebSocket() {  
    101.         websocket.close();  
    102.     }  
    103.   
    104.     //发送消息  
    105.     function send() {  
    106.         var message = document.getElementById('text').value;  
    107.         websocket.send(message);  
    108.     }  
    109.       
    110.  // stun和turn服务器  
    111.     var iceServer = {  
    112.         "iceServers" : [ {  
    113.             "url" : "stun:stun.l.google.com:19302"  
    114.         }, {  
    115.             "url" : "turn:numb.viagenie.ca",  
    116.             "username" : "webrtc@live.com",  
    117.             "credential" : "muazkh"  
    118.         } ]  
    119.     };  
    120.   
    121.       
    122.   
    123.     // 如果检测到媒体流连接到本地,将其绑定到一个video标签上输出  
    124.     pc.onaddstream = function(event) {  
    125.         document.getElementById('vid2').src = URL  
    126.                 .createObjectURL(event.stream);  
    127.     };  
    128.   
    129.     // 发送offer和answer的函数,发送本地session描述  
    130.     var sendOfferFn = function(desc) {  
    131.         pc.setLocalDescription(desc);  
    132.         websocket.send(JSON.stringify({  
    133.             "event" : "_offer",  
    134.             "data" : {  
    135.                 "sdp" : desc  
    136.             }  
    137.         }));  
    138.     }, sendAnswerFn = function(desc) {  
    139.         pc.setLocalDescription(desc);  
    140.         websocket.send(JSON.stringify({  
    141.             "event" : "_answer",  
    142.             "data" : {  
    143.                 "sdp" : desc  
    144.             }  
    145.         }));  
    146.     };  
    147.   
    148.     // 获取本地音频和视频流  
    149.     navigator.webkitGetUserMedia({  
    150.         "audio" : true,  
    151.         "video" : true  
    152.     },  
    153.             function(stream) {  
    154.                 //绑定本地媒体流到video标签用于输出  
    155.                 document.getElementById('vid1').src = URL  
    156.                         .createObjectURL(stream);  
    157.                 //向PeerConnection中加入需要发送的流  
    158.                 pc.addStream(stream);  
    159.                 //如果是发起方则发送一个offer信令  
    160.                 if (isCaller) {  
    161.                     pc.createOffer(sendOfferFn, function(error) {  
    162.                         console.log('Failure callback: ' + error);  
    163.                     });  
    164.                 }   
    165.             }, function(error) {  
    166.                 //处理媒体流创建失败错误  
    167.                 console.log('getUserMedia error: ' + error);  
    168.             });  
    169.       
    170.     window.onload=function(){   
    171.         if(isCaller==null||isCaller==undefined) {  
    172.             var tips = document.getElementById("tips");  
    173.             tips.remove();  
    174.         } else {  
    175.             var create = document.getElementById("create");  
    176.             create.remove();  
    177.         }  
    178.     };  
    179.     function init() {  
    180.         location.reload();  
    181.     }  
    182. </script>  
    183. </html>  

    [java]  view plain  copy
    1. package me.gacl.websocket;  
    2.   
    3. import java.io.IOException;  
    4. import java.util.concurrent.CopyOnWriteArraySet;  
    5.   
    6. import javax.websocket.*;  
    7. import javax.websocket.server.ServerEndpoint;  
    8.   
    9. /** 
    10.  * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, 
    11.  * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 
    12.  */  
    13. @ServerEndpoint("/websocket")  
    14. public class WebSocketTest {  
    15.     //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。  
    16.     private static int onlineCount = 0;  
    17.   
    18.     //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识  
    19.     private static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();  
    20.   
    21.     //与某个客户端的连接会话,需要通过它来给客户端发送数据  
    22.     private Session session;  
    23.   
    24.     /** 
    25.      * 连接建立成功调用的方法 
    26.      * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 
    27.      */  
    28.     @OnOpen  
    29.     public void onOpen(Session session){  
    30.         this.session = session;  
    31.         webSocketSet.add(this);     //加入set中  
    32.         addOnlineCount();           //在线数加1  
    33.         System.out.println(session.getId()+"有新连接加入!当前在线人数为" + getOnlineCount());  
    34.     }  
    35.   
    36.     /** 
    37.      * 连接关闭调用的方法 
    38.      */  
    39.     @OnClose  
    40.     public void onClose(){  
    41.         webSocketSet.remove(this);  //从set中删除  
    42.         subOnlineCount();           //在线数减1  
    43.         System.out.println(session.getId()+"有一连接关闭!当前在线人数为" + getOnlineCount());  
    44.     }  
    45.   
    46.     /** 
    47.      * 收到客户端消息后调用的方法 
    48.      * @param message 客户端发送过来的消息 
    49.      * @param session 可选的参数 
    50.      */  
    51.     @OnMessage  
    52.     public void onMessage(String message, Session session) {  
    53.         System.out.println(session.getId()+"来自客户端的消息:" + message);  
    54.         //群发消息  
    55.         for(WebSocketTest item: webSocketSet){  
    56.             try {  
    57.                 item.sendMessage(message);  
    58.             } catch (IOException e) {  
    59.                 e.printStackTrace();  
    60.                 continue;  
    61.             }  
    62.         }  
    63.     }  
    64.   
    65.     /** 
    66.      * 发生错误时调用 
    67.      * @param session 
    68.      * @param error 
    69.      */  
    70.     @OnError  
    71.     public void onError(Session session, Throwable error){  
    72.         System.out.println("发生错误");  
    73.         error.printStackTrace();  
    74.     }  
    75.   
    76.     /** 
    77.      * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 
    78.      * @param message 
    79.      * @throws IOException 
    80.      */  
    81.     public void sendMessage(String message) throws IOException{  
    82.         this.session.getBasicRemote().sendText(message);  
    83.         //this.session.getAsyncRemote().sendText(message);  
    84.     }  
    85.   
    86.     public static synchronized int getOnlineCount() {  
    87.         return onlineCount;  
    88.     }  
    89.   
    90.     public static synchronized void addOnlineCount() {  
    91.         WebSocketTest.onlineCount++;  
    92.     }  
    93.   
    94.     public static synchronized void subOnlineCount() {  
    95.         WebSocketTest.onlineCount--;  
    96.     }  
    97. }  

    展开全文
  • webrtc-websocket-源码

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

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

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

    区别

    • WebSockets允许浏览器和Web服务器之间的全双工通信
    • WebRTC的PeerConnection允许两个浏览器之间的全双工通信
    展开全文
  • 通过webRTC+websocket实现视频通话

    千次阅读 2020-10-19 17:16:49
    最近空闲时间较多,于是写了...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实现多对多视频通话 项目目录说明 index.html // 页面地址 index.js // ws服务端 多对多实现方案 一个RTCPeerConnection对应一个人,创建多个RTCPeerConnection对接多个人进行链接。
  • 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的音视频流的传输。



    展开全文
  • 未命名网络 这是一个unnamed-network核心库,提供了一个由 WebRTCWebSocket 组成的实验性 p2p 网络。 安装 npm install --save 'git+https://github.com/pastleo/unnamed-network.git' 例子
  • WebRTC直播间 演示链接 ​ WebRTC介绍 ​ 原理简单解释: ​ 浏览器提供获取屏幕、音频等媒体数据的接口, ​ 双方的媒体流数据通过Turn服务器传输。 ​ 项目构造(非常简单) 前端:就一个html文件,js和css直接放...
  • 前言 上一次进行了手动交换sdp成功进行了ice连接,但是正常情况下,不可能是让你手动交换,因为你能手动交换,说明你们之间已经有了传输通道,不然怎么获取对方的sdp。...const wss = new webSocket.Server
  • W3 WebRTCWebSocket官网API

    千次阅读 2013-12-20 15:23:22
    http://www.w3.org/TR/webrtc/ http://dev.w3.org/html5/websockets/
  • 聊天 iCollege & ERP 系统的中间件组件,即即时消息系统。 先决条件 确保您拥有 node.js 并确定 PATH 配置。 下载并以配置它。 如何开始 git clone repo npm install依赖项。 npm start项目 ...
  • 这篇文章主要参考了Webrtc WebSocket实现音视频通讯,非常感谢提供代码 前端部分完全是从这篇文章复制过来的,只是修改了webscket的url,还有加入了webrtc-adapterjs,至于做什么,可以点击链接进行了解 前端...
  • 2、用websocket作为信令通道,构建WebRTC视频通话。 -------------------------------------------------------2014-12-02 开发IDE:MyEclipse 8.6 工程编码方式:UTF-8 环境要求: 1、Tomcat 要求为7.0以上的版本 ...
  • 使用实现的用于信令的简单WebSocket服务器 go build编译编译二进制文件 ./dhyanio-video-chat在:8000上运行后端服务器 前端 client是用React编写的,并且将用于开发服务器。 在client目录中运行以下命令 npm i安装...
  • 然后通过 WebSocket 发送信号。 使用基于 NuxtJS 和 NodeJS 服务器构建的客户端。 特征 视频群呼 使用 WebRTC 构建视频通话。 现在,为了处理所有连接的客户端,我们使用具有网状拓扑的对等连接。 有关完整的文档...

空空如也

空空如也

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

webrtcwebsocket