var websocket_server = null;
if(window.location.protocol === 'http:')
websocket_server = "ws://" + window.location.hostname + "/janus-ws/janus";
else
websocket_server = "wss://" + window.location.hostname + "/janus-ws/janus";
var janus = null;
var streaming = null;
var mixertest = null;
var opaqueId = "streamingwithfeedback-"+Janus.randomString(12);
var bitrateTimer = null;
var spinner = null;
var simulcastStarted = false, svcStarted = false;
var selectedStream = null;
var myroom = 1234; // Demo room
var myusername = null;
var myid = null;
var webrtcUp = false;
var audioenabled = false;
$(document).ready(function() {
// Initialize the library (all console debuggers enabled)
Janus.init({debug: "all", callback: function() {
// Use a button to start the demo
$('#start').one('click', function() {
$(this).attr('disabled', true).unbind('click');
// Make sure the browser supports WebRTC
if(!Janus.isWebrtcSupported()) {
bootbox.alert("No WebRTC support... ");
return;
}
// Create session
janus = new Janus(
{
server: [websocket_server, "/janus"],
iceServers: [{url: "turn:morla.jones.dk", username: "myturn", credential: "notsecure"},
{url: "turn:jawa.homebase.dk", username: "myturn", credential: "notsecure"}],
success: function() {
// Attach to streaming plugin
janus.attach(
{
plugin: "janus.plugin.streaming",
opaqueId: opaqueId,
success: function(pluginHandle) {
$('#details').remove();
streaming = pluginHandle;
Janus.log("Plugin attached! (" + streaming.getPlugin() + ", id=" + streaming.getId() + ")");
// Setup streaming session
$('#update-streams').click(updateStreamsList);
updateStreamsList();
$('#start').removeAttr('disabled').html("Stop")
.click(function() {
$(this).attr('disabled', true);
clearInterval(bitrateTimer);
janus.destroy();
$('#streamslist').attr('disabled', true);
$('#watch').attr('disabled', true).unbind('click');
$('#start').attr('disabled', true).html("Bye").unbind('click');
});
},
error: function(error) {
Janus.error(" -- Error attaching plugin... ", error);
bootbox.alert("Error attaching plugin... " + error);
},
onmessage: function(msg, jsep) {
Janus.debug(" ::: Got a message :::");
Janus.debug(msg);
var result = msg["result"];
if(result !== null && result !== undefined) {
if(result["status"] !== undefined && result["status"] !== null) {
var status = result["status"];
if(status === 'starting')
$('#status').removeClass('hide').text("Starting, please wait...").show();
else if(status === 'started')
$('#status').removeClass('hide').text("Started").show();
else if(status === 'stopped')
stopStream();
} else if(msg["streaming"] === "event") {
// Is simulcast in place?
var substream = result["substream"];
var temporal = result["temporal"];
if((substream !== null && substream !== undefined) || (temporal !== null && temporal !== undefined)) {
if(!simulcastStarted) {
simulcastStarted = true;
addSimulcastButtons(temporal !== null && temporal !== undefined);
}
// We just received notice that there's been a switch, update the buttons
updateSimulcastButtons(substream, temporal);
}
// Is VP9/SVC in place?
var spatial = result["spatial_layer"];
temporal = result["temporal_layer"];
if((spatial !== null && spatial !== undefined) || (temporal !== null && temporal !== undefined)) {
if(!svcStarted) {
svcStarted = true;
addSvcButtons();
}
// We just received notice that there's been a switch, update the buttons
updateSvcButtons(spatial, temporal);
}
}
} else if(msg["error"] !== undefined && msg["error"] !== null) {
bootbox.alert(msg["error"]);
stopStream();
return;
}
if(jsep !== undefined && jsep !== null) {
Janus.debug("Handling SDP as well...");
Janus.debug(jsep);
// Offer from the plugin, let's answer
streaming.createAnswer(
{
jsep: jsep,
// We want recvonly audio/video and, if negotiated, datachannels
media: { audioSend: false, videoSend: false, data: true },
success: function(jsep) {
Janus.debug("Got SDP!");
Janus.debug(jsep);
var body = { "request": "start" };
streaming.send({"message": body, "jsep": jsep});
$('#watch').html("Stop").removeAttr('disabled').click(stopStream);
},
error: function(error) {
Janus.error("WebRTC error:", error);
bootbox.alert("WebRTC error... " + JSON.stringify(error));
}
});
}
},
onremotestream: function(stream) {
Janus.debug(" ::: Got a remote stream :::");
Janus.debug(stream);
var addButtons = false;
if($('#remotevideo').length === 0) {
addButtons = true;
$('#stream').append('');
// Show the stream and hide the spinner when we get a playing event
$("#remotevideo").bind("playing", function () {
$('#waitingvideo').remove();
if(this.videoWidth)
$('#remotevideo').removeClass('hide').show();
if(spinner !== null && spinner !== undefined)
spinner.stop();
spinner = null;
var videoTracks = stream.getVideoTracks();
if(videoTracks === null || videoTracks === undefined || videoTracks.length === 0)
return;
var width = this.videoWidth;
var height = this.videoHeight;
$('#curres').removeClass('hide').text(width+'x'+height).show();
if(Janus.webRTCAdapter.browserDetails.browser === "firefox") {
// Firefox Stable has a bug: width and height are not immediately available after a playing
setTimeout(function() {
var width = $("#remotevideo").get(0).videoWidth;
var height = $("#remotevideo").get(0).videoHeight;
$('#curres').removeClass('hide').text(width+'x'+height).show();
}, 2000);
}
});
}
Janus.attachMediaStream($('#remotevideo').get(0), stream);
var videoTracks = stream.getVideoTracks();
if(videoTracks === null || videoTracks === undefined || videoTracks.length === 0) {
// No remote video
$('#remotevideo').hide();
if($('#stream .no-video-container').length === 0) {
$('#stream').append(
'
' +
'' +
'No remote video available' +
'
');
}
} else {
$('#stream .no-video-container').remove();
$('#remotevideo').removeClass('hide').show();
}
if(!addButtons)
return;
if(videoTracks && videoTracks.length &&
(Janus.webRTCAdapter.browserDetails.browser === "chrome" ||
Janus.webRTCAdapter.browserDetails.browser === "firefox" ||
Janus.webRTCAdapter.browserDetails.browser === "safari")) {
$('#curbitrate').removeClass('hide').show();
bitrateTimer = setInterval(function() {
// Display updated bitrate, if supported
var bitrate = streaming.getBitrate();
//~ Janus.debug("Current bitrate is " + streaming.getBitrate());
$('#curbitrate').text(bitrate);
// Check if the resolution changed too
var width = $("#remotevideo").get(0).videoWidth;
var height = $("#remotevideo").get(0).videoHeight;
if(width > 0 && height > 0)
$('#curres').removeClass('hide').text(width+'x'+height).show();
}, 1000);
}
},
ondataopen: function(data) {
Janus.log("The DataChannel is available!");
$('#waitingvideo').remove();
$('#stream').append(
''
);
if(spinner !== null && spinner !== undefined)
spinner.stop();
spinner = null;
},
ondata: function(data) {
Janus.debug("We got data from the DataChannel! " + data);
$('#datarecv').val(data);
},
oncleanup: function() {
Janus.log(" ::: Got a cleanup notification :::");
$('#waitingvideo').remove();
$('#remotevideo').remove();
$('#datarecv').remove();
$('.no-video-container').remove();
$('#bitrate').attr('disabled', true);
$('#bitrateset').html('Bandwidth');
$('#curbitrate').hide();
if(bitrateTimer !== null && bitrateTimer !== undefined)
clearInterval(bitrateTimer);
bitrateTimer = null;
$('#curres').hide();
$('#simulcast').remove();
simulcastStarted = false;
}
});
// Attach to Audio Bridge test plugin
janus.attach(
{
plugin: "janus.plugin.audiobridge",
opaqueId: opaqueId,
success: function(pluginHandle) {
$('#details').remove();
mixertest = pluginHandle;
Janus.log("Plugin attached! (" + mixertest.getPlugin() + ", id=" + mixertest.getId() + ")");
// Prepare the username registration
$('#audiojoin').removeClass('hide').show();
$('#registernow').removeClass('hide').show();
$('#register').click(registerUsername);
$('#username').focus();
$('#start').removeAttr('disabled').html("Stop")
.click(function() {
$(this).attr('disabled', true);
janus.destroy();
});
},
error: function(error) {
Janus.error(" -- Error attaching plugin...", error);
bootbox.alert("Error attaching plugin... " + error);
},
consentDialog: function(on) {
Janus.debug("Consent dialog should be " + (on ? "on" : "off") + " now");
if(on) {
// Darken screen and show hint
$.blockUI({
message: '',
css: {
border: 'none',
padding: '15px',
backgroundColor: 'transparent',
color: '#aaa',
top: '10px',
left: (navigator.mozGetUserMedia ? '-100px' : '300px')
} });
} else {
// Restore screen
$.unblockUI();
}
},
onmessage: function(msg, jsep) {
Janus.debug(" ::: Got a message :::");
Janus.debug(msg);
var event = msg["audiobridge"];
Janus.debug("Event: " + event);
if(event != undefined && event != null) {
if(event === "joined") {
// Successfully joined, negotiate WebRTC now
myid = msg["id"];
Janus.log("Successfully joined room " + msg["room"] + " with ID " + myid);
if(!webrtcUp) {
webrtcUp = true;
// Publish our stream
mixertest.createOffer(
{
media: { video: false}, // This is an audio only room
success: function(jsep) {
Janus.debug("Got SDP!");
Janus.debug(jsep);
var publish = { "request": "configure", "muted": false };
mixertest.send({"message": publish, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error:", error);
bootbox.alert("WebRTC error... " + JSON.stringify(error));
}
});
}
// Any room participant?
if(msg["participants"] !== undefined && msg["participants"] !== null) {
var list = msg["participants"];
Janus.debug("Got a list of participants:");
Janus.debug(list);
for(var f in list) {
var id = list[f]["id"];
var display = list[f]["display"];
var setup = list[f]["setup"];
var muted = list[f]["muted"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp'+id).length === 0) {
// Add to the participants list
$('#list').append(''+display+
' ' +
' ');
$('#rp'+id + ' > i').hide();
}
if(muted === true || muted === "true")
$('#rp'+id + ' > i.abmuted').removeClass('hide').show();
else
$('#rp'+id + ' > i.abmuted').hide();
if(setup === true || setup === "true")
$('#rp'+id + ' > i.absetup').hide();
else
$('#rp'+id + ' > i.absetup').removeClass('hide').show();
}
}
} else if(event === "roomchanged") {
// The user switched to a different room
myid = msg["id"];
Janus.log("Moved to room " + msg["room"] + ", new ID: " + myid);
// Any room participant?
$('#list').empty();
if(msg["participants"] !== undefined && msg["participants"] !== null) {
var list = msg["participants"];
Janus.debug("Got a list of participants:");
Janus.debug(list);
for(var f in list) {
var id = list[f]["id"];
var display = list[f]["display"];
var setup = list[f]["setup"];
var muted = list[f]["muted"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp'+id).length === 0) {
// Add to the participants list
$('#list').append(''+display+
' ' +
' ');
$('#rp'+id + ' > i').hide();
}
if(muted === true || muted === "true")
$('#rp'+id + ' > i.abmuted').removeClass('hide').show();
else
$('#rp'+id + ' > i.abmuted').hide();
if(setup === true || setup === "true")
$('#rp'+id + ' > i.absetup').hide();
else
$('#rp'+id + ' > i.absetup').removeClass('hide').show();
}
}
} else if(event === "destroyed") {
// The room has been destroyed
Janus.warn("The room has been destroyed!");
bootbox.alert("The room has been destroyed", function() {
window.location.reload();
});
} else if(event === "event") {
if(msg["participants"] !== undefined && msg["participants"] !== null) {
var list = msg["participants"];
Janus.debug("Got a list of participants:");
Janus.debug(list);
for(var f in list) {
var id = list[f]["id"];
var display = list[f]["display"];
var setup = list[f]["setup"];
var muted = list[f]["muted"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp'+id).length === 0) {
// Add to the participants list
$('#list').append(''+display+
' ' +
' ');
$('#rp'+id + ' > i').hide();
}
if(muted === true || muted === "true")
$('#rp'+id + ' > i.abmuted').removeClass('hide').show();
else
$('#rp'+id + ' > i.abmuted').hide();
if(setup === true || setup === "true")
$('#rp'+id + ' > i.absetup').hide();
else
$('#rp'+id + ' > i.absetup').removeClass('hide').show();
}
} else if(msg["error"] !== undefined && msg["error"] !== null) {
if(msg["error_code"] === 485) {
// This is a "no such room" error: give a more meaningful description
bootbox.alert(
"Apparently room " + myroom + "
(the one this demo uses as a test room) " +
"does not exist...
Do you have an updated janus.plugin.audiobridge.cfg
" +
"configuration file? If not, make sure you copy the details of room " + myroom + "
" +
"from that sample in your current configuration file, then restart Janus and try again."
);
} else {
bootbox.alert(msg["error"]);
}
return;
}
// Any new feed to attach to?
if(msg["leaving"] !== undefined && msg["leaving"] !== null) {
// One of the participants has gone away?
var leaving = msg["leaving"];
Janus.log("Participant left: " + leaving + " (we have " + $('#rp'+leaving).length + " elements with ID #rp" +leaving + ")");
$('#rp'+leaving).remove();
}
}
}
if(jsep !== undefined && jsep !== null) {
Janus.debug("Handling SDP as well...");
Janus.debug(jsep);
mixertest.handleRemoteJsep({jsep: jsep});
}
},
onlocalstream: function(stream) {
Janus.debug(" ::: Got a local stream :::");
Janus.debug(stream);
// We're not going to attach the local audio stream
$('#audiojoin').hide();
$('#room').removeClass('hide').show();
$('#participant').removeClass('hide').html(myusername).show();
},
onremotestream: function(stream) {
$('#room').removeClass('hide').show();
var addButtons = false;
if($('#roomaudio').length === 0) {
addButtons = true;
$('#mixedaudio').append('');
}
Janus.attachMediaStream($('#roomaudio').get(0), stream);
if(!addButtons)
return;
// Mute button
audioenabled = true;
$('#toggleaudio').click(
function() {
audioenabled = !audioenabled;
if(audioenabled)
$('#toggleaudio').html("Mute").removeClass("btn-success").addClass("btn-danger");
else
$('#toggleaudio').html("Unmute").removeClass("btn-danger").addClass("btn-success");
mixertest.send({message: { "request": "configure", "muted": !audioenabled }});
}).removeClass('hide').show();
},
oncleanup: function() {
webrtcUp = false;
Janus.log(" ::: Got a cleanup notification :::");
$('#participant').empty().hide();
$('#list').empty();
$('#mixedaudio').empty();
$('#room').hide();
}
});
},
error: function(error) {
Janus.error(error);
bootbox.alert(error, function() {
window.location.reload();
});
},
destroyed: function() {
window.location.reload();
}
});
});
}});
});
function updateStreamsList() {
$('#update-streams').unbind('click').addClass('fa-spin');
var body = { "request": "list" };
Janus.debug("Sending message (" + JSON.stringify(body) + ")");
streaming.send({"message": body, success: function(result) {
setTimeout(function() {
$('#update-streams').removeClass('fa-spin').click(updateStreamsList);
}, 500);
if(result === null || result === undefined) {
bootbox.alert("Got no response to our query for available streams");
return;
}
if(result["list"] !== undefined && result["list"] !== null) {
$('#streams').removeClass('hide').show();
$('#streamslist').empty();
$('#watch').attr('disabled', true).unbind('click');
var list = result["list"];
Janus.log("Got a list of available streams");
Janus.debug(list);
for(var mp in list) {
Janus.debug(" >> [" + list[mp]["id"] + "] " + list[mp]["description"] + " (" + list[mp]["type"] + ")");
$('#streamslist').append("
" + list[mp]["description"] + " (" + list[mp]["type"] + ")" + "");
}
$('#streamslist a').unbind('click').click(function() {
selectedStream = $(this).attr("id");
$('#streamset').html($(this).html()).parent().removeClass('open');
return false;
});
$('#watch').removeAttr('disabled').unbind('click').click(startStream);
}
}});
}
function startStream() {
Janus.log("Selected video id #" + selectedStream);
if(selectedStream === undefined || selectedStream === null) {
bootbox.alert("Select a stream from the list");
return;
}
$('#streamset').attr('disabled', true);
$('#streamslist').attr('disabled', true);
$('#watch').attr('disabled', true).unbind('click');
var body = { "request": "watch", id: parseInt(selectedStream) };
streaming.send({"message": body});
// No remote video yet
$('#stream').append('');
if(spinner == null) {
var target = document.getElementById('stream');
spinner = new Spinner({top:100}).spin(target);
} else {
spinner.spin();
}
}
function stopStream() {
$('#watch').attr('disabled', true).unbind('click');
var body = { "request": "stop" };
streaming.send({"message": body});
streaming.hangup();
$('#streamset').removeAttr('disabled');
$('#streamslist').removeAttr('disabled');
$('#watch').html("Watch or Listen").removeAttr('disabled').unbind('click').click(startStream);
$('#status').empty().hide();
$('#bitrate').attr('disabled', true);
$('#bitrateset').html('Bandwidth');
$('#curbitrate').hide();
if(bitrateTimer !== null && bitrateTimer !== undefined)
clearInterval(bitrateTimer);
bitrateTimer = null;
$('#curres').empty().hide();
$('#simulcast').remove();
simulcastStarted = false;
}
// Helpers to create Simulcast-related UI, if enabled
function addSimulcastButtons(temporal) {
$('#curres').parent().append(
'' +
'
' +
'
' +
' ' +
' ' +
' ' +
'
' +
'
' +
'
' +
'
' +
' ' +
' ' +
' ' +
'
' +
'
' +
'
');
// Enable the simulcast selection buttons
$('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Switching simulcast substream, wait for it... (lower quality)", null, {timeOut: 2000});
if(!$('#sl-2').hasClass('btn-success'))
$('#sl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
if(!$('#sl-1').hasClass('btn-success'))
$('#sl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
$('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
streaming.send({message: { request: "configure", substream: 0 }});
});
$('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Switching simulcast substream, wait for it... (normal quality)", null, {timeOut: 2000});
if(!$('#sl-2').hasClass('btn-success'))
$('#sl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
$('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
if(!$('#sl-0').hasClass('btn-success'))
$('#sl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
streaming.send({message: { request: "configure", substream: 1 }});
});
$('#sl-2').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Switching simulcast substream, wait for it... (higher quality)", null, {timeOut: 2000});
$('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
if(!$('#sl-1').hasClass('btn-success'))
$('#sl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
if(!$('#sl-0').hasClass('btn-success'))
$('#sl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
streaming.send({message: { request: "configure", substream: 2 }});
});
if(!temporal) // No temporal layer support
return;
$('#tl-0').parent().removeClass('hide');
$('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Capping simulcast temporal layer, wait for it... (lowest FPS)", null, {timeOut: 2000});
if(!$('#tl-2').hasClass('btn-success'))
$('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
if(!$('#tl-1').hasClass('btn-success'))
$('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
$('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
streaming.send({message: { request: "configure", temporal: 0 }});
});
$('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Capping simulcast temporal layer, wait for it... (medium FPS)", null, {timeOut: 2000});
if(!$('#tl-2').hasClass('btn-success'))
$('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
$('#tl-1').removeClass('btn-primary btn-info').addClass('btn-info');
if(!$('#tl-0').hasClass('btn-success'))
$('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
streaming.send({message: { request: "configure", temporal: 1 }});
});
$('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Capping simulcast temporal layer, wait for it... (highest FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
if(!$('#tl-1').hasClass('btn-success'))
$('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
if(!$('#tl-0').hasClass('btn-success'))
$('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
streaming.send({message: { request: "configure", temporal: 2 }});
});
}
function updateSimulcastButtons(substream, temporal) {
// Check the substream
if(substream === 0) {
toastr.success("Switched simulcast substream! (lower quality)", null, {timeOut: 2000});
$('#sl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
} else if(substream === 1) {
toastr.success("Switched simulcast substream! (normal quality)", null, {timeOut: 2000});
$('#sl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
$('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
} else if(substream === 2) {
toastr.success("Switched simulcast substream! (higher quality)", null, {timeOut: 2000});
$('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
$('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
}
// Check the temporal layer
if(temporal === 0) {
toastr.success("Capped simulcast temporal layer! (lowest FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
} else if(temporal === 1) {
toastr.success("Capped simulcast temporal layer! (medium FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
$('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
} else if(temporal === 2) {
toastr.success("Capped simulcast temporal layer! (highest FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
$('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
}
}
// Helpers to create SVC-related UI for a new viewer
function addSvcButtons() {
if($('#svc').length > 0)
return;
$('#curres').parent().append(
'' +
'
' +
'
' +
' ' +
' ' +
'
' +
'
' +
'
' +
'
' +
' ' +
' ' +
' ' +
'
' +
'
' +
'
'
);
// Enable the VP8 simulcast selection buttons
$('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Switching SVC spatial layer, wait for it... (low resolution)", null, {timeOut: 2000});
if(!$('#sl-1').hasClass('btn-success'))
$('#sl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
$('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
streaming.send({message: { request: "configure", spatial_layer: 0 }});
});
$('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Switching SVC spatial layer, wait for it... (normal resolution)", null, {timeOut: 2000});
$('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
if(!$('#sl-0').hasClass('btn-success'))
$('#sl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
streaming.send({message: { request: "configure", spatial_layer: 1 }});
});
$('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Capping SVC temporal layer, wait for it... (lowest FPS)", null, {timeOut: 2000});
if(!$('#tl-2').hasClass('btn-success'))
$('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
if(!$('#tl-1').hasClass('btn-success'))
$('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
$('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
streaming.send({message: { request: "configure", temporal_layer: 0 }});
});
$('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Capping SVC temporal layer, wait for it... (medium FPS)", null, {timeOut: 2000});
if(!$('#tl-2').hasClass('btn-success'))
$('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
$('#tl-1').removeClass('btn-primary btn-info').addClass('btn-info');
if(!$('#tl-0').hasClass('btn-success'))
$('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
streaming.send({message: { request: "configure", temporal_layer: 1 }});
});
$('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary')
.unbind('click').click(function() {
toastr.info("Capping SVC temporal layer, wait for it... (highest FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
if(!$('#tl-1').hasClass('btn-success'))
$('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
if(!$('#tl-0').hasClass('btn-success'))
$('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
streaming.send({message: { request: "configure", temporal_layer: 2 }});
});
}
function updateSvcButtons(spatial, temporal) {
// Check the spatial layer
if(spatial === 0) {
toastr.success("Switched SVC spatial layer! (lower resolution)", null, {timeOut: 2000});
$('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
} else if(spatial === 1) {
toastr.success("Switched SVC spatial layer! (normal resolution)", null, {timeOut: 2000});
$('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
$('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
}
// Check the temporal layer
if(temporal === 0) {
toastr.success("Capped SVC temporal layer! (lowest FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
} else if(temporal === 1) {
toastr.success("Capped SVC temporal layer! (medium FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
$('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
} else if(temporal === 2) {
toastr.success("Capped SVC temporal layer! (highest FPS)", null, {timeOut: 2000});
$('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
$('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
$('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
}
}
function checkEnter(field, event) {
var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
if(theCode == 13) {
registerUsername();
return false;
} else {
return true;
}
}
function registerUsername() {
if($('#username').length === 0) {
// Create fields to register
$('#register').click(registerUsername);
$('#username').focus();
} else {
// Try a registration
$('#username').attr('disabled', true);
$('#register').attr('disabled', true).unbind('click');
var username = $('#username').val();
if(username === "") {
$('#you')
.removeClass().addClass('label label-warning')
.html("Insert your display name (e.g., pippo)");
$('#username').removeAttr('disabled');
$('#register').removeAttr('disabled').click(registerUsername);
return;
}
if(/[^a-zA-Z0-9]/.test(username)) {
$('#you')
.removeClass().addClass('label label-warning')
.html('Input is not alphanumeric');
$('#username').removeAttr('disabled').val("");
$('#register').removeAttr('disabled').click(registerUsername);
return;
}
var register = { "request": "join", "room": myroom, "display": username };
myusername = username;
mixertest.send({"message": register});
}
}