阅读 21

webRTC

4.可以把采集到的音视频数据录制下来吗?

服务端录制:
    优点是不用担心客户因自身电脑问题造成录制失败(如磁盘空间不足),也不
    会因录制时抢占资源(CPU占用率过高)而导致其他应用出现问题等;缺点是实现的复杂度很高。
客户端录制:
    方便操控,客户端摄像头分辨率很高的(如1280x720),所以客户端录制出视频清晰
    度高;本地高清的视频上传服务端时由于网络带宽不足,视频的分辨率很有可能会
    被自动缩小到了 640x360,这就导致用户回看时视频特别模糊,用户体验差。
    客户端录制的缺点就是录制失败率高。特别耗 CPU,对内存、硬盘的要求也特别高。
 WebRTC库实现客户端录制音视频流
    01.录制后音视频流的存储格式是什么呢?
        直接录制原始数据
            制效率高;录制方法简单,音频与视频数据存放到不同的二进制文件中
            文件中的每一块数据可以由下面的结构体描述:
                struct data 
                    int media_type; // 数据类型,0: 音频 1: 视频 
                    int64_t ts; // timestamp,记录数据收到的时间
                    int data_size; // 数据大小 
                    char* data; // 指定具体的数据
                } media_data;
            弊端是录制完成后还要做音视频合流、输出多媒体文件等工作。等一段时间才能看到视频
        录制成某种多媒体格式(如 MP4 )\
            FLV 媒体文件本身就是流式的
            将直播的视频按 N 分钟为单位,录制成一段一段的 FLV,然后录完一段播一段,这样就实现了上面所讲的边录边看的效果了。
            弊端:
                多人互动的场景不能满足,FLV 只能同时存在一路视频和一路音频
                将音视频流存成 FLV 文件的前提条件是音视频流是按顺序来的,而实际上,音视频数据经过 UDP
                这种不可靠传输网络时,是无法保证音视频数据到达的先后顺序的。因此,在处理音视频录制时,你不仅要考虑录制的事情,还要自
                己做音视频数据排序的工作。
    02.录制下来的音视频流如何播放?
        多人互动类型,且回放时也要和直播时一样,那么你就必须使用私有播放器,
        因为普通播放器是不支持同时播放多路视频的
    03.第三个,启动录制后多久可以回放呢?
        1.边录边看,即开始录制几分钟之后用户就可以观看了
        2.录制完立即回放,即当录制结束后,用户就可以回看录制了。
        3.录完后过一段时间可观看。
js基础知识:
    WebRTC 录制音视频流之后,最终是通过 Blob 对象将数据保存成多媒体文件的
    ArrayBuffer:
        抽象类
        固定长度的二进制数据缓冲区,
        用它存储图片、视频
        只描述一块空间用来存放二进制数据,但内存中并没真正为其分配空间
        let buffer = new ArrayBuffer(16); // 创建一个长度为 16 的 buffer
        let view = new Uint32Array(buffer);
    ArrayBufferView:
        代表不同类型的 Array 的描述
        类型包括:Int8Array、Uint8Array、DataView
        也就是说 Int8Array、Uint8Array 等才是 JavaScript 在内存中真正可以分配的对象。
            Int8Array :在内存空间每一个元素都是 8 位的整数。
            Uint8Array :内存中分配一块每个元素大小为 8 位的无符号整数的空间。
    blob:
        二进制对象
        var blob = new Blob( array, options );
        参数说明:
            array:ArrayBuffer、ArrayBufferView、Blob、DOMString 等类型 option,用于指定存储成的媒体类型。
如何录制本地音视频
    MediaRecorder类:
        var mediaRecorder = new MediaRecorder(stream[, options]);
        stream:
            通过getUserMedia 获取的本地视频流
            或者是
            通过 RTCPeerConnection 获取的远程视频流。
        options,可选项,指定视频格式、编解码器、码率等相关信息
            如mimeType: 'video/webm;codecs=vp8'。
        ondataavailable事件:
            MediaRecoder捕获到数据时就会触发该事件
            通过它,我们才能将音视频数据录制下来。
    //开始录制 
        mediaRecorder.start(10);
        
        
        
        
下载录制好的文件:
    btnDownload.onclick = ()=> {
        var a = document.createElement('a')
        // 创建blob
        var blob = new Blob(buffer, {type: 'video/webm'}); 
        // 产生一个url
        var url = window.URL.createObjectURL(blob); 
        // 设置href
        a.href = url; 
        // 隐藏
        a.style.display = 'none';
        // 下载好的文件名称
        a.download = 'aaa.webm';
        // 模拟点击
        a.click();
    }
    
    
    
    
    
    


复制代码

5.WebRTC中的RTP及RTCP详解?

实时互动直播系统
    UDP 虽然传输快,但不可靠
    TCP在极端网络情况下,为传输可靠性会“发送 -> 确认;超时 -> 重发”的反复
    TCP重发:定时器的超时时间会按 2 的指数增长
    如果第七次之后仍然超时,则断开 TCP 连接。
RTP/RTCP
    先给音视频数据加RTP 头,再交给 UDP 进行传输
复制代码

7.SDP是WebRTC的驱动核心

SDP:用文本描述的各端音频编解码器,传输协议等能力,由一个会话描述和多个媒体描述组成。
两个客户端进行1对1通话时,首先要进行信令交互,而交互的一个重要信息就是 SDP 的交换。
一方收到对端传来的 SDP信息后,取交集,就是协商最终用的音视频参数及传输协议了
标准SDP规范:
    试例:
        v=0o=- 4007659306182774937 2 IN IP4 127.0.0.1s=-t=0 0
        //以上表示会话描述...
        //下面的媒体描述,在媒体描述部分包括音频和视频两路媒体
        m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
        ...
        a=rtpmap:111 opus/48000/2  //对RTP数据的描述
        a=fmtp:111 minptime=10;useinbandfec=1 //对格式参数的描述
        ...
        a=rtpmap:103 ISAC/16000
        a=rtpmap:104 ISAC/32000...
        //上面是音频媒体描述,下面是视频媒体描述
        m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 114 115 116
        ...
        a=rtpmap:96 VP8/90000
        ...
    SDP 描述格式
    SDP 结构 :
        会话描述
            位置:
                会话级的作用域是整个会话,从v=行开始到第一个媒体描述为止。
        媒体信息描述:
            位置:
                媒体级是对单个的媒体流进行描述,其位置是从m=行开始到下一个媒体描述(即下一个 m=)为止
            内容:
                媒体类型
                媒体格式
                传输协议
                传输的 IP 和端口
SDP的结构:
    1)会话描述
        v= version,必选。例子:v=0 ,SDP版本号。
        o=,必选 
            例子:o=<username> <session id> <version> <network type> <address type> <address>对一个会话发起者的描述
                <username>:用户名,当不关心用户名时,可以用 “-” 代替 ;
                <session id> :数字串,在整个会话中,必须是唯一的,建议使用 NTP 时间戳;
                <version>:版本号,每次会话数据修改后,该版本值会递增;
                <network type> :网络类型,一般为“IN”,表示“internet”;
                <address type>:地址类型,一般为 IP4;<address>:IP 地址。
        Session Name(必选):
            例子:s=SessionName,
            整个 SDP 中有且只有一个会话Session Name,用来表示一个会话,
        t:
            例子:t=<starttime><stoptime>,
            会话的开始时间和结束时间。 NTP 时间,单位是秒;都为零时,表示持久会话。
    2)媒体描述
        重点介绍四个字段:
            m=<media> <port> <transport> <fmt list>
                <media>:媒体类型,比如 audio/video 等;
                <port>:端口;
                <transport>:传输协议,有两种——RTP/AVP 和 UDP;
                <fmt list>:媒体格式,即数据负载类型 (Payload Type) 列表。
            a=*。表示属性,用于进一步描述媒体信息
            rtpmap(可选):
                rtpmap 是 rtp 与 map 的结合,即 RTP 参数映射表。
                <payload type> :负载类型,对应 RTP 包中的音视频数据负载类型。
                <encoding name>:编码器名称,如 VP8、VP9、OPUS 等。
                <sample rate>:采样率,如音频的采样率频率 32000、48000 等。
                <encodingparameters>:编码参数,如音频是否是双声道,默认为单声道。
            fmtp。
                例子:
                    a=fmtp:<payload type> <format specific parameters>。
                    fmtp,格式参数,即 format  parameters;
                    <payload type> ,负载类型,同样对应 RTP 包中的音视频数据负载类型;
                    < format specific parameters>指具体参数
WebRTC中的SDP
    会话元数据: SDP 标准规范中的会话层描述;
    流描述、网络描述:SDP标准规范中的媒体层描述
    安全描述:
        进行网络连通性检测时,对用户身份进行认证;
        收发数据时,对用户身份的认证,以免受到对方的攻击
    服务质量描述:
        启动哪些功能以保证音视频的质量,
            如启动带宽评估,当用户发送数据量太大超过评估的带宽时,
            要及时减少数据包的发送;启动防拥塞功能,
            当预测到要发生拥塞时,通过降低流量的方式防止拥塞的发生等等
...
    //=======安全描述============
    a=ice-ufrag:1uEe //进入连通性检测的用户名
    a=ice-pwd:RQe+y7SOLQJET+duNJ+Qbk7z//密码,这两个是用于连通性检测的凭证
    a=fingerprint:sha-256 35:6F:40:3D:F6:9B:BA:5B:F6:2A:7F:65:59:60:6D:6B:F9:C7:AE:46:44:B4:E4:73:F8:60:67:4D:58:E2:EB:9C //DTLS 指纹认证,以识别是否是合法用户
    ...
    //========服务质量描述=========
    a=rtcp-mux
    a=rtcp-rsize
    a=rtpmap:96 VP8/90000
    a=rtcp-fb:96 goog-remb //使用 google 的带宽评估算法
    a=rtcp-fb:96 transport-cc //启动防拥塞
    a=rtcp-fb:96 ccm fir //解码出错,请求关键帧
    a=rtcp-fb:96 nack    //启用丢包重传功能
    a=rtcp-fb:96 nack pli //与fir 类似
...
复制代码

8.论媒体协商

WebRTC 中媒体协商的作用
    端到端之间的媒体协商,就是基于 RTCPeerConnection 对象实现的。
    双方通信时,必须清楚彼此使用的编解码器,必须知道传输的音视频流的 SSRC
RTCPeerConnection
    表示的就是端与端之间建立的连接
    Offer,呼叫方发送的 SDP 消息
    Answer,被呼叫方发送的 SDP 消息
    协商过程:
        1.呼叫方创建 Offer,调用 setLocalDescriptoin 将 Offer 保存到本地 Local 域,然后通过信令将 Offer 发送给被呼叫方。
        2.被呼叫方收到 Offer后,调用 setRemoteDescription 将 offer保存到 Remote 域。作为应答,被呼叫方要创建  Answer 类型的 SDP 消息,创建成功后,调用 setLocalDescription 将 Answer 保存到Local 域。被呼叫方将 Answer 通过信令发送给呼叫方。至此,被呼叫方的工作就完部完成了。
        4.呼叫方收到 Answer ,调用 RTCPeerConnecton 对象的 setRemoteDescription 方法,将 Answer 保存到它的 Remote 域。
    浏览器提供了几个非常方便的 API:
        createOffer ,创建 Offer;
            参数:两个回调函数
                创建成功和出错的回调函数
            例子:
                pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
            
        createAnswer,创建 Answer;
        setLocalDescription,设置本地 SDP 信息;
        setRemoteDescription,设置远端的 SDP 信息。

复制代码

9.WebRTC建立连接的神秘面纱

传输效率与连通率是WebRTC 建立连接的基本策略
    1. 场景一:双方处于同一网段内
        一种是双方通过内网直接进行连接;
        二是通过公网,通过公司的网关,从公网绕一圈再进入公司实现双方的通信。
    2. 场景二:双方处于不同地点
        一是通过 P2P 的方式双方直接建立连接;
        二是通过中继服务器进行中转(会增加 A 与 B 之间传输的时长)
    WebRTC:优先使用 P2P 方式;P2P 方式不通,才会使用中继的方式。

复制代码