// 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. /* global iceServers:readonly, Janus:readonly, server:readonly */ var janus = null; var recordplay = null; var opaqueId = "recordplaytest-" + Janus.randomString(12); var localTracks = {}, localVideos = 0, remoteTracks = {}, remoteVideos = 0; var bandwidth = 1024 * 1024; var myname = null; var recording = false; var playing = false; var recordingId = null; var selectedRecording = null; var selectedRecordingInfo = null; var acodec = getQueryStringValue("acodec") !== "" ? getQueryStringValue("acodec") : null; var vcodec = getQueryStringValue("vcodec") !== "" ? getQueryStringValue("vcodec") : null; var vprofile = getQueryStringValue("vprofile") !== "" ? getQueryStringValue("vprofile") : null; var doSimulcast = getQueryStringValue("simulcast") === "yes" || getQueryStringValue("simulcast") === "true"; var doOpusred = getQueryStringValue("opusred") === "yes" || getQueryStringValue("opusred") === "true"; var recordData = getQueryStringValue("data") !== "" ? getQueryStringValue("data") : null; if (recordData !== "text" && recordData !== "binary") recordData = null; $(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: 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 Record&Play plugin janus.attach({ plugin: "janus.plugin.recordplay", opaqueId: opaqueId, success: function (pluginHandle) { $("#details").remove(); recordplay = pluginHandle; Janus.log( "Plugin attached! (" + recordplay.getPlugin() + ", id=" + recordplay.getId() + ")" ); // Prepare the name prompt $("#recordplay").removeClass("hide"); $("#start") .removeAttr("disabled") .html("Stop") .click(function () { $(this).attr("disabled", true); janus.destroy(); }); updateRecsList(); }, 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: '
', baseZ: 3001, css: { border: "none", padding: "15px", backgroundColor: "transparent", color: "#aaa", top: "10px", left: "100px", }, }); } else { // Restore screen $.unblockUI(); } }, iceState: function (state) { Janus.log("ICE state changed to " + state); }, mediaState: function (medium, on, mid) { Janus.log( "Janus " + (on ? "started" : "stopped") + " receiving our " + medium + " (mid=" + mid + ")" ); }, webrtcState: function (on) { Janus.log( "Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now" ); $("#videobox").parent().unblock(); }, 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); let result = msg["result"]; if (result) { if (result["status"]) { let event = result["status"]; if (event === "preparing" || event === "refreshing") { Janus.log("Preparing the recording playout"); recordplay.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" }], success: function (jsep) { Janus.debug("Got SDP!", jsep); let body = { request: "start" }; recordplay.send({ message: body, jsep: jsep }); }, error: function (error) { Janus.error("WebRTC error:", error); bootbox.alert("WebRTC error... " + error.message); }, }); if (result["warning"]) bootbox.alert(result["warning"]); } else if (event === "recording") { // Got an ANSWER to our recording OFFER if (jsep) recordplay.handleRemoteJsep({ jsep: jsep }); let id = result["id"]; if (id) { Janus.log("The ID of the current recording is " + id); recordingId = id; } } else if (event === "playing") { Janus.log("Playout has started!"); } else if (event === "stopped") { Janus.log("Session has stopped!"); let id = result["id"]; if (recordingId) { if (recordingId !== id) { Janus.warn("Not a stop to our recording?"); return; } bootbox.alert( "Recording completed! Check the list of recordings to replay it." ); } if (selectedRecording) { if (selectedRecording !== id) { Janus.warn("Not a stop to our playout?"); return; } } // FIXME Reset status $("#videobox").empty(); $("#video").addClass("invisible"); recordingId = null; recording = false; playing = false; recordplay.hangup(); $("#record").removeAttr("disabled").click(startRecording); $("#play").removeAttr("disabled").click(startPlayout); $("#list").removeAttr("disabled").click(updateRecsList); $("#recset").removeAttr("disabled"); $("#recslist").removeAttr("disabled"); updateRecsList(); } } } else { // FIXME Error? let error = msg["error"]; bootbox.alert(error); // FIXME Reset status $("#videobox").empty(); $("#video").addClass("invisible"); recording = false; playing = false; recordplay.hangup(); $("#record").removeAttr("disabled").click(startRecording); $("#play").removeAttr("disabled").click(startPlayout); $("#list").removeAttr("disabled").click(updateRecsList); $("#recset").removeAttr("disabled"); $("#recslist").removeAttr("disabled"); updateRecsList(); } }, onlocaltrack: function (track, on) { if (playing === true) return; Janus.debug( "Local track " + (on ? "added" : "removed") + ":", track ); // We use the track ID as name of the element, but it may contain invalid characters let trackId = track.id.replace(/[{}]/g, ""); if (!on) { // Track removed, get rid of the stream and the rendering let stream = localTracks[trackId]; if (stream) { try { let tracks = stream.getTracks(); for (let i in tracks) { let mst = tracks[i]; if (mst) mst.stop(); } // eslint-disable-next-line no-unused-vars } catch (e) {} } if (track.kind === "video") { $("#thevideo" + trackId).remove(); localVideos--; if (localVideos === 0) { // No video, at least for now: show a placeholder if ($("#videobox .no-video-container").length === 0) { $("#videobox").append( '
' + '' + 'No webcam available' + "
" ); } } } delete localTracks[trackId]; return; } // If we're here, a new track was added let stream = localTracks[trackId]; if (stream) { // We've been here already return; } $("#videotitle").html("Recording..."); $("#stop").unbind("click").click(stopRecPlay); $("#video").removeClass("invisible"); if (track.kind === "audio") { // We ignore local audio tracks, they'd generate echo anyway if (localVideos === 0) { // No video, at least for now: show a placeholder if ($("#videobox .no-video-container").length === 0) { $("#videobox").append( '
' + '' + 'No webcam available' + "
" ); } } } else { // New video track: create a stream out of it localVideos++; $("#videobox .no-video-container").remove(); let stream = new MediaStream([track]); localTracks[trackId] = stream; Janus.log("Created local stream:", stream); $("#videobox").append( '