webrtc 实时视频 .net websocket信令服务器
这篇文章主要参考了 Webrtc WebSocket实现音视频通讯,非常感谢提供代码
前端部分完全是从这篇文章复制过来的,只是修改了webscket的url,还有加入了webrtc-adapterjs,至于做什么,可以点击链接进行了解
前端代码部分(主要来自开头提及的博文)
<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title></title>
</head> <body>
Welcome<br/><input id="text" type="text" />
<button onclick="send()">发送消息</button>
<hr/>
<button onclick="closeWebSocket()">关闭WebSocket连接</button>
<hr/>
<div id="message"></div> <video id="vid1" width="320" height="240" autoplay></video>
<video id="vid2" width="320" height="240" autoplay></video><br>
<a id="create" href="webrtc.html#true" onclick="init()">点击此链接新建聊天室</a><br>
<p id="tips" style="background-color:red">请在其他浏览器中打开:http://此电脑 加入此视频聊天</p> <script type="text/javascript" src="http://cdn.staticfile.org/webrtc-adapter/zv4.1.1/adapter.min.js"></script>
<script type="text/javascript">
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia; var isCaller = window.location.href.split('#')[1];
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window) {
websocket = new WebSocket("ws://192.168.31.175:8181");
} else {
alert('当前浏览器 Not support websocket')
} //连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("WebSocket连接发生错误");
}; //连接成功建立的回调方法
websocket.onopen = function() {
setMessageInnerHTML("WebSocket连接成功");
} // 创建PeerConnection实例 (参数为null则没有iceserver,即使没有stunserver和turnserver,仍可在局域网下通讯)
var pc = new window.RTCPeerConnection(null); // 发送ICE候选到其他客户端
pc.onicecandidate = function(event) {
setMessageInnerHTML("我看看 1");
if(event.candidate !== null) {
setMessageInnerHTML("我看看 2");
websocket.send(JSON.stringify({
"event": "_ice_candidate",
"data": {
"candidate": event.candidate
}
}));
}
}; //接收到消息的回调方法
websocket.onmessage = function(event) {
setMessageInnerHTML("接收到的信息");
setMessageInnerHTML(event.data);
if(event.data == "new user") {
console.log("new user");
location.reload();
} else {
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));
// 如果是一个offer,那么需要回复一个answer
if(json.event === "_offer") {
pc.createAnswer(sendAnswerFn, function(error) {
console.log('Failure callback: ' + error);
});
}
}
}
} //连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("WebSocket连接关闭");
} //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
closeWebSocket();
} //将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
} //关闭WebSocket连接
function closeWebSocket() {
websocket.close();
} //发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
} // stun和turn服务器
var iceServer = {
"iceServers": [{
"url": "stun:stunserver.org"
}, {
"url": "turn:numb.viagenie.ca",
"username": "webrtc@live.com",
"credential": "muazkh"
}]
}; // 如果检测到媒体流连接到本地,将其绑定到一个video标签上输出
pc.onaddstream = function(event) {
document.getElementById('vid2').src = URL.createObjectURL(event.stream);
}; // 发送offer和answer的函数,发送本地session描述
var sendOfferFn = function(desc) {
pc.setLocalDescription(desc);
websocket.send(JSON.stringify({
"event": "_offer",
"data": {
"sdp": desc
}
}));
},
sendAnswerFn = function(desc) {
pc.setLocalDescription(desc);
websocket.send(JSON.stringify({
"event": "_answer",
"data": {
"sdp": desc
}
}));
}; // 获取本地音频和视频流
navigator.getUserMedia({
"audio": true,
"video": true
},
function(stream) {
//绑定本地媒体流到video标签用于输出
document.getElementById('vid1').src = URL.createObjectURL(stream);
document.getElementById('vid1').muted = true;
//向PeerConnection中加入需要发送的流
pc.addStream(stream);
//如果是发起方则发送一个offer信令
if(isCaller) {
pc.createOffer(sendOfferFn, function(error) {
console.log('Failure callback: ' + error);
});
}
},
function(error) {
//处理媒体流创建失败错误
console.log('getUserMedia error: ' + error);
}); window.onload = function() {
if(isCaller == null || isCaller == undefined) {
var tips = document.getElementById("tips");
tips.remove();
} else {
var create = document.getElementById("create");
create.remove();
}
}; function init() {
location.reload();
}
</script> </body> </html>
提及博文的java部分,我用了.net 控制台程序简单实现了一个,相当于一个极简的信令服务器吧(Fleck 可以在vs的管理nuget程序包中获得)
static void Main(string[] args)
{
//客户端url以及其对应的Socket对象字典
IDictionary<string, IWebSocketConnection> dic_Sockets = new Dictionary<string, IWebSocketConnection>(); var server = new WebSocketServer("ws://192.168.31.175:8181"); //出错后重启
server.RestartAfterListenError = true; server.Start(socket =>
{
socket.OnOpen = () => {
//获取客户端网页的url
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
dic_Sockets.Add(clientUrl, socket);
Console.WriteLine(DateTime.Now.ToString() + "|服务器:和客户端网页:" + clientUrl + " 建立WebSock连接!"); };
socket.OnClose = () => //连接关闭事件
{
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
//如果存在这个客户端,那么对这个socket进行移除
if (dic_Sockets.ContainsKey(clientUrl))
{
//注:Fleck中有释放
//关闭对象连接
//if (dic_Sockets[clientUrl] != null)
//{
//dic_Sockets[clientUrl].Close();
//}
dic_Sockets.Remove(clientUrl);
}
Console.WriteLine(DateTime.Now.ToString() + "|服务器:和客户端网页:" + clientUrl + " 断开WebSock连接!");
};
socket.OnMessage = message => //接受客户端网页消息事件
{
string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
foreach (var item in dic_Sockets.Where(a=>a.Key!=clientUrl))
{
item.Value.Send(message);
}
//Console.WriteLine(DateTime.Now.ToString() + "|服务器:【收到】来客户端网页:" + clientUrl + "的信息:\n" + message);
};
socket.OnBinary = b => { };
}); Console.ReadKey();
}
记录完毕,这个东西仅仅只是个demo,可以拿来玩一下
webrtc 实时视频 .net websocket信令服务器的更多相关文章
- 如何搭建WebRTC信令服务器
WebRTC 有一整套规范,如怎样使用它的接口.使用SDP进行媒体协商.通过ICE收集地址并进行连通性检测等等.除此之外,WebRTC还需要房间服务器将多端聚集到一起管理,以及信令服务器进行信令数据交 ...
- WebRTC 信令服务器
WebRTC 信令服务器 node.js & V8 libuv socket.io https://socket.io/ node-static SSR https://github.com/ ...
- 一步一步搭建客服系统 (2) 如何搭建SimpleWebRTC信令服务器
上次介绍了<3分钟实现网页版多人文本.视频聊天室 (含完整源码)>使用的是default 信令服务器,只是为了方便快速开始而已.SimapleWebRTC官方文档里第一条就讲到,不要在生产 ...
- 基于Tomcat7、Java、WebSocket的服务器推送聊天室
http://blog.csdn.net/leecho571/article/details/9707497 http://blog.fens.me/java-websocket-intro/ jav ...
- Tomcat学习总结(4)——基于Tomcat7、Java、WebSocket的服务器推送聊天室
前言 HTML5 WebSocket实现了服务器与浏览器的双向通讯,双向通讯使服务器消息推送开发更加简单,最常见的就是即时通讯和对信息实时性要求比较高的应用.以前的服务器消息推送大 ...
- Nodejs搭建音视频通信-信令服务器 总结
1.安装nodejs node-v10.16.3-x64.msi 2.安装配置环境变量 这里的环境配置主要配置的是npm安装的全局模块所在的路径,以及缓存cache的路径,之所以要配置,是因为以后在 ...
- WebSocket部署服务器外网无法连接解决方案
首先要说的是我遇见的问题: WebSocket connection to 'ws://www.xxxx.com/xxx/xx' failed: Error during WebSocket hand ...
- WebRTC MCU( Multipoint Conferencing Unit)服务器调研
接触过的有licode.kurento. licode的缺陷:文档支持有限,licode的app client库只有js的 kurento的优势:文档齐全,Demo俱备,封装API比较齐全.它的主要特 ...
- 使用Websocket与服务器建立连接
handleMessage = () => { const url = '////'; //某url const token = getCookie('xnToken');//向后端发请求得登陆 ...
随机推荐
- Java获取URL中的顶级域名domain的工具类
方式一: import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import jav ...
- 用C#学习数据结构之链表
单链表的定义 链表是用一组任意的存储单元来存储线性表中的数据元素(这组存储单元可以是连续的,也可以是不连续的).那么,怎么表示两个数据元素逻辑上的相邻关系呢?即如何表示数据元素之间的线性关系呢?为此, ...
- 从零开始学 Web 之 DOM(七)事件冒泡
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... +-------------------------------------------------------- ...
- Vue + Element UI 实现权限管理系统 前端篇(十四):菜单功能实现
菜单功能实现 菜单接口封装 菜单管理是一个对菜单树结构的增删改查操作. 提供一个菜单查询接口,查询整颗菜单树形结构. http/modules/menu.js 添加 findMenuTree 接口. ...
- C# 中集合类型需要按多个条件排序
在 C# (.net 3.5 之后) 中集合是可以通过 OrderBy() 和 OrderByDescending()方法来进行排序的,如果需要集合中的元素是对象,还可以通过 Lambda表达式进行按 ...
- 逆向知识之CS辅助/外挂专题.2.实现CS1.6无限夜视仪.无限闪光烟雾高爆弹.
逆向知识之CS辅助/外挂专题.2.实现CS1.6无限夜视仪.无限闪光烟雾高爆弹. 关于人物子弹无限可以观看上一篇博客. 一丶无限夜视仪. 无限夜视仪找法. 1.CE附加游戏. 2.搜索0或者1. 3. ...
- npm包
https://www.cnblogs.com/xinxingyu/p/5736244.html node - glob模块讲解 https://github.com/isaacs/node- ...
- c# 生成验证码图片
/// <summary> /// 生成验证码图片 /// </summary> /// <returns></returns> public byte ...
- sql 去掉 空格
一.问题描述: 数据库中字段 nvarchar类型 存放数据如下: '3.3×10' 二.解决方案: --测试用例CREATE TABLE #temp(NAME NVARCHAR(20) null) ...
- Transformation和Action
spark的运算操作有两种类型:分别是Transformation和Action,区别如下: Transformation:代表的是转化操作就是我们的计算流程,返回是RDD[T],可以是一个链式的 ...