`
myten
  • 浏览: 134024 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

WebRTC学习实现视频

 
阅读更多

工作中遇到要视频直播的需求,前提是不能依赖Flash前端,于是就找到了WebRtc的相关资料.

什么GetUserMedia,RTCPeerConnection,DataChannel我不多说.

 

简单讲就是谷歌把实时通信层打包进浏览器.而这一套实时通信层又是来源于电信通信领域.

所以浏览器两端交互需要依赖一个叫做信令服务器的东西,来协助两端完成连接.

简单说下流程

以A呼叫B为例

A呼叫B

1.告知Server,我要找B

2.Server查一下有没有B,有就传达,没有就不传达,至于结果需不需要告知A,那全看心情了.反正这东西是自己实现的.WebRTC里就提了一嘴这东西,没具体规范.

3.B得到A的呼叫(准确说叫Offer)

4.B解析Offer,回应(Answer)到Server,Server回给A 

5.A收到Answer,解析.

6.这时,A和B就算勾搭上了.剩下的事情就交给他们自己办了.

 

 

 

Offer 和 Answer 都属于SDP.具体规范http://datatracker.ietf.org/doc/draft-nandakumar-rtcweb-sdp/01/

 

解析这些是交给浏览器做的.

先看Server端的Java实现

package org.rtc.sip;

import java.io.IOException;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import com.google.gson.Gson;

@ServerEndpoint(value = "/sipserver")
public class SignalWorker {

	private Gson gson = new Gson();
	private Session session;

	public Session getSession() {
		return session;
	}

	public void setSession(Session session) {
		this.session = session;
	}

	public SignalWorker() {
		
	}

	@OnClose
	public void onClose(Session session) {
	
	}

	@OnError
	public void onError(Throwable throwable) {

	}

	@OnMessage
	public void onMessage(String message, Session session) {
		System.out.println("收到消息:" + message);
		SIPObject sip = gson.fromJson(message, SIPObject.class);
		try {
			if(sip.getAction().equals("login")){
				SIPSessionManager.addNewSession(sip.getFrom(), this);
			}else if(sip.getAction().equals("offer")){
				SignalWorker sker=SIPSessionManager.getSignalWorker(sip.getTo());
					if(sker!=null){
						sker.getSession().getBasicRemote().sendText(message);
					}
					else{
						miss();
					}
			}else if(sip.getAction().equals("answer")){
				SignalWorker sker=SIPSessionManager.getSignalWorker(sip.getTo());
				if(sker!=null){
					sker.getSession().getBasicRemote().sendText(message);
				}
				else{
						miss();
				}
			}else if(sip.getAction().equals("candidate")){
				SignalWorker sker=SIPSessionManager.getSignalWorker(sip.getTo());
				if(sker!=null){
					sker.getSession().getBasicRemote().sendText(message);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@OnOpen
	public void onOpen(Session session) {
		this.session = session;
	}
	public void miss(){
		SIPObject resp=new SIPObject();
		resp.setAction("miss");
		try {
			session.getBasicRemote().sendText(gson.toJson(resp));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void send(String msg) {
		System.out.println(msg);
		session.getAsyncRemote().sendText(msg);
	}
}

 代码逻辑很简单,就是A->B,B->A,

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebRtc</title>
<script src="rtc_suit/jquery-2.1.3.min.js"></script>
<script src="rtc_suit/yuhan_rtc.js"></script>
</head>
<body>
<video  id="localVideo"  style="width:400px;height:400px;" ></video>
<button onclick="Call('Baidu')"> call</button>
<br/>
<video  id="remoteVideo"   style="width:400px;height:400px;" ></video>
<script>

var rtcg=new RTCSuit({id:"Google",to:"Baidu",sipws:"ws://192.168.0.119:8080/WebTest/sipserver"});
rtcg.connectSip();

var rtcb=new RTCSuit({id:"Baidu",to:"Google",sipws:"ws://192.168.0.119:8080/WebTest/sipserver"});
rtcb.connectSip();
rtcb.bindRemoteMedia("remoteVideo");

function Call(to){
	rtcg.bindLocalMedia("localVideo",true,true,function(rst,stream){
		if(rst){
			rtcg.sendOffer();
		}
	});
}

//rtc.sendOffer();
</script>
</body>
</html>

 上面HTML代码逻辑也很简单.

两端Baidu和Google先要登陆在SIPServer上.

Google呼叫baidu是在本地完成了摄像头视频获取后发出的Offer.

整个WebRtc交互用一个JS库屏蔽掉了复杂的代码.

代码只简单实现了功能,未完善.贴出来分享.

/**
 * 
 */
// define override
var RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection
		|| window.webkitRTCPeerConnection;
navigator.getUserMedia = navigator.webkitGetUserMedia
		|| navigator.mozGetUserMedia;
//ICE SERVER
var iceServer = {
        "iceServers": [{
            "url": "stun:stun.l.google.com:19302"
        }]
};
//LOG
function log(msg,level){
	console.log(new Date().toLocaleString()+" "+msg);
}



function RTCSuit(opt) {
	this.sipws=opt.sipws;//信令服务器地址
	this.id=opt.id||new Date().getTime();//身份信息
	this.to=opt.to;
	this.conn=null;//websocket对象,connect时初始化
	
	this.sessionId=null;
	this.peercn=new RTCPeerConnection(opt.ice||iceServer);
	this.peercn.rtc=this;
	//init peer
	this.peercn.onicecandidate = RTCSuit.prototype.onIceCandidate;
	this.peercn.onconnecting = RTCSuit.prototype.onPeerConnecting;
	this.peercn.onopen = RTCSuit.prototype.onPeerOpen;
	this.peercn.onaddstream = RTCSuit.prototype.onRemotePeerStreamAdd;
	this.peercn.onremovestream = RTCSuit.prototype.onPeerStreamRemove;
	
	this.localNode=null;
	this.remoteNode=null;
	return this;
}

//视频媒体交互
RTCSuit.prototype.bindLocalMedia=function(id, enableAudio, enableVideo,callback)
{
	var rtc=this;
	navigator.getUserMedia({
		"audio" : enableAudio,
		"video" : enableVideo
	}, function(stream) {//success
		var videoNode=document.getElementById(id);
		rtc.localNode=videoNode;
		videoNode.autoplay=true;
		videoNode.src= URL.createObjectURL(stream);
		rtc.peercn.addStream(stream);
		//触发事件,通知视频流绑定成功
		if(typeof(callback)=="function"){
			callback(true,stream);	
		}
		log("bind local media success");
	},function(error){//error
		if(typeof(callback)=="function"){
			callback(false,null);	
		}
	});
};

RTCSuit.prototype.bindRemoteMedia=function(id){
	var videoNode=document.getElementById(id);
	videoNode.autoplay=true;
	this.remoteNode=videoNode;
};
//PEER交互
RTCSuit.prototype.sendOffer=function(){
	var rtc=this;
	if(!rtc.conn.readyState){
		setTimeout(function(){rtc.sendOffer()},300);return;
	}
	this.peercn.createOffer(function(desc){//success
		rtc.peercn.setLocalDescription(desc);
		rtc.send({action:"offer",sdpWrap:desc});
	},function(error){
		rtc.onSendOfferError(error);
	});
};
RTCSuit.prototype.sendAnswer=function(){
	var rtc=this;
	if(!rtc.conn.readyState){
		setTimeout(function(){rtc.sendOffer()},300);return;
	}
	this.peercn.createAnswer(function(desc){//success
		rtc.peercn.setLocalDescription(desc);
		rtc.send({action:"answer",sdpWrap:desc});
	},function(error){
	});
}

RTCSuit.prototype.onAddStreamToPeer=function(){
	log("get here");
};
RTCSuit.prototype.onIceCandidate=function(event){
	var rtc=this.rtc;
	if (event.candidate) {
		rtc.send({action:"candidate",sdpWrap:{
			type : "candidate",
			label : event.candidate.sdpMLineIndex,
			id : event.candidate.sdpMid,
			candidate : event.candidate.candidate
		}});
	} else {
		console.log("End of candidates.");
	}
};
RTCSuit.prototype.onPeerConnecting=function(){
	log(" peer connecting");
};
RTCSuit.prototype.onPeerOpen=function(){
	log(" peer open");
};
RTCSuit.prototype.onRemotePeerStreamAdd=function(event){
	var url = webkitURL.createObjectURL(event.stream);
	this.rtc.remoteNode.src=url;
};
RTCSuit.prototype.onPeerStreamRemove=function(){
	
};

//信令交互
RTCSuit.prototype.send=function(json){
	var rtc=this;
	json.from=rtc.id;
	json.to=rtc.to;
	var smsg=JSON.stringify(json);
	if(rtc.conn.readyState)
	rtc.conn.send(smsg);
	log(rtc.id+" 发送"+smsg);
};
RTCSuit.prototype.connectSip=function(sipws,callback){
	sipws=sipws||this.sipws;
	var rtc=this;
	this.conn=new WebSocket(sipws);
	this.conn.onopen=function(){
		rtc.send({id:rtc.id,action:"login"});
		log("sip server connected");
	};
	//core msg process
	this.conn.onmessage=function(e){
		log(rtc.id+" 收到消息:"+e.data);
		var msg=e.data;
		var json=eval("("+msg+")");
		if(typeof(rtc["on"+json.action]) == "function"){
			rtc["on"+json.action](json);
		}else{
			log("error response:"+msg);
		}
	};
};

RTCSuit.prototype.onoffer=function(json){
	this.peercn.setRemoteDescription(new RTCSessionDescription(json.sdpWrap));
	this.sendAnswer();
	log("recv offer")
};
RTCSuit.prototype.onanswer=function(json){
	this.peercn.setRemoteDescription(new RTCSessionDescription(json.sdpWrap));
	log("recv  answer");
};
RTCSuit.prototype.oncandidate=function(json){
		var msg=json.sdpWrap;
		var candidate = new RTCIceCandidate({
		sdpMLineIndex : msg.label,
		candidate : msg.candidate
		});
	this.peercn.addIceCandidate(candidate);
	
};

 

最后代码奉上....环境 tomcat8.0 java 1.8

 

分享到:
评论
1 楼 ykbj117 2015-10-28  
你们知道刘绍华么?就是北邮的一个教授,专门研究WebRTC的资深大牛,他开网络公开课了:http://www.lookybang.cc/forum.php?mod=viewthread&tid=409&extra=page%3D1,并且据说会持续发布,大家可以去看看,据说有问题也能给解答的!

相关推荐

    基于webrtc的视频会议系统源码.zip

    【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设...基于webrtc的视频会议系统源码.zip基于webrtc的视频会议系统源码.zip

    基于WebSocket、WebRTC实现浏览器视频通话

    基于WebSocket、WebRTC实现浏览器视频通话, 仅供参考,大家一起讨论学习!

    基于webRTC的简单视频会议app源码+项目说明.zip

    基于webRTC的简单视频会议app源码+项目说明.zip基于webRTC的简单视频会议app源码+项目说明.zip基于webRTC的简单视频会议app源码+项目说明.zip基于webRTC的简单视频会议app源码+项目说明.zip基于webRTC的简单视频会议...

    vue+node(socket.io)+webRTC一对一视频通讯demo

    这个项目是一个很好的学习资源,展示了如何将Vue.js、Node.js(借助socket.io)和WebRTC结合,实现现代实时通信应用的基础架构。通过理解和实践这个示例,开发者能够更好地掌握这些技术的整合与应用。

    基于tomcat7利用webrtc API实现一对一视频通话

    这个项目中,你将学习到如何将WebRTC技术与WebSocket结合,实现在浏览器之间的一对一视频通话。同时,还会涉及到HTML5、JavaScript和Java后端编程的相关知识,对理解现代Web实时通信有极大的帮助。

    基于C#和SuperWebSocket、WebRtc开发的网页视频聊天源码

    总的来说,这个项目提供了从后端到前端的完整视频聊天解决方案,对于学习C#、WebSocket以及WebRTC技术的开发者来说,是一个宝贵的实践资源。通过深入研究这个项目,不仅可以掌握实时通信的基本原理,还能了解到如何...

    《WebRTC音视频实时互动技术》大纲

    《WebRTC音视频实时互动技术》大纲...通过以上知识点的学习,读者可以全面理解WebRTC技术,并具备开发实时音视频互动应用的基础。此外,书中还可能涵盖了这些技术的实际应用案例和源码分析,以加深理解并提升实践能力。

    基于JavaScript WebRTC实现跨平台音视频通话(源码+项目说明)(实现1对1视频,多人视频等).zip

    【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用!...基于JavaScript WebRTC实现跨平台音视频通话(源码+项目说明)(实现1对1视频,多人视频,视频直播,视频会议,房间管理,权限管理等).zip

    WebRtc音视频通话demo

    WebRTC(Web Real-Time...总之,“WebRtc音视频通话demo”为Android开发者提供了一个快速实现音视频通话功能的基础框架,通过学习和理解这个示例,开发者可以更深入地掌握WebRTC技术,进而构建出更多复杂和高效的应用。

    基于webrtc+clmtrackr.js实现的视频录制、人脸检测、活体检测源码+体验地址.zip

    基于webrtc+clmtrackr.js实现的视频录制、人脸检测、活体检测源码+体验地址.zip 基于webrtc+clmtrackr.js实现的视频录制、人脸检测、活体检测源码+体验地址.zip 基于webrtc+clmtrackr.js实现的视频录制、人脸检测、...

    WebRTC学习之三:录音和播放

    在本文中,我们将深入探讨如何使用WebRTC技术在C++环境中实现录音和播放功能,并结合Qt库构建用户界面。WebRTC(Web Real-Time Communication)是一种开放的API规范,旨在为浏览器和移动应用程序提供实时通信(RTC)...

    vue3实现WebRTC实战1v1通话

    Vue3实现WebRTC实战1v1通话是一种在现代前端开发中构建实时通信应用的方法,它结合了Vue.js的组件化优势和WebRTC的实时通信能力。WebRTC(Web Real-Time Communication)是浏览器之间进行音视频通信的一套开放标准,...

    基于WebRTC的在线视频会议(源码+项目说明)(高分毕设).zip

    基于WebRTC的在线视频会议(源码+项目说明)(高分毕设).zip基于WebRTC的在线视频会议(源码+项目说明)(高分毕设).zip基于WebRTC的在线视频会议(源码+项目说明)(高分毕设).zip基于WebRTC的在线视频会议...

    基于Chrome、Java、WebSocket、WebRTC实现浏览器视频通话

    本项目“基于Chrome、Java、WebSocket、WebRTC实现浏览器视频通话”旨在利用这些技术构建一个可以在主流浏览器上运行的视频通话系统。以下是关于这些关键技术的详细解释: **WebRTC(Web Real-Time Communication)...

    webrtc视频在线示例

    通过阅读源代码,你可以更深入地理解WebRTC的工作原理,以及如何在Android环境下实现视频通话功能。这个项目通常会包含客户端和服务器端的代码,客户端处理Android端的实现,而服务器端可能负责信令的传递和处理。 ...

    WEBRTC多人视频通话demo

    WebRTC(Web Real-Time Communication)是一项开放的技术标准,旨在实现浏览器之间的实时通信,无需借助插件或第三方软件。...对于开发者来说,这是一个很好的学习和实践WebRTC多人视频通话功能的实例。

    WebRTC的Android实现 源码下载 包括服务器,pc端,android端

    WebRTC(Web Real-Time Communication)是一项开放的网络技术,它允许网页浏览器进行实时通信(RTC),无需安装任何插件或第三方软件...学习并理解这些源码将有助于深入掌握WebRTC技术,并能快速地在自己的项目中应用。

    WebRTC语音视频通话demo

    WebRTC(Web Real-Time...开发者可以通过研究这个demo,学习如何在自己的应用程序中集成WebRTC,实现类似的功能。无论是进行一对一的私密通话,还是多用户的群组会议,WebRTC都为现代Web应用带来了强大的实时通信能力。

Global site tag (gtag.js) - Google Analytics