WebRtc与信令服务器通信的流程分析

webrtc

WebRTC,即Web Real-Time Communication,web实时通信技术。简单地说就是在web浏览器里面引入实时通信,包括音视频通话等。WebRTC实现了基于网页的语音对话或视频通话,目的是无插件实现web端的实时通信的能力。WebRTC提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、展示等功能,并且还支持跨平台,包括linux、windows、mac、android等。

Demo

经过大量的收集后在github上发现了这个项目
,下载运行并进行分析,虽然在很多地方存在不足,但是基本能实现通信的过程,所以就以本demo进行简要分析,过程弄清除了可以完全自己再重新写一个完整的

注意:本demo下需要自己配置node.js服务器进行验证,在本地搭建的时候需要将项目中的信令服务器地址修改为本机的ip地址

流程分析

注意:demo中分客户端 ClientA 和ClientB(本demo是通过循环一一建立连接,如下描述的单个建立连接的过程)

1.ClientA当点击进入的时候会将房间的id传递给信令服务器

sendMessage("createAndJoinRoom",message);

2.信令服务器收到消息后会回调到接口里面,此接口为:createdListener

返回的参数有:
socket id(用于建立webrtc连接用的标志)
room id  (房间id)
peer     (其他客户端的数据)

3.在接口中拿到信令服务器返回的东西后开始遍历peers,如果这个时候集合为空表示自己是房间的创造者,并且处于等到状态,如果集合不为空则开始遍历这个集合并与他们一一建立通过方法getOrCreateRtcConnect进行webrtc连接(建立连接是通过服务器返回的SocketId来进行连接的)并且一一给他们发送offer

for (int i = 0; i < peers.length(); i++) {
    JSONObject otherPeer = peers.getJSONObject(i);
    String otherSocketId = otherPeer.getString("id");
    //创建WebRtcPeerConnection
    Peer pc = getOrCreateRtcConnect(otherSocketId);
    //通过getOrCreateRtcConnect建立的连接后再通过pc.getPc().addTrack(localVideoTrack)设置视频流!并将这个链接保存起来
    //创建offer
    pc.getPc().createOffer(pc,sdpMediaConstraints);
}

4.offer的创建成功会回调到下面这个方法里面:
onCreateSuccess(SessionDescription sdp)
这个时候在回调方法里面通过前面的roomid socketid等等信息创建sdp信息并再次发送给信令服务器,让信令服务器把这些消息传递给对方
具体流程如下:

调用PeerConnection的CreateOffer方法创建一个用于offer的SDP对象,SDP对象中保存当前音视频的相关参数。a通过PeerConnection的SetLocalDescription方法将该SDP对象保存起来并且构建信息再此发送给信令服务器,这个时候发送了offer

//设置本地LocalDescription
pc.setLocalDescription(Peer.this, sdp);
//构建信令数据
try {
    JSONObject message = new JSONObject();
    message.put("from",webRtcClient.getSocketId());
    message.put("to",id);
    message.put("room",webRtcClient.getRoomId());
    message.put("sdp",sdp.description);
    //向信令服务器发送信令
    webRtcClient.sendMessage(type,message);

5.当信令服务器接受到上面发送过来的offer的时候再回调offerListener,其他客户端一一接收到ClientA发送过的offer SDP对象,通过PeerConnection的SetRemoteDescription方法将其保存起来,这时再设置自己的视频流,并调用PeerConnection的CreateAnswer方法创建一个应答的SDP对象answer,通过PeerConnection的SetLocalDescription的方法保存该 Answer SDP对象并将它通过信令服务器发。

//获取id
String fromId = data.getString("from");
//获取peer
Peer pc = getOrCreateRtcConnect(fromId);
//构建RTCSessionDescription参数
SessionDescription sdp = new SessionDescription(
        SessionDescription.Type.fromCanonicalForm("offer"),
        data.getString("sdp")
);
//设置远端setRemoteDescription
pc.getPc().setRemoteDescription(pc,sdp);
//设置answer
pc.getPc().createAnswer(pc,sdpMediaConstraints);

6.当信令服务器再次接受到信息时候会回调answerListener,a接收到发送过来的应答SDP对象,将其通过PeerConnection的SetRemoteDescription方法保存起来

//获取id
String fromId = data.getString("from");
//获取peer
Peer pc = getOrCreateRtcConnect(fromId);
//构建RTCSessionDescription参数
SessionDescription sdp = new SessionDescription(
        SessionDescription.Type.fromCanonicalForm("answer"),
        data.getString("sdp")
);
//设置远端setRemoteDescription
pc.getPc().setRemoteDescription(pc,sdp);

7.在SDP信息的offer/answer流程中,ClientA和ClientB已经根据SDP信息创建好相应的音频Channel和视频Channel并开启Candidate数据的收集,Candidate数据可以简单地理解成Client端的IP地址信息(本地IP地址、公网IP地址、Relay服务端分配的地址)

8.这个时候ClientA和ClientB开始使用穿透技术获取自己的公网地址等等信息,各自获取到后会回调到方法onIceCandidate里面并通过webRtcClient.sendMessage("candidate",message)方法将ip等信息发送给信令服务器

//新ice地址被找到触发
@Override
public void onIceCandidate(IceCandidate iceCandidate) {
    Log.d(TAG,"onIceCandidate "+iceCandidate.sdpMid);
    try {
        //构建信令数据
        JSONObject message = new JSONObject();
        message.put("from",webRtcClient.getSocketId());
        message.put("to",id);
        message.put("room",webRtcClient.getRoomId());
        //candidate参数
        JSONObject candidate = new JSONObject();
        candidate.put("sdpMid",iceCandidate.sdpMid);
        candidate.put("sdpMLineIndex",iceCandidate.sdpMLineIndex);
        candidate.put("sdp",iceCandidate.sdp);
        message.put("candidate",candidate);
        //向信令服务器发送信令
        webRtcClient.sendMessage("candidate",message);
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

9.信令服务器接受到后会回调到接口candidateListener

//获取id
String fromId = data.getString("from");
//获取peer
Peer pc = getOrCreateRtcConnect(fromId);
//获取candidate
JSONObject candidate = data.getJSONObject("candidate");
IceCandidate iceCandidate = new IceCandidate(
        candidate.getString("sdpMid"), //描述协议id
        candidate.getInt("sdpMLineIndex"),//描述协议的行索引
        candidate.getString("sdp")//描述协议
);
//添加远端设备路由描述
pc.getPc().addIceCandidate(iceCandidate);

10.这样ClientA和ClientB就已经建立了音视频传输的P2P通道,ClientB接收到ClientA传送过来的音视频流,会通过PeerConnection的OnAddStream回调接口返回一个标识ClientA端音视频流的MediaStream对象,在ClientB端渲染出来即可。同样操作也适应ClientB到ClientA的音视频流的传输,本demo使用onTrack回调代替了这个渲染的过程

public interface RtcListener {

    //远程音视频流加入 Peer通道
    void onAddRemoteStream(String peerId,VideoTrack videoTrack);

    //远程音视频流移除 Peer通道销毁
    void onRemoveRemoteStream(String peerId);
}


//用这个方法代替了OnAddStream方法进行了视频流的渲染
@Override
public void onTrack(RtpTransceiver transceiver) {
    MediaStreamTrack track = transceiver.getReceiver().track();
    Log.d(TAG,"onTrack "+ track.id());
    if (track instanceof VideoTrack) {
        webRtcClient.getRtcListener().onAddRemoteStream(id,(VideoTrack)track);
    }
}

总结

感谢作者提供本demo进行分析,webrtc开源项目比较庞大,编译时间很长,希望通过本简要分析能明白其中通信的原理方便自己后续开发!如有疑惑之处望交流

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

推荐阅读更多精彩内容