爱编程的欧巴

让我们成长吧~
  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理
打开支付宝首页搜“555176706”领红包,即可加好友

<%@ page language="java" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <% String ctx = request.getContextPath() + "/"; pageContext.setAttribute("ctx", ctx); %> <html> <head> <link rel="canonical" href="${roomLink}" /> <meta http-equiv="X-UA-Compatible" content="chrome=1" /> <script src="./js/channel.js"></script> <!-- type="text/javascript"> (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })(); --> <style type="text/css"> a:link { color: #ffffff; } a:visited { color: #ffffff; } html,body { background-color: #000000; height: 100%; font-family: Verdana, Arial, Helvetica, sans-serif; } body { margin: 0; padding: 0; } #container { background-color: #000000; position: relative; min-height: 100%; width: 100%; margin: 0px auto; -webkit-perspective: 1000; } #card { -webkit-transition-property: rotation; -webkit-transition-duration: 2s; -webkit-transform-style: preserve-3d; } #local { position: absolute; width: 100%; -webkit-transform: scale(-1, 1); -webkit-backface-visibility: hidden; } #remote { position: absolute; width: 100%; -webkit-transform: rotateY(180deg); -webkit-backface-visibility: hidden; } #mini { position: absolute; height: 30%; width: 30%; bottom: 32px; right: 4px; -webkit-transform: scale(-1, 1); opacity: 1.0; } #localVideo { opacity: 0; -webkit-transition-property: opacity; -webkit-transition-duration: 2s; } #remoteVideo { opacity: 0; -webkit-transition-property: opacity; -webkit-transition-duration: 2s; } #miniVideo { opacity: 0; -webkit-transition-property: opacity; -webkit-transition-duration: 2s; } #footer { spacing: 4px; position: absolute; bottom: 0; width: 100%; height: 28px; background-color: #3F3F3F; color: rgb(255, 255, 255); font-size: 13px; font-weight: bold; line-height: 28px; text-align: center; } #hangup { font-size: 13px; font-weight: bold; color: #FFFFFF; width: 128px; height: 24px; background-color: #808080; border-style: solid; border-color: #FFFFFF; margin: 2px; } #logo { display: block; top: 4; right: 4; position: absolute; float: right; opacity: 0.5; } </style> </head> <body> <script type="text/javascript"> var localVideo; var miniVideo; var remoteVideo; var localStream; var remoteStream; var channel; var channelReady = false; var pc; var socket; var footer; var initiator = ${initiator}; var started = false; var isRTCPeerConnection = true; var mediaConstraints = { 'mandatory':{ 'OfferToReceiveAudio' : true, 'OfferToReceiveVideo' : true } }; var isVideoMuted = false; var isAudioMuted = false; var URL; function initialize() { console.log("Initializing; room=${roomKey}."); card = document.getElementById("card"); localVideo = document.getElementById("localVideo"); footer = document.getElementById("footer"); miniVideo = document.getElementById("miniVideo"); remoteVideo = document.getElementById("remoteVideo"); resetStatus(); openChannel(); getUserMedia(); console.log("initialize1"); URL = (window.URL || window.webkitURL || window.msURL || window.oURL); } function getUserMedia() { navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; // if(navigator.getUserMedia){ try { // navigator.webkitGetUserMedia({ navigator.getUserMedia({ "audio": true, "video": true }, onUserMediaSuccess, onUserMediaError); console.log("Requested access to local media with new syntax."); } catch (e) { try { navigator.getUserMedia("video,audio",onUserMediaSuccess, onUserMediaError); console.log("Requested access to local media with old syntax."); } catch (e) { alert("webkitGetUserMedia() failed. Is the MediaStream flag enabled in about:flags?"); console.log("webkitGetUserMedia failed with exception: "+ e.message); } } console.log("getUserMedia2"); } // } function onUserMediaSuccess(stream) { console.log("User has granted access to local media."); // var url = webkitURL.createObjectURL(stream); var url = URL.createObjectURL(stream); localVideo.style.opacity = 1; localVideo.src = url; localStream = stream; // Caller creates PeerConnection. if (initiator) maybeStart(); console.log("onUserMediaSuccess3"); } function maybeStart() { if (!started && localStream && channelReady) { setStatus("连接中..."); console.log("Creating PeerConnection."); createPeerConnection(); console.log("Adding local stream."); pc.addStream(localStream); started = true; // Caller initiates offer to peer. if (initiator) doCall(); } console.log("maybeStart4"); } function doCall() { console.log("Sending offer to peer."); if (isRTCPeerConnection) { pc.createOffer(setLocalAndSendMessage, null, mediaConstraints); // pc.createOffer(setLocalAndSendMessage,function (error) { // console.log('Failure callback: ' + error); // }); } else { var offer = pc.createOffer(mediaConstraints); pc.setLocalDescription(pc.SDP_OFFER, offer); sendMessage({ type : 'offer', sdp : offer.toSdp() }); pc.startIce(); } console.log("doCall5"); } function setLocalAndSendMessage(sessionDescription) { pc.setLocalDescription(sessionDescription); sendMessage(sessionDescription); console.log("setLocalAndSendMessage6"); } function sendMessage(message) { var msgString = JSON.stringify(message); console.log('发出信息 : ' + msgString); path = 'message?r=${roomKey}' + '&u=${user}'; var xhr = new XMLHttpRequest(); xhr.open('POST', path, true); xhr.send(msgString); console.log("sendMessage7"); } function openChannel() { console.log("Opening channel."); socket = new WebSocket("ws://"+window.location.host+"${ctx}websocket?u=${user}"); // socket = new WebSocket("ws://10.74.0.154:8080"); socket.onopen = onChannelOpened; socket.onmessage = onChannelMessage; socket.onclose = onChannelClosed; console.log("openChannel8"); } function resetStatus() { if (!initiator) { setStatus("让别人加入视频聊天: <a href=\"${roomLink}\">${roomLink}</a>"); } else { setStatus("初始化..."); } console.log("resetStatus9"); } function createPeerConnection() { console.log("createPeerConnection9"); var pc_config = { "iceServers" : [ { "url" : "stun:stun.l.google.com:19302" } ] }; try { pc = new webkitRTCPeerConnection(pc_config); pc.onicecandidate = onIceCandidate; console.log("Created webkitRTCPeerConnnection with config \"" + JSON.stringify(pc_config) + "\"."); } catch (e) { try { var stun_server = ""; if (pc_config.iceServers.length !== 0) { stun_server = pc_config.iceServers[0].url.replace( 'stun:', 'STUN '); } pc = new webkitPeerConnection00(stun_server, onIceCandidate00); isRTCPeerConnection = false; console.log("Created webkitPeerConnnection00 with config \"" + stun_server + "\"."); } catch (e) { console.log("Failed to create PeerConnection, exception: " + e.message); alert("Cannot create PeerConnection object; Is the 'PeerConnection' flag enabled in about:flags?"); return; } } pc.onconnecting = onSessionConnecting; pc.onopen = onSessionOpened; pc.onaddstream = onRemoteStreamAdded; pc.onremovestream = onRemoteStreamRemoved; } function setStatus(state) { footer.innerHTML = state; console.log("setStatus10"); } function doAnswer() { console.log("doAnswer11"); console.log("Sending answer to peer."); if (isRTCPeerConnection) { pc.createAnswer(setLocalAndSendMessage,null,mediaConstraints); // pc.createAnswer(setLocalAndSendMessage,function (error) { // console.log('Failure callback: ' + error); // }); } else { var offer = pc.remoteDescription; var answer = pc.createAnswer(offer.toSdp(), mediaConstraints); pc.setLocalDescription(pc.SDP_ANSWER, answer); sendMessage({ type : 'answer', sdp : answer.toSdp() }); pc.startIce(); } } function processSignalingMessage00(message) { console.log("processSignalingMessage0012"); var msg = JSON.parse(message); // if (msg.type == 'offer') should not happen here. if (msg.type == 'answer' && started) { pc.setRemoteDescription(pc.SDP_ANSWER, new SessionDescription( msg.sdp)); } else if (msg.type == 'candidate' && started) { var candidate = new IceCandidate(msg.label, msg.candidate); pc.processIceMessage(candidate); } else if (msg.type == 'bye' && started) { onRemoteHangup(); } } var channelOpenTime; var channelCloseTime; function onChannelOpened() { console.log("onChannelOpened13"); channelOpenTime = new Date(); console.log("Channel opened.Open time is : " + channelOpenTime.toLocaleString()); channelReady = true; if (initiator) maybeStart(); } function onChannelMessage(message) { console.log("onChannelMessage14"); console.log('收到信息 : ' + message.data); if (isRTCPeerConnection) processSignalingMessage(message.data);//建立视频连接 else processSignalingMessage00(message.data); } function processSignalingMessage(message) { console.log("processSignalingMessage15"); var msg = JSON.parse(message); console.log("msg.type:"+msg.type); if (msg.type == 'offer') { // Callee creates PeerConnection if (!initiator && !started) maybeStart(); // We only know JSEP version after createPeerConnection(). if (isRTCPeerConnection) pc.setRemoteDescription(new RTCSessionDescription(msg)); else pc.setRemoteDescription(pc.SDP_OFFER,new SessionDescription(msg.sdp)); doAnswer(); } else if (msg.type == 'answer' && started) { pc.setRemoteDescription(new RTCSessionDescription(msg)); } else if (msg.type == 'candidate' && started) { var nativeRTCIceCandidate = (window.mozRTCIceCandidate || window.RTCIceCandidate); var candidate = new nativeRTCIceCandidate({ sdpMLineIndex : msg.label, candidate : msg.candidate }); pc.addIceCandidate(candidate); } else if (msg.type == 'bye' && started) { onRemoteHangup(); } } function onChannelError() { console.log('Channel error.16'); } function onChannelClosed() { console.log('onChannelClosed.17'); if(!channelOpenTime){ channelOpenTime = new Date(); } channelCloseTime = new Date(); console.log("Channel closed.Close time is " + channelOpenTime.toLocaleString() + " ,Keep time : " + ((channelCloseTime.getTime() - channelOpenTime .getTime()) / 1000 + "s")); openChannel(); } function onUserMediaError(error) { console.log('onUserMediaError.18'); console.log("Failed to get access to local media. Error code was "+ error.code); alert("Failed to get access to local media. Error code was "+ error.code + "."); } function onIceCandidate(event) { console.log('onIceCandidate.19'); if (event.candidate) { sendMessage({ type : 'candidate', label : event.candidate.sdpMLineIndex, id : event.candidate.sdpMid, candidate : event.candidate.candidate }); } else { console.log("End of candidates."); } } function onIceCandidate00(candidate, moreToFollow) { console.log('onIceCandidate00.20'); if (candidate) { sendMessage({ type : 'candidate', label : candidate.label, candidate : candidate.toSdp() }); } if (!moreToFollow) { console.log("End of candidates."); } } function onSessionConnecting(message) { console.log('onSessionConnecting.21'); console.log("Session connecting."); } function onSessionOpened(message) { console.log('onSessionConnecting.22'); console.log("Session opened."); } function onRemoteStreamAdded(event) { console.log('onRemoteStreamAdded.23'); console.log("Remote stream added."); console.log("输出远程流"+event.stream); // var url = webkitURL.createObjectURL(event.stream); var url = URL.createObjectURL(event.stream); miniVideo.src = localVideo.src; remoteVideo.src = url; console.log(url+"www.baidu.com"); remoteStream = event.stream; waitForRemoteVideo(); } function onRemoteStreamRemoved(event) { console.log('onRemoteStreamAdded.24'); console.log("Remote stream removed."); } function onHangup() { console.log('onHangup.25'); console.log("Hanging up."); transitionToDone(); stop(); socket.close(); } function onRemoteHangup() { console.log('onRemoteHangup.26'); console.log('Session terminated.'); transitionToWaiting(); stop(); initiator = 0; } function stop() { console.log('stop.27'); started = false; isRTCPeerConnection = true; isAudioMuted = false; isVideoMuted = false; pc.close(); pc = null; } function waitForRemoteVideo() { console.log('waitForRemoteVideo.28'); console.log("videoTracks:"+remoteStream.getVideoTracks().length); console.log("remoteVideo.currentTime:"+remoteVideo.currentTime); // console.log("remoteStream.videoTracks.length:"+remoteStream.videoTracks.length); if (remoteStream.getVideoTracks().length == 1 || remoteVideo.currentTime > 0) { transitionToActive(); } else { setTimeout(waitForRemoteVideo, 100); } } function transitionToActive() { console.log('transitionToActive.29'); remoteVideo.style.opacity = 1; card.style.webkitTransform = "rotateY(180deg)"; setTimeout(function() { localVideo.src = ""; }, 500); setTimeout(function() { miniVideo.style.opacity = 1; }, 1000); setStatus("<input type=\"button\" id=\"hangup\" value=\"Hang up\" onclick=\"onHangup()\" />"); } function transitionToWaiting() { console.log('transitionToWaiting.30'); card.style.webkitTransform = "rotateY(0deg)"; setTimeout(function() { localVideo.src = miniVideo.src; miniVideo.src = ""; remoteVideo.src = "" }, 500); miniVideo.style.opacity = 0; remoteVideo.style.opacity = 0; resetStatus(); } function transitionToDone() { console.log('transitionToDone.31'); localVideo.style.opacity = 0; remoteVideo.style.opacity = 0; miniVideo.style.opacity = 0; setStatus("You have left the call. <a href=\"{{ room_link }}\">Click here</a> to rejoin."); } function enterFullScreen() { console.log('enterFullScreen.32'); container.webkitRequestFullScreen(); } function toggleVideoMute() { console.log('toggleVideoMute.33'); if (localStream.getVideoTracks().length == 0) { console.log("No local video available."); return; } if (isVideoMuted) { for (i = 0; i < localStream.getVideoTracks().length; i++) { localStream.getVideoTracks[i].enabled = true; } console.log("Video unmuted."); } else { for (i = 0; i < localStream.getVideoTracks().length; i++) { localStream.getVideoTracks[i].enabled = false; } console.log("Video muted."); } isVideoMuted = !isVideoMuted; } function toggleAudioMute() { console.log("toggleAudioMute34"); if (localStream.getAudioTracks().length == 0) { console.log("No local audio available."); return; } if (isAudioMuted) { for (i = 0; i < localStream.getAudioTracks().length; i++) { localStream.audioTracks[i].enabled = true; } console.log("Audio unmuted."); } else { for (i = 0; i < localStream.getAudioTracks().length; i++) { localStream.getAudioTracks()[i].enabled = false; } console.log("Audio muted."); } isAudioMuted = !isAudioMuted; } setTimeout(initialize, 1); // Send BYE on refreshing(or leaving) a demo page // to ensure the room is cleaned for next session. window.onbeforeunload = function() { sendMessage({ type : 'bye' }); } // Ctrl-D: toggle audio mute; Ctrl-E: toggle video mute. // On Mac, Command key is instead of Ctrl. // Return false to screen out original Chrome shortcuts. document.onkeydown = function() { if (navigator.appVersion.indexOf("Mac") != -1) { if (event.metaKey && event.keyCode == 68) { toggleAudioMute(); return false; } if (event.metaKey && event.keyCode == 69) { toggleVideoMute(); return false; } } else { if (event.ctrlKey && event.keyCode == 68) { toggleAudioMute(); return false; } if (event.ctrlKey && event.keyCode == 69) { toggleVideoMute(); return false; } } } </script> <div id="container" ondblclick="enterFullScreen()"> <div id="card"> <div id="local"> <video width="100%" height="100%" id="localVideo" autoplay="autoplay" /> </div> <div id="remote"> <video width="100%" height="100%" id="remoteVideo" autoplay="autoplay"> </video> <div id="mini"> <video width="100%" height="100%" id="miniVideo" autoplay="autoplay" /> </div> </div> </div> <div id="footer"></div> <a href="http://www.webrtc.org"> <img id="logo" alt="WebRTC" src="${ctx}images/webrtc_black_20p.png"> </a> </div> </body> </html>

环境必须是jdk1.7,tomcat7才能把项目运行起来,把tomat的lib包下的catalian.jar,tomcat-coyote.jar加入项目中

package org.rtc.servlet;

import java.io.IOException;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.rtc.room.WebRTCRoomManager;

@WebServlet(urlPatterns = {"/room"})
public class WebRTCRoomServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String r = request.getParameter("r");
        if(StringUtils.isEmpty(r)){
            //如果房间为空,则生成一个新的房间号
            r = String.valueOf(System.currentTimeMillis());
            response.sendRedirect("room?r=" + r);
        }else{
            Integer initiator = 1;
            String user = UUID.randomUUID().toString().replace("-", "");//生成一个用户ID串
            if(!WebRTCRoomManager.haveUser(r)){//第一次进入可能是没有人的,所以就要等待连接,如果有人进入了带这个房间好的页面就会发起视频通话的连接
                initiator = 0;//如果房间没有人则不发送连接的请求
            }
            WebRTCRoomManager.addUser(r, user);//向房间中添加一个用户
            String roomLink = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort() +  request.getContextPath() +"/room?r=" + r;
            String roomKey = r;//设置一些变量
            request.setAttribute("initiator", initiator);
            request.setAttribute("roomLink", roomLink);
            request.setAttribute("roomKey", roomKey);
            request.setAttribute("user", user);
            request.getRequestDispatcher("index.jsp").forward(request, response);
        }
    }
}
package org.rtc.servlet;

import java.io.BufferedReader;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.rtc.room.WebRTCRoomManager;
import org.rtc.websocket.WebRTCMessageInboundPool;

import net.sf.json.JSONObject;

@WebServlet(urlPatterns = {"/message"})
public class WebRTCMessageServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        super.doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String r = request.getParameter("r");//房间号
        String u = request.getParameter("u");//通话人
        BufferedReader br = request.getReader();
        String line = null;
        StringBuilder sb = new StringBuilder();
        while((line = br.readLine())!=null){
            sb.append(line); //获取输入流,主要是视频定位的信息
        }
        
        String message = sb.toString();
        JSONObject json = JSONObject.fromObject(message);
        if (json != null) {
            String type = json.getString("type");
            if ("bye".equals(type)) {//客户端退出视频聊天
                System.out.println("user :" + u + " exit..");
                if(StringUtils.isNotEmpty(r)){
                    WebRTCRoomManager.removeUser(r, u);
                }else{
                    System.out.println("没有该房间号");
                }
package org.rtc.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
import org.rtc.websocket.WebRTCMessageInbound;
@WebServlet(urlPatterns = { "/websocket"})
public class WebRTCWebSocketServlet extends WebSocketServlet {

    private static final long serialVersionUID = 1L;

    private String user;
    
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.user = request.getParameter("u");
        super.doGet(request, response);
    }

    @Override
    protected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request) {
        return new WebRTCMessageInbound(user);
    }
}

package org.rtc.room;

import java.util.HashMap;
import java.util.Map;

public class WebRTCRoomManager {

    private static final Map<String,WebRTCSimpleRoom> provider = new HashMap<String,WebRTCSimpleRoom>();
    
    public static void addUser(String roomKey,String user){
        WebRTCSimpleRoom room = provider.get(roomKey);
        if(room == null){
            System.out.println("add room : " + roomKey);
            room = new WebRTCSimpleRoom(roomKey,user);
            provider.put(roomKey, room);
        }else{
            room.addUser(user);
        }
    }
    
    public static void removeUser(String roomKey,String user){
        WebRTCSimpleRoom room = provider.get(roomKey);
        if(room != null){
            System.out.println("remove user : " + user);
            room.removeUser(user);
        }
        if(!room.haveUser()){
            provider.remove(roomKey);
            System.out.println("remove room : " + roomKey);
        }
    }
    
    public static boolean haveUser(String key){
        WebRTCSimpleRoom room = provider.get(key);
        if(room != null){
            return room.haveUser();
        }else{
            return false;
        }
    }
    
    public static String getOtherUser(String roomKey,String user){
        WebRTCSimpleRoom room = provider.get(roomKey);
        return room.getOtherUser(user);
    }
}
package org.rtc.room;

import org.apache.commons.lang.StringUtils;

public class WebRTCSimpleRoom {

    private String key;

    private String user1;

    private String user2;
    
    public WebRTCSimpleRoom(){
        
    }
    
    public WebRTCSimpleRoom(String key,String user1){
        this.key = key;
        this.user1 = user1;
    }

    /**
     * @return the key
     */
    public String getKey() {
        return key;
    }

    /**
     * @param key
     *            the key to set
     */
    public void setKey(String key) {
        this.key = key;
    }

    public String getUser1() {
        return user1;
    }

    public void setUser1(String user1) {
        this.user1 = user1;
    }

    public String getUser2() {
        return user2;
    }

    public void setUser2(String user2) {
        this.user2 = user2;
    }

    public void addUser(String user) {
        if (StringUtils.isEmpty(user1)) {
            this.setUser1(user);
        } else if (StringUtils.isEmpty(user2)) {
            this.setUser2(user);
        }
    }

    public void removeUser(String user) {
        if (StringUtils.isNotEmpty(user1)) {
            if (user1.equals(user)) {
                this.setUser1(null);
            }
        } else if (StringUtils.isNotEmpty(user2)) {
            if (user2.equals(user)) {
                this.setUser2(null);
            }
        }
    }

    public boolean haveUser() {
        return !(this.getUser1() == null && this.getUser2() == null);
    }
    
    public String getOtherUser(String user){
        if(user.equals(user1)){
            return user2;
        }else{
            return user1;
        }
    }
}
package org.rtc.websocket;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;

public class WebRTCMessageInbound extends MessageInbound {

    private final String user;

    public WebRTCMessageInbound(String user) {
        this.user = user;
    }
    
    public String getUser(){
        return this.user;
    }

    @Override
    protected void onOpen(WsOutbound outbound) {
        //触发连接事件,在连接池中添加连接
        WebRTCMessageInboundPool.addMessageInbound(this);
    }

    @Override
    protected void onClose(int status) {
        //触发关闭事件,在连接池中移除连接
        WebRTCMessageInboundPool.removeMessageInbound(this);
    }

    @Override
    protected void onBinaryMessage(ByteBuffer message) throws IOException {
        throw new UnsupportedOperationException(
                "Binary message not supported.");
    }

    @Override
    protected void onTextMessage(CharBuffer message) throws IOException {
        
    }
}
package org.rtc.websocket;

import java.io.IOException;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Map;

public class WebRTCMessageInboundPool {

    private static final Map<String,WebRTCMessageInbound > connections = new HashMap<String,WebRTCMessageInbound>();
    
    public static void addMessageInbound(WebRTCMessageInbound inbound){
        //添加连接
        System.out.println("user : " + inbound.getUser() + " join..");
        connections.put(inbound.getUser(), inbound);
    }
    
    public static void removeMessageInbound(WebRTCMessageInbound inbound){
        //移除连接
        System.out.println("user : " + inbound.getUser() + " exit..");
        connections.remove(inbound.getUser());
    }
    
    public static void sendMessage(String user,String message){
        try {
            //向特定的用户发送数据
            System.out.println("send message to user : " + user + " ,message content : " + message);
            WebRTCMessageInbound inbound = connections.get(user);
            if(inbound != null){
                inbound.getWsOutbound().writeTextMessage(CharBuffer.wrap(message));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 


            }
        }
        String otherUser = WebRTCRoomManager.getOtherUser(r, u);//获取通话的对象
        if (u.equals(otherUser)) {
            message = message.replace("\"offer\"", "\"answer\"");
            message = message.replace("a=crypto:0 AES_CM_128_HMAC_SHA1_32",
                    "a=xrypto:0 AES_CM_128_HMAC_SHA1_32");
            message = message.replace("a=ice-options:google-ice\\r\\n", "");
        }
        //向对方发送连接数据
        WebRTCMessageInboundPool.sendMessage(otherUser, message);
    }
}

可以新建一个web项目部署一下试试。