Iz janusa na proxied mjpeg

sbc
Jurij Podgoršek 2023-06-06 13:24:19 +02:00
parent c3f55bd9ff
commit 959f21359c
4 changed files with 401 additions and 339 deletions

View File

@ -15,6 +15,22 @@
<script type="text/javascript" src="js/streaming.js"></script> <script type="text/javascript" src="js/streaming.js"></script>
<link rel="stylesheet" href="stil.css" type="text/css"/> <link rel="stylesheet" href="stil.css" type="text/css"/>
<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="https://anal.kompot.si/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '4']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->
</head> </head>
<body> <body>
@ -23,8 +39,9 @@
<h2>je umetniška instalacija, ki je del razstave Nevidni sopotnik v Mestni galeriji Nova Gorica. &nbsp;&nbsp;Spodnja konzola vam omogoča upravljanje tamkajšnjega lebdečega objekta.</h2> <h2>je umetniška instalacija, ki je del razstave Nevidni sopotnik v Mestni galeriji Nova Gorica. &nbsp;&nbsp;Spodnja konzola vam omogoča upravljanje tamkajšnjega lebdečega objekta.</h2>
<section class="zaslon cakam"> <section class="zaslon">
<video id="videofeed" muted="" autoplay="" playsinline=""></video> <!--video id="videofeed" muted="" autoplay="" playsinline=""></video-->
<img id="videofeed" src="/stream"></video>
<button id="predvajaj"></button> <button id="predvajaj"></button>
<section class="gumbi"> <section class="gumbi">

View File

@ -1,23 +1,3 @@
// We import the settings.js file to know which address we should contact
// to talk to Janus, and optionally which STUN/TURN servers should be
// used as well. Specifically, that file defines the "server" and
// "iceServers" properties we'll pass when creating the Janus session.
var janus = null;
var streaming = null;
var opaqueId = "streamingtest-"+Janus.randomString(12);
var remoteTracks = {}, dataMid = null;
var bitrateTimer = {};
var spinner = {};
var simulcastStarted = {}, svcStarted = {};
var streamsList = {};
// Kar fiksiramo na 666
var selectedStream = 666;
window.addEventListener('DOMContentLoaded', function () { window.addEventListener('DOMContentLoaded', function () {
var predvajaj = document.querySelector('#predvajaj'); var predvajaj = document.querySelector('#predvajaj');
@ -44,328 +24,26 @@ window.addEventListener('DOMContentLoaded', function () {
}); });
} }
// Gumbi levo in desno
function gremoLevo() { gLevo.addEventListener('click', function () {
console.log('GREMO LEVO!'); console.log('GREMO LEVO!');
window.peljiLevo(); window.peljiLevo();
onemogociGumbe();
omogociGumbe(DOLZINA + PAVZA);
}
function gremoRavno() {
console.log('GREMO RAVNO!');
window.peljiRavno();
onemogociGumbe(); onemogociGumbe();
omogociGumbe(DOLZINA + PAVZA); omogociGumbe(DOLZINA + PAVZA);
} });
function gremoDesno() { gDesno.addEventListener('click', function () {
console.log('GREMO DESNO!'); console.log('GREMO DESNO!');
window.peljiDesno(); window.peljiDesno();
onemogociGumbe(); onemogociGumbe();
omogociGumbe(DOLZINA + PAVZA); omogociGumbe(DOLZINA + PAVZA);
} });
gRavno.addEventListener('click', function () {
console.log('GREMO RAVNO!');
window.peljiRavno();
// Initialize the library (all console debuggers enabled) onemogociGumbe();
Janus.init({debug: "all", callback: function() { omogociGumbe(DOLZINA + PAVZA);
// Make sure the browser supports WebRTC
if(!Janus.isWebrtcSupported()) {
console.log("ERROR cannot start; no WebRTC support... ");
return;
}
// Create session
janus = new Janus({
server: server,
iceServers: iceServers,
// Should the Janus API require authentication, you can specify either the API secret or user token here too
// token: "mytoken",
// or
// apisecret: "serversecret",
success: function() {
// Attach to Streaming plugin
janus.attach({
plugin: "janus.plugin.streaming",
opaqueId: opaqueId,
success: function(pluginHandle) {
streaming = pluginHandle;
Janus.log("Plugin attached! (" + streaming.getPlugin() + ", id=" + streaming.getId() + ")");
// Setup streaming session
updateStreamsList();
/* ustavitev neka?
for(var i in bitrateTimer)
clearInterval(bitrateTimer[i]);
bitrateTimer = {};
janus.destroy();
*/
// Kar zacnimo stream
startStream();
},
error: function(error) {
Janus.error(" -- Error attaching plugin... ", error);
},
iceState: function(state) {
Janus.log("ICE state changed to " + state);
},
webrtcState: function(on) {
Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now");
if (on) {
// Gumbi levo in desno
gLevo.addEventListener('click', gremoLevo);
gDesno.addEventListener('click', gremoDesno);
gRavno.addEventListener('click', gremoRavno);
} else {
gLevo.removeEventListener('click', gremoLevo);
gDesno.removeEventListener('click', gremoDesno);
gRavno.removeEventListener('click', gremoRavno);
}
},
slowLink: function(uplink, lost, mid) {
Janus.warn("Janus reports problems " + (uplink ? "sending" : "receiving") +
" packets on mid " + mid + " (" + lost + " lost packets)");
},
onmessage: function(msg, jsep) {
Janus.debug(" ::: Got a message :::", msg);
var result = msg["result"];
if(result) {
if(result["status"]) {
var status = result["status"];
// if(status === 'starting')
// else if(status === 'started')
// else if(status === 'stopped')
if(status === 'stopped') {
stopStream();
}
} else if(msg["streaming"] === "event") {
// Does this event refer to a mid in particular?
var mid = result["mid"] ? result["mid"] : "0";
// Is simulcast in place?
var substream = result["substream"];
var temporal = result["temporal"];
if((substream !== null && substream !== undefined) || (temporal !== null && temporal !== undefined)) {
if(!simulcastStarted[mid]) {
simulcastStarted[mid] = true;
}
}
// Is VP9/SVC in place?
var spatial = result["spatial_layer"];
temporal = result["temporal_layer"];
}
} else if(msg["error"]) {
console.log('NAPAKA', msg["error"]);
stopStream();
return;
}
if(jsep) {
Janus.debug("Handling SDP as well...", jsep);
var stereo = (jsep.sdp.indexOf("stereo=1") !== -1);
// Offer from the plugin, let's answer
streaming.createAnswer({
jsep: jsep,
// We only specify data channels here, as this way in
// case they were offered we'll enable them. Since we
// don't mention audio or video tracks, we autoaccept them
// as recvonly (since we won't capture anything ourselves)
tracks: [{ type: 'data' }],
customizeSdp: function(jsep) {
if(stereo && jsep.sdp.indexOf("stereo=1") == -1) {
// Make sure that our offer contains stereo too
jsep.sdp = jsep.sdp.replace("useinbandfec=1", "useinbandfec=1;stereo=1");
}
},
success: function(jsep) {
Janus.debug("Got SDP!", jsep);
var body = { request: "start" };
streaming.send({ message: body, jsep: jsep });
},
error: function(error) {
Janus.error("WebRTC error:", error);
}
}); });
} }
},
onremotetrack: function(track, mid, on, metadata) {
Janus.debug("Remote track (mid=" + mid + ") " + (on ? "added" : "removed") +
(metadata ? " (" + metadata.reason + ") ": "") + ":", track
);
var mstreamId = "mstream"+mid;
if(streamsList[selectedStream] && streamsList[selectedStream].legacy) {
mstreamId = "mstream0";
}
console.log('dodam?', on);
if(true) {
// If we're here, a new track was added
var stream = null;
// New video track: create a stream out of it
stream = new MediaStream([track]);
console.log('MOJ PRETOK!', stream, track);
remoteTracks[mid] = stream;
Janus.log("Created remote video stream:", stream);
var vidEl = document.querySelector('#videofeed');
var zaslonEl = document.querySelector('.zaslon');
/* bitrate in resolucija
if(!bitrateTimer[mid]) {
bitrateTimer[mid] = setInterval(function() {
// Display updated bitrate, if supported
var bitrate = streaming.getBitrate(mid);
console.log('bitrate:', bitrate);
// Check if the resolution changed too
var width = vidEl.videoWidth;
var height = vidEl.videoHeight;
if (width > 0 && height > 0) console.log('resolucija', width+'x'+height);
}, 1000);
}
*/
console.log('dodajam pretok', vidEl, stream);
Janus.attachMediaStream(vidEl, stream);
vidEl.addEventListener('canplay', function () {
console.log('lahko predvajam!');
zaslonEl.classList.remove('cakam');
});
// Moramo kliknit za predvajanje :/
// predvajaj.style.display = 'block';
predvajaj.addEventListener('click', function () {
predvajaj.style.display = 'none';
vidEl.play();
});
vidEl.addEventListener('play', function () {
glavno.classList.add('predvajam');
predvajaj.style.display = 'none';
});
//vidEl.play();
}
},
ondataopen: function(data) {
Janus.log("The DataChannel is available!");
window.dataKanal = data;
},
ondata: function(data) {
Janus.debug("We got data from the DataChannel!", data);
console.log('DUBU DATA', data);
obdelajData(data);
},
oncleanup: function() {
Janus.log(" ::: Got a cleanup notification :::");
for(var i in bitrateTimer)
clearInterval(bitrateTimer[i]);
bitrateTimer = {};
remoteTracks = {};
dataMid = null;
}
});
},
error: function(error) {
Janus.error(error);
},
destroyed: function() {
window.location.reload();
}
});
}});
});
function updateStreamsList() {
var body = { request: "list" };
Janus.debug("Sending message:", body);
streaming.send({ message: body, success: function(result) {
if(!result) {
console.log("Error: Got no response to our query for available streams");
return;
}
if(result["list"]) {
var list = result["list"];
if(list && Array.isArray(list)) {
list.sort(function(a, b) {
if(!a || a.id < (b ? b.id : 0))
return -1;
if(!b || b.id < (a ? a.id : 0))
return 1;
return 0;
});
}
Janus.log("Got a list of available streams:", list);
streamsList = {};
for(var mp in list) {
Janus.debug(" >> [" + list[mp]["id"] + "] " + list[mp]["description"] + " (" + list[mp]["type"] + ")");
// Check the nature of the available streams, and if there are some multistream ones
list[mp].legacy = true;
if(list[mp].media) {
var audios = 0, videos = 0;
for(var mi in list[mp].media) {
if(!list[mp].media[mi])
continue;
if(list[mp].media[mi].type === "audio")
audios++;
else if(list[mp].media[mi].type === "video")
videos++;
if(audios > 1 || videos > 1) {
list[mp].legacy = false;
break;
}
}
}
// Keep track of all the available streams
streamsList[list[mp]["id"]] = list[mp];
}
// Dajmo kar zacet
startStream();
}
}});
}
function getStreamInfo() {
// Send a request for more info on the mountpoint we subscribed to
var body = { request: "info", id: parseInt(selectedStream) || selectedStream };
streaming.send({ message: body, success: function(result) {
if(result && result.info && result.info.metadata) {
console.log('STREAM META', result.info.metadata);
}
}});
}
function startStream() {
Janus.log("Selected video id #" + selectedStream);
console.log('zacenjam', selectedStream, streamsList[selectedStream]);
if(!selectedStream || !streamsList[selectedStream]) {
console.log("Error: No stream selected to start");
return;
}
if(streamsList[selectedStream].legacy) {
for(mi in streamsList[selectedStream].media) {
// Add a new panel
var type = streamsList[selectedStream].media[mi].type;
if(type === "video") {
mid = streamsList[selectedStream].media[mi].mid;
break;
}
}
}
// Prepare the request to start streaming and send it
var body = { request: "watch", id: parseInt(selectedStream) || selectedStream };
streaming.send({ message: body });
getStreamInfo();
}
function stopStream() {
streaming.send({ message: body });
streaming.hangup();
}
function obdelajData(data) {
console.log('obdelam webrtc podatke', data);
}

View File

@ -0,0 +1,367 @@
// We import the settings.js file to know which address we should contact
// to talk to Janus, and optionally which STUN/TURN servers should be
// used as well. Specifically, that file defines the "server" and
// "iceServers" properties we'll pass when creating the Janus session.
var janus = null;
var streaming = null;
var opaqueId = "streamingtest-"+Janus.randomString(12);
var remoteTracks = {}, dataMid = null;
var bitrateTimer = {};
var spinner = {};
var simulcastStarted = {}, svcStarted = {};
var streamsList = {};
// Kar fiksiramo na 666
var selectedStream = 666;
window.addEventListener('DOMContentLoaded', function () {
var predvajaj = document.querySelector('#predvajaj');
var gumbi = document.querySelector('#predvajaj');
var glavno = document.querySelector('#glavno');
var gLevo = document.querySelector('#levo');
var gDesno = document.querySelector('#desno');
var gRavno = document.querySelector('#ravno');
var vsiGumbi = [gLevo, gDesno, gRavno];
// Funkcije za veckratno rabo
function omogociGumbe(kdaj) {
setTimeout(function () {
vsiGumbi.forEach(function (gEl) {
gEl.toggleAttribute('disabled', false);
});
}, kdaj);
}
function onemogociGumbe() {
vsiGumbi.forEach(function (gEl) {
gEl.toggleAttribute('disabled', true);
});
}
// Initialize the library (all console debuggers enabled)
Janus.init({debug: "all", callback: function() {
// Make sure the browser supports WebRTC
if(!Janus.isWebrtcSupported()) {
console.log("ERROR cannot start; no WebRTC support... ");
return;
}
// Create session
janus = new Janus({
server: server,
iceServers: iceServers,
// Should the Janus API require authentication, you can specify either the API secret or user token here too
// token: "mytoken",
// or
// apisecret: "serversecret",
success: function() {
// Attach to Streaming plugin
janus.attach({
plugin: "janus.plugin.streaming",
opaqueId: opaqueId,
success: function(pluginHandle) {
streaming = pluginHandle;
Janus.log("Plugin attached! (" + streaming.getPlugin() + ", id=" + streaming.getId() + ")");
// Setup streaming session
updateStreamsList();
/* ustavitev neka?
for(var i in bitrateTimer)
clearInterval(bitrateTimer[i]);
bitrateTimer = {};
janus.destroy();
*/
// Kar zacnimo stream
startStream();
},
error: function(error) {
Janus.error(" -- Error attaching plugin... ", error);
},
iceState: function(state) {
Janus.log("ICE state changed to " + state);
},
webrtcState: function(on) {
Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now");
if (on) {
// Gumbi levo in desno
gLevo.addEventListener('click', function () {
console.log('GREMO LEVO!');
window.peljiLevo();
onemogociGumbe();
omogociGumbe(DOLZINA + PAVZA);
});
gDesno.addEventListener('click', function () {
console.log('GREMO DESNO!');
window.peljiDesno();
onemogociGumbe();
omogociGumbe(DOLZINA + PAVZA);
});
gRavno.addEventListener('click', function () {
console.log('GREMO RAVNO!');
window.peljiRavno();
onemogociGumbe();
omogociGumbe(DOLZINA + PAVZA);
});
} else {
gLevo.removeEventListener('click');
gDesno.removeEventListener('click');
gRavno.removeEventListener('click');
}
},
slowLink: function(uplink, lost, mid) {
Janus.warn("Janus reports problems " + (uplink ? "sending" : "receiving") +
" packets on mid " + mid + " (" + lost + " lost packets)");
},
onmessage: function(msg, jsep) {
Janus.debug(" ::: Got a message :::", msg);
var result = msg["result"];
if(result) {
if(result["status"]) {
var status = result["status"];
// if(status === 'starting')
// else if(status === 'started')
// else if(status === 'stopped')
if(status === 'stopped') {
stopStream();
}
} else if(msg["streaming"] === "event") {
// Does this event refer to a mid in particular?
var mid = result["mid"] ? result["mid"] : "0";
// Is simulcast in place?
var substream = result["substream"];
var temporal = result["temporal"];
if((substream !== null && substream !== undefined) || (temporal !== null && temporal !== undefined)) {
if(!simulcastStarted[mid]) {
simulcastStarted[mid] = true;
}
}
// Is VP9/SVC in place?
var spatial = result["spatial_layer"];
temporal = result["temporal_layer"];
}
} else if(msg["error"]) {
console.log('NAPAKA', msg["error"]);
stopStream();
return;
}
if(jsep) {
Janus.debug("Handling SDP as well...", jsep);
var stereo = (jsep.sdp.indexOf("stereo=1") !== -1);
// Offer from the plugin, let's answer
streaming.createAnswer({
jsep: jsep,
// We only specify data channels here, as this way in
// case they were offered we'll enable them. Since we
// don't mention audio or video tracks, we autoaccept them
// as recvonly (since we won't capture anything ourselves)
tracks: [{ type: 'data' }],
customizeSdp: function(jsep) {
if(stereo && jsep.sdp.indexOf("stereo=1") == -1) {
// Make sure that our offer contains stereo too
jsep.sdp = jsep.sdp.replace("useinbandfec=1", "useinbandfec=1;stereo=1");
}
},
success: function(jsep) {
Janus.debug("Got SDP!", jsep);
var body = { request: "start" };
streaming.send({ message: body, jsep: jsep });
},
error: function(error) {
Janus.error("WebRTC error:", error);
}
});
}
},
onremotetrack: function(track, mid, on, metadata) {
Janus.debug("Remote track (mid=" + mid + ") " + (on ? "added" : "removed") +
(metadata ? " (" + metadata.reason + ") ": "") + ":", track
);
var mstreamId = "mstream"+mid;
if(streamsList[selectedStream] && streamsList[selectedStream].legacy) {
mstreamId = "mstream0";
}
console.log('dodam?', on);
if(true) {
// If we're here, a new track was added
var stream = null;
// New video track: create a stream out of it
stream = new MediaStream([track]);
console.log('MOJ PRETOK!', stream, track);
remoteTracks[mid] = stream;
Janus.log("Created remote video stream:", stream);
var vidEl = document.querySelector('#videofeed');
var zaslonEl = document.querySelector('.zaslon');
/* bitrate in resolucija
if(!bitrateTimer[mid]) {
bitrateTimer[mid] = setInterval(function() {
// Display updated bitrate, if supported
var bitrate = streaming.getBitrate(mid);
console.log('bitrate:', bitrate);
// Check if the resolution changed too
var width = vidEl.videoWidth;
var height = vidEl.videoHeight;
if (width > 0 && height > 0) console.log('resolucija', width+'x'+height);
}, 1000);
}
*/
console.log('dodajam pretok', vidEl, stream);
Janus.attachMediaStream(vidEl, stream);
vidEl.addEventListener('canplay', function () {
console.log('lahko predvajam!');
zaslonEl.classList.remove('cakam');
});
// Moramo kliknit za predvajanje :/
// predvajaj.style.display = 'block';
predvajaj.addEventListener('click', function () {
predvajaj.style.display = 'none';
vidEl.play();
});
vidEl.addEventListener('play', function () {
glavno.classList.add('predvajam');
predvajaj.style.display = 'none';
});
//vidEl.play();
}
},
ondataopen: function(data) {
Janus.log("The DataChannel is available!");
window.dataKanal = data;
},
ondata: function(data) {
Janus.debug("We got data from the DataChannel!", data);
console.log('DUBU DATA', data);
obdelajData(data);
},
oncleanup: function() {
Janus.log(" ::: Got a cleanup notification :::");
for(var i in bitrateTimer)
clearInterval(bitrateTimer[i]);
bitrateTimer = {};
remoteTracks = {};
dataMid = null;
}
});
},
error: function(error) {
Janus.error(error);
},
destroyed: function() {
window.location.reload();
}
});
}});
});
function updateStreamsList() {
var body = { request: "list" };
Janus.debug("Sending message:", body);
streaming.send({ message: body, success: function(result) {
if(!result) {
console.log("Error: Got no response to our query for available streams");
return;
}
if(result["list"]) {
var list = result["list"];
if(list && Array.isArray(list)) {
list.sort(function(a, b) {
if(!a || a.id < (b ? b.id : 0))
return -1;
if(!b || b.id < (a ? a.id : 0))
return 1;
return 0;
});
}
Janus.log("Got a list of available streams:", list);
streamsList = {};
for(var mp in list) {
Janus.debug(" >> [" + list[mp]["id"] + "] " + list[mp]["description"] + " (" + list[mp]["type"] + ")");
// Check the nature of the available streams, and if there are some multistream ones
list[mp].legacy = true;
if(list[mp].media) {
var audios = 0, videos = 0;
for(var mi in list[mp].media) {
if(!list[mp].media[mi])
continue;
if(list[mp].media[mi].type === "audio")
audios++;
else if(list[mp].media[mi].type === "video")
videos++;
if(audios > 1 || videos > 1) {
list[mp].legacy = false;
break;
}
}
}
// Keep track of all the available streams
streamsList[list[mp]["id"]] = list[mp];
}
// Dajmo kar zacet
startStream();
}
}});
}
function getStreamInfo() {
// Send a request for more info on the mountpoint we subscribed to
var body = { request: "info", id: parseInt(selectedStream) || selectedStream };
streaming.send({ message: body, success: function(result) {
if(result && result.info && result.info.metadata) {
console.log('STREAM META', result.info.metadata);
}
}});
}
function startStream() {
Janus.log("Selected video id #" + selectedStream);
console.log('zacenjam', selectedStream, streamsList[selectedStream]);
if(!selectedStream || !streamsList[selectedStream]) {
console.log("Error: No stream selected to start");
return;
}
if(streamsList[selectedStream].legacy) {
for(mi in streamsList[selectedStream].media) {
// Add a new panel
var type = streamsList[selectedStream].media[mi].type;
if(type === "video") {
mid = streamsList[selectedStream].media[mi].mid;
break;
}
}
}
// Prepare the request to start streaming and send it
var body = { request: "watch", id: parseInt(selectedStream) || selectedStream };
streaming.send({ message: body });
getStreamInfo();
}
function stopStream() {
streaming.send({ message: body });
streaming.hangup();
}
function obdelajData(data) {
console.log('obdelam webrtc podatke', data);
}

View File

@ -37,7 +37,7 @@ h2 {
height: auto; height: auto;
} }
video { #videofeed {
width: 100%; width: 100%;
height: auto; height: auto;
box-sizing: border-box; box-sizing: border-box;