• 一文带你了解webrtc基本原理(动手实现1v1视频通话)


    webrtc (Web Real-Time Communications) 是一个实时通讯技术,也是实时音视频技术的标准和框架。
    大白话讲,webrtc是一个集大成的实时音视频技术集,包含了各种客户端api、音视频编/解码lib、流媒体传输协议、回声消除、安全传输等。
    对于开发者来说可以借助webrtc非常方便的实现低延时视频通话能力。
    现在主流的直播系统、会议系统基本都是基于webrtc来实现。

    一、webrtc 三种架构

    我们先大概了解下webrtc的几种架构及各自适用场景。

    webrtc_arch.png

    【Mesh】

    Mesh架构,需要所有参与连接的peer建立与所有其他peer的媒体连接。
    该架构需要n-1个上下行,以此带来的带宽消耗(流量)、编/解码消耗(手机性能)成线性增长。
    该架构只能适用3-4个人的小型会议场景。

    【MCU】

    所有本房间的peer将本地媒体流推到远程媒体服务器,由媒体服务器进行混流,然后再推到所有连接的peer端。
    该架构的优点就是只需要1路上下行,随着peer人数不断增加,依然不会对用户造成带宽、手机性能影响。
    该架构将压力转嫁到服务端,由专用媒体服务器来完成混流,转推等功能。

    【SFU】

    相对于MCU来说SFU只做转发,媒体服务器压力有限。与mesh架构相比,只需要n-1个下行,1个上行。
    在大规模的场合该架构具有伸缩性。

    二、实现 1v1 视频通话

    废话不多说,动手实践下。
    (麻雀虽小,五脏俱全。通过实现1v1的功能,来整体了解下webrtc协议的原理。)
    github:https://github.com/Plen-wang/webrtc-demo-1v1

    mesh_p2p.png

    由于是私有证书问题,chrome会有安全提示。(demo地址暂时还能用 -_- )

    有两个方法可以试下。

    第一个方法,手动设置一个类似不安全白名单列表,然后重启浏览器。

    chrome://flags/#unsafely-treat-insecure-origin-as-secure

    如果不行,我们试下第二个方法肯定可以。

    点击空白页输入 thisisunsafe 字符。

    动手之前,我们先简单了解下webrtc的连接的大致流程和涉及的相关技术点。

    【WebRTC P2P】

    【NAT穿透】
    peer基本都在内网,需要通过nat穿透技术来与peer建立连接。
    根据nat的拓扑情况大致分为如下几种:完全锥形、IP锥形、端口锥形、对称形。
    stun\turn协议:stun协议用来拿到peer公网ip,turn用来做relay数据转发。

    5Figure41.png

    【SDP】
    sdp是会话描述协议。
    是媒体协商时使用,用于将本地支持的媒体(编解码等)信息、candidate(连接候选者)信息打包发送到信令服务器。
    sdp的交换是通过中间服务器(信令服务器)来完成的。

    【ICE】
    ICE是一个不断尝试连接的协议,不同的网络情况下ICE大概会尝试如下几种方式来建立通讯通道。
    host(peers都在内网)、 srflx(nat穿透)、prflx(nat穿透-Full Cone)、relay(中继)

    【服务端】
    在整个连接生命周期中都是需要服务端参与。参与webrtc协作的服务端大概分为这几种类型。
    stun/turn服务器(p2p穿透)、信令服务器、媒体服务器(媒体信息处理)、业务服务器(可选)

    整体流程大致如下。

    webrtc_connection.png

    (上述技术点较多,感兴趣可以自行查询相关资料)

    【部署STUN\TURN服务器】

    为了支持1v1公网访问,我们需要搭建一个stun/turn服务器。
    这里我们使用 Coturn 开源组件,coturn的镜像有很多,可自行选择。
    (注意准备coturn配置文件时,记得设置用户名和密码。)

        docker run -d  --rm --name turn-server --network=host   \
                   -v ${pwd}/turnserver.conf:/etc/coturn/turnserver.conf \
               instrumentisto/coturn
    

    部署好之后可以通过ICE测试工具测试下
    https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice

        stun:1.15.11.173:3478?transport=tcp
        turn:1.15.11.173:3478?transport=tcp:user:pwd
    

    如果正常返回了ICE尝试的连接类型,说明部署没有问题。

    【实现信令服务器与客户端代码】

    我们采用golang来实现一个简单的信令服务器,使用开源组件go-socket。
    同时还需要实现一个web客户端。
    demo代码就不贴到文章里了,放在github上。整体代码比较简单,感兴趣可以看下。
    git@github.com:Plen-wang/webrtc-demo-1v1.git

    【部署信令服务器】
    当在本地debug的差不多了,我们把信令服务器打个镜像发到云主机上。
    (如果部署本demo,可以直接使用此镜像。)

        docker push wangqingpei/rtc-signal-server:latest
        docker run --name signal-server -d -p:8080:8080 wangqingpei/rtc-signal-server
        
    

    【部署web服务器】
    部署好信令服务器之后,我们把静态文件放到web服务器里,直接使用nginx镜像部署非常简单。

        docker run -d -p 80:80 -p 443:443  --rm --name webrtc-nginx   \
        -v /data/rtc-nginx.conf:/etc/nginx/nginx.conf  \
        -v /data/pem/server.key:/etc/nginx/server.key  \
        -v /data/pem/server.pem:/etc/nginx/server.pem  \
        -v /data/rtc-static-file:/usr/share/nginx/html  nginx
    

    部署前,记得修改js里的stun服务器地址。

    //创建RTCPeerConnection对象
    function createRTCPeerConnection() {
        try {
    	    
    	    const configuration = {'iceServers': [{'urls': 'stun:1.15.11.173:3478?transport=tcp'}]}
    	    
            rtcConnObject = new RTCPeerConnection(configuration);
            rtcConnObject.onicecandidate = handleRtcICECandidate;//ice 交互
            rtcConnObject.onaddstream = handleRtcAddStream;//远程stream加入
            rtcConnObject.onremovestream = handleRtcRemoveStream;//远程stream移除
            rtcConnObject.addStream(localStreamObject);//添加本地stream
            console.log("create local RTCPeerConnection object ok.");
        } catch (e) {
            console.error("create RTCPeerConnection err.", e);
        }
    }
    
    

    两边peer就可以借助stun服务器拿到公网ip实现nat穿透。

    三、实现MCU/SFU 多人通话

    MCU/SFU架构需要 专用媒体服务器 参与。

    【媒体服务器选择】

    专用媒体服务器有 OWT(open webrtc toolkit)、TWS(Kurento Media Server)等重量级的开源产品。

    这两款开源框架都支持MCU、SFU架构功能。

    我们选择OWT捣鼓下。

    先看下部署起来的效果,默认MCU模式。

    owt_ok.png

    红框部分是服务端混流之后的效果。

    【部署OWT】

    注意,owt-server-4.3镜像与最新版chrome有兼容性问题,会报错 Empty candidate 错误。

    owt_empty_candidate.png

    我们直接使用5.0的镜像部署。

    docker run -d --name owt-demo --network host lmshao/owt-server
    

    由于该镜像是使用默认配置打的,启动后手动进入容器修改下相关配置,换成你云主机的公网ip,然后重启服务。

    配置文件路径

    vi dist/webrtc_agent/agent.toml
    

    配置项,这里修改成你的公网ip

    network_interfaces = [{name = "eth0", replaced_ip_address = "1.116.175.232"}]  # default: []
    

    stun服务器可选

    stunport = 3478 #default: 0
    stunserver = "1.15.11.173" #default: ""
    

    然后修改下portal.toml文件,文件路径。

    vi dist/portal/portal.toml
    

    修改成公网ip

    ip_address = "1.116.175.232" #default: ""
    

    重启下相关服务

    ./bin.restart-all.sh 
    

    注意启动日志里有一个id、key,这是用来进入管理页面用的。(没错,owt提供了后台管理页面 -_-)

    superServiceId: xxx
    superServiceKey: xxx
    
    sampleServiceId: xxx
    sampleServiceKey: xxx
    
    

    默认3004端口下是mcu模式,连线的人多了就会明显卡顿(看服务器配置)。

    我们切到SFU模式试下流畅度和服务器负载情况。

    通过 ?forward=true 参数控制

    https://1.116.175.232:3004/?forward=true

    demo_sfu.png

    OWT还配有管理后台用于控制媒体服务器的相关参数。
    owt_room.png
    owt_room_detail.png

    OWT还是比较强大的,有兴趣可以研究研究。

    参考资料:
    github.com/googollee/go-socket.io
    《WebRTC技术详解:从0到1构建多人视频会议系统》
    《WebRTC音视频实时互动技术:原理、实战与源码分析》
    《FFmpeg 音视频开发基础与实战》

  • 相关阅读:
    Golang数组Array
    转:【专题六】UDP编程
    转:【专题五】TCP编程
    转:【专题四】自定义Web浏览器
    转:【专题三】自定义Web服务器
    转:【专题二】HTTP协议详解
    转:【专题一】网络协议简介
    转:[你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单
    转:[你必须知道的异步编程]——基于任务的异步模式
    转:[你必须知道的异步编程]——基于事件的异步编程模式
  • 原文地址:https://www.cnblogs.com/wangiqngpei557/p/16557821.html
Copyright © 2020-2023  润新知