1. 概述
本文档介绍如何通过SRS 4.0搭建 WebRTC视频通话环境,涵盖环境配置、服务器编译启动、逻辑分析及测试方法。SRS 源码包提供了信令服务器以及显示UI静态web页面分别在3rdparty/signaling 3rdparty/httpx-static。信令服务器是基于go语言编写,所以需要搭建go环境。
2. 环境搭建
2.1 安装go语⾔环境
#下载安装包
cd /usr/local/
wget https://dl.google.com/go/go1.16.5.linux-amd64.tar.gz --no-check-certificate
tar -C /usr/local -xzf go1.16.5.linux-amd64.tar.gz
#配置环境变量
vim /etc/profile
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
source /etc/profile
2.2 编译启动 SRS 流媒体服务器
编译可参考SRS流媒体服务器(1)概述和环境搭建-优快云博客
#vim conf/rtc.conf
rtc_server {
enabled on;
listen 8000;
#改成自己云服务器ip
candidate xxx.81;
}
# 启动 SRS
./objs/srs -c conf/rtc.conf
2.3 编译启动信令服务器
cd 3rdparty/signaling
make && ./objs/signaling # 默认端口 1989
2.4 编译启动 Web 服务器(支持 HTTPS/WSS)
#编译
cd 3rdparty/httpx-static
make
#生成 SSL 证书
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt -days 3650
#启动
./objs/httpx-static -http 80 -https 443 -ssk server.key -ssc server.crt \
--proxy http://127.0.0.1:1989/sig \
--proxy http://127.0.0.1:1985/rtc \
--proxy http://127.0.0.1:8080/
3. 测试方法
访问以下 URL 进行测试(替换
localhost为实际 IP):
https://localhost/demos/
https://192.168.3.6/demos/

3.1 排查失败之云服务器端口开放
当你在公网部署且访问一直在转圈失败,连摄像头都无法打开,那可能是端口未开放。这里排查了很久,居然需要打开3306这个端口!以及8000(rtp配置文件端口)
除此之外SRS 流媒体服务器其他端口说明如图:

4. 源码分析
入口代码 one2one.html:297 $("#btn_start").click(startDemo);
SrsRtcSignalingParse:
- 解析出连接信令服务器的地址
- 房间号:可填或随机
- 显示名:可填或随机
- 主机
拉流和推流函数对象主要做:
- 1.确定协议
- 2.addtrack
- 3. offer/answer协商
- 5.RTCPeerConnection
- 6.parseUrl xxx + '/rtc/v1/play/ 如: 'https://117.72.13.81:443/rtc/v1/push or play/'
var startDemo = async function () {
sig = new SrsRtcSignalingAsync(); //srs.sig.js:28 创建SrsRtcSignalingAsync,RTC信令
sig.onmessage = function (msg) { //onmessage订阅新的信令消息
console.log('Notify: ', msg);
if (msg.event === 'leave') {
$('#player').hide();
}
if (msg.event === 'publish') {//房间已经存在的参与者,收到publish信令后再去订阅新加入者
if (msg.peer && msg.peer.publishing && msg.peer.display !== display) {
startPlay(host, room, msg.peer.display);
}
}
};
await sig.connect(conf.wsSchema, conf.wsHost, room, display);//连接websock,见下面SrsRtcSignalingAsync代码
let r0 = await sig.send({action:'join', room:room, display:display}); //向信令服务器发送join信令,会返回房间列表。
console.log('Signaling: join ok', r0);
// 对于一对一演示,当房间已满时发出警报并忽略。
if (r0.participants.length > 2) {
alert('Room is full, already ' + (r0.participants.length - 1) + ' participants');
sig.close();
return;
}
// 如果信令正常,开始推流
await startPublish(host, room, display); //向srs流媒体服务器开始推流
let r1 = await sig.send({action:'publish', room:room, display:display}); //向信令服务器发送publish信令
console.log('Signaling: publish ok', r1);
// 拉其他人的流
r0.participants.forEach(function(participant) {
if (participant.display === display || !participant.publishing) return;
startPlay(host, room, participant.display);// 对于新进的房间,会拉取房间内另一个人的流
});
if (r0.participants.length >= 2) {
$('.srs_merge').show();
}
};
var startPublish = function (host, room, display) {
$(".ff_first").each(function(i,e) {
$(e).text(display);
});
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
$('#rtc_media_publisher').show();
$('#publisher').show();
if (publisher) {
publisher.close();
}
publisher = new SrsRtcPublisherAsync(); //创建RTC异步推流 srs.sdk.js:20 与下文类似
$('#rtc_media_publisher').prop('srcObject', publisher.stream);
};
var startPlay = function (host, room, display) { //向srs服务器拉流
$(".ff_second").each(function(i,e) {
$(e).text(display);
});
//拼接url "webrtc://117.72.13.81/63838c2/1907a7c",其中webrtc://是协议头,"117.72.13.81"是srs服务器ip,"63838c2"是房间号,"1907a7c"是参与者昵称
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
$('#rtc_media_player').show();
$('#player').show();
if (player) {
player.close();
}
player = new SrsRtcPlayerAsync();//创建RTC异步拉流 srs.sdk.js:278 1.确定协议 2.addtrack 3. offer/answer协商 5.RTCPeerConnection 6.parseUrl xxx + '/rtc/v1/play/ 如: 'https://117.72.13.81:443/rtc/v1/publish/',
$('#rtc_media_player').prop('srcObject', player.stream);
};
// Pass-by to SRS url. 用于解析出连接信令服务器的地址
let conf = SrsRtcSignalingParse(window.location);
$("#btn_start").click(startDemo);
// Never play util windows loaded @see https://github.com/ossrs/srs/issues/2732
if (conf.autostart) {
window.addEventListener("load", function(){ startDemo(); });
}
});
SrsRtcSignalingAsync 信令函数对象主要做:
- connect:连接信令服务器 wss://xxxx/sig/v1/rtc
- onmessage:处理接收到的消息
- send : 把对象序列化后发送到服务器
- close: 关闭
function SrsRtcSignalingAsync() { //信令函数
var self = {};
// The schema is ws or wss, host is ip or ip:port, display is nickname
// of user to join the room.
self.connect = async function (schema, host, room, display) {
var url = schema + '://' + host + '/sig/v1/rtc'; //如:api:"wss://117.72.13.81/sig/v1/rtc"
self.ws = new WebSocket(url + '?room=' + room + '&display=' + display); //与url建立连接 参数:房间号,昵称
self.ws.onmessage = function(event) { //收到消息的处理函数
var r = JSON.parse(event.data);
var promise = self._internals.msgs[r.tid];
if (promise) {
promise.resolve(r.msg);
delete self._internals.msgs[r.tid];
} else {
self.onmessage(r.msg);
}
};
};
//消息是一个json对象。
self.send = async function (message) {
return new Promise(function (resolve, reject) {
var r = {tid: Number(parseInt(new Date().getTime()*Math.random()*100)).toString(16).substr(0, 7), msg: message};
self._internals.msgs[r.tid] = {resolve: resolve, reject: reject};
self.ws.send(JSON.stringify(r));
});
};
self.close = function () {
self.ws && self.ws.close();
self.ws = null;
for (const tid in self._internals.msgs) {
var promise = self._internals.msgs[tid];
promise.reject('close');
}
};
return self;
}
4.1 总体流程

学习资料分享
1万+

被折叠的 条评论
为什么被折叠?



