WebRTC实践信令服务

在实际应用过程中各终端之间要创建并保持WebRTC通话, 需要互相交换元数据信息, 这个过程被称为信令传输(signaling)。

具体内容包括:

  • Offer视频邀请函描述信息
  • Answer视频邀请响应信息
  • Candidate视频终端ICE候选网络信息
  • 候选网络信息(Candidate)
  • resolution视频分辨率
  • codec视频编解码器

我们可以使用信令服务器(signaling server), 来为WebRTC客户端(peers)之间传递消息。实际上这些信令消息都是纯文本格式的, 也就是将JavaScript对象序列化为字符串的形式。

WebRTC使用客户端方式的JavaScript API, 在实际应用中, 需要有信令服务器(消息服务)的支持, 有时还需要使用 STUN 和 TURN 服务器。

信令服务

本教程使用 Socket.IO 作为信令服务器。由于Socket.IO 内置了 “聊天室”(rooms) 这个概念,所以非常适合用于学习WebRTC信令。

在实际项目中可以自身情况自由选择成熟的信令服务软件,如:Socket.IO 、WebSocket、kafka、RabbitMQ等服务软件。

实践代码

结构思路

在这里插入图片描述

CSDN站内私信我,领取最新最全C++音视频学习提升资料,内容包括(C/C++Linux 服务器开发,FFmpeg webRTC rtmp hls rtsp ffplay srs

客户端

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
		<title>WebRTC实践信令服务</title>
		<script src="../javascript/trace.js"></script>
		<script src="../javascript/socket.io.js"></script>
		<script src="../javascript/jquery-1.11.1.min.js"></script>
		<script type="text/javascript">
			$.extend({
				io: {
					id: null,
					socket: null,
					connect: function(action) {
						var curObj = this;
						this.socket = io("ws://127.0.0.1:8000");
						this.socket.on('ready', function(id, persons) {
							curObj.id = id;
							trace($("#sname").val() + ' 连接成功!');
							showPersons(persons);
							action(persons);
						});
						this.socket.on('change', function(persons) {
							showPersons(persons);
							action(persons);
						});

						function showPersons(persons) {
							var onlineUser = '在线用户:';
							persons.forEach(element => {
								onlineUser = onlineUser + JSON.stringify(element) + ",";
							});
							trace(onlineUser);
						}
					},
					receive: function(callback) {
						this.socket.on('message', function(message) {
							callback(message);
						});
					},
					send: function(conent, toid) {
						var body = {
							to: toid,
							type: 'text',
							content: conent
						}
						this.socket.emit('message', body);
					},
					disconnect: function() {
						if(this.socket != null) {
							this.socket.emit('bye');
							this.socket = null;
						}
					}
				}
			});
		</script>
		<script type="text/javascript">
			$(function() {
				onunload =$.io.disconnect;
				$("#btnConn").click(function() {
					$.io.connect(function(person) {
						$("#users").empty();
						$.each(person, function() {
							if(this.id != $.io.id) {
								$("#users").append('<input type="radio" id="' + this.id + '" value=' + this.id + ' name="g"><label for="' + this.id + '">' + this.id + '</label>');
							}
						});
					});
					$.io.receive(function(body) {
						trace("收到:" + JSON.stringify(body));
					});
				});
				$("#btnSend").click(function() {
					$.io.send($("#sconent").val(), $("input[name='g']:checked").val());
				});
			})
		</script>
	</head>
	<body>
		<h1>WebRTC实践信令服务</h1>
		<fieldset>
			<legend>信令</legend>
			<table border="0" style="width: 100%;">
				<tr>
					<td>服务:</td>
					<td><input id="sserver" type="text" value="ws://127.0.0.1:8000" style="width: 97%;" /></td>
					<td><input id="btnConn" type="button" value="连接" /></td>
				</tr>
				<tr>
					<td>姓名:</td>
					<td><input id="sname" style="width: 97%;" type="text" /></td>
				</tr>
				<tr>
					<td>用户:</td>
					<td>
						<div id="users"></div>
					</td>
				</tr>
				<tr>
					<td>内容:</td>
					<td><input id="sconent" type="text" style="width: 97%;" /></td>
					<td><input id="btnSend" type="button" value="发送" /></td>
				</tr>
			</table>
		</fieldset>
		<fieldset>
			<legend>运行日志</legend>
			<div id="outDiv"></div>
		</fieldset>
	</body>
</html>

服务端

var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');

var fileServer = new(nodeStatic.Server)();
var app = http.createServer(function(req, res) {
    fileServer.serve(req, res);
}).listen(8000);


var io = socketIO.listen(app);
var persons = [];
var getPersonSeq = function() {
    var tempSeq = Math.floor(Math.random() * 5) + 1;
    persons.forEach(p => {
        if (p.seq == tempSeq) {
            tempSeq = getPersonSeq();
        }
    });
    return tempSeq;
}
io.sockets.on('connection', function(socket) {
    if (persons.indexOf(socket.id) == -1) {
        persons.push({ id: socket.id, seq: getPersonSeq() });
    }

    function trace() {
        //socket.emit('server', arguments);
        console.log(arguments);
    }

    console.log("用户 '" + socket.id + "' 连接成功!");
    socket.emit('ready', socket.id, persons);
    socket.broadcast.emit('change', persons);
    socket.on('disconnect', function() {
        trace('终端(' + socket.id + ')已断开。 ');
        var tempPersons = [];
        persons.forEach(e => {
            if (e.id != socket.id) {
                tempPersons.push(e);
            }
        });
        persons = tempPersons;
        socket.broadcast.emit('change', persons);
    });
    socket.on('message', function(body) {
        var d = new Date();
        body.from = socket.id;
        body.time = d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
        socket.to(body.to).emit('message', body);
        trace('终端(' + socket.id + "):", body);
    });
    socket.on('ipaddr', function() {
        var ifaces = os.networkInterfaces();
        for (var dev in ifaces) {
            ifaces[dev].forEach(function(details) {
                if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
                    socket.emit('ipaddr', details.address);
                }
            });
        }
    });
});

 运行结果

猜你喜欢

转载自blog.csdn.net/m0_60259116/article/details/124713420