美文网首页音视频直播技术FFmpeg程序员
通过WebRTC进行实时通信-通过RTCPeerConnecti

通过WebRTC进行实时通信-通过RTCPeerConnecti

作者: 音视频直播技术专家 | 来源:发表于2018-10-16 23:01 被阅读18次

    目录

    我们将要学习的知识点

    在这一步,我们将知道下面的事情怎么做:

    • 简单介绍浏览器与WebRTC的不同。
    • 使用 RTCPeerConnection API 传输视频。
    • 控制媒体的捕获与传输。

    本步完整的版本在 step-02目录下。

    什么是RTCPeerConnection

    RTCPeerConnection 是调用WebRTC传输音视频和交换数据的API。这个例子是在同一个页面中两个RTCPeerConnection对象之间建立连接。没有什么实际价值,但却能很好的证明RTCPeerConnection是如何工作的。

    添加视频元素和控制按钮

    在index.html里将一个video元素替换为两个video元素和三个按钮。

    <video id="localVideo" autoplay playsinline></video>
    <video id="remoteVideo" autoplay playsinline></video>
    
    <div>
      <button id="startButton" >start</button>
      <button id="callButton">call</button>
      <button id="hangupButton">hang up</button>
    </div>
    

    一个视频元素用于显示从getUserMedia()上获取的视频流,另一个通过RTCPeerConnection显示同样的视频流。在真实的应用中,一个视频元素显示本地流,另一个显示远端流。

    添加 adapter.js 片段

    在main.js链接之上,添加一个到当前 adapter.js版本的连接。

    <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
    

    adapter.js是一个填充程序,可以将应用程序与规范更改和前缀差异隔离开来。 (尽管实际上,用于WebRTC实现的标准和协议非常稳定,并且只有少数前缀名称。)

    在这一步中,我们已链接到最新版本的adapter.js,这对于codelab来说很好,但对于生产应用程序来说可能不合适。 adapter.js GitHub repo 解释了确保您的应用始终访问最新版本的技巧。

    有关WebRTC互操作的完整信息,请参阅webrtc.org/web-apis/interop

    index.html应该看起来像下面这样子:

    <!DOCTYPE html>
    <html>
    
    <head>
      <title>Realtime communication with WebRTC</title>
      <link rel="stylesheet" href="css/main.css" />
    </head>
    
    <body>
      <h1>Realtime communication with WebRTC</h1>
    
      <video id="localVideo" autoplay playsinline></video>
      <video id="remoteVideo" autoplay playsinline></video>
    
      <div>
        <button id="startButton">Start</button>
        <button id="callButton">Call</button>
        <button id="hangupButton">Hang Up</button>
      </div>
    
      <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
      <script src="js/main.js"></script>
    </body>
    </html>
    

    安装 RTCPeerConnection 代码

    用 step-02目录中的版本替换main.js

    在 codelab里对大段代码做剪切复制不是很好的做法。但是为了得到 RTCPeerConnection 并使它运行,没有别的办法,只能全力以赴。

    很快你就会学会如何进行编码工作。

    呼叫

    打开 index.html, 点击Start button 从webcam 获取视频, 点击 Call 建军一个对等连接 。 你将看到在两个video元素上显示同样的来自于webcam的视频。看浏览器的console ,可以看到 WebRTC的日志。

    它是如何工作的?

    这部分有很多内容...

    如果你想跳过下面的说明也没问题。

    你仍然可以继续 codelab!
    WebRTC使用 RTCPeerConnection API在 WebRTC客户端之间建立连接传输视频,称之为 peers。

    在这个例子中,两个 RTCPeerConnection 对象是在同一页上,pc1 和pc2。没什么实际价值,但很好的证明了 API 的工作。

    在 WebRTC peer之间建立一个呼叫,包括三个任务:

    • 为呼叫的每个端创建一个RTCPeerConnection,并且在每端都添加一个从getUserMedia()获取的本地流。
    • 获得并共享的网络信息:潜在的连接端点称为ICE 候选者。
    • 获得并共享本地与远端描述信息:本地多媒体的元数据用SDP格式。

    想像一下Alice和 Bob想使用 RTCPeerConnection建立视频聊天。

    首先,Alice和 Bob交换网络信息,“查找候选者”一词是指使用ICE框架查找网络端口的过程。

    1. Alice 创建带有icecandidate handler(addEventListener('icecandidate'))的 RTCPeerConnection 对象。 这对应下面 main.js中的代码:
    let localPeerConnection;
    
    localPeerConnection = new RTCPeerConnection(servers);
    localPeerConnection.addEventListener('icecandidate', handleConnection);
    localPeerConnection.addEventListener(
        'iceconnectionstatechange', handleConnectionChange);
    

    在这个例子中,RTCPeerConnection 的 servers参数没什么用处。

    这里可以指定 STUN 和 TURN 服务的地址。

    WebRTC旨在实现点对点工作,因此用户可以通过最直接的路由进行连接。但是,WebRTC旨在应对现实世界的网络: 客户端应用程序需要遍历NAT网关和防火墙,并且在直接连接失败的情况下,对等网络需要回退。

    作为这个过程的一部分, 在点对点连接失败的情况下,WebRTC APIs 使用 STUN 服务得到你的计算机的IP 地址,并且使用 TURN 服务作为 relay 服务。 WebRTC in the real world 阐明了更多细节。

    1. Alice 调用 getUserMedia() 并且添加传递给它的流:
    navigator.mediaDevices.getUserMedia(mediaStreamConstraints).
      then(gotLocalMediaStream).
      catch(handleLocalMediaStreamError);
    
    function gotLocalMediaStream(mediaStream) {
      localVideo.srcObject = mediaStream;
      localStream = mediaStream;
      trace('Received local stream.');
      callButton.disabled = false;  // Enable call button.
    }
    
    localPeerConnection.addStream(localStream);
    trace('Added local stream to localPeerConnection.');
    
    1. 当网络候选者变为有效时,在第一步中的 onicecandidate handler将被调用。
    2. Alice 将序列化后的候选者数据发给 Bob,在真实的应用中,这个过程(称为信令)通过消息服务发生- 在后面的步骤中,你将学到如何处理它。当然,在本步骤中,在同一页中的两个RTCPeerConnection对象直接通信不需要额外的消息。
    3. 当Bob从Alice得到候选者消息后,他调用 addIceCandidate()添加候选者到远端描述:
    function handleConnection(event) {
      const peerConnection = event.target;
      const iceCandidate = event.candidate;
    
      if (iceCandidate) {
        const newIceCandidate = new RTCIceCandidate(iceCandidate);
        const otherPeer = getOtherPeer(peerConnection);
    
        otherPeer.addIceCandidate(newIceCandidate)
          .then(() => {
            handleConnectionSuccess(peerConnection);
          }).catch((error) => {
            handleConnectionFailure(peerConnection, error);
          });
    
        trace(`${getPeerName(peerConnection)} ICE candidate:\n` +
              `${event.candidate.candidate}.`);
      }
    }
    

    WebRTC端点之间还需要找出并交换本地和远程音频和视频媒体信息,例如分辨率和编解码器能力。 通过使用称为SDP的会话描述协议格式交换元数据blob(称为 offer 和 answer)来进行交换媒体配置信息的信令:

    1. Alice 运行 RTCPeerConnection 的 createOffer() 方法. 返回值提供了一个RTCSessionDescription,也就是 Alice的本地会话描述:
    trace('localPeerConnection createOffer start.');
    localPeerConnection.createOffer(offerOptions)
      .then(createdOffer).catch(setSessionDescriptionError);
    
    1. 如果成功,Alice使用setLocalDescription()设置本地描述,然后通过其信令通道将此会话描述发送给Bob。
    2. Bob 使用setRemoteDescription设置 Alice 发送给它的描述作为远端描述。
    3. Bob 运行RTCPeerConnection的 createAnswer () 方法,将他从Alice哪儿得到的远端描术传递给它,这样就可以生成一个与她兼容的本地会话。必须传递给 createAnswer() 一个 RTCSessionDescription,并发送给 Alice。
    4. 当 Alice 得到 Bob的描述会话时,她给setRemoteDescription设置一个远程会话。
    // Logs offer creation and sets peer connection session descriptions.
    function createdOffer(description) {
      trace(`Offer from localPeerConnection:\n${description.sdp}`);
    
      trace('localPeerConnection setLocalDescription start.');
      localPeerConnection.setLocalDescription(description)
        .then(() => {
          setLocalDescriptionSuccess(localPeerConnection);
        }).catch(setSessionDescriptionError);
    
      trace('remotePeerConnection setRemoteDescription start.');
      remotePeerConnection.setRemoteDescription(description)
        .then(() => {
          setRemoteDescriptionSuccess(remotePeerConnection);
        }).catch(setSessionDescriptionError);
    
      trace('remotePeerConnection createAnswer start.');
      remotePeerConnection.createAnswer()
        .then(createdAnswer)
        .catch(setSessionDescriptionError);
    }
    
    // Logs answer to offer creation and sets peer connection session descriptions.
    function createdAnswer(description) {
      trace(`Answer from remotePeerConnection:\n${description.sdp}.`);
    
      trace('remotePeerConnection setLocalDescription start.');
      remotePeerConnection.setLocalDescription(description)
        .then(() => {
          setLocalDescriptionSuccess(remotePeerConnection);
        }).catch(setSessionDescriptionError);
    
      trace('localPeerConnection setRemoteDescription start.');
      localPeerConnection.setRemoteDescription(description)
        .then(() => {
          setRemoteDescriptionSuccess(localPeerConnection);
        }).catch(setSessionDescriptionError);
    }
    
    
    1. Ping!

    点滴

    1. 看一下chrome://webrtc-internals,这个提供了WebRTC的状态和调试数据。(Chrom URLs的完整列表是在 chrome://about
    2. 这页的CSS风格:
    • 将视频并排放置
    • 将Button设置成相同宽度和文本大小。
    • 确何布局适用于移动端
    1. 从 Chrome Dev Tool 控制台,看localSteam, localPeerConnection 以及 remotePeerConnection。
    2. 从控制台看localPeerConnectionpc1.localDescription SDP格式看起来是什么样儿?

    我们学到了什么

    在这一步你学会了如何去:

    • 摘要浏览器与WebRTC的差异,adapter.js
    • 使用RTCPeerConnection API传输视频。
    • 控制媒体的捕获和传输
    • 在端点之间共享媒体和网络信息开启WebRTC呼叫。

    本步骤完整的版本在 step-2目录中。

    提示

    在这一步学习了很多内容,另一个详细的解释了RTCPeerConnection的资源是webrtc.org/start.这页包括了JavaScript架构的建议 - 如果你喜欢 WebRTC,而且不想因API扯皮。

    • 可以从adapter.js GitHub repo找到更多的关于 adapter.js的片段。
    • 想看看世界上最好的视频聊天应用程序是什么样的?看看AppRTC,这是WebRTC项目的WebRTC调用的规范应用程序:app, code。呼叫建立时间小于500毫秒。

    最佳实践

    为了使您的代码能够面向未来,请使用新的基于Promise的API,并通过使用 adapter.js实现与不支持它们的浏览器的兼容性。

    接下来

    此步骤显示如何使用WebRTC在端点之间传输视频 - 但此codelab与数据无关!

    在下一步中,了解如何使用RTCDataChannel流式传输任意数据。

    相关文章

      网友评论

        本文标题:通过WebRTC进行实时通信-通过RTCPeerConnecti

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