zoukankan      html  css  js  c++  java
  • webRTC脱坑笔记(三)— webRTC API之RTCPeerConnection

    RTCPeerConnection API是每个浏览器之间点对点连接的核心,RTCPeerConnectionWebRTC组件,用于处理对等体之间流数据的稳定和有效通信。

    RTCPeerConnection可以保护Web开发人员免受潜伏在其中的无数复杂性的影响。WebRTC使用的编解码器和协议可以进行大量工作,即使在不可靠的网络上也可以进行实时通信:

    • 丢包隐藏
    • 回声消除
    • 带宽适应性
    • 动态抖动缓冲
    • 自动增益控制
    • 降噪和抑制
    • 图像’清洁’。
    // 创建实例
    let pc = RTCPeerConnection(serverConfig);

    根据你是发起者还是被发起对象,在连接的每一边会使用稍微不同的方式使用RtcPeerConnection对象。

    serverConfigconfig配置参数中包含iceServers参数。它是包含有关STUNTURN服务器的信息的URL对象数组,在查找ICE候选时使用。可以在code.google.com找到可用的公共STUN服务器的列表。

    现实中,无论你的应用如何见到那,webRTC都需要服务器,因为:

    • 通信用户发现彼此并交换自己的“真实世界”的详细信息;
    • webRTC客户端(对等方)交换网络信息;
    • peers交换有关每天的数据,如视频格式和分辨率
    • webRTC客户端遍历NAT网关和防火墙

    换句话说,WebRTC需要四种类型的服务器端功能:

    • 发现用户并沟通。
    • 使用STUN服务器连接用户信号。
    • 使用NAT /防火墙遍历。
    • 在对等通信失败的情况下,使用中继服务器。

    ICE是用于连接对等体的框架,例如两个视频聊天客户端。最初,ICE尝试通过UDP直接连接对等端,以尽可能低的延迟。在此过程中,STUN服务器只有一个任务:使NAT后面的对等体能够找到其公共地址和端口。

    下面是调用流程:

    1.获取本地媒体设备成功之后,创建一个新的RTCPeerConnection对象,初始化将本地音视频轨道加入到RTCPeerConnection

     function createConn(stream) {
         localStream = stream
         // 显示本地视频流
        localVideo.srcObject = stream;
         //谷歌公共stun服务器
        let serverConfig = {
            "iceServers": [
                { "urls": ["turn:192.168.1.133:3478"], 
                "username": "webrtc", 
                "credential": "webrtc" 
                }
            ]
        };
         // 呼叫者
        let localPeer = new RTCPeerConnection(serverConfig)
        // 被呼叫者
        let remotePeer = new RTCPeerConnection(serverConfig)
        // 设置媒体流监听,将本地流添加到RTCPeerConnection对象
        localStream.getTracks().forEach((track) => {
          localPeer.addTrack(track, localStream);
        });
        localPeer.addStream(stream)
        
     }

    2.注册onicecandidate处理程序,并监听获取自己的ICE协商信息,它将任何ICE候选发送给其他对等方

    function createConn(stream) {
        ...
        // 当获得到自己的公网地址后,发送给其它客户端
        localPeer.onicecandidate = function(event) {
        console.log('I got my icecandidate info')
        if (event.candidate) {
            console.log(event.candidate.candidate)
        }
            socket.emit('onicecandidate', event.candidate);
        }
        // 如果监测到本地媒体流连接到本地,将其绑定到一个video标签上输出
         localPeer.ontrack = function(e) {
             // 因为媒体流是一个数组
            if (remoteVideo.srcObject !== e.streams[0]) {
            remoteVideo.srcObject = e.streams[0];
            console.log('received remote stream');
        }
        };
    }

    3.提前注册消息处理程序。信令服务器还应该有一个处理来自远程计算机的消息处理程序。如果消息包含RTCSessionDescription对象,则应该使用RTCSessionDescription()方法将其添加到RTCPeerConnection对象。如果消息包含RTCIceCandidate对象,则应该使用addIceCandidate()方法将其添加到RTCPeerConnection对象。

    消息处理程序会根据谁是呼叫方和被呼叫方被调用。

    //呼叫方收到对方回复的SDP时调用的消息处理程序
        localPeer.setRemoteDescription(new RTCSessionDescription(answer));
    
    
    //被呼叫方收到对方发送的SOP时调用的消息处理程序
        localPeer.addIceCandidate(new RTCIceCandidate(candidate));

    4.拨通对方,发送自己的SDP信息,开始提供/回答协商过程,这是呼叫者的流量不同于被呼叫者的唯一步骤。呼叫者使用createoffer( )方法开始协商,并注册一个收到RTCSessiondescription对象的回调。然后这个回调应该使用setlocaldescription( )将这个rtcsessiondescription对象添加到rtcpeerconnection对象中。最后,调用者应该使用信令服务器将这个rtcsessiondescription发送到远程计算机。另一方面,被呼叫者,在createanswer()方法中注册相同的回调。请注意,只有在从调用者收到通知后,才会启动流。

    //当本地开始拨打对方的时候,发送自己的SDP信息
    const offerOptions = {
        offerToReceiveAudio: 1,
        offerToReceiveVideo: 1
    };
    function call() {
        console.log('Starting call');
    
        try {
            console.log('localPeerConnection createOffer start');
            const offer = await pc1.createOffer(offerOptions);
            console.log(offer);
            localPeer.setLocalDescription(offer)
            socket.emit('offer', offer);
        } catch (e) {
            console.log(`Failed to create session description: ${e.toString()}`);
        }
    }
    
    // 当本地收到对方的拨号通知时 收到对方的SDP信息,然后生成回复SDP信息
    function handleOffer(offer, name) {
        connectedUser = name;
        console.log("I got offer: ");
        localPeer.setRemoteDescription(new RTCSessionDescription(offer));
        //create an answer to an offer 
        localPeer.createAnswer(function(answer) {
            localPeer.setLocalDescription(answer);
             console.log("I will reply a answer")
            send({
                type: "answer",
                answer: answer
            });
        }, function(error) {
            alert("Error when creating an answer");
        });
    };
    // 当拨号方收到对方回复的SDP后,设置到连接中,调用消息处理程序
    socket.on('answer', (desc) => {
        console.log("I got answer: ", desc.sdp);
        localPeerConnection.setRemoteDescription(desc);
    })
  • 相关阅读:
    [Database] Oracle 中的where 可以后接group by
    [Hibernate] inner Join和 left Join
    [Hibernate] 分页查询
    [Hibernate] 通过 properties 类和 hql 语句进行动态查询
    [Oracle11g] 通过伪列查询
    [Hibernate] hibernate.cfg.xml 配置文件的一些设置
    [Hibernate] One-To-Many 配置文件和注解的方式以及HQL语句
    Kayleigh O'Connor
    java 对象拷贝工具
    clone的深拷贝 or 浅拷贝
  • 原文地址:https://www.cnblogs.com/suRimn/p/11314914.html
Copyright © 2011-2022 走看看