Getting Started with WebRTC [note]

Getting Started with WebRTC

原文html

RTCPeerConnectionhtml5

1.caller和callee互相發現彼此web

2.而且交換capabilities信息瀏覽器

3.初始化session服務器

4.開始實時交換數據session

 名詞解釋:app

信令:在客戶端之間傳遞控制信息,經過控制信息處理客戶端之間的發現、鏈接創建、鏈接維護和鏈接關閉等任務的機制。socket

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:\n" + "  \"" +
      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
相關文章
相關標籤/搜索