1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

SquashSRS4: Add demo for RTC

This commit is contained in:
winlin 2021-05-05 13:26:25 +08:00
parent 206d95879f
commit becbe45bcd
34 changed files with 836 additions and 85 deletions

View file

@ -7,7 +7,19 @@
<body>
<h3><a href="https://github.com/ossrs/signaling">Signaling</a> works!</h3>
<p>
Run demo for <a href="one2one.html">WebRTC: One to One over SFU(SRS)</a><br/>
点击进入<a href="one2one.html">SRS一对一通话演示</a>
Run demo for <a class="srs_demo" href="one2one.html?autostart=true">WebRTC: One to One over SFU(SRS)</a><br/>
点击进入<a class="srs_demo" href="one2one.html?autostart=true">SRS一对一通话演示</a>
</p>
<p>
Run demo for <a class="srs_demo" href="room.html?autostart=true">WebRTC: Video Room over SFU(SRS)</a><br/>
点击进入<a class="srs_demo" href="room.html?autostart=true">SRS多人通话演示</a>
</p>
<script>
let roomName = Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16).substr(3);
let elems = document.getElementsByClassName('srs_demo');
for (var i = 0; i < elems.length; i++) {
let elem = elems.item(i);
elem.setAttribute('href', elem.getAttribute('href') + '&room=' + roomName);
}
</script>
</body>

View file

@ -57,7 +57,7 @@ function SrsRtcPublisherAsync() {
self.pc.addTransceiver("video", {direction: "sendonly"});
var stream = await navigator.mediaDevices.getUserMedia(
{audio: true, video: {height: {max: 320}}}
{audio: true, video: {width: {max: 320}}}
);
// @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream#Migrating_to_addTrack
stream.getTracks().forEach(function (track) {
@ -144,7 +144,7 @@ function SrsRtcPublisherAsync() {
return {
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
tid: new Date().getTime().toString(16)
tid: Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16)
};
},
parse: function (url) {
@ -361,7 +361,7 @@ function SrsRtcPlayerAsync() {
return {
apiUrl: apiUrl, streamUrl: streamUrl, schema: schema, urlObject: urlObject, port: port,
tid: new Date().getTime().toString(16)
tid: Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16)
};
},
parse: function (url) {

View file

@ -59,7 +59,7 @@ function SrsRtcSignalingAsync() {
// The message is a json object.
self.send = async function (message) {
return new Promise(function (resolve, reject) {
var r = {tid: new Date().getTime().toString(16), msg: message};
var r = {tid: Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16), msg: message};
self._internals.msgs[r.tid] = {resolve: resolve, reject: reject};
self.ws.send(JSON.stringify(r));
});
@ -100,21 +100,49 @@ function SrsRtcSignalingParse(location) {
let wsPort = location.href.split('wsp=')[1];
wsPort = wsPort? wsPort.split('&')[0] : location.host.split(':')[1];
wsHost = wsPort? wsHost.split(':')[0] + ':' + wsPort : wsHost;
let host = location.href.split('host=')[1];
host = host? host.split('&')[0] : location.hostname;
let room = location.href.split('room=')[1];
room = room? room.split('&')[0] : null;
let display = location.href.split('display=')[1];
display = display? display.split('&')[0] : new Date().getTime().toString(16).substr(3);
display = display? display.split('&')[0] : Number(new Date().getTime() + parseInt(String(Math.random() * 10000000000))).toString(16).substr(3);
let autostart = location.href.split('autostart=')[1];
autostart = autostart && autostart.split('&')[0] === 'true';
// Remove data in query.
let rawQuery = query;
if (query) {
query = query.replace('wss=' + wsSchema, '');
query = query.replace('wsh=' + wsHost, '');
query = query.replace('wsp=' + wsPort, '');
query = query.replace('host=' + host, '');
if (room) {
query = query.replace('room=' + room, '');
}
query = query.replace('display=' + display, '');
query = query.replace('autostart=' + autostart, '');
while (query.indexOf('&&') >= 0) {
query = query.replace('&&', '&');
}
query = query.replace('?&', '?');
if (query.lastIndexOf('?') === query.length - 1) {
query = query.substr(0, query.length - 1);
}
if (query.lastIndexOf('&') === query.length - 1) {
query = query.substr(0, query.length - 1);
}
}
// Regenerate the host of websocket.
wsHost = wsPort? wsHost.split(':')[0] + ':' + wsPort : wsHost;
return {
query: query, wsSchema: wsSchema, wsHost: wsHost, host: host,
query: query, rawQuery: rawQuery, wsSchema: wsSchema, wsHost: wsHost, host: host,
room: room, display: display, autostart: autostart,
};
}

View file

@ -5,7 +5,7 @@
<meta charset="utf-8">
<style>
body{
padding-top: 55px;
padding-top: 30px;
}
</style>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
@ -15,15 +15,16 @@
<script type="text/javascript" src="js/srs.sig.js"></script>
</head>
<body>
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/rtcpublisher'/>
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/one2one'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="https://github.com/ossrs/srs">SRS</a>
<div class="nav-collapse collapse">
<ul class="nav">
<ul class="nav srs_nav">
<li class="active"><a href="#">一对一通话</a></li>
<li>
<li><a href="room.html">多人通话</a></li>
<li class="srs_ignore">
<a href="https://github.com/ossrs/signaling">
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/signaling?style=social">
</a>
@ -45,26 +46,89 @@
</div>
<div class="row">
<div class="span5">
<div class="span4 hide" id="publisher">
<label></label>
<video id="rtc_media_publisher" width="320" autoplay muted controls></video>
<video id="rtc_media_publisher" width="310" autoplay muted controls></video>
<label></label>
<span id='self'></span>
</div>
<div class="span6">
<div class="span6 hide" id="player">
<label></label>
<video id="rtc_media_player" width="320" autoplay muted controls></video>
<video id="rtc_media_player" width="310" autoplay muted controls></video>
<label></label>
<span id='peer'></span>
<a href="javascript:control_refresh_peer()">Refresh</a>
<input type="text" id="txt_alert" class="input-medium" value="">
<a href="javascript:control_alert_peer()">Alert</a>
</div>
</div>
<label></label>
<div class="accordion hide srs_merge">
<div class="accordion-group">
<div class="accordion-heading">
<a href="javascript:void(0)" class="accordion-toggle">FFmpeg合流转直播</a>
</div>
<div class="accordion-body collapse in">
<div class="accordion-inner" style="overflow:auto">
ffmpeg -f flv -i rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/<span class="ff_first"></span> -f flv -i rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/<span class="ff_second"></span> \ <br/>
&nbsp;&nbsp;&nbsp;&nbsp; -filter_complex "[1:v]scale=w=96:h=72[ckout];[0:v][ckout]overlay=x=W-w-10:y=H-h-10[out]" -map "[out]" \ <br/>
&nbsp;&nbsp;&nbsp;&nbsp; -c:v libx264 -profile:v high -preset medium \ <br/>
&nbsp;&nbsp;&nbsp;&nbsp; -filter_complex amix -c:a aac \ <br/>
&nbsp;&nbsp;&nbsp;&nbsp; -f flv -y
<span id="ff_output">
rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/merge
</span>
<span id="ff_wxvideo"></span>
&& <br/>
echo "ok"
</div>
<div class="accordion-inner">
<a href="#" id="ff_preview" target="_blank" class="accordion-toggle">
预览rtmp://<span class="ff_host"></span>/<span class="ff_app"></span>/merge
</a>
</div>
</div>
</div>
</div>
<label></label>
<div class="accordion hide srs_merge">
<div class="accordion-group">
<div class="accordion-heading">
<a href="javascript:void(0)" class="accordion-toggle">
视频号推流信息
</a>
</div>
<div class="accordion-body collapse in">
<div class="accordion-inner">
推流地址 <input type="text" id="txt_wx_video_tcurl" class="input-xxlarge">
</div>
<div class="accordion-inner">
推流密钥 <input type="text" id="txt_wx_video_stream" class="input-xxlarge">
</div>
<div class="accordion-inner">
<button class="btn btn-primary" id="btn_apply">应用</button>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<p>&copy; SRS 2020</p>
</div>
</footer>
<script type="text/javascript">
var sig = null;
var publisher = null;
var player = null;
var control_refresh_peer = null;
var control_alert_peer = null;
$(function(){
console.log('?wss=x to specify the websocket schema, ws or wss');
console.log('?wsh=x to specify the websocket server ip');
@ -85,13 +149,44 @@
sig = new SrsRtcSignalingAsync();
sig.onmessage = function (msg) {
console.log('Notify: ', msg);
msg.participants.forEach(function (participant) {
if (participant.display === display || !participant.publishing) return;
startPlay(host, room, participant.display);
});
if (msg.event === 'leave') {
$('#player').hide();
}
if (msg.event === 'publish') {
if (msg.peer && msg.peer.publishing && msg.peer.display !== display) {
startPlay(host, room, msg.peer.display);
}
}
if (msg.event === 'control') {
if (msg.param === 'refresh') {
setTimeout(function () {
window.location.reload();
}, 500);
} else if (msg.param === 'alert') {
alert('From ' + msg.peer.display + ': ' + msg.data);
}
}
if (msg.participants.length >= 2) {
$('.srs_merge').show();
} else {
$('.srs_merge').hide();
}
};
await sig.connect(conf.wsSchema, conf.wsHost, room, display);
control_refresh_peer = async function () {
let r1 = await sig.send({action:'control', room:room, display:display, call:'refresh'});
console.log('Signaling: control peer to refresh ok', r1);
};
control_alert_peer = async function () {
let r1 = await sig.send({action:'control', room:room, display:display, call:'alert', data:$('#txt_alert').val()});
console.log('Signaling: control peer to alert ok', r1);
};
let r0 = await sig.send({action:'join', room:room, display:display});
console.log('Signaling: join ok', r0);
@ -112,11 +207,20 @@
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();
@ -128,7 +232,7 @@
};
return publisher.publish(url).then(function(session){
$('#self').text('Self: ' + display);
$('#self').text('Self: ' + url);
}).catch(function (reason) {
publisher.close();
$('#rtc_media_publisher').hide();
@ -137,8 +241,13 @@
};
var startPlay = function (host, room, display) {
$(".ff_second").each(function(i,e) {
$(e).text(display);
});
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
$('#rtc_media_player').show();
$('#player').show();
if (player) {
player.close();
@ -160,15 +269,38 @@
});
};
$('#rtc_media_publisher').hide();
$('#rtc_media_player').hide();
$("#btn_start").click(startDemo);
// Pass-by to SRS url.
let conf = SrsRtcSignalingParse(window.location);
$('#txt_host').val(conf.host);
conf.room && $('#txt_room').val(conf.room);
$('#txt_display').val(conf.display);
$(".ff_host").each(function(i,e) {
$(e).text(conf.host);
});
$(".ff_app").each(function(i,e) {
$(e).text($('#txt_room').val());
});
$('#ff_preview').attr('href', 'http://ossrs.net/players/srs_player.html?app=' + $('#txt_room').val() + '&stream=merge.flv&server=' + conf.host + '&vhost=' + conf.host + '&autostart=true');
// Update href for all navs.
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').not("[href='#']").each(function (i, e) {
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
});
$('#btn_apply').click(function () {
if ($('#txt_wx_video_tcurl').val() !== '' && $('#txt_wx_video_stream').val() !== '') {
$('#ff_wxvideo').text('"' + $('#txt_wx_video_tcurl').val() + $('#txt_wx_video_stream').val() + '"').show();
$('#ff_output').hide();
$('#ff_preview').parent().hide();
} else {
$('#ff_wxvideo').hide();
$('#ff_output').show();
$('#ff_preview').parent().show();
}
});
$("#btn_start").click(startDemo);
if (conf.autostart) {
startDemo();
}

View file

@ -0,0 +1,212 @@
<!DOCTYPE html>
<html>
<head>
<title>SRS</title>
<meta charset="utf-8">
<style>
body{
padding-top: 30px;
}
</style>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/adapter-7.4.0.min.js"></script>
<script type="text/javascript" src="js/srs.sdk.js"></script>
<script type="text/javascript" src="js/srs.sig.js"></script>
</head>
<body>
<img src='https://ossrs.net/gif/v1/sls.gif?site=ossrs.net&path=/player/room'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="https://github.com/ossrs/srs">SRS</a>
<div class="nav-collapse collapse">
<ul class="nav srs_nav">
<li><a href="one2one.html">一对一通话</a></li>
<li class="active"><a href="#">多人通话</a></li>
<li class="srs_ignore">
<a href="https://github.com/ossrs/signaling">
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/ossrs/signaling?style=social">
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
<div class="form-inline">
SRS:
<input type="text" id="txt_host" class="input-medium" value="">
Room:
<input type="text" id="txt_room" class="input-small" value="live">
Display:
<input type="text" id="txt_display" class="input-small" value="">
<button class="btn btn-primary" id="btn_start">加入房间</button>
</div>
<div class="row srs_players">
<div class="span4 hide" id="publisher">
<label></label>
<video id="rtc_media_publisher" width="310" autoplay muted controls></video>
<label></label>
<span id='self'></span>
</div>
<div class="span4 hide" id="player">
<label></label>
<video id="rtc_media_player" width="310" autoplay muted controls></video>
<label></label>
<span id='peer'></span>
</div>
</div>
</div>
<script type="text/javascript">
var sig = null;
var publisher = null;
var players = {}; // Key is display, value is a player object.
$(function(){
console.log('?wss=x to specify the websocket schema, ws or wss');
console.log('?wsh=x to specify the websocket server ip');
console.log('?wsp=x to specify the websocket server port');
console.log('?host=x to specify the SRS server');
console.log('?room=x to specify the room to join');
console.log('?display=x to specify your nick name');
var startDemo = async function () {
var host = $('#txt_host').val();
var room = $('#txt_room').val();
var display = $('#txt_display').val();
// Connect to signaling first.
if (sig) {
sig.close();
}
sig = new SrsRtcSignalingAsync();
sig.onmessage = function (msg) {
console.log('Notify: ', msg);
// Subscribe if new user start to publish.
if (msg.event === 'publish') {
if (msg.peer && msg.peer.publishing && msg.peer.display !== display) {
startPlay(host, room, msg.peer.display);
}
}
// Remove dead players.
if (msg.event === 'join' || msg.event === 'leave') {
$.each(players, function(k, obj) {
let stillAlive = false;
msg.participants.forEach(function (participant) {
if (participant.display === k) stillAlive = true;
});
if (!stillAlive) {
obj.player.close();
obj.ui.remove();
}
});
}
};
await sig.connect(conf.wsSchema, conf.wsHost, room, display);
let r0 = await sig.send({action:'join', room:room, display:display});
console.log('Signaling: join ok', r0);
// Start publish media if signaling is ok.
await startPublish(host, room, display);
let r1 = await sig.send({action:'publish', room:room, display:display});
console.log('Signaling: publish ok', r1);
// Play the stream already in room.
r0.participants.forEach(function(participant) {
if (participant.display === display || !participant.publishing) return;
startPlay(host, room, participant.display);
});
};
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();
publisher.onaddstream = function (event) {
console.log('Start publish, event: ', event);
$('#rtc_media_publisher').prop('srcObject', event.stream);
};
return publisher.publish(url).then(function(session){
$('#self').text('Self: ' + url);
}).catch(function (reason) {
publisher.close();
$('#rtc_media_publisher').hide();
console.error(reason);
});
};
var startPlay = function (host, room, display) {
$(".ff_second").each(function(i,e) {
$(e).text(display);
});
// Remove exists.
if (players[display]) {
players[display].ui.remove();
players[display].player.close();
}
// Clone a player from template.
let ui = $('#player').clone().attr('id', 'player-' + display);
let video = ui.children('#rtc_media_player');
console.log(video.length);
let player = new SrsRtcPlayerAsync();
players[display] = {ui:ui, video:video, player:player};
$('.srs_players').append(ui);
// Start play for this user.
var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query;
video.show();
ui.show();
player.onaddstream = function (event) {
console.log('Start play, event: ', event);
video.prop('srcObject', event.stream);
};
player.play(url).then(function(session){
ui.children('#peer').text('Peer: ' + url);
video.prop('muted', false);
}).catch(function (reason) {
player.close();
video.hide();
console.error(reason);
});
};
// Pass-by to SRS url.
let conf = SrsRtcSignalingParse(window.location);
$('#txt_host').val(conf.host);
conf.room && $('#txt_room').val(conf.room);
$('#txt_display').val(conf.display);
// Update href for all navs.
$('ul.srs_nav').children('li').not('.srs_ignore').children('a').not("[href='#']").each(function (i, e) {
$(e).attr('href', $(e).attr('href') + conf.rawQuery);
});
$("#btn_start").click(startDemo);
if (conf.autostart) {
startDemo();
}
});
</script>