天天看点

基于DataChannel.js(WebRTC_Experiment)实现的多端点的通信

DataChannel.js是webRTC封装库的一个js对象文件,由muaz-khan发布在GitHub上,https://github.com/muazkhan/WebRTCExperiment/tree/master/DataChannel。DataChannel.js是一个用于实现多对多用户组文件/数据分享或者文本聊天Web APP的javascript库,语法简单而且易于使用,极大地简化了一些复杂的任务,例如:消息传输,用户的加入和退出,等等。同时提供了许多扩展功能:可以直接借用DataChannel的现有的funcition来处理用户的加入,会话的关闭等情形,也可以扩展DataChannel的功能,比如 可以扩展DataChannel.js的一些function来实现对在线用户的检测。

而且DataChannel.js极好地一点是,无论是文本消息,文件,还是一般数据,大小都是不限制的。

由此可以借助DataChannel来实现Cloud_TV中视频段传输的功能,当然在本文中仅仅是对DataChannel的一次验证性使用,来尝试使用其各种功能。

首先来介绍一下使用到得DataChannel.js 的一些function:

open("channel_name");// 创建或者打开一个以channel_name为名的channel

connect("channel_name");//加入一个以channel_name标示的channel,前提是该channel已经被打开

send(file|data|"text-message");//向该channel内的所有终端发送文件/数据/文本消息

onopen(userid);//当检测所某个user_id为userid的用户加入channel时的处理方法,可以被ovverride

onmessage(message,userid,latency)//当检测到某个user_id为userid的用户向channel内发送消息时的处理方法,可以被ovverride,latency是消息的延迟时间

channels[userid].send(file|data|'text message');//向channel内用user_id为userid的用户直接发送消息(文件,数据或者文本消息)

leave();离开当前channel,中止会话

onleave(userid);检测到user_id为userid 的用户离开时的处理函数

join(data_channel); //使用join的方式加入一个channel

join({id:datachannel.id,owner:datachannel.owner});//使用join的方式加入一个channel

使用上面的function,通过<script src="https://www.webrtc-experiment.com/DataChannel.js"> </script> 引入DataChannel.js, 可以很容易实现多终端通信的基础功能

在此基础上尝试加入在线channel列表功能,共有两种实现方式:

(1)override DataChannel的ondatachannel function,这个function用来处理有新的channel创建这一事件,可以用如下的代码段:

//search for existing data channels
//"ondatachannel" is fired for each new data channel, and this function is provided by DataChannel.js
//In our finnal designation, when ever one open a channel, the channel info will be added to the Sever
channel.ondatachannel = function(data_channel) {
	var alreadyExist = document.getElementById(data_channel.id);
	if (alreadyExist) return;

	var tr = document.createElement('tr');
	tr.setAttribute('id', data_channel.owner);
	tr.innerHTML = '<td>' + data_channel.id + '</td>' +
		'<td><button class="join" id="' + data_channel.id + '">Join</button></td>';

	channelsList.insertBefore(tr, channelsList.firstChild);
	channelsList.style.display = '';
	// when someone clicks table-row; joining the relevant data channel
	tr.onclick = function() {
		// id:    unique identifier for the session
		// owner: unique identifier for the session initiator
		channel.join({
			id: this.querySelector('.join').id,
			owner: this.id
		});
	};
};
           

可以看到函数的传入参数便是最新创建的channel,然后根据其属性值进行一些可以自定义的操作。

现在我们来看一下DataChannel.js中的几行代码:

self.config = {
                ondatachannel: function (room) {
                    if (!dataConnector) {
                        self.room = room;
                        return;
                    }

                    var tempRoom = {
                        id: room.roomToken,
                        owner: room.broadcaster
                    };

                    if (self.ondatachannel) return self.ondatachannel(tempRoom);

                    if (self.joinedARoom) return;
                    self.joinedARoom = true;

                    self.join(tempRoom);
                },
           

从代码中可以看出,当我们为channel 定义了ondatachannel方法之后,直接返回ondatachannel(temproom)。

此时后面的join(temproom)不再执行

根据其他代码可以发现,此时的connect(channel_name);函数已经无法执行了,此时只能通过调用join();函数来加入一个channel

(2) 在中心服务器数据库中建一张channel表 和一张 user 表结构大体如下:

channel 表,用于存放当前打开的channel,当channel被open时存入数据库,当owner离开时进行从数据表中delete

id                              int(10)               primary

channel_name      varchar(30)      unique 

channel_id             int(10)               

channel_owner     varchar(30)     

user表,用于存储用户的相关信息 当用户进入网页时通过登录行为验证身份并获取用户相关信息

id                              int(10)               primary

user_id                   int(10)               unique

user_name            varchar(30)      unique

…(other useful user info)

通过访问channel表获取最新的channel信息并刷新显示在web页面上

具体的代码尚未实现,基本的function如下:

var channel_list_data = new Array();
      function getChannelList(){
		  //$post, visit the Server to get the Channel Info
	      return channel_list_data;
	  }	
	  function getUserName(){
		  //$post, visit the Server to get the UserName Info
          return "XiaoMing";
	  }
	  //get the children elements which classname is sClass of oParent
	  function getByClass(oParent, sClass)
	  {
		var aEle=oParent.getElementsByTagName('*');
		var aResult=[];
		var re=new RegExp('\\b'+sClass+'\\b', 'i');
		var i=0;
		
		for(i=0;i<aEle.length;i++)
		{
				if(re.test(aEle[i].className))
				{
						aResult.push(aEle[i]);
				}
		}
		
		return aResult;
	  }
	  //show the ChannelList on the page
	  function showChannelList(){
	      var list = getChannelList();
		  //alert(0);
		  var count = list.length;
		  var table = document.getElementById('ChannelList');
		  //var childs = table.children; 
		  //alert(0);
		  var childs = getByClass(table,"channel_list_col");
		  //alert(1);
		  //alert("childslength" + childs.length);
		  for(var i=0;i<childs.length;i++){
			  //alert(i);
		      $(".channel_list_col")[i].remove();
		  }
		  //alert(count);
		  for(var i=0;i<count;i++){
			  var tr = table.insertRow(1);
			  tr.className = "channel_list_col";
			  tr.innerHTML = "<td>" + list[i]['user_name'] + "</td>" + "<td>" + list[i]['channel_name'] + "</td>" + "<td>" +  "Undefine" + "</td>"; 
		  }
	  }
	  //
	  function addChannel(user,channel){
		    //visit the Server and push the addedChannel to the Server
	  		var count_list = channel_list_data.length;
            channel_list_data[count_list] = new Array();
			channel_list_data[count_list]['user_name']=user;
			channel_list_data[count_list]['channel_name']=channel;
	  }
           

*某些说明性注释部分是有待实现的访问数据库的功能

继续阅读