美文网首页实时通信程序员开发
WEB p2p视频聊天?! -- WebRTC 初入探究 与 实

WEB p2p视频聊天?! -- WebRTC 初入探究 与 实

作者: MeIsLZHua | 来源:发表于2016-08-18 00:08 被阅读2827次

    前言

    本片demo中 的实现为纯前端js实现,所以 而且可以在本机下运行(有网络即可正常链接服务器),所以你可以修改 代码(界面好丑,处理时间不多....)

    这里感谢一下(没有广告费...只是免费用了别人的资源,总得感谢下)
    leancloud 的 免费云平台(现在不是免费了)
    openshift 的 免费平台

    本篇文章内容:

    • WebRTC的基础知识
    • WebRTC的连接基本流程
    • WebRTC的基础接口介绍
    • WebRTC的注意事项
    • WebRTC的 demo

    WebRTC 的基础知识

    借来的 webRTC结构图

    什么是WebRTC

    WebRTC : 网页实时通信(Web Real-Time Communication),故名思意.
    对于浏览器来说,它要实现三大模块
    音频处理模块,视频处理模块,网络传输模块

    它主要是由浏览器底层实现的,对于我们来说,是调用它开放出来的JS api
    相关的主要有

    • MediaStream 系列API(主要是获取 媒体流的,例如摄像头啊,麦克风,音频输出设备啊等等的)
    • RTCPeerConnection 系列API(主要是用来 进行 p2p连接的)
    • RTCDataChannel (其实这个应该也算在RTCPeerConnection系列里,不同的是,不是传输媒体流,而且传输数据)

    WebRTC的连接方式

    RTCPeerConnection底层下实现了ice的支持,ICE,全名叫交互式连接建立(Interactive Connectivity Establishment)
    支持stun 和 turn 服务器,先用stun来进行nat穿透链接,官方数据称85%是可以穿透的.(我是那15%,心累),如果穿不透,还可以turn服务器来进行桥接
    (由于我的韩国服务器本来网速就不怎么好,于是就忽略了turn)

    WebRTC的连接基本流程

    1. 首先 A,B 生成 RTCPeerConnection

    2. 然后 A 调用createOffer 生成 Description,
      调用setLocalDescription,
      然后再把Description发送给B

    3. B收到A的Description后,
      调用setRemoteDescription,
      然后调用createAnswer 生成 B的Description,
      然后把B的Description发送给A

    4. A收到B的Description后,setRemoteDescription

    没错,就是这么简单,其实就是一个交换Description的过程
    第一个生成Description的叫offer,第二个生成Description的叫answer
    这个交换的过程需要你自己的信令服务器(即是通信服务器)去传递

    还有一点,上面操作的过程中,RTCPeerConnection可能产生icecandidate数据,需要把数据传给对方
    基本流程如下:

    1. A 实现peer.onicecandidate,使其可以监听到icecandidate数据的产生
    2. A 监听到 icecandidate数据产生,通过信令服务器传输给B
    3. B 收到来自A的icecandidate数据,调用 peer.addIceCandidate(new RTCIceCandidate(message.candidate)) 设置数据

    上面这个操作,A,B都需要做,双方都会产生icecandidate数据,然后发送给对方,这个p2p链接的过程

    基础接口介绍

    由于各个浏览器的函数名,以及参数都不一样,所以我采用了adapter.js,来消除浏览器之间的差异...(一直在chrome下调试,跑一下火狐的,各种参数报错后...马上用了adapter)

    下面函数也是才用了adapter.js后进行介绍的;

    navigator.mediaDevices.getUserMedia()

    看着上面函数名,就知道它是获取你本机的摄像头麦克风的了,就是说,即使不做 视频聊天,也可以来玩玩摄像头→_→

    //还有一个facingMode,资料不多,写上了
    var usermedia = navigator.mediaDevices.getUserMedia({
      audio:true,
      video:{
        //ideal表示期望值,希望能拿到,拿不到就按照最大最小
        //(不要乱设值,不然获取不了摄像头就别说我没提醒了)赤裸裸的恐吓你→_→
        height:{ min: 320, ideal: 1280, max: 1920 },
        width:{ min: 240, ideal: 720, max: 1080 },
        frameRate: { ideal: 10, max: 15 }  //帧率
      }
    });
    
    //经过adapter翻译后
    chrome: 
    {
      "audio":true,
      "video":{
        "optional":[
          {"minHeight":1280},
          {"maxHeight":1280},
          {"minWidth":720},
          {"maxWidth":720},
          {"minFrameRate":10},
          {"maxFrameRate":10}
        ],
        "mandatory":{
          "minHeight":320,
          "maxHeight":1920,
          "minWidth":240,
          "maxWidth":1080,
          "maxFrameRate":15
        }
      }
    }
    
    usermedia.then(funcion(stream){
      //stream就是你获得的媒体流
    })
    

    相关的还有以下等等,就不详细介绍了:
    navigator.mediaDevices.enumerateDevices() //获取媒体设备(video可以用它拿到的id,来决定在那个音频输出设备中输出哦~)
    MediaRecorder //记录媒体流(可以录影,转化成编码再传输,再转为流,再播放,挺好玩的东西)

    RTCPeerConnection 系列

    就是建立p2p连接那个,这里说明部分api的用法

    new RTCPeerConnection()
    //生成一个peer连接,但还没开始链接
    var peer = new RTCPeerConnection({
      "iceServers": [  //ice服务器,可以设置stun,turn服务器
        {"url": "stun:stun.l.google.com:19302"}
      ]
    });
    
    peer.onaddstream
    //获取到对方发送的媒体流,event.stream,至于要干嘛....你看着办
    peer.onaddstream = function (event) {    
      Vue.set(client, "stream", event.stream);
    };
    
    peer.onicecandidate
    //获取到icecandidate信息,要发送给p2p的对方
    //不然p2p链接就进行不下去了!
    //(我发现是一般setLocalDescription,setRemoteDescription后得到)
    peer.onicecandidate = function (event) {    
      if (!event.candidate) return;
      messageServer.sendRoomMessage({        
        action: "client_icecandidate",
        target: client.id,
        candidate: event.candidate
      })
    };
    
    peer.oniceconnectionstatechange
    //简单的可以理解成连接状态事件
    //这部分建议还是看文档
    //https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState
    peer.oniceconnectionstatechange = function(){
      switch (peer.iceConnectionState) {
        case "failed":
          //显然是失败
        case "checking":
          //连接中...
        case "connected":
         //连接成功
        case "completed":
          //链接完成
        case "disconnected":
          //连接断开
      }
    }
    
    peer.createOffer
    //部分浏览起会因为没有这个config而报错的,所以还是加上吧
    //测试一下config中两个值设置为0的时候,发送offer的,没有拿到stream
    //目测是用来之指定需要怎么样的资料的
    //更多的资料找不到
    var config = {    
      offerToReceiveAudio: 1,
      offerToReceiveVideo: 1
    }
    peer.createOffer(config).then(function (dp) {    
      //获取到的Description,应该发送给对方设置
      client.peer.setLocalDescription(dp);    
      messageServer.sendRoomMessage({        
        action: "client_offer",        
        target: client.id,        
        sdp: dp    
      });
    });
    
    peer.createAnswer
    //这个又很奇怪,加上config就会报错,不加问事....好奇怪
    //其实这个函数就是获取到对方的offer后进行的应答
    client.peer.createAnswer().then(function (dp) {    
      //获取到本地Description后,记得发送给对方设置
      messageServer.sendRoomMessage({       
        action: "client_answer",        
        target: client.id,        
        sdp: dp    
      });    
      client.peer.setLocalDescription(dp);
    }).catch(function () {    
      console.log(client.id + ":生成 answer 失败")  
    });
    

    RTCDataChannel在这里就不介绍
    更详细的接口信息,可以查看 https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API

    WebRTC的注意事项

    1. 在部分浏览器中,getUserMedia 需要有 https才能打开,例如chrome,所以要如果挂带外网,需要https的支持
    2. 在实际开发中,请才用上面的adapter.js来控制好不同浏览器之间的区别
    3. 在getUserMedia的时候,如果乱设置,可能获取不到设备的情况哦!

    WebRTC的 demo

    由于代码过长就不直接贴了

    代码缩略图

    demo地址:https://static.meislzhua.online/
    手机打开的话 需要手机chrome才可以(没测试哪部分不兼容的)
    桌面浏览器在chrome 51 和 ff48中测试成功
    代码地址:https://github.com/meislzhua/webrtc-demo

    后语

    在8月10的时候,突然想写一个webrtc的demo...
    于是
    10 号上午看了webrtc的相关资料,下午复习一下leancloud的通信
    11 号一直在调leancloud的通信...(试过推送和实时通信)
    12 号正式开始写demo
    13 号 demo完成,但成功率很低..(发现是原来我的网络不行)..然后准备方案二
    14 号 研究了一整天的视频录制与传输,后被leancloud实时磨得没耐心(5K/s限制),放弃了
    15-16号,酱油了一下,把demo打包成了electron应用,并在linux,window,mac osx下测试
    17号 随意重构了一下代码,写了本篇文章....

    我本来打算demo用electron应用来代替的..这样可以保密一些东西,后来想想,还是算了~相信读者素质
    欢问题迎留言 或者指出本文的错误

    相关文章

      网友评论

      • 36b6f3b643e1:您好!我看到您也研究了视频录制功能,
        14 号 研究了一整天的视频录制与传输,后被leancloud实时磨得没耐心(5K/s限制),放弃了

        请问下浏览器调用摄像头进行录制视频,边录制边上传到服务器端,有什么方法吗?
        目前我只是用webRTC+websocket 实现了客户端浏览器与客户端浏览器之间的P2P视频通话,但是服务器端不能获取到客户端浏览器的视频流,从而把录制的视频保存到服务器端。
      • 36b6f3b643e1:我学习了进一周时间,您的这篇文章非常精简易懂,纯属干货,谢谢您!
      • 4e5a607797a7:realtime.browser.min.js找不到
        MeIsLZHua:可能是leancloud改版的原因吧,其实理解了大概,不需要leancloud,自己写一个通讯服务器基本问题也不大
      • 20fef5789080:文章写的很不错,对于了解webrtc很有价值。可是好像demo一直有问题,本地的话,拉了你的demo,本地目前跑不起来,得配个环境才行。
        MeIsLZHua:@Perkin 哦,这个可能是用了leancloud的原因哦
      • Leviathan:你好,我在github上观看源码发现是纯前端页面,点开index.html是无法运行的,请问我需要什么后端语言才能运行这个demo,非常感谢。
        MeIsLZHua: @Leviathan 好吧,你可以查看一下网络库加载情况。应该是vue加载失败
        Leviathan:@MeIsLZHua 两个浏览器都尝试了,显示出来的结果都只是text没有button,选择房间显示为{{r.name}}{{r.number}}。
        MeIsLZHua: @Leviathan 请使用firefox或者chrome打开
      • whaike:目前在学前端,看到这个技术很是令人向往,可以指点下想要完成这个需要学习哪些东西吗?不止WebRTC吧 谢谢
        whaike:@MeIsLZHua 恩 ,谢谢你的回答 :+1:
        MeIsLZHua: @whaike 其实要完成这个,其实真的需要一个信令服务器就可以了,如demo中的leancloud。
        剩余的都是逻辑处理和ui处理了。
        逻辑处理就没啥好说了
        ui处理,你可以用原生js,jq等来处理dom,
        也可以选择vue,react等mvvm.框架来处理,demo中使用了vue
        学会最少一个mvvm框架,对于前端来说还是很重要的(虽我是全栈,但没有很喜欢前端→_→)

      本文标题:WEB p2p视频聊天?! -- WebRTC 初入探究 与 实

      本文链接:https://www.haomeiwen.com/subject/euymsttx.html