WEB p2p视频聊天?! -- WebRTC 初入探究 与 实现

前言

本片demo中 的实现为纯前端js实现,所以 而且可以在本机下运行(有网络即可正常链接服务器),所以你可以修改 代码(界面好丑,处理时间不多....)

这里感谢一下(没有广告费...只是免费用了别人的资源,总得感谢下)
leancloud 的 免费云平台(现在不是免费了)
openshift 的 免费平台

本篇文章内容:

  • WebRTC的基础知识
  • WebRTC的连接基本流程
  • WebRTC的基础接口介绍
  • WebRTC的注意事项
  • WebRTC的 demo

WebRTC 的基础知识

借来的 webRTC结构图

什么是WebRTC

WebRTC : 网页实时通信(Web Real-Time Communication),故名思意.
对于浏览器来说,它要实现三大模块
音频处理模块,视频处理模块,网络传输模块

它主要是由浏览器底层实现的,对于我们来说,是调用它开放出来的JS api
相关的主要有

  • MediaStream 系列API(主要是获取 媒体流的,例如摄像头啊,麦克风,音频输出设备啊等等的)
  • RTCPeerConnection 系列API(主要是用来 进行 p2p连接的)
  • RTCDataChannel (其实这个应该也算在RTCPeerConnection系列里,不同的是,不是传输媒体流,而且传输数据)

WebRTC的连接方式

RTCPeerConnection底层下实现了ice的支持,ICE,全名叫交互式连接建立(Interactive Connectivity Establishment)
支持stun 和 turn 服务器,先用stun来进行nat穿透链接,官方数据称85%是可以穿透的.(我是那15%,心累),如果穿不透,还可以turn服务器来进行桥接
(由于我的韩国服务器本来网速就不怎么好,于是就忽略了turn)

WebRTC的连接基本流程

  1. 首先 A,B 生成 RTCPeerConnection

  2. 然后 A 调用createOffer 生成 Description,
    调用setLocalDescription,
    然后再把Description发送给B

  3. B收到A的Description后,
    调用setRemoteDescription,
    然后调用createAnswer 生成 B的Description,
    然后把B的Description发送给A

  4. A收到B的Description后,setRemoteDescription

没错,就是这么简单,其实就是一个交换Description的过程
第一个生成Description的叫offer,第二个生成Description的叫answer
这个交换的过程需要你自己的信令服务器(即是通信服务器)去传递

还有一点,上面操作的过程中,RTCPeerConnection可能产生icecandidate数据,需要把数据传给对方
基本流程如下:

  1. A 实现peer.onicecandidate,使其可以监听到icecandidate数据的产生
  2. A 监听到 icecandidate数据产生,通过信令服务器传输给B
  3. B 收到来自A的icecandidate数据,调用 peer.addIceCandidate(new RTCIceCandidate(message.candidate)) 设置数据

上面这个操作,A,B都需要做,双方都会产生icecandidate数据,然后发送给对方,这个p2p链接的过程

基础接口介绍

由于各个浏览器的函数名,以及参数都不一样,所以我采用了adapter.js,来消除浏览器之间的差异...(一直在chrome下调试,跑一下火狐的,各种参数报错后...马上用了adapter)

下面函数也是才用了adapter.js后进行介绍的;

navigator.mediaDevices.getUserMedia()

看着上面函数名,就知道它是获取你本机的摄像头麦克风的了,就是说,即使不做 视频聊天,也可以来玩玩摄像头→_→

//还有一个facingMode,资料不多,写上了
var usermedia = navigator.mediaDevices.getUserMedia({
  audio:true,
  video:{
    //ideal表示期望值,希望能拿到,拿不到就按照最大最小
    //(不要乱设值,不然获取不了摄像头就别说我没提醒了)赤裸裸的恐吓你→_→
    height:{ min: 320, ideal: 1280, max: 1920 },
    width:{ min: 240, ideal: 720, max: 1080 },
    frameRate: { ideal: 10, max: 15 }  //帧率
  }
});

//经过adapter翻译后
chrome: 
{
  "audio":true,
  "video":{
    "optional":[
      {"minHeight":1280},
      {"maxHeight":1280},
      {"minWidth":720},
      {"maxWidth":720},
      {"minFrameRate":10},
      {"maxFrameRate":10}
    ],
    "mandatory":{
      "minHeight":320,
      "maxHeight":1920,
      "minWidth":240,
      "maxWidth":1080,
      "maxFrameRate":15
    }
  }
}

usermedia.then(funcion(stream){
  //stream就是你获得的媒体流
})

相关的还有以下等等,就不详细介绍了:
navigator.mediaDevices.enumerateDevices() //获取媒体设备(video可以用它拿到的id,来决定在那个音频输出设备中输出哦~)
MediaRecorder //记录媒体流(可以录影,转化成编码再传输,再转为流,再播放,挺好玩的东西)

RTCPeerConnection 系列

就是建立p2p连接那个,这里说明部分api的用法

new RTCPeerConnection()
//生成一个peer连接,但还没开始链接
var peer = new RTCPeerConnection({
  "iceServers": [  //ice服务器,可以设置stun,turn服务器
    {"url": "stun:stun.l.google.com:19302"}
  ]
});
peer.onaddstream
//获取到对方发送的媒体流,event.stream,至于要干嘛....你看着办
peer.onaddstream = function (event) {    
  Vue.set(client, "stream", event.stream);
};
peer.onicecandidate
//获取到icecandidate信息,要发送给p2p的对方
//不然p2p链接就进行不下去了!
//(我发现是一般setLocalDescription,setRemoteDescription后得到)
peer.onicecandidate = function (event) {    
  if (!event.candidate) return;
  messageServer.sendRoomMessage({        
    action: "client_icecandidate",
    target: client.id,
    candidate: event.candidate
  })
};
peer.oniceconnectionstatechange
//简单的可以理解成连接状态事件
//这部分建议还是看文档
//https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceConnectionState
peer.oniceconnectionstatechange = function(){
  switch (peer.iceConnectionState) {
    case "failed":
      //显然是失败
    case "checking":
      //连接中...
    case "connected":
     //连接成功
    case "completed":
      //链接完成
    case "disconnected":
      //连接断开
  }
}
peer.createOffer
//部分浏览起会因为没有这个config而报错的,所以还是加上吧
//测试一下config中两个值设置为0的时候,发送offer的,没有拿到stream
//目测是用来之指定需要怎么样的资料的
//更多的资料找不到
var config = {    
  offerToReceiveAudio: 1,
  offerToReceiveVideo: 1
}
peer.createOffer(config).then(function (dp) {    
  //获取到的Description,应该发送给对方设置
  client.peer.setLocalDescription(dp);    
  messageServer.sendRoomMessage({        
    action: "client_offer",        
    target: client.id,        
    sdp: dp    
  });
});
peer.createAnswer
//这个又很奇怪,加上config就会报错,不加问事....好奇怪
//其实这个函数就是获取到对方的offer后进行的应答
client.peer.createAnswer().then(function (dp) {    
  //获取到本地Description后,记得发送给对方设置
  messageServer.sendRoomMessage({       
    action: "client_answer",        
    target: client.id,        
    sdp: dp    
  });    
  client.peer.setLocalDescription(dp);
}).catch(function () {    
  console.log(client.id + ":生成 answer 失败")  
});

RTCDataChannel在这里就不介绍
更详细的接口信息,可以查看 https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API

WebRTC的注意事项

  1. 在部分浏览器中,getUserMedia 需要有 https才能打开,例如chrome,所以要如果挂带外网,需要https的支持
  2. 在实际开发中,请才用上面的adapter.js来控制好不同浏览器之间的区别
  3. 在getUserMedia的时候,如果乱设置,可能获取不到设备的情况哦!

WebRTC的 demo

由于代码过长就不直接贴了

代码缩略图

demo地址:https://static.meislzhua.online/
手机打开的话 需要手机chrome才可以(没测试哪部分不兼容的)
桌面浏览器在chrome 51 和 ff48中测试成功
代码地址:https://github.com/meislzhua/webrtc-demo

后语

在8月10的时候,突然想写一个webrtc的demo...
于是
10 号上午看了webrtc的相关资料,下午复习一下leancloud的通信
11 号一直在调leancloud的通信...(试过推送和实时通信)
12 号正式开始写demo
13 号 demo完成,但成功率很低..(发现是原来我的网络不行)..然后准备方案二
14 号 研究了一整天的视频录制与传输,后被leancloud实时磨得没耐心(5K/s限制),放弃了
15-16号,酱油了一下,把demo打包成了electron应用,并在linux,window,mac osx下测试
17号 随意重构了一下代码,写了本篇文章....

我本来打算demo用electron应用来代替的..这样可以保密一些东西,后来想想,还是算了~相信读者素质
欢问题迎留言 或者指出本文的错误

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容