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:\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?
Getting Started with WebRTC [note]的更多相关文章
- Build Android Webrtc Libjingle Library On Ubuntu
		Our team is developing an app to help people solve problem face to face. We choose webrtc protocol a ... 
- A Study of WebRTC Security
		转自:http://webrtc-security.github.io/ A Study of WebRTC Security Abstract Web Real-Time Communication ... 
- WebRTC音视频引擎研究(1)--整体架构分析
		WebRTC技术交流群:234795279 原文地址:http://blog.csdn.net/temotemo/article/details/7530504 1.WebRTC目的 ... 
- WebRTC is for Losers:WebRTC是输家
		该文章是引述,仅代表作者Dave Michels观点 WebRTC is for Losers WebRTC technology has fallen short on many of its pr ... 
- Android IOS WebRTC 音视频开发总结(七)-- 基于浏览器的开发
		前面写的一系列总结都是讲webrtc如何下载,编译,开发的,有些人可能有点云里雾里了,WEBRTC不是用来搞跨浏览器开发的吗,怎么我讲的这些跟浏览器扯不上任何关系,其实看看下面这个架构图,你就明白了, ... 
- webrtc学习——RTCPeerConnection
		The RTCPeerConnection interface represents a WebRTC connection and handles efficient streaming of da ... 
- WebRTC 音视频开发之路
		早在2014年就通过WebRTC实现了PC客户端的实时视频语音,那时P2P连接的建立使用的WebRTC自带的libjingle库,使用peerconnection的API实现的.后来在做远程桌面,文件 ... 
- webrtc之视频显示模块--video_render
		在上一篇博文中,简单介绍了webrtc为我们提供了跨平台的视频采集模块,这篇博文也简单介绍下webrtc为我们提供的跨平台的视频显示模块:video_render. 该模块的源码结构如下: 如上图,我 ... 
- webrtc之视频捕获模块--video_capture
		webrtc的video_capture模块,为我们在不同端设备上采集视频提供了一个跨平台封装的视频采集功能,如下图中的webrtc的video_capture源码,现webrtc的video_cap ... 
随机推荐
- RPC学习--C#使用Thrift简介,C#客户端和Java服务端相互交互
			本文主要介绍两部分内容: C#中使用Thrift简介 用Java创建一个服务端,用C#创建一个客户端通过thrift与其交互. 用纯C#实现Client和Server C#服务端,Java客户端 其中 ... 
- 16.10.17学到的Java知识
			1. 例:3-2.6==0.4的值是什么?可能乍一看,感觉是返回TRUE,因为3-2.6=0.4,0.4==0.4:所以返回TRUE. 然而,上面分析在JAVA中是错的. 由于浮点数的运算在JAVA中 ... 
- iOS实现类似于歌词进度效果
			先看效果 这里关键的地方在于镂空文字的实现,可以用UILabel的drawRect方法. .h文件 @interface HollowLabel : UILabel @end .m文件 @interf ... 
- maven学习(5)-maven中常见错误
			maven报错非法字符:\65279 错误 开发中一个项目很早就报这个错,maven报错非法字符:\ 错误, 开发过程中偶尔会遇到,今天终于下决心要解决这个问题 编译java 文件的时候,有些java ... 
- LSD-SLAM深入学习(1)-基本介绍与ros下的安装
			前言 借鉴来自RGB-D数据处理的两种方法-基于特征与基于整体的,同样可以考虑整个图片的匹配,而不是只考虑特征点的…… 一般这种稠密的方法需要很大的计算量,DTAM: Dense tracking a ... 
- hdu 1069 (DP) Monkey and Banana
			题目:这里 题意: Description 一组研究人员正在设计一项实验,以测试猴子的智商.他们将挂香蕉在建筑物的屋顶,同时,提供一些砖块给这些猴子.如果猴子足够聪明,它应当能够通过合理的放置一些砖块 ... 
- city-picker 选择省市县的一个控件,好用。
			我觉得好奇怪,这么好一个插件,为什么没有设置值的方法,还是我才疏学浅?? 我看有的人做法是把,把源代码里面的自动扫描机制注释掉 // $(function () { // $('[data-toggl ... 
- 一点一滴学shell
			1. 获取shell脚本的名称 ${BASH_SOURCE-$0} 2. 获取shell脚本的路径 dirname "${BASH_SOURCE-$0}" 这个路径不一定是脚本的真 ... 
- Thinkphp 学习笔记
			前后台配置: 在根目录文件夹中创建一个Conf文件夹 Conf文件夹下建立一个config.php文件,里面存放公共配置信息,方便前后台调用. 简单定义404页面 伪静态去除.html Config中 ... 
- iOS遍历相册中的图片
			//获取相册的所有图片 - (void)reloadImagesFromLibrary { self.images = [[NSMutableArray alloc] init]; dispatch_ ... 
