• 一文学会使用WebRTC API


    WebRTC(Web Real-Time Communication)是一项开放标准和技术集合,由 W3CIETF 等组织共同推动和维护,旨在通过Web浏览器实现实时通信媒体流传输。WebRTC于2011年6月1日开源并在Google、Mozilla、Opera支持下被纳入万维网联盟的W3C推荐标准,其提供了一组API和协议,使开发者能够在浏览器中构建实时音视频通信、数据传输和协作应用。目前WebRTC已得到包括主流的Web浏览器(如Chrome、Firefox、Safari)和移动设备平台的广泛的支持和应用。

    • WebRTC API 简介
    • WebRTC SDP状态机
    • WebRTC API 使用——媒体流传输
    • WebRTC API 使用——DataChannel
    • WebRTC API 使用——RTCSessionDescription

    一、API 简介

    WebRTC(Web Real-Time Communication)提供了一组丰富的 API 方法,用于在浏览器中实现实时通信。这些 API 方法涵盖了音视频捕获、连接建立、媒体流传输和数据传输等方面。下面是对 WebRTC 中一些核心 API 方法的详细介绍,并提供了相应的使用示例:

    WebRTC API 使用

    • 呼叫端通过 navigator.mediaDevices.getUserMedia()捕捉本地媒体;
    • 呼叫端创建一个RTCPeerConnection 并调用 RTCPeerConnection.addTrack()
    • 呼叫端调用 RTCPeerConnection.createOffer()来创建一个提议 (offer);
    • 呼叫端调用 RTCPeerConnection.setLocalDescription()将提议 (Offer) 设置为本地描述 (即,连接的本地描述);
    • 呼叫端请求 STUN 服务创建 ice 候选 (ice candidates);
    • 呼叫端通过信令服务器(如 websocket)将提议 (offer) 传递至接收端
    • 接收端收到了提议 (offer) 并调用 RTCPeerConnection.setRemoteDescription() 将其记录为远程描述 (也就是连接的另一端的描述);
    • 接收端捕获本地媒体,通过RTCPeerConnection.addTrack()添加到连接中;
    • 接收端通过 RTCPeerConnection.createAnswer() 创建一个应答;
    • 接收端调用 RTCPeerConnection.setLocalDescription() 将应答 (answer) 设置为本地描述。此时,接收端已经获知连接双方的配置了。
    • 接收端通过信令服务器(如 websocket)将应答传递到呼叫端
    • 呼叫端接受到应答。
    • 呼叫端调用 RTCPeerConnection.setRemoteDescription()将应答设定为远程描述。如此,呼叫端已经获知连接双方的配置了。

    二、会话描述状态机

    JSEP是一种用于在WebRTC应用程序中建立和管理通信会话的机制,其由RFC8829 JSEP:规范,定义了JavaScript API和信令交换的规范,以便在浏览器之间建立点对点的实时通信。

    通过JSEP规范,我们可以了解到WebRTC SDP 会话描述状态机:

    RFC8829 JSEP 状态机

    • 呼叫端通过调用 createOffer API 来创建提议 (offer);
    • 呼叫端使用这个 offer 通过 setLocalDescription API 来设置其本地配置;
    • 呼叫端通过信令服务器(如 websocket)将提议 (offer) 传递至接收端

    为了完成 offer/answer 交换:

    • 接收端收到了提议 (offer) 并调用 setRemoteDescription() 将其记录为远程描述;
    • 接收端使用 createAnswer API 生成应答 (answer) ,使用 setLocalDescription API 来应用answer;
    • 接收端通过信令服务器(如 websocket)将应答传递到呼叫端

    呼叫端接受到应答:

    • 呼叫端调用 RTCPeerConnection.setRemoteDescription()将应答设定为远程描述,完成初始化。

    三、WebRTC API 使用——媒体流传输

    1. navigator.mediaDevices.getUserMedia(constraints)

      • 描述:请求访问音视频设备并获取本地媒体。
      • 示例:
    navigator.mediaDevices.getUserMedia({ video: true, audio: true })
      .then(function(stream) {
        // 处理获取到的媒体流
      })
      .catch(function(error) {
        // 处理错误
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. RTCPeerConnection(configuration)

      • 描述:创建一个 PeerConnection 对象,用于建立和管理点对点连接。
      • 示例:
    var configuration = { iceServers: [{ urls: '192.168.1.1:19302' }] };
    var peerConnection = new RTCPeerConnection(configuration);
    
    • 1
    • 2
    1. peerConnection.addTrack(track, stream)

      • 描述:将音视频轨道添加到 PeerConnection 中。
      • 示例:
    var localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
    localStream.getTracks().forEach(function(track) {
      peerConnection.addTrack(track, localStream);
    });
    
    • 1
    • 2
    • 3
    • 4
    1. peerConnection.createOffer(options)

      • 描述:创建一个SDP提议 (offer),用于发起连接。
      • 示例:
    peerConnection.createOffer()
      .then(function(offer) {
    	return peerConnection.setLocalDescription(offer);
      })
      .then(function() {
    	// 将 SDP offer 发送给远程端
      })
      .catch(function(error) {
    	// 处理错误
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    1. peerConnection.setLocalDescription(description)

      • 描述:将本地描述设置为提供的 SDP(Session Description Protocol)对象。
      • 示例:
    var localDescription = // 从信令服务器获取的本地描述信息
    peerConnection.setLocalDescription(localDescription)
    
    • 1
    • 2
    1. peerConnection.setRemoteDescription(description)

      • 描述:将远程描述设置为提供的 SDP 对象。
      • 示例:
    var remoteDescription = // 从信令服务器获取的远程描述信息
    peerConnection.setRemoteDescription(remoteDescription)
    
    • 1
    • 2
    1. peerConnection.addIceCandidate(candidate)

      • 描述:将 ICE(Interactive Connectivity Establishment)候选项添加到 PeerConnection 中。
      • 示例:
    var iceCandidate = // 从信令服务器获取的 ICE 候选项
    peerConnection.addIceCandidate(iceCandidate)
    
    • 1
    • 2
    1. peerConnection.ontrack

      • 描述:当远程端添加媒体轨道时触发的事件处理函数。
      • 示例:
    peerConnection.ontrack = function(event) {
      var remoteVideo = document.getElementById('remoteVideo');
      remoteVideo.srcObject = event.streams[0];
    };
    
    • 1
    • 2
    • 3
    • 4
    1. peerConnection.onicecandidate

      • 描述:当 ICE 候选项可用时触发的事件处理函数。
      • 示例:
    peerConnection.onicecandidate = function(event) {
      if (event.candidate) {
    	// 将 ICE 候选项发送给远程端
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. peerConnection.onconnectionstatechange

      • 描述:当 PeerConnection 的连接状态发生变化时触发的事件处理函数。
      • 示例:
    peerConnection.onconnectionstatechange = function(event) {
      if (peerConnection.connectionState === 'connected') {
    	// 连接已建立
      } else if (peerConnection.connectionState === 'disconnected') {
    	// 连接已断开
      } else if (peerConnection.connectionState === 'failed') {
    	// 连接失败
      }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    四、WebRTC API 使用——DataChannel

    要在两个 WebRTC 端点之间直接传输非媒体流信息,需要使用 DataChannel API。DataChannel 允许在两个对等连接之间传输任意类型的数据,包括文本、图片等数据内容。
    下面是一个使用 WebRTC DataChannel 在两个端点之间发送文字内容的详细代码实现:

    1. 发送端代码(例如浏览器 A):
    // 创建 PeerConnection
    var peerConnection = new RTCPeerConnection();
    // 创建 DataChannel
    var dataChannel = peerConnection.createDataChannel('textChannel');
    // 事件处理:当 DataChannel 开启时
    dataChannel.onopen = function() {
      // 发送文字内容
      dataChannel.send('Hello, WebRTC DataChannel!');
    };
    
    // 事件处理:当 DataChannel 收到消息时
    dataChannel.onmessage = function(event) {
      var receivedMessage = event.data;
      console.log('Received message:', receivedMessage);
    };
    
    // 创建 SDP offer
    peerConnection.createOffer()
      .then(function(offer) {
        return peerConnection.setLocalDescription(offer);
      })
      .then(function() {
        // 将 SDP offer 发送给远程端
        var offer = peerConnection.localDescription;
        // 发送 offer 给远程端,例如通过信令服务器
      })
      .catch(function(error) {
        console.error('Error creating offer:', error);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    1. 接收端代码(例如浏览器 B):
    // 创建 PeerConnection
    var peerConnection = new RTCPeerConnection();
    
    // 事件处理:当收到来自远程端的 SDP offer 时
    function handleOffer(offer) {
      // 设置远程描述为 SDP offer
      peerConnection.setRemoteDescription(offer)
        .then(function() {
          // 创建 SDP answer
          return peerConnection.createAnswer();
        })
        .then(function(answer) {
          return peerConnection.setLocalDescription(answer);
        })
        .then(function() {
          // 将 SDP answer 发送给远程端
          var answer = peerConnection.localDescription;
          // 发送 answer 给远程端,例如通过信令服务器
        })
        .catch(function(error) {
          console.error('Error creating or setting local description:', error);
        });
    }
    
    // 事件处理:当 PeerConnection 收到来自远程端的 DataChannel 时
    peerConnection.ondatachannel = function(event) {
      var receivedDataChannel = event.channel;
    
      // 事件处理:当 DataChannel 开启时
      receivedDataChannel.onopen = function() {
        // 发送文字内容
        receivedDataChannel.send('Hi, WebRTC DataChannel!');
      };
    
      // 事件处理:当 DataChannel 收到消息时
      receivedDataChannel.onmessage = function(event) {
        var receivedMessage = event.data;
        console.log('Received message:', receivedMessage);
      };
    };
    
    // 事件处理:当收到来自信令服务器的 SDP offer 时
    var receivedOffer = // 从信令服务器获取的 SDP offer
    handleOffer(receivedOffer);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在上述代码中,发送端创建了一个 DataChannel,并在 DataChannel 开启后发送文字内容。
    接收端在 PeerConnection 上监听 “ondatachannel” 事件,当收到来自远程端的 DataChannel 时,设置相应的事件处理函数,并在 DataChannel 开启后发送文字内容。

    五、WebRTC API 使用——RTCSessionDescription

    举例RTCSessionDescription的数据结构,并对举例中的sdp行进行详细注释:

    // RTCSessionDescription: sdp
    {
      type: 'offer',
      sdp: 
           // v=0: 版本号,表示SDP的版本。
           'v=0\r\n' +
           // 会话的所有者是"-",会话标识为1234567890,IN表示使用的网络类型为Internet,IP4表示使用IPv4,192.168.0.1是会话的IP地址。
           'o=- 1234567890 1 IN IP4 192.168.0.1\r\n' +
           // 会话的主题或会议名称。
           's=Example SDP\r\n' +
           // 会话的时间描述,以秒为单位。t=0 0表示会话的持续时间是从0秒到0秒,即没有特定的时间限制。
           't=0 0\r\n' +
           // 表示音频和视频被分组在一起,一起传输。
           'a=group:BUNDLE audio video\r\n' +
           // 音频使用RTP传输,端口号是50000,SAVPF表示使用安全的RTP传输,111、103和104是音频编解码器的标识符。
           'm=audio 50000 RTP/SAVPF 111 103 104\r\n' +
           // 指定了媒体流的IP地址和网络类型。
           'c=IN IP4 192.168.0.1\r\n' +
           // 111是opus编解码器的标识符,48000表示采样率为48kHz,2表示声道数为双声道。
           'a=rtpmap:111 opus/48000/2\r\n' +
           // 103是ISAC编解码器的标识符,16000表示采样率为16kHz。
           'a=rtpmap:103 ISAC/16000\r\n' +
           // 104是ISAC编解码器的标识符,32000表示采样率为32kHz。
           'a=rtpmap:104 ISAC/32000\r\n' +
           // RTCP(实时传输控制协议)的连接信息,指定了RTCP的端口号。
           'a=rtcp:50001\r\n' +
           // 视频使用RTP传输,端口号是50002,SAVPF表示使用安全的RTP传输,100、101和102是视频编解码器的标识符。
           'm=video 50002 RTP/SAVPF 100 101 102\r\n' +
           // 媒体流的IP地址和网络类型。
           'c=IN IP4 192.168.0.1\r\n' +
           // 100是VP8编解码器的标识符,90000表示时钟频率。
           'a=rtpmap:100 VP8/90000\r\n' +
           // 101是VP9编解码器的标识符,90000表示时钟频率。
           'a=rtpmap:101 VP9/90000\r\n' +
           // 102是H264编解码器的标识符,90000表示时钟频率。
           'a=rtpmap:102 H264/90000\r\n' +
           // 指定了RTCP的端口号
           'a=rtcp:50003\r\n'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    参考:

    W3C WebRTC API:
    https://www.w3.org/TR/webrtc/

    RFC8829 JSEP:
    https://datatracker.ietf.org/doc/html/rfc8829

    WebRTC API:
    https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API

  • 相关阅读:
    3.4向量范数与矩阵范数&3.5线性方程组的迭代解法
    Java面试之数据类型
    干货 | 如何快速实现 BitSail Connector?
    【React】portal
    深入浅出 OkHttp 源码解析及应用实践
    C 语言通用MySQL 功能增删查改功能.
    一起误删cni0虚拟网卡引发的k8s事故
    智能DNA分子纳米机器人模型来了
    C++程序员养成记
    图像运算和图像增强十
  • 原文地址:https://blog.csdn.net/aiwusheng/article/details/133884311