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

webrtc学习笔记九 (datachannel在jslinux的应用,java版本)

阅读更多
目标:使用java的websocket作为datachannl建立连接
让jslinux可以实现两个浏览器数据互通。

效果图

原理:
jslinux已经实现了/dev/clipboard与浏览器的textarea的联通,
利用datachannel把两个浏览器的textarea交互,实现jslinux之间的数据交互

增加room概念,进入同一个room的两个页面才可以互相通信
要求tomcat7.0.62
java代码,java的websocket使给datachannel建立连接.
package com.hao;

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

import javax.servlet.http.HttpServletRequest;

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

public class RoomWebSocketServlet extends WebSocketServlet {
	public static Map<String, MyMessageInbound> slist = new HashMap<String, MyMessageInbound>();

	protected StreamInbound createWebSocketInbound(String subProtocol,
			HttpServletRequest request) {
		System.out.println("room:"+request.getParameter("r"));
		String arg="0";
		if(null!=request.getParameter("r")){
			arg=request.getParameter("r");
		}
		return new MyMessageInbound(arg);
	}

	public int getUserCount() {
		return slist.size();
	}

	private class MyMessageInbound extends MessageInbound {
		WsOutbound myoutbound;
		String mykey;
		String room;
		public MyMessageInbound(String room){
			this.room=room;
		}
		@Override
		public void onOpen(WsOutbound outbound) {
			try {
				System.out.println("websocket Client open.");
				this.myoutbound = outbound;
				mykey = "" + System.currentTimeMillis();
				slist.put(room+"::"+mykey, this);
				System.out.println("slist size:" + slist.size());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		@Override
		public void onClose(int status) {
			System.out.println("websocket Close."+mykey);
			slist.remove(mykey);
		}

		@Override
		protected void onTextMessage(CharBuffer message) throws IOException {
			System.out.println("onTextMessage-------->");
			for (Map.Entry<String, MyMessageInbound> entry : slist.entrySet()) {
				String socketroom=entry.getKey().split("::")[0];
				String socketkey=entry.getKey().split("::")[1];
				if(this.room.equals(socketroom)&&!this.mykey.equals(socketkey)){//向room相同但是不是当前websocket发送消息
					System.out.println("-------->" + message.toString());
					System.out.println("--->socketroom:"+socketroom+",socketkey:"+socketkey);
					MyMessageInbound mmib = (MyMessageInbound) entry.getValue();
					CharBuffer buffer = CharBuffer.wrap(message);
					mmib.myoutbound.writeTextMessage(buffer);
					mmib.myoutbound.flush();
				}
			}
		}

		@Override
		protected void onBinaryMessage(ByteBuffer arg0) throws IOException {

		}
	}

}


web.xml中:
配置websocket的servlet
<servlet>
      <servlet-name>room</servlet-name>
      <servlet-class>com.hao.RoomWebSocketServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>room</servlet-name>
      <url-pattern>/hao/room</url-pattern>
    </servlet-mapping>


jslinux中的index修改
加入datachannel和<textarea>的交互
index.html为
<!DOCTYPE html>
<html>
<head>
<title>Javascript PC Emulator</title>
<style>
.term {
    font-family: courier,fixed,swiss,monospace,sans-serif;
    font-size: 14px;
    color: #f0f0f0;
    background: #000000;
}

.termReverse {
    color: #000000;
    background: #00ff00;
}
#note {
    font-size: 12px;
}
#copyright {
    font-size: 10px;
}
#clipboard {
    font-size: 12px;
}
</style>
</head>
<body >
<input type="button" value="start linux" onclick="start();">
<table border="0">
<tr valign="top"><td>
<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript" src="term.js"></script>
<script type="text/javascript" src="cpux86.js"></script>
<script type="text/javascript" src="jslinux.js"></script>
<div id="copyright">&copy; 2011 Fabrice Bellard - <a href="news.html">News</a> - <a href="faq.html">FAQ</a> - <a href="tech.html">Technical notes</a></div>
<input type="button" value="Clear clipboard" onclick="clear_clipboard();"><br><textarea row="4" cols="16" id="text_clipboard" ></textarea></br>


</table>
<script type="text/javascript" >
		function GetRequest() { 
			var url = location.search; //获取url中"?"符后的字串 
			var theRequest = new Object(); 
			if (url.indexOf("?") != -1) { 
				var str = url.substr(1); 
				strs = str.split("&"); 
				for(var i = 0; i < strs.length; i ++) { 
					theRequest[strs[i].split("=")[0]]=unescape(strs[i].split("=")[1]); 
				} 
			} 
			return theRequest; 
		} 
		var Request = new Object(); 
		Request = GetRequest();
		var iceServer = null;
		var pc = new window.webkitRTCPeerConnection(iceServer,{optional: [{RtpDataChannels: true}]});
		
        var isCaller = Request['c'];//window.location.href.split('#')[1];
        console.log("isCaller--------"+isCaller);
        var socket = new WebSocket("ws://killinux.com/hao/room?r="+Request['r']);
        var thissend = function (message, callback) {
		    this.waitForConnection(function () {
		        socket.send(message);
		        if (typeof callback !== 'undefined') {
		          callback();
		        }
		    }, 1000);
		};

		this.waitForConnection = function (callback, interval) {
		    if (socket.readyState === 1) {
		        callback();
		    } else {
		        var that = this;
		        // optional: implement backoff for interval here
		        setTimeout(function () {
		            that.waitForConnection(callback, interval);
		        }, interval);
		    }
		};
        socket.onmessage = function(event){
            var json = JSON.parse(event.data);
            //console.log('onmessage: ', json);
            //如果是一个ICE的候选,则将其加入到PeerConnection中,否则设定对方的session描述为传递过来的描述
            if( json.event === "_ice_candidate" ){
                pc.addIceCandidate(new RTCIceCandidate(json.data.candidate));
            } else {
                pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp));
                console.log("---------------->pc.setRemote");
                // 如果是一个offer,那么需要回复一个answer
                if(json.event === "_offer") {
                	console.log("------->createAnswer");
                    pc.createAnswer(function(desc){
			            pc.setLocalDescription(desc);
			            console.log("---------------->pc.setLocal");
			            thissend(JSON.stringify({ 
			                "event": "_answer",
			                "data": {
			                    "sdp": desc
			                }
			            }));
			        }, function (error) {
                        console.log('Failure callback: ' + error);
                    });
                }else{
                	console.log("------->receive Answer---('"+json.event+"')");
                }
                
            }
        };
        
        
        try {
		    sendChannel = pc.createDataChannel('sendDataChannel',{reliable: true});
		} catch (e) {
		    alert('createDataChannel() failed with exception: ' + e.message);
		}
		sendChannel.onopen = console.log('--Send channel open state is : ' +sendChannel.readyState);
  		sendChannel.onclose = console.log('--Send channel close  state is: ' +sendChannel.readyState);
        // 发送ICE候选到其他客户端
        pc.onicecandidate = function(event){
        	console.log("onicecandidate----------->");
            if (event.candidate !== null) {
            	console.log("event.candidate   !=   null");
                thissend(JSON.stringify({
                    "event": "_ice_candidate",
                    "data": {
                        "candidate": event.candidate
                    }
                }));
            }else{
            	console.log("event.candidate   == null");
            }
        };
    	sendChannel.onmessage = function(event) {
    		  console.log("-sendChannel.onmessage--");
   			  document.getElementById('text_clipboard').value = event.data;
		};
        function sendData() {
		  var data = document.getElementById('text_clipboard').value;
		  console.log("---->>>>sendData():"+data);
		  sendChannel.send(data);
		}
		if(isCaller){
        	console.log("------->createOffer");
            pc.createOffer(function(desc){
            //	console.log(desc);
	            pc.setLocalDescription(desc);
	            console.log("---------------->pc.setLocal");
	            thissend(JSON.stringify({ 
	                "event": "_offer",
	                "data": {
	                    "sdp": desc
	                }
	            }));
	        }, function (error) {
                console.log('Failure callback: ' + error);
            });
        }
        
		console.log("---over");
</script>
<!--button id="sendButton" onclick="sendData()">Send</button>
<textarea id="dataChannelSend" >abc</textarea>
<div id="result"></div--> 

</body>
</html>


jslinux.js增加datachannel的senddata操作
jslinux.js修改为:
/* 
   Linux launcher

   Copyright (c) 2011-2012 Fabrice Bellard

   Redistribution or commercial use is prohibited without the author's
   permission.
*/
"use strict";

var term, pc, boot_start_time, init_state;

function term_start()
{
    term = new Term(80, 130, term_handler);

    term.open();
}

/* send chars to the serial port */
function term_handler(str)
{
    pc.serial.send_chars(str);
}
console.log("hao:version 1.2")
function clipboard_set(val)
{
	console.log("hao:clipboard_set---sendData->");
	
    var el;
    el = document.getElementById("text_clipboard");
    el.value = val;
    sendData();
}

function clipboard_get()
{
	console.log("hao:clipboard_get---->");
    var el;
    el = document.getElementById("text_clipboard");
    return el.value;
}

function clear_clipboard()
{
    var el;
    el = document.getElementById("text_clipboard");
    el.value = "";
}

/* just used to display the boot time in the VM */
function get_boot_time()
{
    return (+new Date()) - boot_start_time;
}

function start()
{
    var params;
    
    init_state = new Object();

    params = new Object();

    /* serial output chars */
    params.serial_write = term.write.bind(term);

    /* memory size (in bytes) */
    params.mem_size = 16 * 1024 * 1024;

    /* clipboard I/O */
    params.clipboard_get = clipboard_get;
    params.clipboard_set = clipboard_set;

    params.get_boot_time = get_boot_time;

    /* IDE drive. The raw disk image is split into files of
     * 'block_size' KB. 
     */
    params.hda = { url: "bin/hda%d.bin", block_size: 64, nb_blocks: 912 };
    
    pc = new PCEmulator(params);

    init_state.params = params;

    //pc.load_binary("vmlinux-2.6.20.bin", 0x00100000, start2);
    pc.load_binary("vmlinux26.bin", 0x00100000, start2);
//    pc.load_binary("vmlinuxtest.bin", 0x00100000, start2);
    //pc.load_binary("vmlinuxnono.bin", 0x00100000, start2);
    //pc.load_binary("vmlinux319.bin", 0x00100000, start2);
    //pc.load_binary("vmlinux319clip.bin", 0x00100000, start2);
}

function start2(ret)
{
    if (ret < 0)
        return;
    init_state.start_addr = 0x10000;
    //pc.load_binary("linuxstartnew.bin", init_state.start_addr, start3);
    pc.load_binary("linuxstart.bin", init_state.start_addr, start3);
}

function start3(ret)
{
    var block_list;
    if (ret < 0)
        return;
    /* Preload blocks so that the boot time does not depend on the
     * time to load the required disk data (optional) */
    block_list = [ 0, 7, 3, 643, 720, 256, 336, 644, 781, 387, 464, 475, 131, 589, 468, 472, 474, 776, 777, 778, 779, 465, 466, 473, 467, 469, 470, 512, 592, 471, 691, 697, 708, 792, 775, 769 ];
    pc.ide0.drives[0].bs.preload(block_list, start4);
}

function start4(ret)
{
    var cmdline_addr;

    if (ret < 0)
        return;

    /* set the Linux kernel command line */
    cmdline_addr = 0xf800;
    pc.cpu.write_string(cmdline_addr, "console=ttyS0 root=/dev/hda ro init=/sbin/init notsc=1 hdb=none");

    pc.cpu.eip = init_state.start_addr;
    pc.cpu.regs[0] = init_state.params.mem_size; /* eax */
    pc.cpu.regs[3] = 0; /* ebx = initrd_size (no longer used) */
    pc.cpu.regs[1] = cmdline_addr; /* ecx */

    boot_start_time = (+new Date());

    pc.start();
}

term_start();


其中websocket放在aws上会有
Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING State.
的错误
参考
http://stackoverflow.com/questions/23898477/tornado-websockets-invalidstateerror-still-in-connecting-state


测试的时候
http://killinux.com/jslinux/?r=5555

http://killinux.com/jslinux/?r=5555&c=true

打开两个网页,r为room号,任意起,两个页面相同即可

然后在一个页面的jslinux中
tail -f /dev/clipboard
echo sssssssssss >/dev/clipboard

具体代码
https://github.com/killinux/rtclinux

微博:http://weibo.com/killinux
  • 大小: 119 KB
分享到:
评论

相关推荐

    WebRTC学习笔记_Demo收集 .docx

    ### WebRTC学习笔记_Demo收集 #### 一、WebRTC现状与历史背景 WebRTC(Web Real-Time Communication)是一项开放的、免费的技术框架,旨在使Web浏览器能够在无需插件的情况下进行实时音视频通信。该技术最初由...

    Webrtc学习笔记-V1

    在实际应用中,如视频采集,开发者首先需要创建`webrtc::VideoEngine`对象,然后通过`webrtc::ViECapture::GetInterface`获取`ViECapture`对象,再调用相应的接口进行设备管理和视频采集。例如,`...

    webrtc(M99版本) linux arm64 静态库

    在本案例中,我们讨论的是WebRTC的M99版本,针对Linux ARM64架构的静态库。 静态库是一种将所有依赖项合并到一个可执行文件中的库类型,这意味着在运行时不需要外部的动态链接库,简化了部署过程。然而,由于静态库...

    webrtc学习笔记一 (视频流)

    这篇“webrtc学习笔记一”主要关注的是视频流处理,是WebRTC技术中的核心部分。在深入讨论之前,先了解一下WebRTC的基本架构和组成部分。 1. **基础概念**: - **Peer Connection**: 是WebRTC的核心组件,负责...

    WebRTC+java实现多人视频通讯

    在“WebRTC+Java实现多人视频通讯”的项目中,WebRTC主要负责前端的音视频采集、编码、传输和解码工作。用户可以在浏览器中直接参与视频通话,得益于WebRTC的API,开发者可以轻松获取用户的摄像头和麦克风权限,并...

    WebRTC学习笔记01-最简单实现一对一视频通讯代码

    在"WebRTC学习笔记01-最简单实现一对一视频通讯代码"中,我们将探讨WebRTC的基础知识以及如何通过简单的代码实现一对一视频通话。 首先,WebRTC的核心组件包括: 1. **RTCPeerConnection**:这是WebRTC中最关键的...

    java版本使用springboot vue websocket webrtc实现视频通话

    在本文中,我们将深入探讨如何使用Java、Spring Boot、Vue.js和WebRTC技术来构建一个实时的视频通话系统。这是一个现代Web应用中的重要组成部分,尤其在远程协作和在线沟通日益增长的需求下。以下是对每个技术栈及其...

    WEBRTC的js实现

    WebRTC,名称源自网页即时通信(英语:Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的API。它于2011年6月1日开源并在Google、Mozilla、Opera支持下被纳入万维网联盟的W3C...

    webrtc中base库在linux平台的编译

    webrtc中base库在linux平台编译,采用cmake编译,可以学习cmake的基本语法

    基于java开发环境的WebRTC 点对点视频通话系统

    在这个基于Java开发环境的WebRTC点对点视频通话系统中,我们将深入探讨如何利用Java和WebRTC构建一个实时音视频通话应用。 首先,Java是一种广泛使用的编程语言,尤其在服务器端开发领域。然而,WebRTC主要是为...

    WebRTC的JS例子,自己编写的,分两端

    自己编写的WebRTC的JS例子。google的PC1,把本端和远端都合在一起了,初学者容易混淆。写了个小例子,分为本端和远端。可以通过手工拷贝SDP和ICE信息,进行呼叫接续。感觉流程比较清晰,可供初学者使用。 测试时,...

    WebRTC自带的peerconenction Linux版

    WebRTC自带的peerconenction Windows版本 WebRTC自带的example里面的peerconenction_client和peerconenction_server,部分代码做了修改,可用于测试及印证源代码。

    java webrtc 视频通话

    Java WebRTC 视频通话是现代互联网通信技术的重要组成部分,尤其在远程协作、在线教育和实时互动娱乐领域中发挥着关键作用。WebRTC(Web Real-Time Communication)是一种开放的API框架,它允许浏览器和其他应用程序...

    webrtc demo(html+js+nodejs)

    WebRTC(Web Real-Time Communication)是一种开放源代码项目,它为网页浏览器提供了实时通信(RTC)的能力,使得用户可以在浏览器之间直接进行音频、视频和数据共享而无需任何插件。这个"webrtc demo...

    webrtc /adapter-latest.js

    webrtc /adapter-latest.js

    java + webrtc 视频聊天室,一对一,多对多,文件传输

    java + webrtc 实现的 视频聊天室 , 多对多的这个资源没有实现,这个资源只实现了一对一,后续的代码会在 github上持续更新 地址为: https://github.com/js1688/cat 成果展示地址:https://www.tanjun.xyz webrtc 真正...

    WebRTC学习之三:录音和播放

    在本项目“WebRTC学习之三:录音和播放”中,我们将探讨如何利用C++来实现WebRTC的功能,特别是录音和播放操作,并结合Qt库创建用户界面。 1. WebRTC基础: WebRTC提供了包括音频、视频和数据共享在内的实时通信...

    webrtc-streamer0.7的ubuntu18.04版本

    webrtc-streamer在国内编译相当困难,这里是本人花了一周时间编译完成的webrtc-streamer最新版本,可在ubuntu18.04及以上版本中使用,如果提示libstdc++版本过低,请升级系统的libstdc++。

    webrtc_Linux源代码获取以及编译

    为了在 Linux 平台上使用 Webrtc,我们需要获取其源代码并编译它。本文将详细介绍如何获取 Webrtc 的源代码、建立编译环境、编译 Webrtc 以及运行示例程序。 一、系统要求 ---------------- 在编译 Webrtc 之前,...

    vue3实现WebRTC实战1v1通话-后端代码(nestjs)

    在本项目中,我们主要关注的是使用Vue3和NestJS构建一个1v1的WebRTC视频通话系统。WebRTC(Web Real-Time Communication)是一种开放的API标准,它允许浏览器之间进行实时通信,包括音频、视频和数据共享,无需任何...

Global site tag (gtag.js) - Google Analytics