Advertisement
jhthompson12

janus_stream.js

Jun 20th, 2021
358
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // We make use of this 'server' variable to provide the address of the
  2. // REST Janus API. By default, in this example we assume that Janus is
  3. // co-located with the web server hosting the HTML pages but listening
  4. // on a different port (8088, the default for HTTP in Janus), which is
  5. // why we make use of the 'window.location.hostname' base address. Since
  6. // Janus can also do HTTPS, and considering we don't really want to make
  7. // use of HTTP for Janus if your demos are served on HTTPS, we also rely
  8. // on the 'window.location.protocol' prefix to build the variable, in
  9. // particular to also change the port used to contact Janus (8088 for
  10. // HTTP and 8089 for HTTPS, if enabled).
  11. // In case you place Janus behind an Apache frontend (as we did on the
  12. // online demos at http://janus.conf.meetecho.com) you can just use a
  13. // relative path for the variable, e.g.:
  14. //
  15. //      var server = "/janus";
  16. //
  17. // which will take care of this on its own.
  18. //
  19. //
  20. // If you want to use the WebSockets frontend to Janus, instead, you'll
  21. // have to pass a different kind of address, e.g.:
  22. //
  23. //      var server = "ws://" + window.location.hostname + ":8188";
  24. //
  25. // Of course this assumes that support for WebSockets has been built in
  26. // when compiling the server. WebSockets support has not been tested
  27. // as much as the REST API, so handle with care!
  28. //
  29. //
  30. // If you have multiple options available, and want to let the library
  31. // autodetect the best way to contact your server (or pool of servers),
  32. // you can also pass an array of servers, e.g., to provide alternative
  33. // means of access (e.g., try WebSockets first and, if that fails, fall
  34. // back to plain HTTP) or just have failover servers:
  35. //
  36. //      var server = [
  37. //          "ws://" + window.location.hostname + ":8188",
  38. //          "/janus"
  39. //      ];
  40. //
  41. // This will tell the library to try connecting to each of the servers
  42. // in the presented order. The first working server will be used for
  43. // the whole session.
  44. //
  45. var server = null;
  46. if(window.location.protocol === 'http:')
  47.     server = "http://" + window.location.hostname + ":8088/janus";
  48. else
  49.     server = "https://" + window.location.hostname + ":8089/janus";
  50.  
  51. var janus = null;
  52. var streaming = null;
  53. var opaqueId = "streamingtest-"+Janus.randomString(12);
  54.  
  55. var bitrateTimer = null;
  56. var spinner = true;
  57.  
  58. var simulcastStarted = false, svcStarted = false;
  59.  
  60. var selectedStream = null;
  61.  
  62.  
  63. $(document).ready(function() {
  64.     // Initialize the library (all console debuggers enabled)
  65.     Janus.init({debug: "all", callback: function() {
  66.         // Use a button to start the demo
  67.         //$('#start').one('click', function() {
  68.             //$(this).attr('disabled', true).unbind('click');
  69.             // Make sure the browser supports WebRTC
  70.             if(!Janus.isWebrtcSupported()) {
  71.                 bootbox.alert("No WebRTC support... ");
  72.                 return;
  73.             }
  74.             // Create session
  75.             janus = new Janus(
  76.                 {
  77.                     server: server,
  78.                     success: function() {
  79.                         // Attach to Streaming plugin
  80.                         janus.attach(
  81.                             {
  82.                                 plugin: "janus.plugin.streaming",
  83.                                 opaqueId: opaqueId,
  84.                                 success: function(pluginHandle) {
  85.                                     $('#details').remove();
  86.                                     streaming = pluginHandle;
  87.                                     Janus.log("Plugin attached! (" + streaming.getPlugin() + ", id=" + streaming.getId() + ")");
  88.                                     // Setup streaming session
  89.                                     $('#update-streams').click(updateStreamsList);
  90.                                     updateStreamsList();
  91.                                     $('#start').removeAttr('disabled').html("Stop")
  92.                                         .click(function() {
  93.                                             $(this).attr('disabled', true);
  94.                                             clearInterval(bitrateTimer);
  95.                                             janus.destroy();
  96.                                             $('#streamslist').attr('disabled', true);
  97.                                             $('#watch').attr('disabled', true).unbind('click');
  98.                                             $('#start').attr('disabled', true).html("Bye").unbind('click');
  99.                                         });
  100.                                 },
  101.                                 error: function(error) {
  102.                                     Janus.error("  -- Error attaching plugin... ", error);
  103.                                     bootbox.alert("Error attaching plugin... " + error);
  104.                                 },
  105.                                 iceState: function(state) {
  106.                                     Janus.log("ICE state changed to " + state);
  107.                                 },
  108.                                 webrtcState: function(on) {
  109.                                     Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now");
  110.                                 },
  111.                                 onmessage: function(msg, jsep) {
  112.                                     Janus.debug(" ::: Got a message :::", msg);
  113.                                     var result = msg["result"];
  114.                                     if(result) {
  115.                                         if(result["status"]) {
  116.                                             var status = result["status"];
  117.                                             if(status === 'starting')
  118.                                                 $('#status').removeClass('hide').text("Starting, please wait...").show();
  119.                                             else if(status === 'started')
  120.                                                 $('#status').removeClass('hide').text("Started").show();
  121.                                             else if(status === 'stopped')
  122.                                                 stopStream();
  123.                                         } else if(msg["streaming"] === "event") {
  124.                                             // Is simulcast in place?
  125.                                             var substream = result["substream"];
  126.                                             var temporal = result["temporal"];
  127.                                             if((substream !== null && substream !== undefined) || (temporal !== null && temporal !== undefined)) {
  128.                                                 if(!simulcastStarted) {
  129.                                                     simulcastStarted = true;
  130.                                                     addSimulcastButtons(temporal !== null && temporal !== undefined);
  131.                                                 }
  132.                                                 // We just received notice that there's been a switch, update the buttons
  133.                                                 updateSimulcastButtons(substream, temporal);
  134.                                             }
  135.                                             // Is VP9/SVC in place?
  136.                                             var spatial = result["spatial_layer"];
  137.                                             temporal = result["temporal_layer"];
  138.                                             if((spatial !== null && spatial !== undefined) || (temporal !== null && temporal !== undefined)) {
  139.                                                 if(!svcStarted) {
  140.                                                     svcStarted = true;
  141.                                                     addSvcButtons();
  142.                                                 }
  143.                                                 // We just received notice that there's been a switch, update the buttons
  144.                                                 updateSvcButtons(spatial, temporal);
  145.                                             }
  146.                                         }
  147.                                     } else if(msg["error"]) {
  148.                                         bootbox.alert(msg["error"]);
  149.                                         stopStream();
  150.                                         return;
  151.                                     }
  152.                                     if(jsep) {
  153.                                         Janus.debug("Handling SDP as well...", jsep);
  154.                                         var stereo = (jsep.sdp.indexOf("stereo=1") !== -1);
  155.                                         // Offer from the plugin, let's answer
  156.                                         streaming.createAnswer(
  157.                                             {
  158.                                                 jsep: jsep,
  159.                                                 // We want recvonly audio/video and, if negotiated, datachannels
  160.                                                 media: { audioSend: false, videoSend: false, data: true },
  161.                                                 customizeSdp: function(jsep) {
  162.                                                     if(stereo && jsep.sdp.indexOf("stereo=1") == -1) {
  163.                                                         // Make sure that our offer contains stereo too
  164.                                                         jsep.sdp = jsep.sdp.replace("useinbandfec=1", "useinbandfec=1;stereo=1");
  165.                                                     }
  166.                                                 },
  167.                                                 success: function(jsep) {
  168.                                                     Janus.debug("Got SDP!", jsep);
  169.                                                     var body = { request: "start" };
  170.                                                     streaming.send({ message: body, jsep: jsep });
  171.                                                     $('#watch').html("Stop").removeAttr('disabled').click(stopStream);
  172.                                                 },
  173.                                                 error: function(error) {
  174.                                                     Janus.error("WebRTC error:", error);
  175.                                                     bootbox.alert("WebRTC error... " + error.message);
  176.                                                 }
  177.                                             });
  178.                                     }
  179.                                 },
  180.                                 onremotestream: function(stream) {
  181.                                     Janus.debug(" ::: Got a remote stream :::", stream);
  182.                                     var addButtons = false;
  183.                                     if($('#remotevideo').length === 1) {
  184.                                         addButtons = true;
  185.                                         //$('#stream').append('<video class="rounded centered hide" id="remotevideo" width="100%" height="100%" playsinline/>');
  186.                                         $('#remotevideo').get(0).volume = 0;
  187.                                         // Show the stream and hide the spinner when we get a playing event
  188.                                         $("#remotevideo").bind("playing", function () {
  189.                                             $('#waitingvideo').remove();
  190.                                             if(this.videoWidth)
  191.                                                 $('#remotevideo').removeClass('hide').show();
  192.                                             if(spinner)
  193.                                                 spinner.stop();
  194.                                             spinner = null;
  195.                                             var videoTracks = stream.getVideoTracks();
  196.                                             if(!videoTracks || videoTracks.length === 0)
  197.                                                 return;
  198.                                             var width = this.videoWidth;
  199.                                             var height = this.videoHeight;
  200.                                             $('#curres').removeClass('hide').text(width+'x'+height).show();
  201.                                             if(Janus.webRTCAdapter.browserDetails.browser === "firefox") {
  202.                                                 // Firefox Stable has a bug: width and height are not immediately available after a playing
  203.                                                 setTimeout(function() {
  204.                                                     var width = $("#remotevideo").get(0).videoWidth;
  205.                                                     var height = $("#remotevideo").get(0).videoHeight;
  206.                                                     $('#curres').removeClass('hide').text(width+'x'+height).show();
  207.                                                 }, 2000);
  208.                                             }
  209.                                         });
  210.                                     }
  211.                                     Janus.attachMediaStream($('#remotevideo').get(0), stream);
  212.                                     $("#remotevideo").get(0).play();
  213.                                     $("#remotevideo").get(0).volume = 1;
  214.                                     var videoTracks = stream.getVideoTracks();
  215.                                     if(!videoTracks || videoTracks.length === 0) {
  216.                                         // No remote video
  217.                                         $('#remotevideo').hide();
  218.                                         if($('#stream .no-video-container').length === 0) {
  219.                                             $('#stream').append(
  220.                                                 '<div class="no-video-container">' +
  221.                                                     '<i class="fa fa-video-camera fa-5 no-video-icon"></i>' +
  222.                                                     '<span class="no-video-text">No remote video available</span>' +
  223.                                                 '</div>');
  224.                                         }
  225.                                     } else {
  226.                                         $('#stream .no-video-container').remove();
  227.                                         $('#remotevideo').removeClass('hide').show();
  228.                                     }
  229.                                     if(!addButtons)
  230.                                         return;
  231.                                     if(videoTracks && videoTracks.length &&
  232.                                             (Janus.webRTCAdapter.browserDetails.browser === "chrome" ||
  233.                                                 Janus.webRTCAdapter.browserDetails.browser === "firefox" ||
  234.                                                 Janus.webRTCAdapter.browserDetails.browser === "safari")) {
  235.                                         $('#curbitrate').removeClass('hide').show();
  236.                                         bitrateTimer = setInterval(function() {
  237.                                             // Display updated bitrate, if supported
  238.                                             var bitrate = streaming.getBitrate();
  239.                                             $('#curbitrate').text(bitrate);
  240.                                             // Check if the resolution changed too
  241.                                             var width = $("#remotevideo").get(0).videoWidth;
  242.                                             var height = $("#remotevideo").get(0).videoHeight;
  243.                                             if(width > 0 && height > 0)
  244.                                                 $('#curres').removeClass('hide').text(width+'x'+height).show();
  245.                                         }, 1000);
  246.                                     }
  247.                                 },
  248.                                 ondataopen: function(data) {
  249.                                     Janus.log("The DataChannel is available!");
  250.                                     $('#waitingvideo').remove();
  251.                                     $('#stream').append(
  252.                                         '<input class="form-control" type="text" id="datarecv" disabled></input>'
  253.                                     );
  254.                                     if(spinner)
  255.                                         spinner.stop();
  256.                                     spinner = null;
  257.                                 },
  258.                                 ondata: function(data) {
  259.                                     Janus.debug("We got data from the DataChannel!", data);
  260.                                     $('#datarecv').val(data);
  261.                                 },
  262.                                 oncleanup: function() {
  263.                                     Janus.log(" ::: Got a cleanup notification :::");
  264.                                     $('#waitingvideo').remove();
  265.                                     $('#remotevideo').remove();
  266.                                     $('#datarecv').remove();
  267.                                     $('.no-video-container').remove();
  268.                                     $('#bitrate').attr('disabled', true);
  269.                                     $('#bitrateset').html('Bandwidth<span class="caret"></span>');
  270.                                     $('#curbitrate').hide();
  271.                                     if(bitrateTimer)
  272.                                         clearInterval(bitrateTimer);
  273.                                     bitrateTimer = null;
  274.                                     $('#curres').hide();
  275.                                     $('#simulcast').remove();
  276.                                     $('#metadata').empty();
  277.                                     $('#info').addClass('hide').hide();
  278.                                     simulcastStarted = false;
  279.                                 }
  280.                             });
  281.                     },
  282.                     error: function(error) {
  283.                         Janus.error(error);
  284.                         bootbox.alert(error, function() {
  285.                             window.location.reload();
  286.                         });
  287.                     },
  288.                     destroyed: function() {
  289.                         window.location.reload();
  290.                     }
  291.                 });
  292.         //});
  293.     }});
  294. });
  295.  
  296. function updateStreamsList() {
  297.     $('#update-streams').unbind('click').addClass('fa-spin');
  298.     var body = { request: "list" };
  299.     Janus.debug("Sending message:", body);
  300.     streaming.send({ message: body, success: function(result) {
  301.         setTimeout(function() {
  302.             $('#update-streams').removeClass('fa-spin').click(updateStreamsList);
  303.         }, 500);
  304.         if(!result) {
  305.             bootbox.alert("Got no response to our query for available streams");
  306.             return;
  307.         }
  308.         if(result["list"]) {
  309.             $('#streams').removeClass('hide').show();
  310.             $('#streamslist').empty();
  311.             $('#watch').attr('disabled', true).unbind('click');
  312.             var list = result["list"];
  313.             Janus.log("Got a list of available streams");
  314.             if(list && Array.isArray(list)) {
  315.                 list.sort(function(a, b) {
  316.                     if(!a || a.id < (b ? b.id : 0))
  317.                         return -1;
  318.                     if(!b || b.id < (a ? a.id : 0))
  319.                         return 1;
  320.                     return 0;
  321.                 });
  322.             }
  323.             Janus.debug(list);
  324.             for(var mp in list) {
  325.                 Janus.debug("  >> [" + list[mp]["id"] + "] " + list[mp]["description"] + " (" + list[mp]["type"] + ")");
  326.                 $('#streamslist').append("<li><a href='#' id='" + list[mp]["id"] + "'>" + list[mp]["description"] + " (" + list[mp]["type"] + ")" + "</a></li>");
  327.             }
  328.             $('#streamslist a').unbind('click').click(function() {
  329.                 selectedStream = $(this).attr("id");
  330.                 $('#streamset').html($(this).html()).parent().removeClass('open');
  331.                 return false;
  332.  
  333.             });
  334.             $('#watch').removeAttr('disabled').unbind('click').click(startStream);
  335.         }
  336.     }});
  337. }
  338.  
  339. function getStreamInfo() {
  340.     $('#metadata').empty();
  341.     $('#info').addClass('hide').hide();
  342.     if(!selectedStream)
  343.         return;
  344.     // Send a request for more info on the mountpoint we subscribed to
  345.     var body = { request: "info", id: parseInt(selectedStream) || selectedStream };
  346.     streaming.send({ message: body, success: function(result) {
  347.         if(result && result.info && result.info.metadata) {
  348.             $('#metadata').html(result.info.metadata);
  349.             $('#info').removeClass('hide').show();
  350.         }
  351.     }});
  352. }
  353.  
  354. function startStream() {
  355.     selectedStream = "1"
  356.     Janus.log("Selected video id #" + selectedStream);
  357.     if(!selectedStream) {
  358.         bootbox.alert("Select a stream from the list");
  359.         return;
  360.     }
  361.     $('#streamset').attr('disabled', true);
  362.     $('#streamslist').attr('disabled', true);
  363.     $('#watch').attr('disabled', true).unbind('click');
  364.     var body = { request: "watch", id: parseInt(selectedStream) || selectedStream};
  365.     streaming.send({ message: body });
  366.     // No remote video yet
  367.     $('#stream').append('<video class="rounded centered" id="waitingvideo" width="100%" height="100%" />');
  368.     if(spinner == null) {
  369.         var target = document.getElementById('stream');
  370.         spinner = new Spinner({top:100}).spin(target);
  371.     } else {
  372.         spinner.spin();
  373.     }
  374.     // Get some more info for the mountpoint to display, if any
  375.     getStreamInfo();
  376. }
  377.  
  378. function stopStream() {
  379.     $('#watch').attr('disabled', true).unbind('click');
  380.     var body = { request: "stop" };
  381.     streaming.send({ message: body });
  382.     streaming.hangup();
  383.     $('#streamset').removeAttr('disabled');
  384.     $('#streamslist').removeAttr('disabled');
  385.     $('#watch').html("Watch or Listen").removeAttr('disabled').unbind('click').click(startStream);
  386.     $('#status').empty().hide();
  387.     $('#bitrate').attr('disabled', true);
  388.     $('#bitrateset').html('Bandwidth<span class="caret"></span>');
  389.     $('#curbitrate').hide();
  390.     if(bitrateTimer)
  391.         clearInterval(bitrateTimer);
  392.     bitrateTimer = null;
  393.     $('#curres').empty().hide();
  394.     $('#simulcast').remove();
  395.     simulcastStarted = false;
  396. }
  397.  
  398. // Helpers to create Simulcast-related UI, if enabled
  399. function addSimulcastButtons(temporal) {
  400.     $('#curres').parent().append(
  401.         '<div id="simulcast" class="btn-group-vertical btn-group-vertical-xs pull-right">' +
  402.         '   <div class"row">' +
  403.         '       <div class="btn-group btn-group-xs" style="width: 100%">' +
  404.         '           <button id="sl-2" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to higher quality" style="width: 33%">SL 2</button>' +
  405.         '           <button id="sl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to normal quality" style="width: 33%">SL 1</button>' +
  406.         '           <button id="sl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to lower quality" style="width: 34%">SL 0</button>' +
  407.         '       </div>' +
  408.         '   </div>' +
  409.         '   <div class"row">' +
  410.         '       <div class="btn-group btn-group-xs hide" style="width: 100%">' +
  411.         '           <button id="tl-2" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 2" style="width: 34%">TL 2</button>' +
  412.         '           <button id="tl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 1" style="width: 33%">TL 1</button>' +
  413.         '           <button id="tl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 0" style="width: 33%">TL 0</button>' +
  414.         '       </div>' +
  415.         '   </div>' +
  416.         '</div>');
  417.     // Enable the simulcast selection buttons
  418.     $('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
  419.         .unbind('click').click(function() {
  420.             toastr.info("Switching simulcast substream, wait for it... (lower quality)", null, {timeOut: 2000});
  421.             if(!$('#sl-2').hasClass('btn-success'))
  422.                 $('#sl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
  423.             if(!$('#sl-1').hasClass('btn-success'))
  424.                 $('#sl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
  425.             $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  426.             streaming.send({ message: { request: "configure", substream: 0 }});
  427.         });
  428.     $('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
  429.         .unbind('click').click(function() {
  430.             toastr.info("Switching simulcast substream, wait for it... (normal quality)", null, {timeOut: 2000});
  431.             if(!$('#sl-2').hasClass('btn-success'))
  432.                 $('#sl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
  433.             $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  434.             if(!$('#sl-0').hasClass('btn-success'))
  435.                 $('#sl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
  436.             streaming.send({ message: { request: "configure", substream: 1 }});
  437.         });
  438.     $('#sl-2').removeClass('btn-primary btn-success').addClass('btn-primary')
  439.         .unbind('click').click(function() {
  440.             toastr.info("Switching simulcast substream, wait for it... (higher quality)", null, {timeOut: 2000});
  441.             $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  442.             if(!$('#sl-1').hasClass('btn-success'))
  443.                 $('#sl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
  444.             if(!$('#sl-0').hasClass('btn-success'))
  445.                 $('#sl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
  446.             streaming.send({ message: { request: "configure", substream: 2 }});
  447.         });
  448.     if(!temporal)   // No temporal layer support
  449.         return;
  450.     $('#tl-0').parent().removeClass('hide');
  451.     $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
  452.         .unbind('click').click(function() {
  453.             toastr.info("Capping simulcast temporal layer, wait for it... (lowest FPS)", null, {timeOut: 2000});
  454.             if(!$('#tl-2').hasClass('btn-success'))
  455.                 $('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
  456.             if(!$('#tl-1').hasClass('btn-success'))
  457.                 $('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
  458.             $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  459.             streaming.send({ message: { request: "configure", temporal: 0 }});
  460.         });
  461.     $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
  462.         .unbind('click').click(function() {
  463.             toastr.info("Capping simulcast temporal layer, wait for it... (medium FPS)", null, {timeOut: 2000});
  464.             if(!$('#tl-2').hasClass('btn-success'))
  465.                 $('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
  466.             $('#tl-1').removeClass('btn-primary btn-info').addClass('btn-info');
  467.             if(!$('#tl-0').hasClass('btn-success'))
  468.                 $('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
  469.             streaming.send({ message: { request: "configure", temporal: 1 }});
  470.         });
  471.     $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary')
  472.         .unbind('click').click(function() {
  473.             toastr.info("Capping simulcast temporal layer, wait for it... (highest FPS)", null, {timeOut: 2000});
  474.             $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  475.             if(!$('#tl-1').hasClass('btn-success'))
  476.                 $('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
  477.             if(!$('#tl-0').hasClass('btn-success'))
  478.                 $('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
  479.             streaming.send({ message: { request: "configure", temporal: 2 }});
  480.         });
  481. }
  482.  
  483. function updateSimulcastButtons(substream, temporal) {
  484.     // Check the substream
  485.     if(substream === 0) {
  486.         toastr.success("Switched simulcast substream! (lower quality)", null, {timeOut: 2000});
  487.         $('#sl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
  488.         $('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
  489.         $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  490.     } else if(substream === 1) {
  491.         toastr.success("Switched simulcast substream! (normal quality)", null, {timeOut: 2000});
  492.         $('#sl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
  493.         $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  494.         $('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
  495.     } else if(substream === 2) {
  496.         toastr.success("Switched simulcast substream! (higher quality)", null, {timeOut: 2000});
  497.         $('#sl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  498.         $('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
  499.         $('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
  500.     }
  501.     // Check the temporal layer
  502.     if(temporal === 0) {
  503.         toastr.success("Capped simulcast temporal layer! (lowest FPS)", null, {timeOut: 2000});
  504.         $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
  505.         $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
  506.         $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  507.     } else if(temporal === 1) {
  508.         toastr.success("Capped simulcast temporal layer! (medium FPS)", null, {timeOut: 2000});
  509.         $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
  510.         $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  511.         $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
  512.     } else if(temporal === 2) {
  513.         toastr.success("Capped simulcast temporal layer! (highest FPS)", null, {timeOut: 2000});
  514.         $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  515.         $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
  516.         $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
  517.     }
  518. }
  519.  
  520. // Helpers to create SVC-related UI for a new viewer
  521. function addSvcButtons() {
  522.     if($('#svc').length > 0)
  523.         return;
  524.     $('#curres').parent().append(
  525.         '<div id="svc" class="btn-group-vertical btn-group-vertical-xs pull-right">' +
  526.         '   <div class"row">' +
  527.         '       <div class="btn-group btn-group-xs" style="width: 100%">' +
  528.         '           <button id="sl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to normal resolution" style="width: 50%">SL 1</button>' +
  529.         '           <button id="sl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Switch to low resolution" style="width: 50%">SL 0</button>' +
  530.         '       </div>' +
  531.         '   </div>' +
  532.         '   <div class"row">' +
  533.         '       <div class="btn-group btn-group-xs" style="width: 100%">' +
  534.         '           <button id="tl-2" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 2 (high FPS)" style="width: 34%">TL 2</button>' +
  535.         '           <button id="tl-1" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 1 (medium FPS)" style="width: 33%">TL 1</button>' +
  536.         '           <button id="tl-0" type="button" class="btn btn-primary" data-toggle="tooltip" title="Cap to temporal layer 0 (low FPS)" style="width: 33%">TL 0</button>' +
  537.         '       </div>' +
  538.         '   </div>' +
  539.         '</div>'
  540.     );
  541.     // Enable the VP8 simulcast selection buttons
  542.     $('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
  543.         .unbind('click').click(function() {
  544.             toastr.info("Switching SVC spatial layer, wait for it... (low resolution)", null, {timeOut: 2000});
  545.             if(!$('#sl-1').hasClass('btn-success'))
  546.                 $('#sl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
  547.             $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  548.             streaming.send({ message: { request: "configure", spatial_layer: 0 }});
  549.         });
  550.     $('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
  551.         .unbind('click').click(function() {
  552.             toastr.info("Switching SVC spatial layer, wait for it... (normal resolution)", null, {timeOut: 2000});
  553.             $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  554.             if(!$('#sl-0').hasClass('btn-success'))
  555.                 $('#sl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
  556.             streaming.send({ message: { request: "configure", spatial_layer: 1 }});
  557.         });
  558.     $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary')
  559.         .unbind('click').click(function() {
  560.             toastr.info("Capping SVC temporal layer, wait for it... (lowest FPS)", null, {timeOut: 2000});
  561.             if(!$('#tl-2').hasClass('btn-success'))
  562.                 $('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
  563.             if(!$('#tl-1').hasClass('btn-success'))
  564.                 $('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
  565.             $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  566.             streaming.send({ message: { request: "configure", temporal_layer: 0 }});
  567.         });
  568.     $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary')
  569.         .unbind('click').click(function() {
  570.             toastr.info("Capping SVC temporal layer, wait for it... (medium FPS)", null, {timeOut: 2000});
  571.             if(!$('#tl-2').hasClass('btn-success'))
  572.                 $('#tl-2').removeClass('btn-primary btn-info').addClass('btn-primary');
  573.             $('#tl-1').removeClass('btn-primary btn-info').addClass('btn-info');
  574.             if(!$('#tl-0').hasClass('btn-success'))
  575.                 $('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
  576.             streaming.send({ message: { request: "configure", temporal_layer: 1 }});
  577.         });
  578.     $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary')
  579.         .unbind('click').click(function() {
  580.             toastr.info("Capping SVC temporal layer, wait for it... (highest FPS)", null, {timeOut: 2000});
  581.             $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-info');
  582.             if(!$('#tl-1').hasClass('btn-success'))
  583.                 $('#tl-1').removeClass('btn-primary btn-info').addClass('btn-primary');
  584.             if(!$('#tl-0').hasClass('btn-success'))
  585.                 $('#tl-0').removeClass('btn-primary btn-info').addClass('btn-primary');
  586.             streaming.send({ message: { request: "configure", temporal_layer: 2 }});
  587.         });
  588. }
  589.  
  590. function updateSvcButtons(spatial, temporal) {
  591.     // Check the spatial layer
  592.     if(spatial === 0) {
  593.         toastr.success("Switched SVC spatial layer! (lower resolution)", null, {timeOut: 2000});
  594.         $('#sl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
  595.         $('#sl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  596.     } else if(spatial === 1) {
  597.         toastr.success("Switched SVC spatial layer! (normal resolution)", null, {timeOut: 2000});
  598.         $('#sl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  599.         $('#sl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
  600.     }
  601.     // Check the temporal layer
  602.     if(temporal === 0) {
  603.         toastr.success("Capped SVC temporal layer! (lowest FPS)", null, {timeOut: 2000});
  604.         $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
  605.         $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
  606.         $('#tl-0').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  607.     } else if(temporal === 1) {
  608.         toastr.success("Capped SVC temporal layer! (medium FPS)", null, {timeOut: 2000});
  609.         $('#tl-2').removeClass('btn-primary btn-success').addClass('btn-primary');
  610.         $('#tl-1').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  611.         $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
  612.     } else if(temporal === 2) {
  613.         toastr.success("Capped SVC temporal layer! (highest FPS)", null, {timeOut: 2000});
  614.         $('#tl-2').removeClass('btn-primary btn-info btn-success').addClass('btn-success');
  615.         $('#tl-1').removeClass('btn-primary btn-success').addClass('btn-primary');
  616.         $('#tl-0').removeClass('btn-primary btn-success').addClass('btn-primary');
  617.     }
  618. }
  619.  
  620. // Start the stream after the entire page has loaded
  621. window.onload = function(){
  622.     setTimeout(function(){
  623.         startStream();
  624.     }, 500);
  625. }
  626.  
  627. $("#remotevideo").hover(function(event) {
  628.     if(event.type === "mouseenter") {
  629.         $(this).attr("controls", "");
  630.     } else if(event.type === "mouseleave") {
  631.         $(this).removeAttr("controls");
  632.     }
  633. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement