• Getting Started with WebRTC [note]


    Getting Started with WebRTC

    原文

    RTCPeerConnection

    1.caller和callee互相发现彼此

    2.并且交换capabilities信息

    3.初始化session

    4.开始实时交换数据

     名词解释:

    信令:在客户端之间传递控制信息,通过控制信息处理客户端之间的发现、连接建立、连接维护和连接关闭等任务的机制。

    function initialize() {
        console.log("Initializing; room=99688636.");
        card = document.getElementById("card");
        localVideo = document.getElementById("localVideo");
        miniVideo = document.getElementById("miniVideo");
        remoteVideo = document.getElementById("remoteVideo");
        resetStatus();
        openChannel('AHRlWrqvgCpvbd9B-Gl5vZ2F1BlpwFv0xBUwRgLF/* ...*/');/*room token 由Google App Engine app 提供*/
        doGetUserMedia();//确认浏览器是否支持getUserMedia API 如果支持则调用onUserMediaSuccess
    }
    /* 建立通道过程
    1.客户端A生成一个唯一的ID
    2.客户端A把ID传给App Engine app,请求获得Channel token
    3.App Engine app 把ID传给 Channel API,请求获得一个channel和token
    4.App把token传给客户端A
    5.客户端A打开socket,监听channel
    */
    function openChannel(channelToken) {
      console.log("Opening channel.");
      var channel = new goog.appengine.Channel(channelToken);
      var handler = {
        'onopen': onChannelOpened,
        'onmessage': onChannelMessage,
        'onerror': onChannelError,
        'onclose': onChannelClosed
      };
      socket = channel.open(handler);
    }
    /*Sending a message works like this:
    
    1.Client B makes a POST request to the App Engine app with an update.
    2.The App Engine app passes a request to the channel.
    3.The channel carries a message to Client A.
    4.Client A's onmessage callback is called.
    */
    //如果浏览器支持getUserMedia,则函数被调用
    function onUserMediaSuccess(stream) {
      console.log("User has granted access to local media.");
      // Call the polyfill wrapper to attach the media stream to this element.
      attachMediaStream(localVideo, stream);//localVideo.src = ... localViedo代表一个标签
      localVideo.style.opacity = 1;
      localStream = stream;
      // Caller creates PeerConnection.
      if (initiator) maybeStart();//initiator 已经被设置为1,直到caller的session终止 所以这里会调用maybeStart
    }
    //connection只会被建立一次 
    //建立前提1.第一次建立 2.localStream已经准备好了,即本地视频 3.信令通道准备好了
    function maybeStart() {
      if (!started && localStream && channelReady) {
        // ...调用func,使用STUN创建RTCPeerConnection(pc),设置各种事件监听函数
        createPeerConnection();
        // ...
        pc.addStream(localStream);
        started = true;
        // Caller initiates offer to peer.
        if (initiator)
          doCall();
      }
    }
    //被maybeStart调用
    //主要目的是使用STUN服务器和回调函数onIceCandidata来建立connection
    //为每一个RTCPeerConnection事件建立handlers
    function createPeerConnection() {
      var pc_config = {"iceServers": [{"url": "stun:stun.l.google.com:19302"}]};
      try {
        // Create an RTCPeerConnection via the polyfill (adapter.js).
        pc = new RTCPeerConnection(pc_config);//在adapter.js中被包装过了
        pc.onicecandidate = onIceCandidate;
        console.log("Created RTCPeerConnnection with config:
    " + "  "" +
          JSON.stringify(pc_config) + "".");
      } catch (e) {
        console.log("Failed to create PeerConnection, exception: " + e.message);
        alert("Cannot create RTCPeerConnection object; WebRTC is not supported by this browser.");
          return;
      }
    
      pc.onconnecting = onSessionConnecting;//log status messages作用
      pc.onopen = onSessionOpened;            //log status messages作用
      pc.onaddstream = onRemoteStreamAdded;    //log status messages作用
      pc.onremovestream = onRemoteStreamRemoved;//为remoteVideo标签设置内容 
    }
    //handler
    function onRemoteStreamAdded(event) {
      // ...
      miniVideo.src = localVideo.src;
      attachMediaStream(remoteVideo, event.stream);
      remoteStream = event.stream;
      waitForRemoteVideo();
    }
    //在maybeStart()调用createPeerConnection()之后, a call is intitiated by creating and offer and sending it to the callee
    function doCall() {
      console.log("Sending offer to peer.");
      pc.createOffer(setLocalAndSendMessage, null, mediaConstraints);
    }
    //创建offer的过程和非信令的例子(caller callee都在一个浏览器内)类似。
    //不同点:message被发送到远端(remote peer),giving a serialized SessionDescription
    //不同点的功能有setLocalAndMessage()完成
    //客户端配置信息叫做Session Description
    function setLocalAndSendMessage(sessionDescription) {
      // Set Opus as the preferred codec in SDP if Opus is present.
      sessionDescription.sdp = preferOpus(sessionDescription.sdp);
      pc.setLocalDescription(sessionDescription);
      sendMessage(sessionDescription);
    }
    /*signaling with the Channel API*/
    /*当createPeerConnection()成功创建RTCPeerConnetion后 回调函数onIceCandidate被调用:
    发送收集来的candidates的信息
    */
     function onIceCandidate(event) {
        if (event.candidate) {
        //使用XHR请求,客户端向服务器发送出站信息
          sendMessage({type: 'candidate',
            label: event.candidate.sdpMLineIndex,
            id: event.candidate.sdpMid,
            candidate: event.candidate.candidate});
        } else {
          console.log("End of candidates.");
        }
      }
    //使用XHR请求,从客户端向服务器发送出站消息(Outbound messaging)
    function sendMessage(message) {
      var msgString = JSON.stringify(message);
      console.log('C->S: ' + msgString);
      path = '/message?r=99688636' + '&u=92246248';
      var xhr = new XMLHttpRequest();
      xhr.open('POST', path, true);
      xhr.send(msgString);
    }
    /*
    客户端->服务器发送信令消息:使用XHR
    服务器->客户端发送信令消息:使用Google App Engine Channel API
    */
    //处理由App Engine server发送来的消息
    function processSignalingMessage(message) {
      var msg = JSON.parse(message);
    
      if (msg.type === 'offer') {
        // Callee creates PeerConnection
        if (!initiator && !started)//initiator代表session是否创建 RTCPeerConnection是否被创建
          maybeStart();
    
        pc.setRemoteDescription(new RTCSessionDescription(msg));
        doAnswer();
      } else if (msg.type === 'answer' && started) {
        pc.setRemoteDescription(new RTCSessionDescription(msg));
      } else if (msg.type === 'candidate' && started) {
        var candidate = new RTCIceCandidate({sdpMLineIndex:msg.label,
                                             candidate:msg.candidate});
        pc.addIceCandidate(candidate);//??
      } else if (msg.type === 'bye' && started) {
        onRemoteHangup();
      }
    }
    function doAnswer() {
      console.log("Sending answer to peer.");
      pc.createAnswer(setLocalAndSendMessage, null, mediaConstraints);
    }
    //在哪里设置msg.type?
    View Code
  • 相关阅读:
    linux ——process
    linux ipc—msgqueue
    JDEclipse源码查看
    用 AXIOM 促进 XML 处理
    使jets3t支持https
    正版太贵了……
    Axis2学习笔记 (Axiom 篇 )
    基于Hadoop的海量文本处理系统介绍
    详解ASP.NET MVC的请求生命周期
    .Net相关的资源连接
  • 原文地址:https://www.cnblogs.com/sook/p/3159007.html
Copyright © 2020-2023  润新知