WebRTC 是一個支持網頁瀏覽器進行實時語音對話或視頻對話的技術 ,,最近工做須要研究了一下,寫一個demo供你們參考,原理方面的東西你們能夠百度一下,須要注意的是demo目前只支持火狐 由於谷歌目前必須是https 訪問 才能夠獲取視頻信息.系統環境爲:tomcat8+jdk7javascript
websocketcss
package com.li.web; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/video/{roomId}/{userId}") public class VideoScoket { /** * 存放房間與用戶 */ private static HashMap<String,Set<User>> usersRoom = new HashMap<String,Set<User>>(); /** * 打開websocket * @param session websocket的session * @param uid 打開用戶的UID */ @OnOpen public void onOpen(Session session, @PathParam("roomId")String roomId, @PathParam("userId")String userId) { Set<User> users = usersRoom.get(roomId); if(users== null ){ users = new HashSet<User>(); } if(users.size()>=2){ sendMessage(session, "peopleMax");//目前只支持兩我的之間的通信 ,因此不能超過兩我的 }else{ User user = new User(); user.setId(userId); user.setSession(session); users.add(user); usersRoom.put(roomId,users); } } /** * websocket關閉 * @param session 關閉的session * @param uid 關閉的用戶標識 */ @OnClose public void onClose(Session session, @PathParam("roomId")String roomId, @PathParam("userId")String userId) { Set<User> users = usersRoom.get(roomId); if(users!=null){ for (User user:users) { if(user.getId().equals(userId)){ users.remove(user); return; }else if(!user.getId().equals(userId)){ sendMessage(user.getSession(), "bye");//退出以後,發送給另外一我的信息,以便讓他斷開視頻鏈接 return; } } } } /** * 收到消息 * @param message 消息內容 * @param session 發送消息的session * @param uid */ @OnMessage public void onMessage(String message,Session session, @PathParam("roomId")String roomId, @PathParam("userId")String userId) { Set<User> users = usersRoom.get(roomId); if(users!=null){ User recipient = null; for (User user:users) {//查詢當前會議中另外一個在線人 if(!user.getId().equals(userId)){ recipient = user; } } if(message.startsWith("query-On-line")){//若是查詢是否有人在線 if(users.size()>1){ sendMessage(session,"query-On-line-Yes"); }else{ sendMessage(session,"query-On-line-No"); } }else if(recipient!=null){ sendMessage(recipient.getSession(), message); } } } /** * 給客戶端發送消息 * @param session * @param message */ public void sendMessage(Session session,String message){ try { if(session.isOpen()) { session.getBasicRemote().sendText(new String(message)); } } catch (IOException e) { e.printStackTrace(); } } }
Userhtml
package com.li.web; import javax.websocket.Session; public class User { private String id; private Session session; public String getId() { return id; } public void setId(String id) { this.id = id; } public Session getSession() { return session; } public void setSession(Session session) { this.session = session; } }
meeting.jspjava
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; String scoketPasePath = "ws://"+request.getServerName()+":"+request.getServerPort()+path+"/video/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta charset="utf-8"> <script src="<%=basePath%>jquery.min.js"></script> <script src="<%=basePath%>monitor.js"></script> <style type="text/css"> .right{ height: 80%; position:absolute; right: 40px; top:40px; width:180px; } .remoteAudio{ margin-top: 20px; list-style:outside none none; height:150px; width: 180px; background-color: black; border: 1px red solid; text-align:center; } .name{ position:absolute; z-index:99999; left:77px; } </style> </head> <body> <input type="text" id="roomId"/> <input type="button" value="進入房間" onclick="goRoom()"/> <script type="text/javascript"> function goRoom(){ var $roomId = $("#roomId").val(); if($roomId==""){ alert("請輸入房間號"); }else{ monitor.initialize("<%=scoketPasePath%>", "localVideo","remoteAudio", $roomId); monitor.openChannel(); } } </script> <div> <video id="localVideo" autoplay="autoplay"></video> </div> <div> <video id="remoteAudio" autoplay="autoplay"></video> </div> </body> </html>
monitor.jsjquery
var monitor ={ initSucess:false, socket :null, PeerConnection:null, pc:null, started:false, localStream:null, remoteVideo:null, localVideo:null, remoteStream:null, scoketPath:null, roomId:null, userId:null, socketSate:false, iceServer:{//打洞服務器地址配置 "iceServers": [{ "url": "stun:1.1.1.1" }]}, log:function(msg){ if(console && console.log){ console.log(msg); } },//初始化一些信息 initialize:function(scoketPath,localVideoId,remoteVideoId,roomId){ PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; monitor.remoteVideo = $("#"+remoteVideoId); monitor.localVideo = $("#"+localVideoId); monitor.scoketPath = scoketPath; monitor.roomId = roomId; monitor.userId = new Date().getTime(); },//打開webscoket openChannel:function(){ monitor.socketSate=true; monitor.socket = new WebSocket(monitor.scoketPath+monitor.roomId+"/"+monitor.userId); monitor.socket.onopen = monitor.onopen; monitor.socket.onmessage = monitor.onChannelMessage; monitor.socket.onclose = monitor.onChannelClosed; }, onopen:function(onopenCallBack){ monitor.log("websocket打開"); monitor.socketSate = true; monitor.getUserMedia(); }, onChannelClosed:function(){ monitor.log("websocket關閉"); monitor.socketSate=false; monitor.openChannel(); }, onChannelMessage:function(message){ monitor.log("收到信息 : " + message.data); if(message.data=="query-On-line-Yes"){ monitor.maybeStart(); }else if(message.data=="peopleMax"){ alert("人數已經超過限制"); }else if(message.data=="bye"){ monitor.onRemoteClose(); }else if(message.data!="query-On-line-No"){ monitor.processSignalingMessage(message.data);//創建視頻鏈接 } }, getUserMedia:function(){ monitor.log("獲取用戶媒體"); navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; navigator.getUserMedia({ "audio" : true, "video" : true },monitor.onUserMediaSuccess, monitor.onUserMediaError); }, onUserMediaSuccess:function(stream){ monitor.log("獲取媒體成功"); monitor.localStream=stream; var url = window.URL.createObjectURL(stream); monitor.localVideo.attr("src",url); monitor.sendMessageByString("query-On-line"); }, onUserMediaError:function(){ monitor.log("獲取用戶流失敗!"); }, maybeStart:function(){ if (!monitor.started) { monitor.createPeerConnection(); monitor.pc.addStream(monitor.localStream); monitor.started = true; monitor.doCall(); } }, createPeerConnection:function(){ monitor.pc = new PeerConnection(monitor.iceServer); monitor.pc.onicecandidate =monitor.onIceCandidate; monitor.pc.onconnecting = monitor.onSessionConnecting; monitor.pc.onopen = monitor.onSessionOpened; monitor.pc.onaddstream = monitor.onRemoteStreamAdded; monitor.pc.onremovestream = monitor.onRemoteStreamRemoved; }, onSessionConnecting:function(message){ monitor.log("開始鏈接"); }, onSessionOpened:function(message){ monitor.log("鏈接打開"); }, onRemoteStreamAdded:function(event){ monitor.log("遠程視頻添加"); if(monitor.remoteVideo!=null){ var url = window.URL.createObjectURL(event.stream); monitor.remoteVideo.attr("src",url); monitor.remoteStream = event.stream; monitor.waitForRemoteVideo(); } }, waitForRemoteVideo:function(){ if (monitor.remoteVideo[0].currentTime > 0) { // 判斷遠程視頻長度 monitor.transitionToActive(); } else { setTimeout(monitor.waitForRemoteVideo, 100); } }, transitionToActive:function(){ monitor.log("鏈接成功!"); monitor.sendMessageByString("connection_open"); }, onRemoteStreamRemoved:function(event){ monitor.log("遠程視頻移除"); }, onIceCandidate:function(event){ if (event.candidate) { monitor.sendMessage({ type : "candidate", label : event.candidate.sdpMLineIndex, id : event.candidate.sdpMid, candidate : event.candidate.candidate }); } else { monitor.log("End of candidates."); } }, processSignalingMessage:function(message){ var msg = JSON.parse(message); if (msg.type === "offer") { if (!monitor.started) monitor.maybeStart(); monitor.pc.setRemoteDescription(new RTCSessionDescription(msg),function(){ monitor.doAnswer(); },function(){ }); } else if (msg.type === "answer" && monitor.started) { monitor.pc.setRemoteDescription(new RTCSessionDescription(msg)); } else if (msg.type === "candidate" && monitor.started) { var candidate = new RTCIceCandidate({ sdpMLineIndex : msg.label, candidate : msg.candidate }); monitor.pc.addIceCandidate(candidate); } }, doAnswer:function (){ monitor.pc.createAnswer(monitor.setLocalAndSendMessage, function(e){ monitor.log("建立相應失敗"+e); }); }, doCall:function(){ monitor.log("開始呼叫"); monitor.pc.createOffer(monitor.setLocalAndSendMessage,function(){ }); }, setLocalAndSendMessage:function(sessionDescription){ monitor.pc.setLocalDescription(sessionDescription); monitor.sendMessage(sessionDescription); }, sendMessage:function(message){ var msgJson = JSON.stringify(message); monitor.sendMessageByString(msgJson); }, sendMessageByString:function(message){ monitor.socket.send(message); monitor.log("發送信息 : " + message); }, onRemoteClose:function(){ monitor.started = false; monitor.pc.close(); monitor.sendMessageByString("connection_colse"); } };
還須要注意的一點是,,若是視頻的兩我的未處在同一個內網中,那則須要部署打洞服務器,,我用的restund 比較簡單...有須要的同窗能夠百度,部署安裝web