From 45ce83283b079f1989752673a7e8fd842f29bd19 Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Tue, 28 Jan 2025 16:46:10 +0530 Subject: [PATCH 01/14] fix --- MediaPushPlugin/redeploy.sh | 6 +++--- .../main/java/io/antmedia/plugin/MediaPushPlugin.java | 10 +++------- .../src/main/resources/e4e4da7454e7cf2e6ffa.js | 1 + 3 files changed, 7 insertions(+), 10 deletions(-) create mode 100644 MediaPushPlugin/src/main/resources/e4e4da7454e7cf2e6ffa.js diff --git a/MediaPushPlugin/redeploy.sh b/MediaPushPlugin/redeploy.sh index 0e2f34b3..e2cfa3c8 100755 --- a/MediaPushPlugin/redeploy.sh +++ b/MediaPushPlugin/redeploy.sh @@ -1,8 +1,8 @@ #!/bin/sh AMS_DIR=/usr/local/antmedia/ -AMS_DIR=~/softwares/ant-media-server/ +AMS_DIR=/home/usama/tem/ant-media-server/ -rm src/main/resources/*.js +# rm src/main/resources/*.js cd src/main/js npm install @@ -25,4 +25,4 @@ if [ $OUT -ne 0 ]; then exit $OUT fi cd $AMS_DIR -./start-debug.sh +# ./start-debug.sh diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index 3fdaf330..7f9124d9 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -87,17 +87,11 @@ public Map getDrivers() { "--remote-allow-origins=*", "--enable-usermedia-screen-capturing", "--allow-http-screen-capture", - "--disable-infobars", - "--hide-scrollbars", "--auto-accept-this-tab-capture", "--no-sandbox", "--autoplay-policy=no-user-gesture-required", - "--disable-background-media-suspend", - "--disable-gpu-vsync", "--disable-audio-output", - "--disable-background-timer-throttling", - "--headless=new", - "--start-fullscreen"); + "--disable-background-timer-throttling"); public static final int TIMEOUT_IN_SECONDS = 30; @@ -300,6 +294,7 @@ public RemoteWebDriver openDriver(int width, int height, String recordTypeString List extraChromeSwitchList, String streamId, String publisherUrl, String targetUrl) throws IOException { RemoteWebDriver driver; driver = createDriver(width, height, streamId, extraChromeSwitchList); + driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(TIMEOUT_IN_SECONDS)); driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(TIMEOUT_IN_SECONDS)); @@ -448,6 +443,7 @@ public RemoteWebDriver createDriver(int width, int height, String streamId, List } } + options.addArguments("--disable-blink-features=AutomationControlled"); options.setExperimentalOption("useAutomationExtension", false); options.setExperimentalOption("excludeSwitches", List.of("enable-automation")); options.addArguments(args); diff --git a/MediaPushPlugin/src/main/resources/e4e4da7454e7cf2e6ffa.js b/MediaPushPlugin/src/main/resources/e4e4da7454e7cf2e6ffa.js new file mode 100644 index 00000000..d88ff1f5 --- /dev/null +++ b/MediaPushPlugin/src/main/resources/e4e4da7454e7cf2e6ffa.js @@ -0,0 +1 @@ +var FRAME_PER_SECOND=10,FRAME_INTERVAL=1/FRAME_PER_SECOND;class VolumeMeter extends AudioWorkletProcessor{constructor(){super(),this._lastUpdate=currentTime,this._volume=0,this.stop=!1,this.port.onmessage=e=>{"stop"===e.data&&(this.port.postMessage({type:"debug",message:"Stop command is received"}),this.stop=!0)}}calculateRMS(e){for(var t=0,s=0;sFRAME_INTERVAL&&(this.calculateRMS(s),this.port.postMessage(this._volume),this._lastUpdate=currentTime),!this.stop}debug(e){this.port.postMessage({type:"debug",message:e})}}registerProcessor("volume-meter",VolumeMeter); \ No newline at end of file From 700a96b61d8bc0bd30570366c28f3a8fd2cc769a Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Wed, 29 Jan 2025 15:24:19 +0530 Subject: [PATCH 02/14] forward stop request when driver is not on same node --- .../io/antmedia/plugin/MediaPushPlugin.java | 201 +++++++++++++++++- .../antmedia/rest/MediaPushRestService.java | 1 + .../src/main/js/src/media-push-publisher.js | 4 +- .../main/resources/media-push-publisher.js | 2 +- .../io/antmedia/plugin/EndpointUnitTest.java | 2 +- .../plugin/MediaPushPluginUnitTest.java | 55 ++++- 6 files changed, 246 insertions(+), 19 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index 7f9124d9..cd6a1c13 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -1,5 +1,5 @@ package io.antmedia.plugin; - +import com.google.gson.Gson; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -15,7 +15,22 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; - +import org.apache.http.impl.client.LaxRedirectStrategy; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import org.apache.http.entity.StringEntity; +import java.util.regex.Pattern; +import java.net.InetAddress; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -42,8 +57,10 @@ import org.springframework.stereotype.Component; import io.antmedia.AntMediaApplicationAdapter; +import io.antmedia.filter.JWTFilter; import io.antmedia.RecordType; import io.antmedia.datastore.db.types.Broadcast; +import io.antmedia.filter.TokenFilterManager; import io.antmedia.model.Endpoint; import io.antmedia.plugin.api.IStreamListener; import io.antmedia.rest.model.Result; @@ -70,6 +87,7 @@ public class MediaPushPlugin implements ApplicationContextAware, IStreamListener private boolean initialized = false; private ApplicationContext applicationContext; + public String myPrivateIp = null; public Map getDrivers() { return drivers; @@ -202,6 +220,20 @@ public static boolean isValidURL(String urlString) { return false; } } + + public String getPrivateIpAddress() { + if(myPrivateIp == null){ + try { + InetAddress localhost = InetAddress.getLocalHost(); + myPrivateIp = localhost.getHostAddress().trim(); + } catch (Exception e) { + e.printStackTrace(); + } + } + return myPrivateIp; + } + + @Override public Result startMediaPush(String streamIdPar, String websocketUrl, int width, int height, String url, String token, String recordTypeString) @@ -212,6 +244,7 @@ public Result startMediaPush(String streamIdPar, String websocketUrl, int width, return startMediaPush(streamIdPar, websocketUrl, endpoint); } + @SuppressWarnings("javasecurity:S5334") @Override public Result startMediaPush(String streamIdPar, String websocketUrl, Endpoint endpoint) @@ -255,7 +288,6 @@ public Result startMediaPush(String streamIdPar, String websocketUrl, Endpoint e String publisherUrl = getPublisherHTMLURL(websocketUrl); - driver = openDriver(width, height, recordTypeString, extraChromeSwitchList, streamId, publisherUrl, url); WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(TIMEOUT_IN_SECONDS)); @@ -267,9 +299,12 @@ public Result startMediaPush(String streamIdPar, String websocketUrl, Endpoint e wait.until(ExpectedConditions.jsReturnsValue("return (typeof window.startBroadcasting != 'undefined')")); + String driverIp = getPrivateIpAddress(); + driverIp = "{\"driverIp\":\"" + driverIp + "\"}"; + + String startBroadcastingCommand = String.format("window.startBroadcasting({websocketURL:'%s',streamId:'%s',width:%d,height:%d,token:'%s',driverIp:'%s'});", + websocketUrl, streamId, width, height, StringUtils.isNotBlank(token) ? token : "",driverIp); - String startBroadcastingCommand = String.format("window.startBroadcasting({websocketURL:'%s',streamId:'%s',width:%d,height:%d,token:'%s'});", - websocketUrl, streamId, width, height, StringUtils.isNotBlank(token) ? token : ""); driver.executeScript(startBroadcastingCommand); @@ -295,6 +330,7 @@ public RemoteWebDriver openDriver(int width, int height, String recordTypeString RemoteWebDriver driver; driver = createDriver(width, height, streamId, extraChromeSwitchList); + driver.get(publisherUrl); driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(TIMEOUT_IN_SECONDS)); driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(TIMEOUT_IN_SECONDS)); @@ -342,7 +378,6 @@ private String clearAndQuit(String streamId, RemoteWebDriver driver, Exception e recordingMap.remove(streamId); return "Error message is " + e.getMessage(); } - public String getPublisherHTMLURL(String websocketUrl) throws InvalidArgumentException, URISyntaxException { @@ -370,16 +405,86 @@ public String getPublisherHTMLURL(String websocketUrl) throws InvalidArgumentExc return publisherHtmlURL; } + public boolean isValidIP(String ip) { + if(ip == null) + return false; + + String ipPattern = + "^(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])\\." + + "(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])\\." + + "(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])\\." + + "(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])$"; + + + return Pattern.matches(ipPattern, ip); + } + + public boolean forwardMediaPushStopRequest(String streamId,String ip){ + + AntMediaApplicationAdapter appAdapter = getApplication(); + logger.info("forwarding media push stop request to {}",ip); + try { + CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); + + String url = "http://"+ ip + ":"+ appAdapter.getServerSettings().getDefaultHttpPort() + applicationContext.getApplicationName() + "/rest/v1/media-push/stop/"+ streamId; + logger.info(url); + + String jwtToken = JWTFilter.generateJwtToken(appAdapter.getAppSettings().getClusterCommunicationKey(), System.currentTimeMillis() + 5000); + HttpUriRequest post = RequestBuilder.post().setUri(url) + .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .setHeader(TokenFilterManager.TOKEN_HEADER_FOR_NODE_COMMUNICATION, jwtToken) + .setEntity(new StringEntity("{}", StandardCharsets.UTF_8)) + .build(); + + CloseableHttpResponse response = client.execute(post); + + if (response.getStatusLine().getStatusCode() == 404) { + return false; + } + else if(response.getStatusLine().getStatusCode() == 200){ + return true; + } + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + @Override public Result stopMediaPush(String streamId) { - Result result = new Result(false); - if (!drivers.containsKey(streamId)) - { - logger.warn("Driver does not exist for stream id: {}", streamId); - result.setMessage("Driver does not exist for stream id: " + streamId); + Result result = new Result(false); + if (!drivers.containsKey(streamId)) { + Broadcast broadcast = getBroadcast(streamId); + + if(broadcast == null){ + logger.warn("Driver does not exist for stream id: {}", streamId); + result.setMessage("Driver does not exist for stream id: " + streamId); + return result; + } + + String metaData = broadcast.getMetaData(); + try { + + if (metaData != null && !metaData.equals("null") && !metaData.isEmpty()){ + JsonObject jsonObject = JsonParser.parseString(metaData).getAsJsonObject(); + String driverIp = jsonObject.get("driverIp").getAsString(); + + if(isValidIP(driverIp) && forwardMediaPushStopRequest(streamId, driverIp)){ + result.setSuccess(true); return result; + } } + result.setMessage("Driver does not exist for stream id: " + streamId); + return result; + } + catch(Exception e){ + logger.error(e.getStackTrace().toString()); + } + return result; + } + + RemoteWebDriver driver = drivers.remove(streamId); recordingMap.remove(streamId); @@ -457,6 +562,80 @@ public RemoteWebDriver createDriver(int width, int height, String streamId, List return new ChromeDriver(options); } + public static StringBuffer readResponse(HttpResponse response) throws IOException { + BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); + + StringBuffer result = new StringBuffer(); + String line = ""; + while ((line = rd.readLine()) != null) { + result.append(line); + } + return result; + } + + public Broadcast getBroadcast(String streamId) { + try { + + CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); + Gson gson = new Gson(); + String url = "http://"+ "127.0.0.1" +":5080" + applicationContext.getApplicationName() + "/rest/v2/broadcasts/"+ streamId; + logger.info(url); + + HttpUriRequest get = RequestBuilder.get().setUri(url) + .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .build(); + + CloseableHttpResponse response = client.execute(get); + + StringBuffer result = readResponse(response); + + if (response.getStatusLine().getStatusCode() == 404) { + logger.info("Response to getBroadcast is 404. It means stream is not found or deleted"); + return null; + } + else if (response.getStatusLine().getStatusCode() != 200){ + throw new Exception("Status code not 200 "); + } + Broadcast broadcast = gson.fromJson(result.toString(), Broadcast.class); + return broadcast; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public Broadcast mediaPushStop(String streamId) { + try { + + CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); + Gson gson = new Gson(); + String url = "http://"+ "127.0.0.1" +":5080" + applicationContext.getApplicationName() + "/rest/v2/broadcasts/"+ streamId; + logger.info(url); + + HttpUriRequest get = RequestBuilder.get().setUri(url) + .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .build(); + + CloseableHttpResponse response = client.execute(get); + + StringBuffer result = readResponse(response); + + if (response.getStatusLine().getStatusCode() == 404) { + logger.info("Response to getBroadcast is 404. It means stream is not found or deleted"); + return null; + } + else if (response.getStatusLine().getStatusCode() != 200){ + throw new Exception("Status code not 200 "); + } + Broadcast broadcast = gson.fromJson(result.toString(), Broadcast.class); + return broadcast; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public AntMediaApplicationAdapter getApplication() { diff --git a/MediaPushPlugin/src/main/java/io/antmedia/rest/MediaPushRestService.java b/MediaPushPlugin/src/main/java/io/antmedia/rest/MediaPushRestService.java index 4e68d76d..21c8e81e 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/rest/MediaPushRestService.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/rest/MediaPushRestService.java @@ -127,3 +127,4 @@ String getApplicationName() { return app.getName(); } } + diff --git a/MediaPushPlugin/src/main/js/src/media-push-publisher.js b/MediaPushPlugin/src/main/js/src/media-push-publisher.js index f84144de..6d5731e4 100644 --- a/MediaPushPlugin/src/main/js/src/media-push-publisher.js +++ b/MediaPushPlugin/src/main/js/src/media-push-publisher.js @@ -91,7 +91,7 @@ async function startBroadcasting(message) { callback : (info, obj) => { if (info == "initialized") { console.log("WebRTC adaptor initialized"); - webRTCAdaptorMediaPush.publish(message.streamId, token, "", "", "", ""); + webRTCAdaptorMediaPush.publish(message.streamId, token, "", "", "", "", message.driverIp ,""); } else if (info == "publish_started") { console.log("mediapush_publish_started"); publishStarted = true; @@ -176,4 +176,4 @@ function stopBroadcasting(message) { window.startBroadcasting = startBroadcasting window.stopBroadcasting = stopBroadcasting -window.isConnected = isConnected \ No newline at end of file +window.isConnected = isConnected diff --git a/MediaPushPlugin/src/main/resources/media-push-publisher.js b/MediaPushPlugin/src/main/resources/media-push-publisher.js index 3c0341f0..7d8b57ca 100644 --- a/MediaPushPlugin/src/main/resources/media-push-publisher.js +++ b/MediaPushPlugin/src/main/resources/media-push-publisher.js @@ -1 +1 @@ -(()=>{"use strict";var e={36:(e,t,i)=>{e.exports=i.p+"e4e4da7454e7cf2e6ffa.js"}},t={};function i(r){var a=t[r];if(void 0!==a)return a.exports;var n=t[r]={exports:{}};return e[r](n,n.exports,i),n.exports}i.m=e,i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e;i.g.importScripts&&(e=i.g.location+"");var t=i.g.document;if(!e&&t&&(t.currentScript&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var a=r.length-1;a>-1&&!e;)e=r[a--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),i.p=e})(),i.b=document.baseURI||self.location.href,(()=>{function e(e,t,i,r,a,n,o){try{var s=e[n](o),d=s.value}catch(e){return void i(e)}s.done?t(d):Promise.resolve(d).then(r,a)}function t(t){return function(){var i=this,r=arguments;return new Promise((function(a,n){var o=t.apply(i,r);function s(t){e(o,a,n,s,d,"next",t)}function d(t){e(o,a,n,s,d,"throw",t)}s(void 0)}))}}function r(e,t,i){return(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var i=e[Symbol.toPrimitive];if(void 0!==i){var r=i.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function a(e,t,i){if(!t.has(e))throw new TypeError("attempted to "+i+" private field on non-instance");return t.get(e)}function n(e,t,i){if(!t.has(e))throw new TypeError("attempted to get private field on non-instance");return i}function o(e,t){if(t.has(e))throw new TypeError("Cannot initialize the same private elements twice on an object")}window.log=function(){var e=function(){},t="undefined",i=typeof window!==t&&typeof window.navigator!==t&&/Trident\/|MSIE /.test(window.navigator.userAgent),r=["trace","debug","info","warn","error"];function a(e,t){var i=e[t];if("function"==typeof i.bind)return i.bind(e);try{return Function.prototype.bind.call(i,e)}catch(t){return function(){return Function.prototype.apply.apply(i,[e,arguments])}}}function n(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function o(t,i){for(var a=0;a=0&&i<=s.levels.SILENT))throw"log.setLevel() called with invalid level: "+i;if(n=i,!1!==a&&function(e){var i=(r[e]||"silent").toUpperCase();if(typeof window!==t&&c){try{return void(window.localStorage[c]=i)}catch(e){}try{window.document.cookie=encodeURIComponent(c)+"="+i+";"}catch(e){}}}(i),o.call(s,i,e),typeof console===t&&i{this.debug&&d.debug("websocket connected"),this.pingTimerId=setInterval((()=>{this.sendPing()}),3e3),this.connected=!0,this.connecting=!1,this.callback("initialized"),void 0!==e&&e()},this.wsConn.onmessage=e=>{var t=JSON.parse(e.data);"start"==t.command?(this.debug&&d.debug("received start command"),this.webrtcadaptor.startPublishing(t.streamId)):"takeCandidate"==t.command?(this.debug&&(d.debug("received ice candidate for stream id "+t.streamId),d.debug(t.candidate)),this.webrtcadaptor.takeCandidate(t.streamId,t.label,t.candidate)):"takeConfiguration"==t.command?(this.debug&&d.debug("received remote description type for stream id: "+t.streamId+" type: "+t.type),this.webrtcadaptor.takeConfiguration(t.streamId,t.sdp,t.type,t.idMapping)):"stop"==t.command?(this.debug&&d.debug("Stop command received"),this.webrtcadaptor.closePeerConnection(t.streamId)):"error"==t.command?this.callbackError(t.definition,t):"notification"==t.command?this.callback(t.definition,t):"streamInformation"==t.command||"roomInformation"==t.command?this.callback(t.command,t):"pong"==t.command?this.callback(t.command):"trackList"==t.command?this.callback(t.command,t):"connectWithNewId"==t.command?(this.multiPeerStreamId=t.streamId,this.join(t.streamId)):"peerMessageCommand"==t.command&&this.callback(t.command,t)},this.wsConn.onerror=e=>{this.connecting=!1,this.connected=!1,d.info(" error occured: "+JSON.stringify(e)),this.clearPingTimer(),this.callbackError("WebSocketNotConnected",e)},this.wsConn.onclose=e=>{this.connecting=!1,this.connected=!1,this.debug&&d.debug("connection closed."),this.clearPingTimer(),this.callback("closed",e)}}clearPingTimer(){-1!=this.pingTimerId&&(this.debug&&d.debug("Clearing ping message timer"),clearInterval(this.pingTimerId),this.pingTimerId=-1)}sendPing(){this.wsConn.send(JSON.stringify({command:"ping"}))}close(){this.wsConn.close()}send(e){if(0!=this.connecting||0!=this.connected)try{this.wsConn.send(e),this.debug&&d.debug("sent message:"+e)}catch(t){d.warn("Cannot send message:"+e)}else this.initWebSocketConnection((()=>{this.send(e)}))}isConnected(){return this.connected}isConnecting(){return this.connecting}}var l=window.log;class h{constructor(e){this.context=e,this.instant=0,this.mic=null,this.volumeMeterNode=null}connectToSource(e,t,r){return this.context.audioWorklet.addModule(new URL(i(36),i.b)).then((()=>{this.mic=this.context.createMediaStreamSource(e),this.volumeMeterNode=new AudioWorkletNode(this.context,"volume-meter"),this.volumeMeterNode.port.onmessage=e=>{"debug"==e.data.type?l.debug(e.data.message):(this.instant=e.data,t(this.instant.toFixed(2)),l.debug("Audio level: "+this.instant.toFixed(2)))},this.mic.connect(this.volumeMeterNode)})).catch((e=>{throw void 0!==r&&r(e),l.error("Error in soundmeter: "+e),e}))}stop(){null!=this.volumeMeterNode&&(this.volumeMeterNode.port.postMessage("stop"),this.volumeMeterNode.disconnect(),this.volumeMeterNode.port.close(),this.volumeMeterNode=null),null!=this.mic&&(this.mic.disconnect(),this.mic=null)}}var u=window.log;class m{constructor(e){for(var t in this.bandwidth=1200,this.debug=!1,this.camera_location="top",this.camera_margin=15,this.camera_percent=15,this.mediaConstraints={video:!0,audio:!0},this.getSender=e.getSender,this.publishStreamId=null,this.localStream=null,this.publishMode="camera",this.callback=(e,t)=>{u.debug("Callback info: "+e+" object: "+typeof t!==void 0?JSON.stringify(t):0)},this.callbackError=e=>{u.error(e)},e.userParameters)e.userParameters.hasOwnProperty(t)&&(this[t]=e.userParameters[t]);this.currentVolume=null,this.previousAudioTrack=null,this.silentAudioTrack=null,this.desktopStream=null,this.smallVideoTrack=null,this.blackVideoTrack=null,this.audioContext=new AudioContext,this.oscillator=null,this.primaryAudioTrackGainNode=null,this.secondaryAudioTrackGainNode=null,this.localStreamSoundMeter=null,this.levelCallback=null,this.blackFrameTimer=null,this.desktopCameraCanvasDrawerTimer=null,this.mutedAudioStream=null,this.isMuted=!1,this.meterRefresh=null,this.cameraEnabled=!0,this.replacementStream=null,this.localVideo=this.localVideoElement||document.getElementById(this.localVideoId),this.dummyCanvas=document.createElement("canvas"),this.mediaConstraints?"camera"==this.mediaConstraints.video?this.publishMode="camera":"screen"==this.mediaConstraints.video?this.publishMode="screen":"screen+camera"==this.mediaConstraints.video&&(this.publishMode="screen+camera"):this.mediaConstraints={video:!0,audio:!0},this.checkBrowserScreenShareSupported()}initLocalStream(){if(this.checkWebRTCPermissions(),void 0!==this.mediaConstraints.video&&0!=this.mediaConstraints.video)return this.openStream(this.mediaConstraints);if(void 0!==this.mediaConstraints.audio&&0!=this.mediaConstraints.audio){var e={audio:this.mediaConstraints.audio};return this.navigatorUserMedia(e,(e=>this.gotStream(e)),!0)}return u.debug("no media requested, just return an empty stream"),new Promise(((e,t)=>{e(null)}))}checkWebRTCPermissions(){return"WebSocket"in window?void 0===navigator.mediaDevices?(u.debug("Cannot open camera and mic because of unsecure context. Please Install SSL(https)"),void this.callbackError("UnsecureContext")):void(void 0!==navigator.mediaDevices&&null!=navigator.mediaDevices&&null!=navigator.mediaDevices||this.callbackError("getUserMediaIsNotAllowed")):(u.debug("WebSocket not supported."),void this.callbackError("WebSocketNotSupported"))}getDevices(){return navigator.mediaDevices.enumerateDevices().then((e=>{var t=new Array,i=!1,r=!1;return e.forEach((e=>{"audioinput"!=e.kind&&"videoinput"!=e.kind||(t.push(e),"audioinput"==e.kind&&(i=!0),"videoinput"==e.kind&&(r=!0))})),this.callback("available_devices",t),0==i&&null==this.localStream&&(u.debug("Audio input not found"),u.debug("Retrying to get user media without audio"),this.inputDeviceNotFoundLimit<2?0!=r?(this.openStream({video:!0,audio:!1}),this.inputDeviceNotFoundLimit++):(u.debug("Video input not found"),alert("There is no video or audio input")):alert("No input device found, publish is not possible")),t})).catch((e=>{throw u.error("Cannot get devices -> error name: "+e.name+": "+e.message),e}))}trackDeviceChange(){navigator.mediaDevices.ondevicechange=()=>{this.getDevices()}}setDesktopwithCameraSource(e,t,i){return this.desktopStream=e,this.navigatorUserMedia({video:!0,audio:!1},(r=>{this.smallVideoTrack=r.getVideoTracks()[0];var a=document.createElement("canvas"),n=a.getContext("2d"),o=document.createElement("video");o.srcObject=e,o.play();var s=document.createElement("video");s.srcObject=r,s.play();var d=a.captureStream(15);null!=i&&(e.getVideoTracks()[0].onended=function(e){i(e)}),(null==this.localStream?this.gotStream(d):this.updateVideoTrack(d,t,onended,null)).then((()=>{this.desktopCameraCanvasDrawerTimer=setInterval((()=>{a.width=o.videoWidth,a.height=o.videoHeight,n.drawImage(o,0,0,a.width,a.height);var e,t=o.videoWidth*(this.camera_percent/100),i=s.videoHeight/s.videoWidth*t,r=a.width-t-this.camera_margin;e="top"==this.camera_location?this.camera_margin:a.height-i-this.camera_margin,n.drawImage(s,r,e,t,i)}),66)}))}),!0)}prepareStreamTracks(e,t,i,r){var a=i.getAudioTracks();if(a.length>0&&"camera"==this.publishMode&&(a[0].stop(),i.removeTrack(a[0])),"undefined"!=t&&0!=t){var n={audio:t};return this.navigatorUserMedia(n).then((n=>{n=this.setGainNodeStream(n);var o=t=>{this.callback("screen_share_stopped"),this.setVideoCameraSource(r,e,null,!0)};return"screen"==this.publishMode?this.updateVideoTrack(i,r,o,!0).then((()=>(a.length>0&&(n=this.mixAudioStreams(i,n)),this.updateAudioTrack(n,r,null)))):"screen+camera"==this.publishMode?(a.length>0&&(n=this.mixAudioStreams(i,n)),this.updateAudioTrack(n,r,null).then((()=>this.setDesktopwithCameraSource(i,r,o)))):(0!=t&&null!=t&&i.addTrack(n.getAudioTracks()[0]),i.getVideoTracks().length>0?this.updateVideoTrack(i,r,null,null).then((()=>this.updateAudioTrack(i,r,null).then((()=>this.gotStream(i))))):i.getAudioTracks().length>0?this.updateAudioTrack(i,r,null).then((()=>this.gotStream(i))):this.gotStream(i))})).catch((e=>{throw"NotFoundError"==e.name?this.getDevices():this.callbackError(e.name,e.message),e}))}return this.gotStream(i)}navigatorUserMedia(e,t,i){if("dummy"==e.video||"dummy"==e.audio){var r=new MediaStream;return"dummy"==e.audio&&r.addTrack(this.getSilentAudioTrack()),"dummy"==e.video&&r.addTrack(this.getBlackVideoTrack()),new Promise(((e,t)=>{e(r)}))}return navigator.mediaDevices.getUserMedia(e).then((e=>(void 0===t&&null==t||t(e),e))).catch((e=>{throw 1==i?"NotFoundError"==e.name?this.getDevices():this.callbackError(e.name,e.message):u.warn(e),e}))}navigatorDisplayMedia(e,t){return navigator.mediaDevices.getDisplayMedia(e).then((e=>(void 0!==t&&t(e),e))).catch((e=>{"NotAllowedError"===e.name&&(u.debug("Permission denied error"),this.callbackError("ScreenSharePermissionDenied"),null==this.localStream?this.openStream({video:!0,audio:!0}):this.switchVideoCameraCapture(streamId))}))}getMedia(e,t){var i=!1;return void 0!==e.audio&&0!=e.audio&&(i=e.audio),null!=this.desktopCameraCanvasDrawerTimer&&(clearInterval(this.desktopCameraCanvasDrawerTimer),this.desktopCameraCanvasDrawerTimer=null),"screen+camera"==this.publishMode||"screen"==this.publishMode?this.navigatorDisplayMedia(e).then((r=>(this.smallVideoTrack&&this.smallVideoTrack.stop(),this.prepareStreamTracks(e,i,r,t)))):this.navigatorUserMedia(e).then((r=>(this.smallVideoTrack&&this.smallVideoTrack.stop(),this.prepareStreamTracks(e,i,r,t)))).catch((e=>{"NotFoundError"==e.name?this.getDevices():this.callbackError(e.name,e.message)}))}openStream(e,t){return this.mediaConstraints=e,this.getMedia(e,t).then((()=>{"dummy"!=this.mediaConstraints.video&&null!=this.mediaConstraints.video&&(this.stopBlackVideoTrack(),this.clearBlackVideoTrackTimer()),"dummy"!=this.mediaConstraints.audio&&null!=this.mediaConstraints.audio&&this.stopSilentAudioTrack()}))}closeStream(){this.localStream&&(this.localStream.getVideoTracks().forEach((function(e){e.onended=null,e.stop()})),this.localStream.getAudioTracks().forEach((function(e){e.onended=null,e.stop()}))),this.videoTrack&&this.videoTrack.stop(),this.audioTrack&&this.audioTrack.stop(),this.smallVideoTrack&&this.smallVideoTrack.stop(),this.previousAudioTrack&&this.previousAudioTrack.stop()}checkBrowserScreenShareSupported(){(void 0!==navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia||navigator.getDisplayMedia)&&this.callback("browser_screen_share_supported")}enableSecondStreamInMixedAudio(e){null!=this.secondaryAudioTrackGainNode&&(this.secondaryAudioTrackGainNode.gain.value=e?1:0)}gotStream(e){return this.localStream=e,this.localVideo&&(this.localVideo.srcObject=e),this.getDevices(),this.trackDeviceChange(),new Promise(((e,t)=>{e()}))}changeLocalVideo(e){this.localVideo=e,this.localStream&&(this.localVideo.srcObject=this.localStream)}enableAudioLevelWhenMuted(){navigator.mediaDevices.getUserMedia({video:!1,audio:!0}).then((e=>{this.mutedAudioStream=e,this.mutedSoundMeter=new h(this.audioContext),soundMeter.connectToSource(this.mutedAudioStream,(e=>{e>.1&&this.callback("speaking_but_muted")}),(e=>{e?alert(e):this.meterRefresh=setInterval((()=>{soundMeter.instant.toFixed(2)>.1&&this.callback("speaking_but_muted")}),200)}))})).catch((function(e){u.debug("Can't get the soundlevel on mute")}))}disableAudioLevelWhenMuted(){null!=this.meterRefresh&&(clearInterval(this.meterRefresh),this.meterRefresh=null),null!=this.mutedSoundMeter&&(this.mutedSoundMeter.stop(),this.mutedSoundMeter=null),null!=this.mutedAudioStream&&this.mutedAudioStream.getTracks().forEach((function(e){e.stop()}))}mixAudioStreams(e,t){var i=new MediaStream;e.getVideoTracks().forEach((function(e){i.addTrack(e)}));var r=this.audioContext.createMediaStreamDestination();return e.getAudioTracks().length>0?(this.primaryAudioTrackGainNode=this.audioContext.createGain(),this.primaryAudioTrackGainNode.gain.value=1,this.audioContext.createMediaStreamSource(e).connect(this.primaryAudioTrackGainNode).connect(r)):u.debug("Origin stream does not have audio track"),t.getAudioTracks().length>0?(this.secondaryAudioTrackGainNode=this.audioContext.createGain(),this.secondaryAudioTrackGainNode.gain.value=1,this.audioContext.createMediaStreamSource(t).connect(this.secondaryAudioTrackGainNode).connect(r)):u.debug("Second stream does not have audio track"),r.stream.getAudioTracks().forEach((function(e){i.addTrack(e),u.debug("audio destination add track")})),i}setGainNodeStream(e){if(0!=this.mediaConstraints.audio&&void 0!==this.mediaConstraints.audio){var t=e.getVideoTracks(),i=e.getAudioTracks();this.audioContext=new AudioContext;var r=this.audioContext.createMediaStreamSource(e),a=this.audioContext.createMediaStreamDestination();this.primaryAudioTrackGainNode=this.audioContext.createGain(),r.connect(this.primaryAudioTrackGainNode),this.primaryAudioTrackGainNode.connect(a),null==this.currentVolume?this.primaryAudioTrackGainNode.gain.value=1:this.primaryAudioTrackGainNode.gain.value=this.currentVolume;var n=a.stream;for(var o of t)n.addTrack(o);for(var s of i)n.addTrack(s);return null!==this.previousAudioTrack&&this.previousAudioTrack.stop(),this.previousAudioTrack=n.getAudioTracks()[1],n}return e}switchDesktopCapture(e){return this.publishMode="screen",void 0!==this.mediaConstraints.video&&0!=this.mediaConstraints.video&&(this.mediaConstraints.video=!0),this.getMedia(this.mediaConstraints,e)}switchDesktopCaptureWithCamera(e){return void 0!==this.mediaConstraints.video&&0!=this.mediaConstraints.video&&(this.mediaConstraints.video=!0),this.publishMode="screen+camera",this.getMedia(this.mediaConstraints,e)}updateLocalAudioStream(e,t){var i=e.getAudioTracks()[0];if(null!=this.localStream&&null!=this.localStream.getAudioTracks()[0]){var r=this.localStream.getAudioTracks()[0];r!=i&&(this.localStream.removeTrack(r),r.stop(),this.localStream.addTrack(i))}else null!=this.localStream?this.localStream.addTrack(i):this.localStream=e;null!=this.localVideo&&(this.localVideo.srcObject=this.localStream),null!=t&&(e.getAudioTracks()[0].onended=function(e){t(e)}),this.isMuted?this.muteLocalMic():this.unmuteLocalMic(),null!=this.localStreamSoundMeter&&this.enableAudioLevelForLocalStream(this.levelCallback)}updateLocalVideoStream(e,t,i){i&&null!=this.desktopStream&&this.desktopStream.getVideoTracks()[0].stop();var r=e.getVideoTracks()[0];if(null!=this.localStream&&null!=this.localStream.getVideoTracks()[0]){var a=this.localStream.getVideoTracks()[0];a!=r&&(this.localStream.removeTrack(a),a.stop(),this.localStream.addTrack(r))}else null!=this.localStream?this.localStream.addTrack(r):this.localStream=e;this.localVideo&&(this.localVideo.srcObject=this.localStream),null!=t&&(e.getVideoTracks()[0].onended=function(e){t(e)})}switchAudioInputSource(e,t){var i=this.localStream.getAudioTracks()[0];if(i?i.stop():u.warn("There is no audio track in local stream"),void 0!==t){!0!==this.mediaConstraints.audio?this.mediaConstraints.audio.deviceId=t:this.mediaConstraints.audio={deviceId:t};var r={video:!1,audio:{deviceId:t}};return this.setAudioInputSource(e,r,null,t)}return new Promise(((e,t)=>{t("There is no device id for audio input source")}))}setAudioInputSource(e,t,i){return this.navigatorUserMedia(t,(r=>(r=this.setGainNodeStream(r),this.updateAudioTrack(r,e,t,i))),!0)}switchVideoCameraCapture(e,t,i){return this.localStream&&this.localStream.getVideoTracks().length>0?this.localStream.getVideoTracks()[0].stop():u.warn("There is no video track in local stream"),this.publishMode="camera",navigator.mediaDevices.enumerateDevices().then((i=>{for(var r=0;r{this.updateLocalAudioStream(e,i)})).catch((function(e){throw u.debug(e.name),e})):(this.updateLocalAudioStream(e,i),new Promise(((e,t)=>{e()})))}updateVideoTrack(e,t,i,r){var a=this.getSender(t,"video");return a?a.replaceTrack(e.getVideoTracks()[0]).then((t=>{this.updateLocalVideoStream(e,i,r)})).catch((e=>{u.debug(e.name)})):(this.updateLocalVideoStream(e,i,r),new Promise(((e,t)=>{e()})))}getBlackVideoTrack(){return this.dummyCanvas.getContext("2d").fillRect(0,0,320,240),this.replacementStream=this.dummyCanvas.captureStream(),null==this.blackFrameTimer&&(this.blackFrameTimer=setInterval((()=>{this.getBlackVideoTrack()}),3e3)),this.blackVideoTrack=this.replacementStream.getVideoTracks()[0],this.blackVideoTrack}getSilentAudioTrack(){this.stopSilentAudioTrack(),this.oscillator=this.audioContext.createOscillator();var e=this.oscillator.connect(this.audioContext.createMediaStreamDestination());return this.oscillator.start(),this.silentAudioTrack=e.stream.getAudioTracks()[0],this.silentAudioTrack}stopSilentAudioTrack(){null!=this.oscillator&&(this.oscillator.stop(),this.oscillator.disconnect(),this.oscillator=null),null!=this.silentAudioTrack&&(this.silentAudioTrack.stop(),this.silentAudioTrack=null)}turnOffLocalCamera(e){var t;return this.getBlackVideoTrack(),null!=this.localStream?(t=null!=e||void 0!==e?e:this.publishStreamId,this.cameraEnabled=!1,this.updateVideoTrack(this.replacementStream,t,null,!0)):new Promise(((e,t)=>{this.callbackError("NoActiveConnection"),t("NoActiveStream")}))}clearBlackVideoTrackTimer(){null!=this.blackFrameTimer&&(clearInterval(this.blackFrameTimer),this.blackFrameTimer=null)}stopBlackVideoTrack(){null!=this.blackVideoTrack&&(this.blackVideoTrack.stop(),this.blackVideoTrack=null)}turnOnLocalCamera(e){return this.clearBlackVideoTrackTimer(),this.stopBlackVideoTrack(),null==this.localStream?this.navigatorUserMedia(this.mediaConstraints,(e=>{this.gotStream(e)}),!1):this.navigatorUserMedia(this.mediaConstraints,(t=>{var i;i=null!=e||void 0!==e?e:this.publishStreamId,this.cameraEnabled=!0,this.updateVideoTrack(t,i,null,!0)}),!1)}muteLocalMic(){this.isMuted=!0,null!=this.localStream?this.localStream.getAudioTracks().forEach((e=>e.enabled=!1)):this.callbackError("NoActiveConnection")}unmuteLocalMic(){this.isMuted=!1,null!=this.localStream?this.localStream.getAudioTracks().forEach((e=>e.enabled=!0)):this.callbackError("NoActiveConnection")}getVideoSender(e){var t=null;return"undefined"!=typeof adapter&&null!==adapter&&("chrome"===adapter.browserDetails.browser||"firefox"===adapter.browserDetails.browser||"safari"===adapter.browserDetails.browser&&adapter.browserDetails.version>=64)&&"RTCRtpSender"in window&&"setParameters"in window.RTCRtpSender.prototype&&(t=this.getSender(e,"video")),t}changeBandwidth(e,t){var i=this.getVideoSender(t);if(null!=i){var r=i.getParameters();return r.encodings||(r.encodings=[{}]),"unlimited"===e?delete r.encodings[0].maxBitrate:r.encodings[0].maxBitrate=1e3*e,i.setParameters(r)}return"Video sender not found to change bandwidth. Streaming may not be active",Promise.reject("Video sender not found to change bandwidth. Streaming may not be active")}setVolumeLevel(e){this.currentVolume=e,null!=this.primaryAudioTrackGainNode&&(this.primaryAudioTrackGainNode.gain.value=e),null!=this.secondaryAudioTrackGainNode&&(this.secondaryAudioTrackGainNode.gain.value=e)}enableAudioLevelForLocalStream(e){return this.levelCallback=e,this.disableAudioLevelForLocalStream(),this.localStreamSoundMeter=new h(this.audioContext),"running"!==this.audioContext.state?this.audioContext.resume().then((()=>this.localStreamSoundMeter.connectToSource(this.localStream,e))):this.localStreamSoundMeter.connectToSource(this.localStream,e)}disableAudioLevelForLocalStream(){null!=this.localStreamSoundMeter&&(this.localStreamSoundMeter.stop(),this.localStreamSoundMeter=null)}applyConstraints(e){var t={};void 0===e.audio&&void 0===e.video?(t.video=e,this.mediaConstraints.video=Object.assign({},this.mediaConstraints.video,t.video)):void 0!==e.video&&(t.video=e.video,this.mediaConstraints.video=Object.assign({},this.mediaConstraints.video,t.video)),void 0!==e.audio&&(t.audio=e.audio,this.mediaConstraints.audio=Object.assign({},this.mediaConstraints.audio,t.audio));var i=null;return void 0!==t.video&&(i=this.localStream&&this.localStream.getVideoTracks().length>0?this.localStream.getVideoTracks()[0].applyConstraints(this.mediaConstraints.video):new Promise(((e,t)=>{t("There is no video track to apply constraints")}))),void 0!==t.audio&&(i=this.setAudioInputSource(this.publishStreamId,{audio:this.mediaConstraints.audio},null)),null!=this.localStreamSoundMeter&&this.enableAudioLevelForLocalStream(this.levelCallback),i}}var p=window.log;class f{constructor(e){this.size=e,this.received=0,this.data=new ArrayBuffer(e)}}class g{static register(e){g.pluginInitMethods.push(e)}constructor(e){for(var t in this.peerconnection_config={iceServers:[{urls:"stun:stun1.l.google.com:19302"}],sdpSemantics:"unified-plan"},this.sdp_constraints={OfferToReceiveAudio:!1,OfferToReceiveVideo:!1},this.remotePeerConnection=new Array,this.remotePeerConnectionStats=new Array,this.remoteDescriptionSet=new Array,this.iceCandidateList=new Array,this.roomName=null,this.playStreamId=new Array,this.isMultiPeer=!1,this.multiPeerStreamId=null,this.webSocketAdaptor=null,this.isPlayMode=!1,this.debug=!1,this.publishStreamId=null,this.idMapping=new Array,this.onlyDataChannel=!1,this.dataChannelEnabled=!0,this.receivingMessages=new Map,this.candidateTypes=["udp","tcp"],this.callback=null,this.callbackError=null,this.reconnectIfRequiredFlag=!0,this.websocket_url=null,this.websocketURL=null,this.initializeComponents=!0,e)e.hasOwnProperty(t)&&(this[t]=e[t]);if(null==this.websocketURL&&(this.websocketURL=this.websocket_url),null==this.websocketURL)throw new Error("WebSocket URL is not defined. It's mandatory");this.remoteVideo=this.remoteVideoElement||document.getElementById(this.remoteVideoId),this.soundMeters=new Array,this.soundLevelList=new Array,this.eventListeners=new Array,this.errorEventListeners=new Array,this.publishToken=null,this.publishSubscriberId=null,this.publishSubscriberCode=null,this.publishStreamName=null,this.publishMainTrack=null,this.publishMetaData=null,this.playToken=null,this.playRoomId=null,this.playEnableTracks=null,this.playSubscriberId=null,this.playSubscriberCode=null,this.playMetaData=null,this.lastReconnectiontionTrialTime=0,this.mediaManager=new m({userParameters:e,webRTCAdaptor:this,callback:(e,t)=>{this.notifyEventListeners(e,t)},callbackError:(e,t)=>{this.notifyErrorEventListeners(e,t)},getSender:(e,t)=>this.getSender(e,t)}),this.initializeComponents&&this.initialize()}initPlugins(){g.pluginInitMethods.forEach((e=>{e(this)}))}addEventListener(e){this.eventListeners.push(e)}addErrorEventListener(e){this.errorEventListeners.push(e)}notifyEventListeners(e,t){this.eventListeners.forEach((i=>{i(e,t)})),null!=this.callback&&this.callback(e,t)}notifyErrorEventListeners(e,t){this.errorEventListeners.forEach((i=>{i(e,t)})),null!=this.callbackError&&this.callbackError(e,t)}initialize(){return this.isPlayMode||this.onlyDataChannel||null!=this.mediaManager.localStream?new Promise(((e,t)=>{this.initPlugins(),this.checkWebSocketConnection(),e("Wait 'initialized' callback from websocket")})):this.mediaManager.initLocalStream().then((()=>(this.initPlugins(),this.checkWebSocketConnection(),new Promise(((e,t)=>{e("Wait 'initialized' callback from websocket")}))))).catch((e=>{throw p.warn(e),e}))}publish(e,t,i,r,a,n,o){if(this.publishStreamId=e,this.mediaManager.publishStreamId=e,this.publishToken=t,this.publishSubscriberId=i,this.publishSubscriberCode=r,this.publishStreamName=a,this.publishMainTrack=n,this.publishMetaData=o,this.onlyDataChannel)this.sendPublishCommand(e,t,i,r,a,n,o,!1,!1);else if(null==this.mediaManager.localStream)this.mediaManager.initLocalStream().then((()=>{var s=!1,d=!1;null!=this.mediaManager.localStream&&(s=this.mediaManager.localStream.getVideoTracks().length>0,d=this.mediaManager.localStream.getAudioTracks().length>0),this.sendPublishCommand(e,t,i,r,a,n,o,s,d)})).catch((e=>{throw p.warn(e),e}));else{var s=this.mediaManager.localStream.getVideoTracks().length>0,d=this.mediaManager.localStream.getAudioTracks().length>0;this.sendPublishCommand(e,t,i,r,a,n,o,s,d)}this.initPeerConnection(e,"publish"),setTimeout((()=>{"checking"!=this.iceConnectionState(this.publishStreamId)&&"connected"!=this.iceConnectionState(this.publishStreamId)&&"completed"!=this.iceConnectionState(this.publishStreamId)&&this.reconnectIfRequired(0)}),5e3)}sendPublishCommand(e,t,i,r,a,n,o,s,d){var c={command:"publish",streamId:e,token:t,subscriberId:void 0!==typeof i&&null!=i?i:"",subscriberCode:void 0!==typeof r&&null!=r?r:"",streamName:void 0!==typeof a&&null!=a?a:"",mainTrack:void 0!==typeof n&&null!=n?n:"",video:s,audio:d,metaData:void 0!==typeof o&&null!=o?o:""};this.webSocketAdaptor.send(JSON.stringify(c))}joinRoom(e,t,i){this.roomName=e;var r={command:"joinRoom",room:e,streamId:t,mode:i};this.webSocketAdaptor.send(JSON.stringify(r))}play(e,t,i,r,a,n,o){this.playStreamId.push(e),this.playToken=t,this.playRoomId=i,this.playEnableTracks=r,this.playSubscriberId=a,this.playSubscriberCode=n,this.playMetaData=o;var s={command:"play",streamId:e,token:void 0!==typeof t&&null!=t?t:"",room:void 0!==typeof i&&null!=i?i:"",trackList:void 0!==typeof r&&null!=r?r:[],subscriberId:void 0!==typeof a&&null!=a?a:"",subscriberCode:void 0!==typeof n&&null!=a?n:"",viewerInfo:void 0!==typeof o&&null!=o?o:""};this.webSocketAdaptor.send(JSON.stringify(s)),this.initPeerConnection(e,"play"),setTimeout((()=>{"checking"!=this.iceConnectionState(e)&&"connected"!=this.iceConnectionState(e)&&"completed"!=this.iceConnectionState(e)&&this.reconnectIfRequired(0)}),5e3)}reconnectIfRequired(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:3e3;this.reconnectIfRequiredFlag&&(e>0?setTimeout((()=>{this.tryAgain()}),e):this.tryAgain())}tryAgain(){var e=Date.now();if(!(e-this.lastReconnectiontionTrialTime<3e3))for(var t in this.lastReconnectiontionTrialTime=e,null!=this.remotePeerConnection[this.publishStreamId]&&"checking"!=this.iceConnectionState(this.publishStreamId)&&"connected"!=this.iceConnectionState(this.publishStreamId)&&"completed"!=this.iceConnectionState(this.publishStreamId)&&(this.notifyEventListeners("reconnection_attempt_for_publisher",this.publishStreamId),this.closePeerConnection(this.publishStreamId),p.log("It will try to publish again because it is not stopped on purpose"),this.publish(this.publishStreamId,this.publishToken,this.publishSubscriberId,this.publishSubscriberCode,this.publishStreamName,this.publishMainTrack,this.publishMetaData)),this.playStreamId){var i=this.playStreamId[t];"null"!=this.remotePeerConnection[i]&&"checking"!=this.iceConnectionState(i)&&"connected"!=this.iceConnectionState(i)&&"completed"!=this.iceConnectionState(i)&&(this.notifyEventListeners("reconnection_attempt_for_player",i),p.log("It will try to play again because it is not stopped on purpose"),this.closePeerConnection(i),this.play(i,this.playToken,this.playRoomId,this.playEnableTracks,this.playSubscriberId,this.playSubscriberCode,this.playMetaData))}}stop(e){if(this.closePeerConnection(e),null!=this.webSocketAdaptor&&this.webSocketAdaptor.isConnected()){var t={command:"stop",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}}join(e){var t={command:"join",streamId:e,multiPeer:this.isMultiPeer&&null==this.multiPeerStreamId,mode:this.isPlayMode?"play":"both"};this.webSocketAdaptor.send(JSON.stringify(t))}onTrack(e,t){if(p.debug("onTrack for stream"),null!=this.remoteVideo)this.remoteVideo.srcObject!==e.streams[0]&&(this.remoteVideo.srcObject=e.streams[0],p.debug("Received remote stream"));else{var i={stream:e.streams[0],track:e.track,streamId:t,trackId:this.idMapping[t][e.transceiver.mid]};this.notifyEventListeners("newTrackAvailable",i),this.notifyEventListeners("newStreamAvailable",i)}}leaveFromRoom(e){for(var t in this.remotePeerConnection)this.closePeerConnection(t);this.roomName=e;var i={command:"leaveFromRoom",room:e};p.debug("leave request is sent for "+e),this.webSocketAdaptor.send(JSON.stringify(i))}leave(e){var t={command:"leave",streamId:this.isMultiPeer&&null!=this.multiPeerStreamId?this.multiPeerStreamId:e};this.webSocketAdaptor.send(JSON.stringify(t)),this.closePeerConnection(e),this.multiPeerStreamId=null}getStreamInfo(e){var t={command:"getStreamInfo",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}requestVideoTrackAssignments(e){var t={command:"getVideoTrackAssignments",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}getBroadcastObject(e){var t={command:"getBroadcastObject",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}updateStreamMetaData(e,t){var i={command:"updateStreamMetaData",streamId:e,metaData:t};this.webSocketAdaptor.send(JSON.stringify(i))}getRoomInfo(e,t){var i={command:"getRoomInfo",streamId:t,room:e};this.webSocketAdaptor.send(JSON.stringify(i))}enableTrack(e,t,i){var r={command:"enableTrack",streamId:e,trackId:t,enabled:i};this.webSocketAdaptor.send(JSON.stringify(r))}getTracks(e,t){this.playStreamId.push(e);var i={command:"getTrackList",streamId:e,token:t};this.webSocketAdaptor.send(JSON.stringify(i))}iceCandidateReceived(e,t){if(e.candidate){var i=!1;if(""==e.candidate.candidate?i=!0:void 0===e.candidate.protocol?this.candidateTypes.forEach((t=>{e.candidate.candidate.toLowerCase().includes(t)&&(i=!0)})):i=this.candidateTypes.includes(e.candidate.protocol.toLowerCase()),i){var r={command:"takeCandidate",streamId:t,label:e.candidate.sdpMLineIndex,id:e.candidate.sdpMid,candidate:e.candidate.candidate};this.debug&&(p.debug("sending ice candiate for stream Id "+t),p.debug(JSON.stringify(e.candidate))),this.webSocketAdaptor.send(JSON.stringify(r))}else p.debug("Candidate's protocol(full sdp: "+e.candidate.candidate+") is not supported. Supported protocols: "+this.candidateTypes),""!=e.candidate.candidate&&this.notifyErrorEventListeners("protocol_not_supported","Support protocols: "+this.candidateTypes.toString()+" candidate: "+e.candidate.candidate)}else p.debug("No event.candidate in the iceCandidate event")}sanitizeHTML(e){return e.includes("script")?e.replace(//g,">"):e}initDataChannel(e,t){t.onerror=i=>{p.debug("Data Channel Error:",i);var r={streamId:e,error:i};p.debug("channel status: ",t.readyState),"closed"!=t.readyState&&this.notifyErrorEventListeners("data_channel_error",r)},t.onmessage=t=>{var i={streamId:e,data:t.data},r=i.data;if("string"==typeof r||r instanceof String)i.data=this.sanitizeHTML(i.data),this.notifyEventListeners("data_received",i);else{var a=r.length||r.size||r.byteLength,n=new Int32Array(r,0,1)[0],o=this.receivingMessages[n];if(null==o){var s=new Int32Array(r,0,2)[1];return o=new f(s),this.receivingMessages[n]=o,void(a>8&&p.debug("something went wrong in msg receiving"))}var d=r.slice(4,a);new Uint8Array(o.data).set(new Uint8Array(d),o.received,a-4),o.received+=a-4,o.size==o.received&&(i.data=o.data,this.notifyEventListeners("data_received",i))}},t.onopen=()=>{this.remotePeerConnection[e].dataChannel=t,p.debug("Data channel is opened"),this.notifyEventListeners("data_channel_opened",e)},t.onclose=()=>{p.debug("Data channel is closed"),this.notifyEventListeners("data_channel_closed",e)}}initPeerConnection(e,t){if(null==this.remotePeerConnection[e]){var i=e;if(p.debug("stream id in init peer connection: "+e+" close stream id: "+i),this.remotePeerConnection[e]=new RTCPeerConnection(this.peerconnection_config),this.remoteDescriptionSet[e]=!1,this.iceCandidateList[e]=new Array,this.playStreamId.includes(e)||null!=this.mediaManager.localStream&&this.mediaManager.localStream.getTracks().forEach((t=>this.remotePeerConnection[e].addTrack(t,this.mediaManager.localStream))),this.remotePeerConnection[e].onicecandidate=e=>{this.iceCandidateReceived(e,i)},this.remotePeerConnection[e].ontrack=e=>{this.onTrack(e,i)},this.remotePeerConnection[e].onnegotiationneeded=e=>{p.debug("onnegotiationneeded")},this.dataChannelEnabled)if("publish"==t)if(this.remotePeerConnection[e].createDataChannel){var r=this.remotePeerConnection[e].createDataChannel(e,{ordered:!0});this.initDataChannel(e,r)}else p.warn("CreateDataChannel is not supported");else if("play"==t)this.remotePeerConnection[e].ondatachannel=t=>{this.initDataChannel(e,t.channel)};else if(this.remotePeerConnection[e].createDataChannel){var a=this.remotePeerConnection[e].createDataChannel(e,{ordered:!0});this.initDataChannel(e,a),this.remotePeerConnection[e].ondatachannel=t=>{this.initDataChannel(e,t.channel)}}else p.warn("CreateDataChannel is not supported");this.remotePeerConnection[e].oniceconnectionstatechange=t=>{var i={state:this.remotePeerConnection[e].iceConnectionState,streamId:e};"failed"!=i.state&&"disconnected"!=i.state&&"closed"!=i.state||this.reconnectIfRequired(3e3),this.notifyEventListeners("ice_connection_state_changed",i),this.isPlayMode||this.playStreamId.includes(e)||"connected"==this.remotePeerConnection[e].iceConnectionState&&this.mediaManager.changeBandwidth(this.mediaManager.bandwidth,e).then((()=>{p.debug("Bandwidth is changed to "+this.mediaManager.bandwidth)})).catch((e=>p.warn(e)))}}}closePeerConnection(e){var t=this.remotePeerConnection[e];if(null!=t){this.remotePeerConnection[e]=null,delete this.remotePeerConnection[e],null!=t.dataChannel&&t.dataChannel.close(),"closed"!=t.signalingState&&t.close();var i=this.playStreamId.indexOf(e);-1!=i&&this.playStreamId.splice(i,1)}null!=this.remotePeerConnectionStats[e]&&(clearInterval(this.remotePeerConnectionStats[e].timerId),delete this.remotePeerConnectionStats[e]),null!=this.soundMeters[e]&&delete this.soundMeters[e]}signallingState(e){return null!=this.remotePeerConnection[e]?this.remotePeerConnection[e].signalingState:null}iceConnectionState(e){return null!=this.remotePeerConnection[e]?this.remotePeerConnection[e].iceConnectionState:null}gotDescription(e,t){this.remotePeerConnection[t].setLocalDescription(e).then((i=>{p.debug("Set local description successfully for stream Id "+t);var r={command:"takeConfiguration",streamId:t,type:e.type,sdp:e.sdp};p.debug("setLocalDescription:"+e.sdp),this.webSocketAdaptor.send(JSON.stringify(r))})).catch((e=>{p.error("Cannot set local description. Error is: "+e)}))}takeConfiguration(e,t,i,r){var a=e,n=i,o=t,s="offer"==n,d="publish";s&&(d="play"),this.idMapping[a]=r,this.initPeerConnection(a,d),p.debug("setRemoteDescription:"+o),this.remotePeerConnection[a].setRemoteDescription(new RTCSessionDescription({sdp:o,type:n})).then((e=>{this.debug&&(p.debug("set remote description is succesfull with response: "+e+" for stream : "+a+" and type: "+n),p.debug(o)),this.remoteDescriptionSet[a]=!0;var t=this.iceCandidateList[a].length;p.debug("Ice candidate list size to be added: "+t);for(var i=0;i{p.debug("created answer for stream id: "+a),e.sdp=e.sdp.replace("useinbandfec=1","useinbandfec=1; stereo=1"),this.gotDescription(e,a)})).catch((e=>{p.error("create answer error :"+e)})))})).catch((e=>{this.debug&&p.error("set remote description is failed with error: "+e),(e.toString().indexOf("InvalidAccessError")>-1||e.toString().indexOf("setRemoteDescription")>-1)&&this.notifyErrorEventListeners("notSetRemoteDescription")}))}takeCandidate(e,t,i){var r=e,a=i,n=new RTCIceCandidate({sdpMLineIndex:t,candidate:a});this.initPeerConnection(r,"peer"),p.debug("takeCandidate:"+a),1==this.remoteDescriptionSet[r]?this.addIceCandidate(r,n):(p.debug("Ice candidate is added to list because remote description is not set yet"),this.iceCandidateList[r].push(n))}addIceCandidate(e,t){var i=!1;""==t.candidate?i=!0:void 0===t.protocol?this.candidateTypes.forEach((e=>{t.candidate.toLowerCase().includes(e)&&(i=!0)})):i=this.candidateTypes.includes(t.protocol.toLowerCase()),i?this.remotePeerConnection[e].addIceCandidate(t).then((t=>{this.debug&&p.debug("Candidate is added for stream "+e)})).catch((i=>{p.error("ice candiate cannot be added for stream id: "+e+" error is: "+i),p.error(t)})):this.debug&&p.debug("Candidate's protocol("+t.protocol+") is not supported.Candidate: "+t.candidate+" Supported protocols:"+this.candidateTypes)}startPublishing(e){var t=e;this.initPeerConnection(t,"publish"),this.remotePeerConnection[t].createOffer(this.sdp_constraints).then((e=>{this.gotDescription(e,t)})).catch((e=>{p.error("create offer error for stream id: "+t+" error: "+e)}))}toggleVideo(e,t,i){var r={command:"toggleVideo",streamId:e,trackId:t,enabled:i};this.webSocketAdaptor.send(JSON.stringify(r))}toggleAudio(e,t,i){var r={command:"toggleAudio",streamId:e,trackId:t,enabled:i};this.webSocketAdaptor.send(JSON.stringify(r))}getStats(e){return p.debug("peerstatsgetstats = "+this.remotePeerConnectionStats[e]),new Promise(((t,i)=>{this.remotePeerConnection[e].getStats(null).then((i=>{var r=-1,a=-1,n=-1,o=-1,s=-1,d=-1,c=-1,l=-1,h=-1,u="",m=-1,p=-1,f=-1,g=-1,v=-1,y=-1,b=-1,S=-1,w=-1,C=-1,k=-1,T=-1,A=-1,E=-1,P=-1,I=1/0;i.forEach((e=>{"inbound-rtp"==e.type&&void 0!==e.kind?(r+=e.bytesReceived,"audio"==e.kind?n=e.packetsLost:"video"==e.kind&&(a=e.packetsLost),o+=e.fractionLost,s=e.timestamp):"outbound-rtp"==e.type?("audio"==e.kind?l=e.packetsSent:"video"==e.kind&&(c=e.packetsSent),d+=e.bytesSent,s=e.timestamp,u=e.qualityLimitationReason,null!=e.framesEncoded&&(m+=e.framesEncoded)):"track"==e.type&&void 0!==e.kind&&"audio"==e.kind?(void 0!==e.audioLevel&&(h=e.audioLevel),void 0!==e.jitterBufferDelay&&void 0!==e.jitterBufferEmittedCount&&(E=e.jitterBufferDelay/e.jitterBufferEmittedCount)):"track"==e.type&&void 0!==e.kind&&"video"==e.kind?(void 0!==e.frameWidth&&(v=e.frameWidth),void 0!==e.frameHeight&&(y=e.frameHeight),void 0!==e.framesDecoded&&(k=e.framesDecoded),void 0!==e.framesDropped&&(T=e.framesDropped),void 0!==e.framesReceived&&(A=e.framesReceived),void 0!==e.jitterBufferDelay&&void 0!==e.jitterBufferEmittedCount&&(P=e.jitterBufferDelay/e.jitterBufferEmittedCount)):"remote-inbound-rtp"==e.type&&void 0!==e.kind?(void 0!==e.packetsLost&&("video"==e.kind?a=e.packetsLost:"audio"==e.kind&&(n=e.packetsLost)),void 0!==e.roundTripTime&&("video"==e.kind?b=e.roundTripTime:"audio"==e.kind&&(w=e.roundTripTime)),void 0!==e.jitter&&("video"==e.kind?S=e.jitter:"audio"==e.kind&&(C=e.jitter))):"media-source"==e.type?"video"==e.kind&&(p=e.width,f=e.height,g=e.framesPerSecond):"candidate-pair"==e.type&&"succeeded"==e.state&&null!=e.availableOutgoingBitrate&&(I=e.availableOutgoingBitrate/1e3)})),this.remotePeerConnectionStats[e].totalBytesReceived=r,this.remotePeerConnectionStats[e].videoPacketsLost=a,this.remotePeerConnectionStats[e].audioPacketsLost=n,this.remotePeerConnectionStats[e].fractionLost=o,this.remotePeerConnectionStats[e].currentTime=s,this.remotePeerConnectionStats[e].totalBytesSent=d,this.remotePeerConnectionStats[e].totalVideoPacketsSent=c,this.remotePeerConnectionStats[e].totalAudioPacketsSent=l,this.remotePeerConnectionStats[e].audioLevel=h,this.remotePeerConnectionStats[e].qualityLimitationReason=u,this.remotePeerConnectionStats[e].totalFramesEncoded=m,this.remotePeerConnectionStats[e].resWidth=p,this.remotePeerConnectionStats[e].resHeight=f,this.remotePeerConnectionStats[e].srcFps=g,this.remotePeerConnectionStats[e].frameWidth=v,this.remotePeerConnectionStats[e].frameHeight=y,this.remotePeerConnectionStats[e].videoRoundTripTime=b,this.remotePeerConnectionStats[e].videoJitter=S,this.remotePeerConnectionStats[e].audioRoundTripTime=w,this.remotePeerConnectionStats[e].audioJitter=C,this.remotePeerConnectionStats[e].framesDecoded=k,this.remotePeerConnectionStats[e].framesDropped=T,this.remotePeerConnectionStats[e].framesReceived=A,this.remotePeerConnectionStats[e].videoJitterAverageDelay=P,this.remotePeerConnectionStats[e].audioJitterAverageDelay=E,this.remotePeerConnectionStats[e].availableOutgoingBitrate=I,this.notifyEventListeners("updated_stats",this.remotePeerConnectionStats[e]),t(!0)})).catch((e=>{t(!1)}))}))}enableStats(e){null==this.remotePeerConnectionStats[e]&&(this.remotePeerConnectionStats[e]=new s(e),this.remotePeerConnectionStats[e].timerId=setInterval((()=>{this.getStats(e)}),5e3))}disableStats(e){null==this.remotePeerConnectionStats[e]&&void 0===this.remotePeerConnectionStats[e]||clearInterval(this.remotePeerConnectionStats[e].timerId)}checkWebSocketConnection(){(null==this.webSocketAdaptor||0==this.webSocketAdaptor.isConnected()&&0==this.webSocketAdaptor.isConnecting())&&(p.debug("websocket url : "+this.websocketURL),this.webSocketAdaptor=new c({websocket_url:this.websocketURL,webrtcadaptor:this,callback:(e,t)=>{"closed"==e&&this.reconnectIfRequired(),this.notifyEventListeners(e,t)},callbackError:(e,t)=>{this.notifyErrorEventListeners(e,t)},debug:this.debug}))}closeWebSocket(){for(var e in this.remotePeerConnection)this.closePeerConnection(e);this.remotePeerConnection=new Array,this.webSocketAdaptor.close()}peerMessage(e,t,i){var r={command:"peerMessageCommand",streamId:e,definition:t,data:i};this.webSocketAdaptor.send(JSON.stringify(r))}forceStreamQuality(e,t){var i={command:"forceStreamQuality",streamId:e,streamHeight:t};this.webSocketAdaptor.send(JSON.stringify(i))}sendData(e,t){if(void 0!==this.remotePeerConnection[e]){var i=this.remotePeerConnection[e].dataChannel;if(null==i||void 0===i)return void p.warn("dataChannel is null or undefined");if("open"!==i.readyState)return void p.warn("dataChannel.readyState is not open: "+i.readyState);var r=t.length||t.size||t.byteLength,a=0;if("string"==typeof t||t instanceof String)i.send(t);else{var n=Math.floor(999999*Math.random()),o=new Int32Array(2);for(o[0]=n,o[1]=r,i.send(o),a=0;a{}),(function(e){e?alert(e):p.debug("Added sound meter for stream: "+t+" = "+i.instant.toFixed(2))})),this.soundMeters[t]=i}getSoundLevelList(e){for(var t=0;ti.length)&&(t=i.length),t-=e.length;var r=i.lastIndexOf(e,t);return-1!==r&&r===t}),function(){function e(e){var t=0;return function(){return t>>0)+"_",a=0;return function e(i){if(this instanceof e)throw TypeError("Symbol is not a constructor");return new t(r+(i||"")+"_"+a++,i)}})),a("Symbol.iterator",(function(t){if(t)return t;t=Symbol("Symbol.iterator");for(var a="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),o=0;o(t=t||0)&&(t=Math.max(t+r,0));tn)r[i++]=n;else{if(2048>n)r[i++]=n>>6|192;else{if(55296<=n&&57343>=n){if(56319>=n&&a=o){n=1024*(n-55296)+o-56320+65536,r[i++]=n>>18|240,r[i++]=n>>12&63|128,r[i++]=n>>6&63|128,r[i++]=63&n|128;continue}a--}if(t)throw Error("Found an unpaired surrogate");n=65533}r[i++]=n>>12|224,r[i++]=n>>6&63|128}r[i++]=63&n|128}}e=r.subarray(0,i)}return e}var O={},_=null;function D(e,t){void 0===t&&(t=0),N(),t=O[t];for(var i=Array(Math.floor(e.length/3)),r=t[64]||"",a=0,n=0;a>2];o=t[(3&o)<<4|s>>4],s=t[(15&s)<<2|d>>6],d=t[63&d],i[n++]=c+o+s+d}switch(c=0,d=r,e.length-a){case 2:d=t[(15&(c=e[a+1]))<<2]||r;case 1:e=e[a],i[n]=t[e>>2]+t[(3&e)<<4|c>>4]+d+r}return i.join("")}function N(){if(!_){_={};for(var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""),t=["+/=","+/","-_=","-_.","-_"],i=0;5>i;i++){var r=e.concat(t[i].split(""));O[i]=r;for(var a=0;a>4),64!=o&&(t(n<<4&240|o>>2),64!=s&&t(o<<6&192|s))}}(i,(function(e){n[o++]=e})),n.subarray(0,o)):t instanceof Uint8Array?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(0),e.h=t,e.j=0,e.i=e.h.length,e.g=e.j}function G(e){var t=e.h,i=t[e.g],r=127&i;return 128>i?(e.g+=1,r):(r|=(127&(i=t[e.g+1]))<<7,128>i?(e.g+=2,r):(r|=(127&(i=t[e.g+2]))<<14,128>i?(e.g+=3,r):(r|=(127&(i=t[e.g+3]))<<21,128>i?(e.g+=4,r):(r|=(15&(i=t[e.g+4]))<<28,128>i?(e.g+=5,r>>>0):(e.g+=5,128<=t[e.g++]&&128<=t[e.g++]&&128<=t[e.g++]&&128<=t[e.g++]&&e.g++,r)))))}function J(e){var t=e.h[e.g],i=e.h[e.g+1],r=e.h[e.g+2],a=e.h[e.g+3];return e.g+=4,e=2*((i=(t<<0|i<<8|r<<16|a<<24)>>>0)>>31)+1,t=i>>>23&255,i&=8388607,255==t?i?NaN:1/0*e:0==t?1401298464324817e-60*e*i:e*Math.pow(2,t-150)*(i+8388608)}U.prototype.reset=function(){this.g=this.j};var H=[];function z(){this.g=new Uint8Array(64),this.h=0}function Y(e,t){for(;127>>=7;e.push(t)}function q(e){var t={},i=void 0!==t.N&&t.N;this.o={v:void 0!==t.v&&t.v},this.N=i,t=this.o,H.length?(i=H.pop(),t&&(i.v=t.v),e&&W(i,e),e=i):e=new U(e,t),this.g=e,this.m=this.g.g,this.h=this.i=this.l=-1,this.j=!1}function X(e){var t=e.g;if((t=t.g==t.i)||(t=e.j)||(t=(t=e.g).l||0>t.g||t.g>t.i),t)return!1;e.m=e.g.g;var i=7&(t=G(e.g));return 0!=i&&5!=i&&1!=i&&2!=i&&3!=i&&4!=i?(e.j=!0,!1):(e.i=t,e.l=t>>>3,e.h=i,!0)}function K(e,t,i){var r=e.g.i,a=G(e.g);return a=e.g.g+a,e.g.i=a,i(t,e),e.g.g=a,e.g.i=r,t}function Q(e){var t=G(e.g),i=(e=e.g).g;if(e.g+=t,e=e.h,R)(r=I)||(r=I=new TextDecoder("utf-8",{fatal:!1})),r=r.decode(e.subarray(i,i+t));else{t=i+t;for(var r,a,n,o,s=[],d=null;i(a=e[i++])?s.push(a):224>a?i>=t?s.push(65533):(n=e[i++],194>a||128!=(192&n)?(i--,s.push(65533)):s.push((31&a)<<6|63&n)):240>a?i>=t-1?s.push(65533):128!=(192&(n=e[i++]))||224===a&&160>n||237===a&&160<=n||128!=(192&(r=e[i++]))?(i--,s.push(65533)):s.push((15&a)<<12|(63&n)<<6|63&r):244>=a?i>=t-2?s.push(65533):128!=(192&(n=e[i++]))||0!=n-144+(a<<28)>>30||128!=(192&(r=e[i++]))||128!=(192&(o=e[i++]))?(i--,s.push(65533)):(a=(7&a)<<18|(63&n)<<12|(63&r)<<6|63&o,a-=65536,s.push(55296+(a>>10&1023),56320+(1023&a))):s.push(65533),8192<=s.length&&(d=E(d,s),s.length=0);r=E(d,s)}return r}function $(){this.h=[],this.i=0,this.g=new z}function Z(e,t){0!==t.length&&(e.h.push(t),e.i+=t.length)}function ee(e){var t=e.i+e.g.length();if(0===t)return new Uint8Array(0);t=new Uint8Array(t);for(var i=e.h,r=i.length,a=0,n=0;nr?1:0)?-r:r)?B=0<1/r?0:2147483648:isNaN(r)?B=2147483647:34028234663852886e22>>0:11754943508222875e-54>r?B=(i<<31|(r=Math.round(r/1401298464324817e-60)))>>>0:(t=Math.floor(Math.log(r)/Math.LN2),r*=Math.pow(2,-t),B=(i<<31|t+127<<23|(r=8388607&Math.round(8388608*r)))>>>0),i=B,e.push(i>>>0&255),e.push(i>>>8&255),e.push(i>>>16&255),e.push(i>>>24&255)}}z.prototype.push=function(e){if(!(this.h+1=e.l?e.h?e.h[t]:void 0:e.g[t+e.j]}function ue(e){var t=void 0!==t&&t,i=he(e,1,t);return null==i&&(i=ce),i===ce&&pe(e,1,i=se([]),t),i}function me(e,t,i){return null==(e=null==(e=he(e,t))?e:+e)?void 0===i?0:i:e}function pe(e,t,i,r){void 0!==r&&r||t>=e.l?(le(e),e.h[t]=i):e.g[t+e.j]=i}function fe(e,t){e.i||(e.i={});var i=e.i[1];if(!i){var r=ue(e);i=[];for(var a=0;a_&&128<=x;_++)O|=(127&(x=M.h[M.g++]))<<7*_;if(128<=x&&(O|=(127&(x=M.h[M.g++]))<<28,R|=(127&x)>>4),128<=x)for(_=0;5>_&&128<=x;_++)R|=(127&(x=M.h[M.g++]))<<7*_+3;128>x?(M=O>>>0,(R=2147483648&(x=R>>>0))&&(x=~x>>>0,0==(M=1+~M>>>0)&&(x=x+1>>>0)),M=4294967296*x+(M>>>0),R=R?-M:M):(M.l=!0,R=void 0),pe(L,6,R);break;default:if(!we(L,I))break e}}L={Z:me(L,1),$:me(L,2),height:me(L,3),width:me(L,4),rotation:me(L,5,0),X:ye(L,6)},R=T.get(P);e:for(I=new Le,R=new q(R);X(R);)if(10===R.i)ge(I,M=K(R,new Pe,Ie),Pe,void 0);else if(!we(I,R))break e;I=fe(I,Pe).map(_e),M=A.get(P);e:for(R=new Ae,M=new q(M);X(M);)if(10===M.i)R.addClassification(K(M,new ke,Te));else if(!we(R,M))break e;L={T:L,O:I,M:Oe(R)},E.push(L)}k=E}else k=[];t[d]=k,e.g=7;break}if("proto_list"===h.type){if(u){for(T=0,k=Array(u.size());TP;var I=(P=Math.abs(P))>>>0;for(P=Math.floor((P-I)/4294967296),P>>>=0,A&&(P=~P>>>0,4294967295<(I=1+(~I>>>0))&&(I=0,4294967295<++P&&(P=0))),A=B=I,I=P;0>>7|I<<25)>>>0,I>>>=7;E.push(A)}if(Se(k,T),C=ee(C),S.call(b,w,C),y.O)for(b=0;bP;P++)A.push(127&I|128),I>>=7;A.push(1)}te(E,2,he(T,2)),null!=(A=he(T,3))&&(A=x(A),Y(E.g,26),Y(E.g,A.length),Z(E,E.g.end()),Z(E,A)),null!=(A=he(T,4))&&(A=x(A),Y(E.g,34),Y(E.g,A.length),Z(E,E.g.end()),Z(E,A)),Se(T,E),k=ee(k),w.call(S,C,k)}}p=p.data;break e;default:p={}}}switch(l=p,h=c.stream,c.type){case"video":a.pushTexture2d(Object.assign(Object.assign({},l),{stream:h,timestamp:r}));break;case"detections":(u=l).stream=h,u.timestamp=r,a.pushDetectionList(u);break;default:throw Error("Unknown input config type: '"+c.type+"'")}}return m.i.send(a),v(i,m.C,4);case 4:a.delete(),i.g=0}}))}))},d.onResults=function(e,t){this.listeners[t||"$"]=e},A("Solution",Ue),A("OptionType",{BOOL:0,NUMBER:1,aa:2,0:"BOOL",1:"NUMBER",2:"STRING"}),(d=He.prototype).close=function(){return this.g.close(),Promise.resolve()},d.onResults=function(e){this.g.onResults(e)},d.initialize=function(){return Ce(this,(function e(){var t=this;return C(e,(function(e){return v(e,t.g.initialize(),0)}))}))},d.reset=function(){this.g.reset()},d.send=function(e){return Ce(this,(function t(){var i=this;return C(t,(function(t){return v(t,i.g.send(e),0)}))}))},d.setOptions=function(e){this.g.setOptions(e)},A("SelfieSegmentation",He),A("VERSION","0.1.1632777926")}.call(void 0);var y=window.log,b=new WeakMap,S=new WeakSet;class w{constructor(e){var t;o(this,t=S),t.add(this),function(e,t,i){o(e,t),t.set(e,{writable:!0,value:null})}(this,b),this.webRTCAdaptor=e,this.selfieSegmentation=null,this.effectCanvas=null,this.ctx=null,this.rawLocalVideo=document.createElement("video"),this.deepAR=null,this.backgroundBlurRange=3,this.edgeBlurRange=4,this.effectName=w.NO_EFFECT,this.startTime=0,this.statTimerId=-1,this.renderedFrameCount=0,this.lastRenderedFrameCount=0,this.effectCanvasFPS=0,this.videoCallbackPeriodMs=0,this.initializeSelfieSegmentation(),this.isInitialized=!0}init(e){var i=this;return t((function*(){yield i.setRawLocalVideo(e);var t=e.getVideoTracks()[0].getSettings();return i.effectCanvasFPS=t.frameRate,i.videoCallbackPeriodMs=1e3/i.effectCanvasFPS,i.effectCanvas=i.createEffectCanvas(t.width,t.height),i.ctx=i.effectCanvas.getContext("2d"),i.canvasStream&&(i.canvasStream.getTracks().forEach((e=>e.stop())),i.canvasStream=null),i.canvasStream=i.effectCanvas.captureStream(i.effectCanvasFPS),new Promise(((e,t)=>{e(i.canvasStream)}))}))()}setRawLocalVideo(e){return this.rawLocalVideo.srcObject=e,this.rawLocalVideo.muted=!0,this.rawLocalVideo.autoplay=!0,this.rawLocalVideo.play()}createEffectCanvas(e,t){var i=document.createElement("canvas");return i.id="effectCanvas",i.width=e,i.height=t,i}initializeSelfieSegmentation(){this.selfieSegmentation=new SelfieSegmentation({locateFile:e=>w.LOCATE_FILE_URL+"/"+e}),this.selfieSegmentation.setOptions({selfieMode:!1,modelSelection:1}),this.selfieSegmentation.onResults((e=>{this.onResults(e)}))}set virtualBackgroundImage(e){var t,i;i=e,function(e,t,i){if(t.set)t.set.call(e,i);else{if(!t.writable)throw new TypeError("attempted to set read only private field");t.value=i}}(t=this,a(t,b,"set"),i)}startFpsCalculation(){this.statTimerId=setInterval((()=>{var e=(new Date).getTime(),t=(e-this.startTime)/1e3;this.startTime=e;var i=(this.renderedFrameCount-this.lastRenderedFrameCount)/t;this.renderedFrameCount=this.lastRenderedFrameCount,y.warn("Fps: "+i+"fps")}),1e3)}stopFpsCalculation(){-1!==this.statTimerId&&(clearInterval(this.statTimerId),this.statTimerId=-1)}processFrame(){var e=this;return t((function*(){yield e.selfieSegmentation.send({image:e.rawLocalVideo}),e.effectName!==w.NO_EFFECT&&setTimeout((()=>{e.processFrame()}),e.videoCallbackPeriodMs)}))()}enableEffect(e,i,r){var a=this;return t((function*(){if(a.isInitialized){switch(e){case w.DEEPAR:case w.VIRTUAL_BACKGROUND:case w.BLUR_BACKGROUND:case w.NO_EFFECT:break;default:return void y.warn("Unknown effect name please use the constants VideoEffect.VIRTUAL_BACKGROUND,VideoEffect.BLUR_BACKGROUND or VideoEffect.NO_EFFECT ")}var t=a.effectName;if(a.effectName=e,t===w.DEEPAR&&e!==w.DEEPAR&&(a.deepAR.shutdown(),a.deepAR=null),e===w.VIRTUAL_BACKGROUND||e===w.BLUR_BACKGROUND)return t===w.NO_EFFECT||t===w.DEEPAR?(w.DEBUG&&a.startFpsCalculation(),navigator.mediaDevices.getUserMedia({video:a.webRTCAdaptor.mediaConstraints.video,audio:!0}).then((e=>a.init(e).then((e=>a.webRTCAdaptor.updateVideoTrack(e,a.webRTCAdaptor.publishStreamId,null,!0).then((()=>{setTimeout((()=>{a.processFrame()}),a.videoCallbackPeriodMs)})))).catch((e=>{throw y.error(e),e}))))):new Promise(((e,t)=>{e()}));if(e!==w.DEEPAR){if(t===w.DEEPAR){var o=yield navigator.mediaDevices.getUserMedia({video:a.webRTCAdaptor.mediaConstraints.video,audio:!0});yield a.setRawLocalVideo(o)}return new Promise(((e,t)=>{a.stopFpsCalculation(),n(a,S,C).call(a),e()}))}if(null!=i&&""!==i&&null!=r&&""!==r)if(t!==w.DEEPAR){t!==w.BLUR_BACKGROUND&&t!==w.VIRTUAL_BACKGROUND||(a.stopFpsCalculation(),yield n(a,S,C).call(a));var s=a.createEffectCanvas(500,500),d=new DeepAR({licenseKey:i,canvas:s,deeparWasmPath:w.DEEP_AR_FOLDER_ROOT_URL+"/wasm/deepar.wasm",callbacks:{onInitialize:function(){d.startVideo(!0)}}});a.deepAR=d,a.deepAR.callbacks.onVideoStarted=()=>{a.canvasStream=s.captureStream(30),a.webRTCAdaptor.updateVideoTrack(a.canvasStream,a.webRTCAdaptor.publishStreamId,null,!0),a.deepAR.switchEffect(0,"slot",w.DEEP_AR_EFFECTS_URL+r+w.DEEP_AR_EXTENSION)},a.deepAR.downloadFaceTrackingModel(w.DEEP_AR_FOLDER_ROOT_URL+"/models/face/models-68-extreme.bin"),a.deepAR.setVideoElement(a.rawLocalVideo,!0)}else a.deepAR.switchEffect(0,"slot",w.DEEP_AR_EFFECTS_URL+r+w.DEEP_AR_EXTENSION);else y.error("DeepAR API key or DeepAR Model is not set!")}else y.error("VideoEffect is not initialized!")}))()}drawSegmentationMask(e){this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height)}onResults(e){this.renderedFrameCount++,this.effectName==w.BLUR_BACKGROUND?this.drawBlurBackground(e.image,e.segmentationMask,this.backgroundBlurRange):this.effectName==w.VIRTUAL_BACKGROUND?this.drawVirtualBackground(e.image,e.segmentationMask,function(e,t){return t.get?t.get.call(e):t.value}(this,a(this,b,"get"))):this.drawImageDirectly(e.image)}drawImageDirectly(e){this.ctx.save(),this.ctx.globalCompositeOperation="source-over",this.ctx.filter="none",this.ctx.drawImage(e,0,0,e.width,e.height),this.ctx.restore()}drawVirtualBackground(e,t,i){this.ctx.save(),this.ctx.filter="none",this.ctx.clearRect(0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.drawImage(t,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="source-out",this.ctx.drawImage(i,0,0,i.naturalWidth,i.naturalHeight,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="destination-atop",this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.restore()}drawBlurBackground(e,t,i){this.ctx.clearRect(0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="copy",this.ctx.filter="none",this.ctx.filter="blur("+this.edgeBlurRange+"px)",this.drawSegmentationMask(t),this.ctx.globalCompositeOperation="source-in",this.ctx.filter="none",this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="destination-over",this.ctx.filter="blur("+i+"px)",this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.restore()}}function C(){return this.rawLocalVideo.pause(),null!=this.canvasStream&&this.canvasStream.getVideoTracks().forEach((e=>e.stop())),this.webRTCAdaptor.switchVideoCameraCapture(this.webRTCAdaptor.publishStreamId)}r(w,"DEEPAR","deepar"),r(w,"VIRTUAL_BACKGROUND","virtual-background"),r(w,"BLUR_BACKGROUND","blur-background"),r(w,"NO_EFFECT","no-effect"),r(w,"deepARModelList",["flower_face","Ping_Pong"]),r(w,"DEBUG",!1),r(w,"LOCATE_FILE_URL","https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation"),r(w,"DEEP_AR_FOLDER_ROOT_URL","https://cdn.jsdelivr.net/npm/deepar@4.0.3"),r(w,"DEEP_AR_EFFECTS_URL","../js/external/deepar-effects/"),r(w,"DEEP_AR_EXTENSION",".deepar"),g.register((e=>{var t=new w(e);Object.defineProperty(e,"enableEffect",{value:function(e,i,r){return t.enableEffect(e,i,r)}}),Object.defineProperty(e,"setBackgroundImage",{value:function(e){t.virtualBackgroundImage=e}})}));var k,T=window.log,A="";class E{constructor(e,t,i){r(this,"playOrder",void 0),r(this,"currentPlayType",void 0),r(this,"is360",!1),r(this,"streamId",void 0),r(this,"playType",void 0),r(this,"token",void 0),r(this,"autoPlay",!0),r(this,"mute",!0),r(this,"targetLatency",3),r(this,"subscriberId",void 0),r(this,"subscriberCode",void 0),r(this,"window",void 0),r(this,"containerElement",void 0),r(this,"placeHolderElement",void 0),r(this,"videojsPlayer",void 0),r(this,"dashPlayer",void 0),r(this,"iceServers",void 0),r(this,"iceConnected",void 0),r(this,"errorCalled",void 0),r(this,"aScene",void 0),r(this,"playerListener",void 0),r(this,"webRTCDataListener",void 0),r(this,"tryNextTechTimer",void 0),E.DEFAULT_PLAY_ORDER=["webrtc","hls"],E.DEFAULT_PLAY_TYPE=["mp4","webm"],E.HLS_EXTENSION="m3u8",E.WEBRTC_EXTENSION="webrtc",E.DASH_EXTENSION="mpd",E.STREAMS_FOLDER="streams",E.VIDEO_HTML=A,E.VIDEO_PLAYER_ID="video-player",this.dom=e.document,this.window=e;var a=v("id",this.window.location.search);if(this.containerElement=t,this.placeHolderElement=i,this.errorCalled=!1,this.iceConnected=!1,this.tryNextTechTimer=-1,this.videojsPlayer=null,this.iceServers='[ { "urls": "stun:stun1.l.google.com:19302" } ]',null==a&&null==(a=v("name",this.window.location.search))&&T.warn("Please use id parameter instead of name parameter."),null==a){var n="Stream id is not set.Please add your stream id to the url as a query parameter such as ?id={STREAM_ID} to the url";throw T.error(n),alert(n),new Error(n)}this.streamId=a;var o=v("is360",this.window.location.search);null!=o&&(this.is360="true"==o.toLocaleLowerCase());var s=v("playType",this.window.location.search);this.playType=null!=s?s.split(","):E.DEFAULT_PLAY_TYPE,this.token=v("token",this.window.location.search),void 0===this.token&&(this.token=null);var d=v("autoplay",this.window.location.search);null!=d&&(this.autoPlay="true"==d.toLocaleLowerCase());var c=v("mute",this.window.location.search);null!=c&&(this.mute="true"==c.toLocaleLowerCase());var l=v("targetLatency",this.window.location.search);if(null!=l){var h=Number(l);isNaN(h)?T.warn("targetLatency parameter is not a number. It will be ignored."):this.targetLatency=h}this.subscriberId=v("subscriberId",this.window.location.search),void 0===this.subscriberId&&(this.subscriberId=null),this.subscriberCode=v("subscriberCode",this.window.location.search),null==this.subscriberCode&&(this.subscriberCode=null);var u=v("playOrder",this.window.location.search);this.playOrder=null!=u?u.split(","):E.DEFAULT_PLAY_ORDER,this.loadScripts(),this.setPlayerVisible(!1)}loadScripts(){if(this.playOrder.includes("hls")||this.playOrder.includes("vod")||this.playOrder.includes("webrtc")){var e=this.dom.createElement("link");e.setAttribute("rel","stylesheet"),e.setAttribute("type","text/css"),e.setAttribute("href","css/external/video-js.css"),this.dom.head.appendChild(e);var t=this.dom.createElement("script");t.type="text/javascript",t.src="js/external/video.js",t.async=!1,this.dom.head.appendChild(t),t.onload=()=>{var e=this.dom.createElement("script");e.type="text/javascript",e.src="js/external/videojs-contrib-quality-levels.min.js",this.dom.head.appendChild(e);var t=this.dom.createElement("script");t.type="text/javascript",t.src="js/external/videojs-hls-quality-selector.min.js",this.dom.head.appendChild(t)}}if(this.playOrder.includes("webrtc")){var i=this.dom.createElement("link");i.setAttribute("rel","stylesheet"),i.setAttribute("type","text/css"),i.setAttribute("href","css/videojs-webrtc-plugin.css"),this.dom.head.appendChild(i);var r=this.dom.createElement("script");r.type="text/javascript",r.src="js/videojs-webrtc-plugin.js",r.async=!1,this.dom.head.appendChild(r)}if(this.playOrder.includes("dash")){var a=this.dom.createElement("script");a.type="text/javascript",a.src="js/external/dash.all.min.js",this.dom.head.appendChild(a)}if(this.is360){var n=this.dom.createElement("script");n.type="text/javascript",n.src="js/external/aframe.min.js",this.dom.head.appendChild(n)}}enable360Player(){this.aScene=this.dom.createElement("a-scene");var e=this.dom.getElementsByTagName("video")[0].id;this.aScene.innerHTML='',this.dom.body.appendChild(this.aScene)}setPlayerVisible(e){if(this.containerElement.style.display=e?"block":"none",this.placeHolderElement.style.display=e?"none":"block",this.is360)if(e)this.enable360Player();else if(null!=this.aScene){for(var t=this.dom.getElementsByTagName("a-scene");t.length>0;)this.dom.body.removeChild(t[0]),t=this.dom.getElementsByTagName("a-scene");this.aScene=null}}handleWebRTCInfoMessages(e){"ice_connection_state_changed"==e.info?(T.debug("ice connection state changed to "+e.obj.state),"completed"==e.obj.state||"connected"==e.obj.state?this.iceConnected=!0:"failed"!=e.obj.state&&"disconnected"!=e.obj.state&&"closed"!=e.obj.state||(T.debug("Ice connection is not connected. tryNextTech to replay"),this.tryNextTech())):"closed"==e.info&&(T.debug("Websocket is closed. tryNextTech to replay"),this.tryNextTech())}playWithVideoJS(e,t){var i;if("mp4"==t)i="video/mp4";else if("webm"==t)i="video/webm";else if("mov"==t)i="video/mp4",alert("Browsers do not support to play mov format");else if("avi"==t)i="video/mp4",alert("Browsers do not support to play avi format");else if("m3u8"==t)i="application/x-mpegURL";else if("mpd"==t)i="application/dash+xml";else{if("webrtc"!=t)return void T.warn("Unknown extension: "+t);i="video/webrtc"}var r=this.streamId;this.streamId.endsWith("_adaptive")&&(r=streamId.substring(0,streamId.indexOf("_adaptive"))),this.videojsPlayer=videojs(E.VIDEO_PLAYER_ID,{poster:"previews/"+r+".png",liveui:"m3u8"==t,liveTracker:{trackingThreshold:0},html5:{vhs:{limitRenditionByPlayerDimensions:!1}},controls:!0,class:"video-js vjs-default-skin vjs-big-play-centered",muted:this.mute,preload:"auto",autoplay:this.autoPlay}),this.videojsPlayer.on("error",(e=>{T.warn("There is an error in playback: "+e),this.errorCalled||(this.errorCalled=!0,setTimeout((()=>{this.tryNextTech(),this.errorCalled=!1}),2500))})),"webrtc"==t&&(this.videojsPlayer.on("webrtc-info",((e,t)=>{this.handleWebRTCInfoMessages(t)})),this.videojsPlayer.on("webrtc-error",((e,t)=>{T.warn("error callback: "+JSON.stringify(t)),"no_stream_exist"==t.error||"WebSocketNotConnected"==t.error||"not_initialized_yet"==t.error||"data_store_not_available"==t.error||"highResourceUsage"==t.error||"unauthorized_access"==t.error||"user_blocked"==t.error?this.tryNextTech():"notSetRemoteDescription"==t.error&&(T.warn("notSetRemoteDescription error. Redirecting to HLS player."),this.playIfExists("hls"))})),this.videojsPlayer.on("webrtc-data-received",((e,t)=>{T.warn("webrtc-data-received: "+JSON.stringify(t)),null!=this.webRTCDataListener&&this.webRTCDataListener(t)}))),"m3u8"==t&&(videojs.Vhs.xhr.beforeRequest=e=>{var t=this.getSecurityQueryParams();return e.uri.includes(t)||(e.uri.endsWith("?")||(e.uri=e.uri+"?"),e.uri+=t),T.debug("hls request: "+e.uri),e},this.videojsPlayer.ready((()=>{"function"==typeof this.videojsPlayer.hlsQualitySelector&&this.videojsPlayer.hlsQualitySelector({displayCurrentQuality:!0});var e=this.videojsPlayer.qualityLevels();e.on("addqualitylevel",(function(t){var i=t.qualityLevel;i.height?i.enabled=!0:(e.removeQualityLevel(i),i.enabled=!1)}))}))),"mp4"!=t&&"webm"!=t&&"m3u8"!=t||this.makeVideoJSVisibleWhenReady(),this.videojsPlayer.on("ended",(()=>{T.warn("stream is ended"),this.setPlayerVisible(!1),"vod"!=this.currentPlayType&&(this.iceConnected?this.playIfExists(this.playOrder[0]):"hls"==this.currentPlayType?(this.setPlayerVisible(!1),(this.playOrder[0]="hls")?setTimeout((()=>{this.playIfExists(this.playOrder[0])}),1e4):this.playIfExists(this.playOrder[0])):this.tryNextTech()),null!=this.playerListener&&this.playerListener("ended")})),this.videojsPlayer.on("play",(()=>{this.setPlayerVisible(!0),null!=this.playerListener&&this.playerListener("play")})),this.iceConnected=!1,this.videojsPlayer.src({src:e,type:i,withCredentials:!0,iceServers:this.iceServers,reconnect:!1}),this.autoPlay&&this.videojsPlayer.play().catch((e=>{T.warn("Problem in playback. The error is "+e)}))}makeVideoJSVisibleWhenReady(){this.videojsPlayer.ready((()=>{this.setPlayerVisible(!0)}))}checkStreamExistsViaHttp(e,t,i){var r="";return t.startsWith(e)||(r+=e+"/"),r+=t,null!=i&&""!=i&&(r+="_adaptive."+i),r=this.addSecurityParams(r),fetch(r,{method:"HEAD"}).then((a=>200==a.status?new Promise((function(e,t){e(r)})):(r=e+"/"+t+"."+i,r=this.addSecurityParams(r),fetch(r,{method:"HEAD"}).then((e=>200==e.status?new Promise((function(e,t){e(r)})):(T.warn("No stream found"),new Promise((function(e,t){t("resource_is_not_available")}))))))))}addSecurityParams(e){var t=this.getSecurityQueryParams();return null!=t&&""!=t&&(e+="?"+t),e}tryNextTech(){if(-1==this.tryNextTechTimer){this.destroyDashPlayer(),this.destroyVideoJSPlayer(),this.setPlayerVisible(!1);var e=this.playOrder.indexOf(this.currentPlayType);-1==e||e==this.playOrder.length-1?e=0:e++,this.tryNextTechTimer=setTimeout((()=>{this.tryNextTechTimer=-1,this.playIfExists(this.playOrder[e])}),3e3)}else T.debug("tryNextTech is already scheduled no need to schedule again")}playViaDash(e){this.destroyDashPlayer(),this.dashPlayer=dashjs.MediaPlayer().create(),this.dashPlayer.extend("RequestModifier",(()=>({modifyRequestHeader:function(e,t){return e},modifyRequestURL:e=>{var t="",i=this.getSecurityQueryParams();return e.includes(i)?e:(e.endsWith("?")||(e+="?"),t=e+i,T.warn(t),t)},modifyRequest(e){}}))),this.dashPlayer.updateSettings({streaming:{delay:{liveDelay:this.targetLatency},liveCatchup:{maxDrift:.05,playbackRate:.5,latencyThreshold:60}}}),this.dashPlayer.initialize(this.containerElement.firstChild,e,this.autoPlay),this.dashPlayer.setMute(this.mute),this.dashLatencyTimer=setInterval((()=>{T.warn("live latency: "+this.dashPlayer.getCurrentLiveLatency())}),2e3),this.makeDashPlayerVisibleWhenInitialized(),this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_PLAYING,(e=>{T.warn("playback started"),this.setPlayerVisible(!0),null!=this.playerListener&&this.playerListener("play")})),this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ENDED,(()=>{T.warn("playback ended"),this.destroyDashPlayer(),this.setPlayerVisible(!1),(this.playOrder[0]="dash")?setTimeout((()=>{this.playIfExists(this.playOrder[0])}),1e4):this.playIfExists(this.playOrder[0]),null!=this.playerListener&&this.playerListener("ended")})),this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ERROR,(e=>{this.tryNextTech()})),this.dashPlayer.on(dashjs.MediaPlayer.events.ERROR,(e=>{this.tryNextTech()}))}makeDashPlayerVisibleWhenInitialized(){this.dashPlayer.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED,(e=>{T.warn("Stream initialized"),this.setPlayerVisible(!0)}))}destroyDashPlayer(){this.dashPlayer&&(this.dashPlayer.destroy(),this.dashPlayer=null,clearInterval(this.dashLatencyTimer))}destroyVideoJSPlayer(){this.videojsPlayer&&(this.videojsPlayer.dispose(),this.videojsPlayer=null)}playIfExists(e){var i=this;return t((function*(){switch(i.currentPlayType=e,i.destroyVideoJSPlayer(),i.destroyDashPlayer(),i.setPlayerVisible(!1),i.containerElement.innerHTML=E.VIDEO_HTML,T.warn("Try to play the stream "+i.streamId+" with "+i.currentPlayType),i.currentPlayType){case"hls":return i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId,E.HLS_EXTENSION).then((e=>{i.playWithVideoJS(e,E.HLS_EXTENSION),T.warn("incoming stream path: "+e)})).catch((e=>{T.warn("HLS stream resource not available for stream:"+i.streamId+" error is "+e+". Try next play tech"),i.tryNextTech()}));case"dash":return i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId+"/"+i.streamId,E.DASH_EXTENSION).then((e=>{i.playViaDash(e)})).catch((e=>{T.warn("DASH stream resource not available for stream:"+i.streamId+" error is "+e+". Try next play tech"),i.tryNextTech()}));case"webrtc":var t=i.window.location.pathname.substring(0,i.window.location.pathname.lastIndexOf("/")+1),r=i.window.location.hostname+":"+i.window.location.port+t+i.streamId+".webrtc",a="ws://"+r;return location.protocol.startsWith("https")&&(a="wss://"+r),i.playWithVideoJS(i.addSecurityParams(a),E.WEBRTC_EXTENSION);case"vod":var n,o=i.streamId.lastIndexOf(".");return-1!=o?(i.playType[0]="",n=i.streamId.substring(o+1)):n=i.playType[0],i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId,i.playType[0]).then((e=>{i.playWithVideoJS(e,n)})).catch((e=>{T.warn("VOD stream resource not available for stream:"+i.streamId+" and play type "+i.playType[0]+". Error is "+e),i.playType.length>1&&(T.warn("Try next play type which is "+i.playType[1]+"."),i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId,i.playType[1]).then((e=>{i.playWithVideoJS(e,i.playType[1])})).catch((e=>{T.warn("VOD stream resource not available for stream:"+i.streamId+" and play type error is "+e)})))}))}}))()}getSecurityQueryParams(){var e="";return null!=this.token&&(e+="&token="+this.token),null!=this.subscriberId&&(e+="&subscriberId="+this.subscriberId),null!=this.subscriberCode&&(e+="&subscriberCode="+this.subscriberCode),e}play(){if(this.streamId.startsWith(E.STREAMS_FOLDER)){var e=this.streamId.lastIndexOf("."),t=this.streamId.substring(e+1);this.playOrder=["vod"],t==E.DASH_EXTENSION?this.playViaDash(this.addSecurityParams(this.streamId),t):this.playWithVideoJS(this.addSecurityParams(this.streamId),t)}else this.playIfExists(this.playOrder[0])}mutePlayer(e){this.mute=e,this.videojsPlayer&&this.videojsPlayer.muted(e),this.dashPlayer&&this.dashPlayer.setMute(e)}isMuted(){return this.mute}addPlayerListener(e){this.playerListener=e}addWebRTCDataListener(e){this.webRTCDataListener=e}sendWebRTCData(e){try{if(this.videojsPlayer&&"webrtc"==this.currentPlayType)return this.videojsPlayer.sendDataViaWebRTC(e),!0;T.warn("Player is not ready or playType is not WebRTC")}catch(e){T.error("An error occurred while sending WebRTC data: ",e)}return!1}}r(E,"DEFAULT_PLAY_ORDER",["webrtc","hls"]),r(E,"DEFAULT_PLAY_TYPE",["mp4","webm"]),r(E,"HLS_EXTENSION","m3u8"),r(E,"WEBRTC_EXTENSION","webrtc"),r(E,"DASH_EXTENSION","mpd"),r(E,"STREAMS_FOLDER","streams"),r(E,"VIDEO_HTML",A),r(E,"VIDEO_PLAYER_ID","video-player");var P=!1;window.startBroadcasting=async function(e){if(console.log("startBroadcasting is called websocket url:"+e.websocketURL+" streamId: "+e.streamId),void 0!==k)throw new Error("Called startBroadcasting while recording is in progress.");let t="",i=1280,r=720;void 0!==e.token&&(t=e.token),void 0!==e.width&&e.width>0&&(i=e.width),void 0!==e.height&&e.height>0&&(r=e.height);const a=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:{max:30}},audio:{channelCount:2,echoCancellation:!1,autoGainControl:!1,noiseSuppression:!1},preferCurrentTab:!0}),n=a.getVideoTracks()[0];console.log("video track settings: ",n.getSettings());const o=a.getAudioTracks()[0];console.log("audio track settings: ",o.getSettings());const s={width:{min:640,ideal:i},height:{min:360,ideal:r},advanced:[{width:i,height:r},{aspectRatio:i/r}],frameRate:{min:15,max:30},resizeMode:"crop-and-scale"};n.applyConstraints(s),k=new g({websocket_url:e.websocketURL,peerconnection_config:{iceServers:[{urls:"stun:stun1.l.google.com:19302"}]},bandwidth:2500,localStream:a,callback:(i,r)=>{"initialized"==i?(console.log("WebRTC adaptor initialized"),k.publish(e.streamId,t,"","","","")):"publish_started"==i?(console.log("mediapush_publish_started"),P=!0):"publish_finished"==i&&(P=!1),console.log(i)},callbackError:function(e,t){var i=JSON.stringify(e);i=void 0!==t?t:JSON.stringify(e),-1!=e.indexOf("WebSocketNotConnected")?i="WebSocket is disconnected.":-1!=e.indexOf("not_initialized_yet")?i="Server is getting initialized.":-1!=e.indexOf("data_store_not_available")?i="Data store is not available. It's likely that server is initialized or getting closed":-1!=e.indexOf("NotFoundError")?i="Camera or Mic are not found or not allowed in your device":-1!=e.indexOf("NotReadableError")||-1!=e.indexOf("TrackStartError")?i="Camera or Mic are already in use and they cannot be opened. Choose another video/audio source if you have on the page below ":-1!=e.indexOf("OverconstrainedError")||-1!=e.indexOf("ConstraintNotSatisfiedError")?i="There is no device found that fits your video and audio constraints. You may change video and audio constraints":-1!=e.indexOf("NotAllowedError")||-1!=e.indexOf("PermissionDeniedError")?i="You are not allowed to access camera and mic.":-1!=e.indexOf("TypeError")?i="Video/Audio is required":-1!=e.indexOf("getUserMediaIsNotAllowed")?i="You are not allowed to reach devices from an insecure origin, please enable ssl":-1!=e.indexOf("ScreenSharePermissionDenied")?(i="You are not allowed to access screen share",$(".video-source").first().prop("checked",!0)):i=-1!=e.indexOf("UnsecureContext")?"Please Install SSL(https). Camera and mic cannot be opened because of unsecure context. ":-1!=e.indexOf("no_stream_exist")?"There is no active live stream with this id to play":e,void 0!==t&&console.log("error callback: "+e+" message: "+i)}}),window.webRTCAdaptorMediaPush=k},window.stopBroadcasting=function(e){k.stop(e.streamId),k.closeWebSocket()},window.isConnected=function(e){var t=!1;if(P){var i=k.signallingState(e);if(null!=i&&"closed"!=i){var r=k.iceConnectionState(e);null!=r&&"failed"!=r&&"disconnected"!=r&&(t=!0)}}return t}})()})(); \ No newline at end of file +(()=>{"use strict";var e={36:(e,t,i)=>{e.exports=i.p+"e4e4da7454e7cf2e6ffa.js"}},t={};function i(r){var a=t[r];if(void 0!==a)return a.exports;var n=t[r]={exports:{}};return e[r](n,n.exports,i),n.exports}i.m=e,i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e;i.g.importScripts&&(e=i.g.location+"");var t=i.g.document;if(!e&&t&&(t.currentScript&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var a=r.length-1;a>-1&&!e;)e=r[a--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),i.p=e})(),i.b=document.baseURI||self.location.href,(()=>{function e(e,t,i,r,a,n,o){try{var s=e[n](o),d=s.value}catch(e){return void i(e)}s.done?t(d):Promise.resolve(d).then(r,a)}function t(t){return function(){var i=this,r=arguments;return new Promise((function(a,n){var o=t.apply(i,r);function s(t){e(o,a,n,s,d,"next",t)}function d(t){e(o,a,n,s,d,"throw",t)}s(void 0)}))}}function r(e,t,i){return(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var i=e[Symbol.toPrimitive];if(void 0!==i){var r=i.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function a(e,t,i){if(!t.has(e))throw new TypeError("attempted to "+i+" private field on non-instance");return t.get(e)}function n(e,t,i){if(!t.has(e))throw new TypeError("attempted to get private field on non-instance");return i}function o(e,t){if(t.has(e))throw new TypeError("Cannot initialize the same private elements twice on an object")}window.log=function(){var e=function(){},t="undefined",i=typeof window!==t&&typeof window.navigator!==t&&/Trident\/|MSIE /.test(window.navigator.userAgent),r=["trace","debug","info","warn","error"];function a(e,t){var i=e[t];if("function"==typeof i.bind)return i.bind(e);try{return Function.prototype.bind.call(i,e)}catch(t){return function(){return Function.prototype.apply.apply(i,[e,arguments])}}}function n(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function o(t,i){for(var a=0;a=0&&i<=s.levels.SILENT))throw"log.setLevel() called with invalid level: "+i;if(n=i,!1!==a&&function(e){var i=(r[e]||"silent").toUpperCase();if(typeof window!==t&&c){try{return void(window.localStorage[c]=i)}catch(e){}try{window.document.cookie=encodeURIComponent(c)+"="+i+";"}catch(e){}}}(i),o.call(s,i,e),typeof console===t&&i{this.debug&&d.debug("websocket connected"),this.pingTimerId=setInterval((()=>{this.sendPing()}),3e3),this.connected=!0,this.connecting=!1,this.callback("initialized"),void 0!==e&&e()},this.wsConn.onmessage=e=>{var t=JSON.parse(e.data);"start"==t.command?(this.debug&&d.debug("received start command"),this.webrtcadaptor.startPublishing(t.streamId)):"takeCandidate"==t.command?(this.debug&&(d.debug("received ice candidate for stream id "+t.streamId),d.debug(t.candidate)),this.webrtcadaptor.takeCandidate(t.streamId,t.label,t.candidate)):"takeConfiguration"==t.command?(this.debug&&d.debug("received remote description type for stream id: "+t.streamId+" type: "+t.type),this.webrtcadaptor.takeConfiguration(t.streamId,t.sdp,t.type,t.idMapping)):"stop"==t.command?(this.debug&&d.debug("Stop command received"),this.webrtcadaptor.closePeerConnection(t.streamId)):"error"==t.command?this.callbackError(t.definition,t):"notification"==t.command?this.callback(t.definition,t):"streamInformation"==t.command||"roomInformation"==t.command?this.callback(t.command,t):"pong"==t.command?this.callback(t.command):"trackList"==t.command?this.callback(t.command,t):"connectWithNewId"==t.command?(this.multiPeerStreamId=t.streamId,this.join(t.streamId)):"peerMessageCommand"==t.command&&this.callback(t.command,t)},this.wsConn.onerror=e=>{this.connecting=!1,this.connected=!1,d.info(" error occured: "+JSON.stringify(e)),this.clearPingTimer(),this.callbackError("WebSocketNotConnected",e)},this.wsConn.onclose=e=>{this.connecting=!1,this.connected=!1,this.debug&&d.debug("connection closed."),this.clearPingTimer(),this.callback("closed",e)}}clearPingTimer(){-1!=this.pingTimerId&&(this.debug&&d.debug("Clearing ping message timer"),clearInterval(this.pingTimerId),this.pingTimerId=-1)}sendPing(){this.wsConn.send(JSON.stringify({command:"ping"}))}close(){this.wsConn.close()}send(e){if(0!=this.connecting||0!=this.connected)try{this.wsConn.send(e),this.debug&&d.debug("sent message:"+e)}catch(t){d.warn("Cannot send message:"+e)}else this.initWebSocketConnection((()=>{this.send(e)}))}isConnected(){return this.connected}isConnecting(){return this.connecting}}var l=window.log;class h{constructor(e){this.context=e,this.instant=0,this.mic=null,this.volumeMeterNode=null}connectToSource(e,t,r){return this.context.audioWorklet.addModule(new URL(i(36),i.b)).then((()=>{this.mic=this.context.createMediaStreamSource(e),this.volumeMeterNode=new AudioWorkletNode(this.context,"volume-meter"),this.volumeMeterNode.port.onmessage=e=>{"debug"==e.data.type?l.debug(e.data.message):(this.instant=e.data,t(this.instant.toFixed(2)),l.debug("Audio level: "+this.instant.toFixed(2)))},this.mic.connect(this.volumeMeterNode)})).catch((e=>{throw void 0!==r&&r(e),l.error("Error in soundmeter: "+e),e}))}stop(){null!=this.volumeMeterNode&&(this.volumeMeterNode.port.postMessage("stop"),this.volumeMeterNode.disconnect(),this.volumeMeterNode.port.close(),this.volumeMeterNode=null),null!=this.mic&&(this.mic.disconnect(),this.mic=null)}}var u=window.log;class m{constructor(e){for(var t in this.bandwidth=1200,this.debug=!1,this.camera_location="top",this.camera_margin=15,this.camera_percent=15,this.mediaConstraints={video:!0,audio:!0},this.getSender=e.getSender,this.publishStreamId=null,this.localStream=null,this.publishMode="camera",this.callback=(e,t)=>{u.debug("Callback info: "+e+" object: "+typeof t!==void 0?JSON.stringify(t):0)},this.callbackError=e=>{u.error(e)},e.userParameters)e.userParameters.hasOwnProperty(t)&&(this[t]=e.userParameters[t]);this.currentVolume=null,this.previousAudioTrack=null,this.silentAudioTrack=null,this.desktopStream=null,this.smallVideoTrack=null,this.blackVideoTrack=null,this.audioContext=new AudioContext,this.oscillator=null,this.primaryAudioTrackGainNode=null,this.secondaryAudioTrackGainNode=null,this.localStreamSoundMeter=null,this.levelCallback=null,this.blackFrameTimer=null,this.desktopCameraCanvasDrawerTimer=null,this.mutedAudioStream=null,this.isMuted=!1,this.meterRefresh=null,this.cameraEnabled=!0,this.replacementStream=null,this.localVideo=this.localVideoElement||document.getElementById(this.localVideoId),this.dummyCanvas=document.createElement("canvas"),this.mediaConstraints?"camera"==this.mediaConstraints.video?this.publishMode="camera":"screen"==this.mediaConstraints.video?this.publishMode="screen":"screen+camera"==this.mediaConstraints.video&&(this.publishMode="screen+camera"):this.mediaConstraints={video:!0,audio:!0},this.checkBrowserScreenShareSupported()}initLocalStream(){if(this.checkWebRTCPermissions(),void 0!==this.mediaConstraints.video&&0!=this.mediaConstraints.video)return this.openStream(this.mediaConstraints);if(void 0!==this.mediaConstraints.audio&&0!=this.mediaConstraints.audio){var e={audio:this.mediaConstraints.audio};return this.navigatorUserMedia(e,(e=>this.gotStream(e)),!0)}return u.debug("no media requested, just return an empty stream"),new Promise(((e,t)=>{e(null)}))}checkWebRTCPermissions(){return"WebSocket"in window?void 0===navigator.mediaDevices?(u.debug("Cannot open camera and mic because of unsecure context. Please Install SSL(https)"),void this.callbackError("UnsecureContext")):void(void 0!==navigator.mediaDevices&&null!=navigator.mediaDevices&&null!=navigator.mediaDevices||this.callbackError("getUserMediaIsNotAllowed")):(u.debug("WebSocket not supported."),void this.callbackError("WebSocketNotSupported"))}getDevices(){return navigator.mediaDevices.enumerateDevices().then((e=>{var t=new Array,i=!1,r=!1;return e.forEach((e=>{"audioinput"!=e.kind&&"videoinput"!=e.kind||(t.push(e),"audioinput"==e.kind&&(i=!0),"videoinput"==e.kind&&(r=!0))})),this.callback("available_devices",t),0==i&&null==this.localStream&&(u.debug("Audio input not found"),u.debug("Retrying to get user media without audio"),this.inputDeviceNotFoundLimit<2?0!=r?(this.openStream({video:!0,audio:!1}),this.inputDeviceNotFoundLimit++):(u.debug("Video input not found"),alert("There is no video or audio input")):alert("No input device found, publish is not possible")),t})).catch((e=>{throw u.error("Cannot get devices -> error name: "+e.name+": "+e.message),e}))}trackDeviceChange(){navigator.mediaDevices.ondevicechange=()=>{this.getDevices()}}setDesktopwithCameraSource(e,t,i){return this.desktopStream=e,this.navigatorUserMedia({video:!0,audio:!1},(r=>{this.smallVideoTrack=r.getVideoTracks()[0];var a=document.createElement("canvas"),n=a.getContext("2d"),o=document.createElement("video");o.srcObject=e,o.play();var s=document.createElement("video");s.srcObject=r,s.play();var d=a.captureStream(15);null!=i&&(e.getVideoTracks()[0].onended=function(e){i(e)}),(null==this.localStream?this.gotStream(d):this.updateVideoTrack(d,t,onended,null)).then((()=>{this.desktopCameraCanvasDrawerTimer=setInterval((()=>{a.width=o.videoWidth,a.height=o.videoHeight,n.drawImage(o,0,0,a.width,a.height);var e,t=o.videoWidth*(this.camera_percent/100),i=s.videoHeight/s.videoWidth*t,r=a.width-t-this.camera_margin;e="top"==this.camera_location?this.camera_margin:a.height-i-this.camera_margin,n.drawImage(s,r,e,t,i)}),66)}))}),!0)}prepareStreamTracks(e,t,i,r){var a=i.getAudioTracks();if(a.length>0&&"camera"==this.publishMode&&(a[0].stop(),i.removeTrack(a[0])),"undefined"!=t&&0!=t){var n={audio:t};return this.navigatorUserMedia(n).then((n=>{n=this.setGainNodeStream(n);var o=t=>{this.callback("screen_share_stopped"),this.setVideoCameraSource(r,e,null,!0)};return"screen"==this.publishMode?this.updateVideoTrack(i,r,o,!0).then((()=>(a.length>0&&(n=this.mixAudioStreams(i,n)),this.updateAudioTrack(n,r,null)))):"screen+camera"==this.publishMode?(a.length>0&&(n=this.mixAudioStreams(i,n)),this.updateAudioTrack(n,r,null).then((()=>this.setDesktopwithCameraSource(i,r,o)))):(0!=t&&null!=t&&i.addTrack(n.getAudioTracks()[0]),i.getVideoTracks().length>0?this.updateVideoTrack(i,r,null,null).then((()=>this.updateAudioTrack(i,r,null).then((()=>this.gotStream(i))))):i.getAudioTracks().length>0?this.updateAudioTrack(i,r,null).then((()=>this.gotStream(i))):this.gotStream(i))})).catch((e=>{throw"NotFoundError"==e.name?this.getDevices():this.callbackError(e.name,e.message),e}))}return this.gotStream(i)}navigatorUserMedia(e,t,i){if("dummy"==e.video||"dummy"==e.audio){var r=new MediaStream;return"dummy"==e.audio&&r.addTrack(this.getSilentAudioTrack()),"dummy"==e.video&&r.addTrack(this.getBlackVideoTrack()),new Promise(((e,t)=>{e(r)}))}return navigator.mediaDevices.getUserMedia(e).then((e=>(void 0===t&&null==t||t(e),e))).catch((e=>{throw 1==i?"NotFoundError"==e.name?this.getDevices():this.callbackError(e.name,e.message):u.warn(e),e}))}navigatorDisplayMedia(e,t){return navigator.mediaDevices.getDisplayMedia(e).then((e=>(void 0!==t&&t(e),e))).catch((e=>{"NotAllowedError"===e.name&&(u.debug("Permission denied error"),this.callbackError("ScreenSharePermissionDenied"),null==this.localStream?this.openStream({video:!0,audio:!0}):this.switchVideoCameraCapture(streamId))}))}getMedia(e,t){var i=!1;return void 0!==e.audio&&0!=e.audio&&(i=e.audio),null!=this.desktopCameraCanvasDrawerTimer&&(clearInterval(this.desktopCameraCanvasDrawerTimer),this.desktopCameraCanvasDrawerTimer=null),"screen+camera"==this.publishMode||"screen"==this.publishMode?this.navigatorDisplayMedia(e).then((r=>(this.smallVideoTrack&&this.smallVideoTrack.stop(),this.prepareStreamTracks(e,i,r,t)))):this.navigatorUserMedia(e).then((r=>(this.smallVideoTrack&&this.smallVideoTrack.stop(),this.prepareStreamTracks(e,i,r,t)))).catch((e=>{"NotFoundError"==e.name?this.getDevices():this.callbackError(e.name,e.message)}))}openStream(e,t){return this.mediaConstraints=e,this.getMedia(e,t).then((()=>{"dummy"!=this.mediaConstraints.video&&null!=this.mediaConstraints.video&&(this.stopBlackVideoTrack(),this.clearBlackVideoTrackTimer()),"dummy"!=this.mediaConstraints.audio&&null!=this.mediaConstraints.audio&&this.stopSilentAudioTrack()}))}closeStream(){this.localStream&&(this.localStream.getVideoTracks().forEach((function(e){e.onended=null,e.stop()})),this.localStream.getAudioTracks().forEach((function(e){e.onended=null,e.stop()}))),this.videoTrack&&this.videoTrack.stop(),this.audioTrack&&this.audioTrack.stop(),this.smallVideoTrack&&this.smallVideoTrack.stop(),this.previousAudioTrack&&this.previousAudioTrack.stop()}checkBrowserScreenShareSupported(){(void 0!==navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia||navigator.getDisplayMedia)&&this.callback("browser_screen_share_supported")}enableSecondStreamInMixedAudio(e){null!=this.secondaryAudioTrackGainNode&&(this.secondaryAudioTrackGainNode.gain.value=e?1:0)}gotStream(e){return this.localStream=e,this.localVideo&&(this.localVideo.srcObject=e),this.getDevices(),this.trackDeviceChange(),new Promise(((e,t)=>{e()}))}changeLocalVideo(e){this.localVideo=e,this.localStream&&(this.localVideo.srcObject=this.localStream)}enableAudioLevelWhenMuted(){navigator.mediaDevices.getUserMedia({video:!1,audio:!0}).then((e=>{this.mutedAudioStream=e,this.mutedSoundMeter=new h(this.audioContext),soundMeter.connectToSource(this.mutedAudioStream,(e=>{e>.1&&this.callback("speaking_but_muted")}),(e=>{e?alert(e):this.meterRefresh=setInterval((()=>{soundMeter.instant.toFixed(2)>.1&&this.callback("speaking_but_muted")}),200)}))})).catch((function(e){u.debug("Can't get the soundlevel on mute")}))}disableAudioLevelWhenMuted(){null!=this.meterRefresh&&(clearInterval(this.meterRefresh),this.meterRefresh=null),null!=this.mutedSoundMeter&&(this.mutedSoundMeter.stop(),this.mutedSoundMeter=null),null!=this.mutedAudioStream&&this.mutedAudioStream.getTracks().forEach((function(e){e.stop()}))}mixAudioStreams(e,t){var i=new MediaStream;e.getVideoTracks().forEach((function(e){i.addTrack(e)}));var r=this.audioContext.createMediaStreamDestination();return e.getAudioTracks().length>0?(this.primaryAudioTrackGainNode=this.audioContext.createGain(),this.primaryAudioTrackGainNode.gain.value=1,this.audioContext.createMediaStreamSource(e).connect(this.primaryAudioTrackGainNode).connect(r)):u.debug("Origin stream does not have audio track"),t.getAudioTracks().length>0?(this.secondaryAudioTrackGainNode=this.audioContext.createGain(),this.secondaryAudioTrackGainNode.gain.value=1,this.audioContext.createMediaStreamSource(t).connect(this.secondaryAudioTrackGainNode).connect(r)):u.debug("Second stream does not have audio track"),r.stream.getAudioTracks().forEach((function(e){i.addTrack(e),u.debug("audio destination add track")})),i}setGainNodeStream(e){if(0!=this.mediaConstraints.audio&&void 0!==this.mediaConstraints.audio){var t=e.getVideoTracks(),i=e.getAudioTracks();this.audioContext=new AudioContext;var r=this.audioContext.createMediaStreamSource(e),a=this.audioContext.createMediaStreamDestination();this.primaryAudioTrackGainNode=this.audioContext.createGain(),r.connect(this.primaryAudioTrackGainNode),this.primaryAudioTrackGainNode.connect(a),null==this.currentVolume?this.primaryAudioTrackGainNode.gain.value=1:this.primaryAudioTrackGainNode.gain.value=this.currentVolume;var n=a.stream;for(var o of t)n.addTrack(o);for(var s of i)n.addTrack(s);return null!==this.previousAudioTrack&&this.previousAudioTrack.stop(),this.previousAudioTrack=n.getAudioTracks()[1],n}return e}switchDesktopCapture(e){return this.publishMode="screen",void 0!==this.mediaConstraints.video&&0!=this.mediaConstraints.video&&(this.mediaConstraints.video=!0),this.getMedia(this.mediaConstraints,e)}switchDesktopCaptureWithCamera(e){return void 0!==this.mediaConstraints.video&&0!=this.mediaConstraints.video&&(this.mediaConstraints.video=!0),this.publishMode="screen+camera",this.getMedia(this.mediaConstraints,e)}updateLocalAudioStream(e,t){var i=e.getAudioTracks()[0];if(null!=this.localStream&&null!=this.localStream.getAudioTracks()[0]){var r=this.localStream.getAudioTracks()[0];r!=i&&(this.localStream.removeTrack(r),r.stop(),this.localStream.addTrack(i))}else null!=this.localStream?this.localStream.addTrack(i):this.localStream=e;null!=this.localVideo&&(this.localVideo.srcObject=this.localStream),null!=t&&(e.getAudioTracks()[0].onended=function(e){t(e)}),this.isMuted?this.muteLocalMic():this.unmuteLocalMic(),null!=this.localStreamSoundMeter&&this.enableAudioLevelForLocalStream(this.levelCallback)}updateLocalVideoStream(e,t,i){i&&null!=this.desktopStream&&this.desktopStream.getVideoTracks()[0].stop();var r=e.getVideoTracks()[0];if(null!=this.localStream&&null!=this.localStream.getVideoTracks()[0]){var a=this.localStream.getVideoTracks()[0];a!=r&&(this.localStream.removeTrack(a),a.stop(),this.localStream.addTrack(r))}else null!=this.localStream?this.localStream.addTrack(r):this.localStream=e;this.localVideo&&(this.localVideo.srcObject=this.localStream),null!=t&&(e.getVideoTracks()[0].onended=function(e){t(e)})}switchAudioInputSource(e,t){var i=this.localStream.getAudioTracks()[0];if(i?i.stop():u.warn("There is no audio track in local stream"),void 0!==t){!0!==this.mediaConstraints.audio?this.mediaConstraints.audio.deviceId=t:this.mediaConstraints.audio={deviceId:t};var r={video:!1,audio:{deviceId:t}};return this.setAudioInputSource(e,r,null,t)}return new Promise(((e,t)=>{t("There is no device id for audio input source")}))}setAudioInputSource(e,t,i){return this.navigatorUserMedia(t,(r=>(r=this.setGainNodeStream(r),this.updateAudioTrack(r,e,t,i))),!0)}switchVideoCameraCapture(e,t,i){return this.localStream&&this.localStream.getVideoTracks().length>0?this.localStream.getVideoTracks()[0].stop():u.warn("There is no video track in local stream"),this.publishMode="camera",navigator.mediaDevices.enumerateDevices().then((i=>{for(var r=0;r{this.updateLocalAudioStream(e,i)})).catch((function(e){throw u.debug(e.name),e})):(this.updateLocalAudioStream(e,i),new Promise(((e,t)=>{e()})))}updateVideoTrack(e,t,i,r){var a=this.getSender(t,"video");return a?a.replaceTrack(e.getVideoTracks()[0]).then((t=>{this.updateLocalVideoStream(e,i,r)})).catch((e=>{u.debug(e.name)})):(this.updateLocalVideoStream(e,i,r),new Promise(((e,t)=>{e()})))}getBlackVideoTrack(){return this.dummyCanvas.getContext("2d").fillRect(0,0,320,240),this.replacementStream=this.dummyCanvas.captureStream(),null==this.blackFrameTimer&&(this.blackFrameTimer=setInterval((()=>{this.getBlackVideoTrack()}),3e3)),this.blackVideoTrack=this.replacementStream.getVideoTracks()[0],this.blackVideoTrack}getSilentAudioTrack(){this.stopSilentAudioTrack(),this.oscillator=this.audioContext.createOscillator();var e=this.oscillator.connect(this.audioContext.createMediaStreamDestination());return this.oscillator.start(),this.silentAudioTrack=e.stream.getAudioTracks()[0],this.silentAudioTrack}stopSilentAudioTrack(){null!=this.oscillator&&(this.oscillator.stop(),this.oscillator.disconnect(),this.oscillator=null),null!=this.silentAudioTrack&&(this.silentAudioTrack.stop(),this.silentAudioTrack=null)}turnOffLocalCamera(e){var t;return this.getBlackVideoTrack(),null!=this.localStream?(t=null!=e||void 0!==e?e:this.publishStreamId,this.cameraEnabled=!1,this.updateVideoTrack(this.replacementStream,t,null,!0)):new Promise(((e,t)=>{this.callbackError("NoActiveConnection"),t("NoActiveStream")}))}clearBlackVideoTrackTimer(){null!=this.blackFrameTimer&&(clearInterval(this.blackFrameTimer),this.blackFrameTimer=null)}stopBlackVideoTrack(){null!=this.blackVideoTrack&&(this.blackVideoTrack.stop(),this.blackVideoTrack=null)}turnOnLocalCamera(e){return this.clearBlackVideoTrackTimer(),this.stopBlackVideoTrack(),null==this.localStream?this.navigatorUserMedia(this.mediaConstraints,(e=>{this.gotStream(e)}),!1):this.navigatorUserMedia(this.mediaConstraints,(t=>{var i;i=null!=e||void 0!==e?e:this.publishStreamId,this.cameraEnabled=!0,this.updateVideoTrack(t,i,null,!0)}),!1)}muteLocalMic(){this.isMuted=!0,null!=this.localStream?this.localStream.getAudioTracks().forEach((e=>e.enabled=!1)):this.callbackError("NoActiveConnection")}unmuteLocalMic(){this.isMuted=!1,null!=this.localStream?this.localStream.getAudioTracks().forEach((e=>e.enabled=!0)):this.callbackError("NoActiveConnection")}getVideoSender(e){var t=null;return"undefined"!=typeof adapter&&null!==adapter&&("chrome"===adapter.browserDetails.browser||"firefox"===adapter.browserDetails.browser||"safari"===adapter.browserDetails.browser&&adapter.browserDetails.version>=64)&&"RTCRtpSender"in window&&"setParameters"in window.RTCRtpSender.prototype&&(t=this.getSender(e,"video")),t}changeBandwidth(e,t){var i=this.getVideoSender(t);if(null!=i){var r=i.getParameters();return r.encodings||(r.encodings=[{}]),"unlimited"===e?delete r.encodings[0].maxBitrate:r.encodings[0].maxBitrate=1e3*e,i.setParameters(r)}return"Video sender not found to change bandwidth. Streaming may not be active",Promise.reject("Video sender not found to change bandwidth. Streaming may not be active")}setVolumeLevel(e){this.currentVolume=e,null!=this.primaryAudioTrackGainNode&&(this.primaryAudioTrackGainNode.gain.value=e),null!=this.secondaryAudioTrackGainNode&&(this.secondaryAudioTrackGainNode.gain.value=e)}enableAudioLevelForLocalStream(e){return this.levelCallback=e,this.disableAudioLevelForLocalStream(),this.localStreamSoundMeter=new h(this.audioContext),"running"!==this.audioContext.state?this.audioContext.resume().then((()=>this.localStreamSoundMeter.connectToSource(this.localStream,e))):this.localStreamSoundMeter.connectToSource(this.localStream,e)}disableAudioLevelForLocalStream(){null!=this.localStreamSoundMeter&&(this.localStreamSoundMeter.stop(),this.localStreamSoundMeter=null)}applyConstraints(e){var t={};void 0===e.audio&&void 0===e.video?(t.video=e,this.mediaConstraints.video=Object.assign({},this.mediaConstraints.video,t.video)):void 0!==e.video&&(t.video=e.video,this.mediaConstraints.video=Object.assign({},this.mediaConstraints.video,t.video)),void 0!==e.audio&&(t.audio=e.audio,this.mediaConstraints.audio=Object.assign({},this.mediaConstraints.audio,t.audio));var i=null;return void 0!==t.video&&(i=this.localStream&&this.localStream.getVideoTracks().length>0?this.localStream.getVideoTracks()[0].applyConstraints(this.mediaConstraints.video):new Promise(((e,t)=>{t("There is no video track to apply constraints")}))),void 0!==t.audio&&(i=this.setAudioInputSource(this.publishStreamId,{audio:this.mediaConstraints.audio},null)),null!=this.localStreamSoundMeter&&this.enableAudioLevelForLocalStream(this.levelCallback),i}}var p=window.log;class f{constructor(e){this.size=e,this.received=0,this.data=new ArrayBuffer(e)}}class g{static register(e){g.pluginInitMethods.push(e)}constructor(e){for(var t in this.peerconnection_config={iceServers:[{urls:"stun:stun1.l.google.com:19302"}],sdpSemantics:"unified-plan"},this.sdp_constraints={OfferToReceiveAudio:!1,OfferToReceiveVideo:!1},this.remotePeerConnection=new Array,this.remotePeerConnectionStats=new Array,this.remoteDescriptionSet=new Array,this.iceCandidateList=new Array,this.roomName=null,this.playStreamId=new Array,this.isMultiPeer=!1,this.multiPeerStreamId=null,this.webSocketAdaptor=null,this.isPlayMode=!1,this.debug=!1,this.publishStreamId=null,this.idMapping=new Array,this.onlyDataChannel=!1,this.dataChannelEnabled=!0,this.receivingMessages=new Map,this.candidateTypes=["udp","tcp"],this.callback=null,this.callbackError=null,this.reconnectIfRequiredFlag=!0,this.websocket_url=null,this.websocketURL=null,this.initializeComponents=!0,e)e.hasOwnProperty(t)&&(this[t]=e[t]);if(null==this.websocketURL&&(this.websocketURL=this.websocket_url),null==this.websocketURL)throw new Error("WebSocket URL is not defined. It's mandatory");this.remoteVideo=this.remoteVideoElement||document.getElementById(this.remoteVideoId),this.soundMeters=new Array,this.soundLevelList=new Array,this.eventListeners=new Array,this.errorEventListeners=new Array,this.publishToken=null,this.publishSubscriberId=null,this.publishSubscriberCode=null,this.publishStreamName=null,this.publishMainTrack=null,this.publishMetaData=null,this.playToken=null,this.playRoomId=null,this.playEnableTracks=null,this.playSubscriberId=null,this.playSubscriberCode=null,this.playMetaData=null,this.lastReconnectiontionTrialTime=0,this.mediaManager=new m({userParameters:e,webRTCAdaptor:this,callback:(e,t)=>{this.notifyEventListeners(e,t)},callbackError:(e,t)=>{this.notifyErrorEventListeners(e,t)},getSender:(e,t)=>this.getSender(e,t)}),this.initializeComponents&&this.initialize()}initPlugins(){g.pluginInitMethods.forEach((e=>{e(this)}))}addEventListener(e){this.eventListeners.push(e)}addErrorEventListener(e){this.errorEventListeners.push(e)}notifyEventListeners(e,t){this.eventListeners.forEach((i=>{i(e,t)})),null!=this.callback&&this.callback(e,t)}notifyErrorEventListeners(e,t){this.errorEventListeners.forEach((i=>{i(e,t)})),null!=this.callbackError&&this.callbackError(e,t)}initialize(){return this.isPlayMode||this.onlyDataChannel||null!=this.mediaManager.localStream?new Promise(((e,t)=>{this.initPlugins(),this.checkWebSocketConnection(),e("Wait 'initialized' callback from websocket")})):this.mediaManager.initLocalStream().then((()=>(this.initPlugins(),this.checkWebSocketConnection(),new Promise(((e,t)=>{e("Wait 'initialized' callback from websocket")}))))).catch((e=>{throw p.warn(e),e}))}publish(e,t,i,r,a,n,o){if(this.publishStreamId=e,this.mediaManager.publishStreamId=e,this.publishToken=t,this.publishSubscriberId=i,this.publishSubscriberCode=r,this.publishStreamName=a,this.publishMainTrack=n,this.publishMetaData=o,this.onlyDataChannel)this.sendPublishCommand(e,t,i,r,a,n,o,!1,!1);else if(null==this.mediaManager.localStream)this.mediaManager.initLocalStream().then((()=>{var s=!1,d=!1;null!=this.mediaManager.localStream&&(s=this.mediaManager.localStream.getVideoTracks().length>0,d=this.mediaManager.localStream.getAudioTracks().length>0),this.sendPublishCommand(e,t,i,r,a,n,o,s,d)})).catch((e=>{throw p.warn(e),e}));else{var s=this.mediaManager.localStream.getVideoTracks().length>0,d=this.mediaManager.localStream.getAudioTracks().length>0;this.sendPublishCommand(e,t,i,r,a,n,o,s,d)}this.initPeerConnection(e,"publish"),setTimeout((()=>{"checking"!=this.iceConnectionState(this.publishStreamId)&&"connected"!=this.iceConnectionState(this.publishStreamId)&&"completed"!=this.iceConnectionState(this.publishStreamId)&&this.reconnectIfRequired(0)}),5e3)}sendPublishCommand(e,t,i,r,a,n,o,s,d){var c={command:"publish",streamId:e,token:t,subscriberId:void 0!==typeof i&&null!=i?i:"",subscriberCode:void 0!==typeof r&&null!=r?r:"",streamName:void 0!==typeof a&&null!=a?a:"",mainTrack:void 0!==typeof n&&null!=n?n:"",video:s,audio:d,metaData:void 0!==typeof o&&null!=o?o:""};this.webSocketAdaptor.send(JSON.stringify(c))}joinRoom(e,t,i){this.roomName=e;var r={command:"joinRoom",room:e,streamId:t,mode:i};this.webSocketAdaptor.send(JSON.stringify(r))}play(e,t,i,r,a,n,o){this.playStreamId.push(e),this.playToken=t,this.playRoomId=i,this.playEnableTracks=r,this.playSubscriberId=a,this.playSubscriberCode=n,this.playMetaData=o;var s={command:"play",streamId:e,token:void 0!==typeof t&&null!=t?t:"",room:void 0!==typeof i&&null!=i?i:"",trackList:void 0!==typeof r&&null!=r?r:[],subscriberId:void 0!==typeof a&&null!=a?a:"",subscriberCode:void 0!==typeof n&&null!=a?n:"",viewerInfo:void 0!==typeof o&&null!=o?o:""};this.webSocketAdaptor.send(JSON.stringify(s)),this.initPeerConnection(e,"play"),setTimeout((()=>{"checking"!=this.iceConnectionState(e)&&"connected"!=this.iceConnectionState(e)&&"completed"!=this.iceConnectionState(e)&&this.reconnectIfRequired(0)}),5e3)}reconnectIfRequired(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:3e3;this.reconnectIfRequiredFlag&&(e>0?setTimeout((()=>{this.tryAgain()}),e):this.tryAgain())}tryAgain(){var e=Date.now();if(!(e-this.lastReconnectiontionTrialTime<3e3))for(var t in this.lastReconnectiontionTrialTime=e,null!=this.remotePeerConnection[this.publishStreamId]&&"checking"!=this.iceConnectionState(this.publishStreamId)&&"connected"!=this.iceConnectionState(this.publishStreamId)&&"completed"!=this.iceConnectionState(this.publishStreamId)&&(this.notifyEventListeners("reconnection_attempt_for_publisher",this.publishStreamId),this.closePeerConnection(this.publishStreamId),p.log("It will try to publish again because it is not stopped on purpose"),this.publish(this.publishStreamId,this.publishToken,this.publishSubscriberId,this.publishSubscriberCode,this.publishStreamName,this.publishMainTrack,this.publishMetaData)),this.playStreamId){var i=this.playStreamId[t];"null"!=this.remotePeerConnection[i]&&"checking"!=this.iceConnectionState(i)&&"connected"!=this.iceConnectionState(i)&&"completed"!=this.iceConnectionState(i)&&(this.notifyEventListeners("reconnection_attempt_for_player",i),p.log("It will try to play again because it is not stopped on purpose"),this.closePeerConnection(i),this.play(i,this.playToken,this.playRoomId,this.playEnableTracks,this.playSubscriberId,this.playSubscriberCode,this.playMetaData))}}stop(e){if(this.closePeerConnection(e),null!=this.webSocketAdaptor&&this.webSocketAdaptor.isConnected()){var t={command:"stop",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}}join(e){var t={command:"join",streamId:e,multiPeer:this.isMultiPeer&&null==this.multiPeerStreamId,mode:this.isPlayMode?"play":"both"};this.webSocketAdaptor.send(JSON.stringify(t))}onTrack(e,t){if(p.debug("onTrack for stream"),null!=this.remoteVideo)this.remoteVideo.srcObject!==e.streams[0]&&(this.remoteVideo.srcObject=e.streams[0],p.debug("Received remote stream"));else{var i={stream:e.streams[0],track:e.track,streamId:t,trackId:this.idMapping[t][e.transceiver.mid]};this.notifyEventListeners("newTrackAvailable",i),this.notifyEventListeners("newStreamAvailable",i)}}leaveFromRoom(e){for(var t in this.remotePeerConnection)this.closePeerConnection(t);this.roomName=e;var i={command:"leaveFromRoom",room:e};p.debug("leave request is sent for "+e),this.webSocketAdaptor.send(JSON.stringify(i))}leave(e){var t={command:"leave",streamId:this.isMultiPeer&&null!=this.multiPeerStreamId?this.multiPeerStreamId:e};this.webSocketAdaptor.send(JSON.stringify(t)),this.closePeerConnection(e),this.multiPeerStreamId=null}getStreamInfo(e){var t={command:"getStreamInfo",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}requestVideoTrackAssignments(e){var t={command:"getVideoTrackAssignments",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}getBroadcastObject(e){var t={command:"getBroadcastObject",streamId:e};this.webSocketAdaptor.send(JSON.stringify(t))}updateStreamMetaData(e,t){var i={command:"updateStreamMetaData",streamId:e,metaData:t};this.webSocketAdaptor.send(JSON.stringify(i))}getRoomInfo(e,t){var i={command:"getRoomInfo",streamId:t,room:e};this.webSocketAdaptor.send(JSON.stringify(i))}enableTrack(e,t,i){var r={command:"enableTrack",streamId:e,trackId:t,enabled:i};this.webSocketAdaptor.send(JSON.stringify(r))}getTracks(e,t){this.playStreamId.push(e);var i={command:"getTrackList",streamId:e,token:t};this.webSocketAdaptor.send(JSON.stringify(i))}iceCandidateReceived(e,t){if(e.candidate){var i=!1;if(""==e.candidate.candidate?i=!0:void 0===e.candidate.protocol?this.candidateTypes.forEach((t=>{e.candidate.candidate.toLowerCase().includes(t)&&(i=!0)})):i=this.candidateTypes.includes(e.candidate.protocol.toLowerCase()),i){var r={command:"takeCandidate",streamId:t,label:e.candidate.sdpMLineIndex,id:e.candidate.sdpMid,candidate:e.candidate.candidate};this.debug&&(p.debug("sending ice candiate for stream Id "+t),p.debug(JSON.stringify(e.candidate))),this.webSocketAdaptor.send(JSON.stringify(r))}else p.debug("Candidate's protocol(full sdp: "+e.candidate.candidate+") is not supported. Supported protocols: "+this.candidateTypes),""!=e.candidate.candidate&&this.notifyErrorEventListeners("protocol_not_supported","Support protocols: "+this.candidateTypes.toString()+" candidate: "+e.candidate.candidate)}else p.debug("No event.candidate in the iceCandidate event")}sanitizeHTML(e){return e.includes("script")?e.replace(//g,">"):e}initDataChannel(e,t){t.onerror=i=>{p.debug("Data Channel Error:",i);var r={streamId:e,error:i};p.debug("channel status: ",t.readyState),"closed"!=t.readyState&&this.notifyErrorEventListeners("data_channel_error",r)},t.onmessage=t=>{var i={streamId:e,data:t.data},r=i.data;if("string"==typeof r||r instanceof String)i.data=this.sanitizeHTML(i.data),this.notifyEventListeners("data_received",i);else{var a=r.length||r.size||r.byteLength,n=new Int32Array(r,0,1)[0],o=this.receivingMessages[n];if(null==o){var s=new Int32Array(r,0,2)[1];return o=new f(s),this.receivingMessages[n]=o,void(a>8&&p.debug("something went wrong in msg receiving"))}var d=r.slice(4,a);new Uint8Array(o.data).set(new Uint8Array(d),o.received,a-4),o.received+=a-4,o.size==o.received&&(i.data=o.data,this.notifyEventListeners("data_received",i))}},t.onopen=()=>{this.remotePeerConnection[e].dataChannel=t,p.debug("Data channel is opened"),this.notifyEventListeners("data_channel_opened",e)},t.onclose=()=>{p.debug("Data channel is closed"),this.notifyEventListeners("data_channel_closed",e)}}initPeerConnection(e,t){if(null==this.remotePeerConnection[e]){var i=e;if(p.debug("stream id in init peer connection: "+e+" close stream id: "+i),this.remotePeerConnection[e]=new RTCPeerConnection(this.peerconnection_config),this.remoteDescriptionSet[e]=!1,this.iceCandidateList[e]=new Array,this.playStreamId.includes(e)||null!=this.mediaManager.localStream&&this.mediaManager.localStream.getTracks().forEach((t=>this.remotePeerConnection[e].addTrack(t,this.mediaManager.localStream))),this.remotePeerConnection[e].onicecandidate=e=>{this.iceCandidateReceived(e,i)},this.remotePeerConnection[e].ontrack=e=>{this.onTrack(e,i)},this.remotePeerConnection[e].onnegotiationneeded=e=>{p.debug("onnegotiationneeded")},this.dataChannelEnabled)if("publish"==t)if(this.remotePeerConnection[e].createDataChannel){var r=this.remotePeerConnection[e].createDataChannel(e,{ordered:!0});this.initDataChannel(e,r)}else p.warn("CreateDataChannel is not supported");else if("play"==t)this.remotePeerConnection[e].ondatachannel=t=>{this.initDataChannel(e,t.channel)};else if(this.remotePeerConnection[e].createDataChannel){var a=this.remotePeerConnection[e].createDataChannel(e,{ordered:!0});this.initDataChannel(e,a),this.remotePeerConnection[e].ondatachannel=t=>{this.initDataChannel(e,t.channel)}}else p.warn("CreateDataChannel is not supported");this.remotePeerConnection[e].oniceconnectionstatechange=t=>{var i={state:this.remotePeerConnection[e].iceConnectionState,streamId:e};"failed"!=i.state&&"disconnected"!=i.state&&"closed"!=i.state||this.reconnectIfRequired(3e3),this.notifyEventListeners("ice_connection_state_changed",i),this.isPlayMode||this.playStreamId.includes(e)||"connected"==this.remotePeerConnection[e].iceConnectionState&&this.mediaManager.changeBandwidth(this.mediaManager.bandwidth,e).then((()=>{p.debug("Bandwidth is changed to "+this.mediaManager.bandwidth)})).catch((e=>p.warn(e)))}}}closePeerConnection(e){var t=this.remotePeerConnection[e];if(null!=t){this.remotePeerConnection[e]=null,delete this.remotePeerConnection[e],null!=t.dataChannel&&t.dataChannel.close(),"closed"!=t.signalingState&&t.close();var i=this.playStreamId.indexOf(e);-1!=i&&this.playStreamId.splice(i,1)}null!=this.remotePeerConnectionStats[e]&&(clearInterval(this.remotePeerConnectionStats[e].timerId),delete this.remotePeerConnectionStats[e]),null!=this.soundMeters[e]&&delete this.soundMeters[e]}signallingState(e){return null!=this.remotePeerConnection[e]?this.remotePeerConnection[e].signalingState:null}iceConnectionState(e){return null!=this.remotePeerConnection[e]?this.remotePeerConnection[e].iceConnectionState:null}gotDescription(e,t){this.remotePeerConnection[t].setLocalDescription(e).then((i=>{p.debug("Set local description successfully for stream Id "+t);var r={command:"takeConfiguration",streamId:t,type:e.type,sdp:e.sdp};p.debug("setLocalDescription:"+e.sdp),this.webSocketAdaptor.send(JSON.stringify(r))})).catch((e=>{p.error("Cannot set local description. Error is: "+e)}))}takeConfiguration(e,t,i,r){var a=e,n=i,o=t,s="offer"==n,d="publish";s&&(d="play"),this.idMapping[a]=r,this.initPeerConnection(a,d),p.debug("setRemoteDescription:"+o),this.remotePeerConnection[a].setRemoteDescription(new RTCSessionDescription({sdp:o,type:n})).then((e=>{this.debug&&(p.debug("set remote description is succesfull with response: "+e+" for stream : "+a+" and type: "+n),p.debug(o)),this.remoteDescriptionSet[a]=!0;var t=this.iceCandidateList[a].length;p.debug("Ice candidate list size to be added: "+t);for(var i=0;i{p.debug("created answer for stream id: "+a),e.sdp=e.sdp.replace("useinbandfec=1","useinbandfec=1; stereo=1"),this.gotDescription(e,a)})).catch((e=>{p.error("create answer error :"+e)})))})).catch((e=>{this.debug&&p.error("set remote description is failed with error: "+e),(e.toString().indexOf("InvalidAccessError")>-1||e.toString().indexOf("setRemoteDescription")>-1)&&this.notifyErrorEventListeners("notSetRemoteDescription")}))}takeCandidate(e,t,i){var r=e,a=i,n=new RTCIceCandidate({sdpMLineIndex:t,candidate:a});this.initPeerConnection(r,"peer"),p.debug("takeCandidate:"+a),1==this.remoteDescriptionSet[r]?this.addIceCandidate(r,n):(p.debug("Ice candidate is added to list because remote description is not set yet"),this.iceCandidateList[r].push(n))}addIceCandidate(e,t){var i=!1;""==t.candidate?i=!0:void 0===t.protocol?this.candidateTypes.forEach((e=>{t.candidate.toLowerCase().includes(e)&&(i=!0)})):i=this.candidateTypes.includes(t.protocol.toLowerCase()),i?this.remotePeerConnection[e].addIceCandidate(t).then((t=>{this.debug&&p.debug("Candidate is added for stream "+e)})).catch((i=>{p.error("ice candiate cannot be added for stream id: "+e+" error is: "+i),p.error(t)})):this.debug&&p.debug("Candidate's protocol("+t.protocol+") is not supported.Candidate: "+t.candidate+" Supported protocols:"+this.candidateTypes)}startPublishing(e){var t=e;this.initPeerConnection(t,"publish"),this.remotePeerConnection[t].createOffer(this.sdp_constraints).then((e=>{this.gotDescription(e,t)})).catch((e=>{p.error("create offer error for stream id: "+t+" error: "+e)}))}toggleVideo(e,t,i){var r={command:"toggleVideo",streamId:e,trackId:t,enabled:i};this.webSocketAdaptor.send(JSON.stringify(r))}toggleAudio(e,t,i){var r={command:"toggleAudio",streamId:e,trackId:t,enabled:i};this.webSocketAdaptor.send(JSON.stringify(r))}getStats(e){return p.debug("peerstatsgetstats = "+this.remotePeerConnectionStats[e]),new Promise(((t,i)=>{this.remotePeerConnection[e].getStats(null).then((i=>{var r=-1,a=-1,n=-1,o=-1,s=-1,d=-1,c=-1,l=-1,h=-1,u="",m=-1,p=-1,f=-1,g=-1,v=-1,y=-1,b=-1,S=-1,w=-1,C=-1,k=-1,T=-1,A=-1,E=-1,P=-1,I=1/0;i.forEach((e=>{"inbound-rtp"==e.type&&void 0!==e.kind?(r+=e.bytesReceived,"audio"==e.kind?n=e.packetsLost:"video"==e.kind&&(a=e.packetsLost),o+=e.fractionLost,s=e.timestamp):"outbound-rtp"==e.type?("audio"==e.kind?l=e.packetsSent:"video"==e.kind&&(c=e.packetsSent),d+=e.bytesSent,s=e.timestamp,u=e.qualityLimitationReason,null!=e.framesEncoded&&(m+=e.framesEncoded)):"track"==e.type&&void 0!==e.kind&&"audio"==e.kind?(void 0!==e.audioLevel&&(h=e.audioLevel),void 0!==e.jitterBufferDelay&&void 0!==e.jitterBufferEmittedCount&&(E=e.jitterBufferDelay/e.jitterBufferEmittedCount)):"track"==e.type&&void 0!==e.kind&&"video"==e.kind?(void 0!==e.frameWidth&&(v=e.frameWidth),void 0!==e.frameHeight&&(y=e.frameHeight),void 0!==e.framesDecoded&&(k=e.framesDecoded),void 0!==e.framesDropped&&(T=e.framesDropped),void 0!==e.framesReceived&&(A=e.framesReceived),void 0!==e.jitterBufferDelay&&void 0!==e.jitterBufferEmittedCount&&(P=e.jitterBufferDelay/e.jitterBufferEmittedCount)):"remote-inbound-rtp"==e.type&&void 0!==e.kind?(void 0!==e.packetsLost&&("video"==e.kind?a=e.packetsLost:"audio"==e.kind&&(n=e.packetsLost)),void 0!==e.roundTripTime&&("video"==e.kind?b=e.roundTripTime:"audio"==e.kind&&(w=e.roundTripTime)),void 0!==e.jitter&&("video"==e.kind?S=e.jitter:"audio"==e.kind&&(C=e.jitter))):"media-source"==e.type?"video"==e.kind&&(p=e.width,f=e.height,g=e.framesPerSecond):"candidate-pair"==e.type&&"succeeded"==e.state&&null!=e.availableOutgoingBitrate&&(I=e.availableOutgoingBitrate/1e3)})),this.remotePeerConnectionStats[e].totalBytesReceived=r,this.remotePeerConnectionStats[e].videoPacketsLost=a,this.remotePeerConnectionStats[e].audioPacketsLost=n,this.remotePeerConnectionStats[e].fractionLost=o,this.remotePeerConnectionStats[e].currentTime=s,this.remotePeerConnectionStats[e].totalBytesSent=d,this.remotePeerConnectionStats[e].totalVideoPacketsSent=c,this.remotePeerConnectionStats[e].totalAudioPacketsSent=l,this.remotePeerConnectionStats[e].audioLevel=h,this.remotePeerConnectionStats[e].qualityLimitationReason=u,this.remotePeerConnectionStats[e].totalFramesEncoded=m,this.remotePeerConnectionStats[e].resWidth=p,this.remotePeerConnectionStats[e].resHeight=f,this.remotePeerConnectionStats[e].srcFps=g,this.remotePeerConnectionStats[e].frameWidth=v,this.remotePeerConnectionStats[e].frameHeight=y,this.remotePeerConnectionStats[e].videoRoundTripTime=b,this.remotePeerConnectionStats[e].videoJitter=S,this.remotePeerConnectionStats[e].audioRoundTripTime=w,this.remotePeerConnectionStats[e].audioJitter=C,this.remotePeerConnectionStats[e].framesDecoded=k,this.remotePeerConnectionStats[e].framesDropped=T,this.remotePeerConnectionStats[e].framesReceived=A,this.remotePeerConnectionStats[e].videoJitterAverageDelay=P,this.remotePeerConnectionStats[e].audioJitterAverageDelay=E,this.remotePeerConnectionStats[e].availableOutgoingBitrate=I,this.notifyEventListeners("updated_stats",this.remotePeerConnectionStats[e]),t(!0)})).catch((e=>{t(!1)}))}))}enableStats(e){null==this.remotePeerConnectionStats[e]&&(this.remotePeerConnectionStats[e]=new s(e),this.remotePeerConnectionStats[e].timerId=setInterval((()=>{this.getStats(e)}),5e3))}disableStats(e){null==this.remotePeerConnectionStats[e]&&void 0===this.remotePeerConnectionStats[e]||clearInterval(this.remotePeerConnectionStats[e].timerId)}checkWebSocketConnection(){(null==this.webSocketAdaptor||0==this.webSocketAdaptor.isConnected()&&0==this.webSocketAdaptor.isConnecting())&&(p.debug("websocket url : "+this.websocketURL),this.webSocketAdaptor=new c({websocket_url:this.websocketURL,webrtcadaptor:this,callback:(e,t)=>{"closed"==e&&this.reconnectIfRequired(),this.notifyEventListeners(e,t)},callbackError:(e,t)=>{this.notifyErrorEventListeners(e,t)},debug:this.debug}))}closeWebSocket(){for(var e in this.remotePeerConnection)this.closePeerConnection(e);this.remotePeerConnection=new Array,this.webSocketAdaptor.close()}peerMessage(e,t,i){var r={command:"peerMessageCommand",streamId:e,definition:t,data:i};this.webSocketAdaptor.send(JSON.stringify(r))}forceStreamQuality(e,t){var i={command:"forceStreamQuality",streamId:e,streamHeight:t};this.webSocketAdaptor.send(JSON.stringify(i))}sendData(e,t){if(void 0!==this.remotePeerConnection[e]){var i=this.remotePeerConnection[e].dataChannel;if(null==i||void 0===i)return void p.warn("dataChannel is null or undefined");if("open"!==i.readyState)return void p.warn("dataChannel.readyState is not open: "+i.readyState);var r=t.length||t.size||t.byteLength,a=0;if("string"==typeof t||t instanceof String)i.send(t);else{var n=Math.floor(999999*Math.random()),o=new Int32Array(2);for(o[0]=n,o[1]=r,i.send(o),a=0;a{}),(function(e){e?alert(e):p.debug("Added sound meter for stream: "+t+" = "+i.instant.toFixed(2))})),this.soundMeters[t]=i}getSoundLevelList(e){for(var t=0;ti.length)&&(t=i.length),t-=e.length;var r=i.lastIndexOf(e,t);return-1!==r&&r===t}),function(){function e(e){var t=0;return function(){return t>>0)+"_",a=0;return function e(i){if(this instanceof e)throw TypeError("Symbol is not a constructor");return new t(r+(i||"")+"_"+a++,i)}})),a("Symbol.iterator",(function(t){if(t)return t;t=Symbol("Symbol.iterator");for(var a="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),o=0;o(t=t||0)&&(t=Math.max(t+r,0));tn)r[i++]=n;else{if(2048>n)r[i++]=n>>6|192;else{if(55296<=n&&57343>=n){if(56319>=n&&a=o){n=1024*(n-55296)+o-56320+65536,r[i++]=n>>18|240,r[i++]=n>>12&63|128,r[i++]=n>>6&63|128,r[i++]=63&n|128;continue}a--}if(t)throw Error("Found an unpaired surrogate");n=65533}r[i++]=n>>12|224,r[i++]=n>>6&63|128}r[i++]=63&n|128}}e=r.subarray(0,i)}return e}var O={},_=null;function D(e,t){void 0===t&&(t=0),N(),t=O[t];for(var i=Array(Math.floor(e.length/3)),r=t[64]||"",a=0,n=0;a>2];o=t[(3&o)<<4|s>>4],s=t[(15&s)<<2|d>>6],d=t[63&d],i[n++]=c+o+s+d}switch(c=0,d=r,e.length-a){case 2:d=t[(15&(c=e[a+1]))<<2]||r;case 1:e=e[a],i[n]=t[e>>2]+t[(3&e)<<4|c>>4]+d+r}return i.join("")}function N(){if(!_){_={};for(var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""),t=["+/=","+/","-_=","-_.","-_"],i=0;5>i;i++){var r=e.concat(t[i].split(""));O[i]=r;for(var a=0;a>4),64!=o&&(t(n<<4&240|o>>2),64!=s&&t(o<<6&192|s))}}(i,(function(e){n[o++]=e})),n.subarray(0,o)):t instanceof Uint8Array?new Uint8Array(t.buffer,t.byteOffset,t.byteLength):new Uint8Array(0),e.h=t,e.j=0,e.i=e.h.length,e.g=e.j}function G(e){var t=e.h,i=t[e.g],r=127&i;return 128>i?(e.g+=1,r):(r|=(127&(i=t[e.g+1]))<<7,128>i?(e.g+=2,r):(r|=(127&(i=t[e.g+2]))<<14,128>i?(e.g+=3,r):(r|=(127&(i=t[e.g+3]))<<21,128>i?(e.g+=4,r):(r|=(15&(i=t[e.g+4]))<<28,128>i?(e.g+=5,r>>>0):(e.g+=5,128<=t[e.g++]&&128<=t[e.g++]&&128<=t[e.g++]&&128<=t[e.g++]&&e.g++,r)))))}function J(e){var t=e.h[e.g],i=e.h[e.g+1],r=e.h[e.g+2],a=e.h[e.g+3];return e.g+=4,e=2*((i=(t<<0|i<<8|r<<16|a<<24)>>>0)>>31)+1,t=i>>>23&255,i&=8388607,255==t?i?NaN:1/0*e:0==t?1401298464324817e-60*e*i:e*Math.pow(2,t-150)*(i+8388608)}U.prototype.reset=function(){this.g=this.j};var H=[];function z(){this.g=new Uint8Array(64),this.h=0}function Y(e,t){for(;127>>=7;e.push(t)}function q(e){var t={},i=void 0!==t.N&&t.N;this.o={v:void 0!==t.v&&t.v},this.N=i,t=this.o,H.length?(i=H.pop(),t&&(i.v=t.v),e&&W(i,e),e=i):e=new U(e,t),this.g=e,this.m=this.g.g,this.h=this.i=this.l=-1,this.j=!1}function X(e){var t=e.g;if((t=t.g==t.i)||(t=e.j)||(t=(t=e.g).l||0>t.g||t.g>t.i),t)return!1;e.m=e.g.g;var i=7&(t=G(e.g));return 0!=i&&5!=i&&1!=i&&2!=i&&3!=i&&4!=i?(e.j=!0,!1):(e.i=t,e.l=t>>>3,e.h=i,!0)}function K(e,t,i){var r=e.g.i,a=G(e.g);return a=e.g.g+a,e.g.i=a,i(t,e),e.g.g=a,e.g.i=r,t}function Q(e){var t=G(e.g),i=(e=e.g).g;if(e.g+=t,e=e.h,R)(r=I)||(r=I=new TextDecoder("utf-8",{fatal:!1})),r=r.decode(e.subarray(i,i+t));else{t=i+t;for(var r,a,n,o,s=[],d=null;i(a=e[i++])?s.push(a):224>a?i>=t?s.push(65533):(n=e[i++],194>a||128!=(192&n)?(i--,s.push(65533)):s.push((31&a)<<6|63&n)):240>a?i>=t-1?s.push(65533):128!=(192&(n=e[i++]))||224===a&&160>n||237===a&&160<=n||128!=(192&(r=e[i++]))?(i--,s.push(65533)):s.push((15&a)<<12|(63&n)<<6|63&r):244>=a?i>=t-2?s.push(65533):128!=(192&(n=e[i++]))||0!=n-144+(a<<28)>>30||128!=(192&(r=e[i++]))||128!=(192&(o=e[i++]))?(i--,s.push(65533)):(a=(7&a)<<18|(63&n)<<12|(63&r)<<6|63&o,a-=65536,s.push(55296+(a>>10&1023),56320+(1023&a))):s.push(65533),8192<=s.length&&(d=E(d,s),s.length=0);r=E(d,s)}return r}function $(){this.h=[],this.i=0,this.g=new z}function Z(e,t){0!==t.length&&(e.h.push(t),e.i+=t.length)}function ee(e){var t=e.i+e.g.length();if(0===t)return new Uint8Array(0);t=new Uint8Array(t);for(var i=e.h,r=i.length,a=0,n=0;nr?1:0)?-r:r)?B=0<1/r?0:2147483648:isNaN(r)?B=2147483647:34028234663852886e22>>0:11754943508222875e-54>r?B=(i<<31|(r=Math.round(r/1401298464324817e-60)))>>>0:(t=Math.floor(Math.log(r)/Math.LN2),r*=Math.pow(2,-t),B=(i<<31|t+127<<23|(r=8388607&Math.round(8388608*r)))>>>0),i=B,e.push(i>>>0&255),e.push(i>>>8&255),e.push(i>>>16&255),e.push(i>>>24&255)}}z.prototype.push=function(e){if(!(this.h+1=e.l?e.h?e.h[t]:void 0:e.g[t+e.j]}function ue(e){var t=void 0!==t&&t,i=he(e,1,t);return null==i&&(i=ce),i===ce&&pe(e,1,i=se([]),t),i}function me(e,t,i){return null==(e=null==(e=he(e,t))?e:+e)?void 0===i?0:i:e}function pe(e,t,i,r){void 0!==r&&r||t>=e.l?(le(e),e.h[t]=i):e.g[t+e.j]=i}function fe(e,t){e.i||(e.i={});var i=e.i[1];if(!i){var r=ue(e);i=[];for(var a=0;a_&&128<=x;_++)O|=(127&(x=M.h[M.g++]))<<7*_;if(128<=x&&(O|=(127&(x=M.h[M.g++]))<<28,R|=(127&x)>>4),128<=x)for(_=0;5>_&&128<=x;_++)R|=(127&(x=M.h[M.g++]))<<7*_+3;128>x?(M=O>>>0,(R=2147483648&(x=R>>>0))&&(x=~x>>>0,0==(M=1+~M>>>0)&&(x=x+1>>>0)),M=4294967296*x+(M>>>0),R=R?-M:M):(M.l=!0,R=void 0),pe(L,6,R);break;default:if(!we(L,I))break e}}L={Z:me(L,1),$:me(L,2),height:me(L,3),width:me(L,4),rotation:me(L,5,0),X:ye(L,6)},R=T.get(P);e:for(I=new Le,R=new q(R);X(R);)if(10===R.i)ge(I,M=K(R,new Pe,Ie),Pe,void 0);else if(!we(I,R))break e;I=fe(I,Pe).map(_e),M=A.get(P);e:for(R=new Ae,M=new q(M);X(M);)if(10===M.i)R.addClassification(K(M,new ke,Te));else if(!we(R,M))break e;L={T:L,O:I,M:Oe(R)},E.push(L)}k=E}else k=[];t[d]=k,e.g=7;break}if("proto_list"===h.type){if(u){for(T=0,k=Array(u.size());TP;var I=(P=Math.abs(P))>>>0;for(P=Math.floor((P-I)/4294967296),P>>>=0,A&&(P=~P>>>0,4294967295<(I=1+(~I>>>0))&&(I=0,4294967295<++P&&(P=0))),A=B=I,I=P;0>>7|I<<25)>>>0,I>>>=7;E.push(A)}if(Se(k,T),C=ee(C),S.call(b,w,C),y.O)for(b=0;bP;P++)A.push(127&I|128),I>>=7;A.push(1)}te(E,2,he(T,2)),null!=(A=he(T,3))&&(A=x(A),Y(E.g,26),Y(E.g,A.length),Z(E,E.g.end()),Z(E,A)),null!=(A=he(T,4))&&(A=x(A),Y(E.g,34),Y(E.g,A.length),Z(E,E.g.end()),Z(E,A)),Se(T,E),k=ee(k),w.call(S,C,k)}}p=p.data;break e;default:p={}}}switch(l=p,h=c.stream,c.type){case"video":a.pushTexture2d(Object.assign(Object.assign({},l),{stream:h,timestamp:r}));break;case"detections":(u=l).stream=h,u.timestamp=r,a.pushDetectionList(u);break;default:throw Error("Unknown input config type: '"+c.type+"'")}}return m.i.send(a),v(i,m.C,4);case 4:a.delete(),i.g=0}}))}))},d.onResults=function(e,t){this.listeners[t||"$"]=e},A("Solution",Ue),A("OptionType",{BOOL:0,NUMBER:1,aa:2,0:"BOOL",1:"NUMBER",2:"STRING"}),(d=He.prototype).close=function(){return this.g.close(),Promise.resolve()},d.onResults=function(e){this.g.onResults(e)},d.initialize=function(){return Ce(this,(function e(){var t=this;return C(e,(function(e){return v(e,t.g.initialize(),0)}))}))},d.reset=function(){this.g.reset()},d.send=function(e){return Ce(this,(function t(){var i=this;return C(t,(function(t){return v(t,i.g.send(e),0)}))}))},d.setOptions=function(e){this.g.setOptions(e)},A("SelfieSegmentation",He),A("VERSION","0.1.1632777926")}.call(void 0);var y=window.log,b=new WeakMap,S=new WeakSet;class w{constructor(e){var t;o(this,t=S),t.add(this),function(e,t,i){o(e,t),t.set(e,{writable:!0,value:null})}(this,b),this.webRTCAdaptor=e,this.selfieSegmentation=null,this.effectCanvas=null,this.ctx=null,this.rawLocalVideo=document.createElement("video"),this.deepAR=null,this.backgroundBlurRange=3,this.edgeBlurRange=4,this.effectName=w.NO_EFFECT,this.startTime=0,this.statTimerId=-1,this.renderedFrameCount=0,this.lastRenderedFrameCount=0,this.effectCanvasFPS=0,this.videoCallbackPeriodMs=0,this.initializeSelfieSegmentation(),this.isInitialized=!0}init(e){var i=this;return t((function*(){yield i.setRawLocalVideo(e);var t=e.getVideoTracks()[0].getSettings();return i.effectCanvasFPS=t.frameRate,i.videoCallbackPeriodMs=1e3/i.effectCanvasFPS,i.effectCanvas=i.createEffectCanvas(t.width,t.height),i.ctx=i.effectCanvas.getContext("2d"),i.canvasStream&&(i.canvasStream.getTracks().forEach((e=>e.stop())),i.canvasStream=null),i.canvasStream=i.effectCanvas.captureStream(i.effectCanvasFPS),new Promise(((e,t)=>{e(i.canvasStream)}))}))()}setRawLocalVideo(e){return this.rawLocalVideo.srcObject=e,this.rawLocalVideo.muted=!0,this.rawLocalVideo.autoplay=!0,this.rawLocalVideo.play()}createEffectCanvas(e,t){var i=document.createElement("canvas");return i.id="effectCanvas",i.width=e,i.height=t,i}initializeSelfieSegmentation(){this.selfieSegmentation=new SelfieSegmentation({locateFile:e=>w.LOCATE_FILE_URL+"/"+e}),this.selfieSegmentation.setOptions({selfieMode:!1,modelSelection:1}),this.selfieSegmentation.onResults((e=>{this.onResults(e)}))}set virtualBackgroundImage(e){var t,i;i=e,function(e,t,i){if(t.set)t.set.call(e,i);else{if(!t.writable)throw new TypeError("attempted to set read only private field");t.value=i}}(t=this,a(t,b,"set"),i)}startFpsCalculation(){this.statTimerId=setInterval((()=>{var e=(new Date).getTime(),t=(e-this.startTime)/1e3;this.startTime=e;var i=(this.renderedFrameCount-this.lastRenderedFrameCount)/t;this.renderedFrameCount=this.lastRenderedFrameCount,y.warn("Fps: "+i+"fps")}),1e3)}stopFpsCalculation(){-1!==this.statTimerId&&(clearInterval(this.statTimerId),this.statTimerId=-1)}processFrame(){var e=this;return t((function*(){yield e.selfieSegmentation.send({image:e.rawLocalVideo}),e.effectName!==w.NO_EFFECT&&setTimeout((()=>{e.processFrame()}),e.videoCallbackPeriodMs)}))()}enableEffect(e,i,r){var a=this;return t((function*(){if(a.isInitialized){switch(e){case w.DEEPAR:case w.VIRTUAL_BACKGROUND:case w.BLUR_BACKGROUND:case w.NO_EFFECT:break;default:return void y.warn("Unknown effect name please use the constants VideoEffect.VIRTUAL_BACKGROUND,VideoEffect.BLUR_BACKGROUND or VideoEffect.NO_EFFECT ")}var t=a.effectName;if(a.effectName=e,t===w.DEEPAR&&e!==w.DEEPAR&&(a.deepAR.shutdown(),a.deepAR=null),e===w.VIRTUAL_BACKGROUND||e===w.BLUR_BACKGROUND)return t===w.NO_EFFECT||t===w.DEEPAR?(w.DEBUG&&a.startFpsCalculation(),navigator.mediaDevices.getUserMedia({video:a.webRTCAdaptor.mediaConstraints.video,audio:!0}).then((e=>a.init(e).then((e=>a.webRTCAdaptor.updateVideoTrack(e,a.webRTCAdaptor.publishStreamId,null,!0).then((()=>{setTimeout((()=>{a.processFrame()}),a.videoCallbackPeriodMs)})))).catch((e=>{throw y.error(e),e}))))):new Promise(((e,t)=>{e()}));if(e!==w.DEEPAR){if(t===w.DEEPAR){var o=yield navigator.mediaDevices.getUserMedia({video:a.webRTCAdaptor.mediaConstraints.video,audio:!0});yield a.setRawLocalVideo(o)}return new Promise(((e,t)=>{a.stopFpsCalculation(),n(a,S,C).call(a),e()}))}if(null!=i&&""!==i&&null!=r&&""!==r)if(t!==w.DEEPAR){t!==w.BLUR_BACKGROUND&&t!==w.VIRTUAL_BACKGROUND||(a.stopFpsCalculation(),yield n(a,S,C).call(a));var s=a.createEffectCanvas(500,500),d=new DeepAR({licenseKey:i,canvas:s,deeparWasmPath:w.DEEP_AR_FOLDER_ROOT_URL+"/wasm/deepar.wasm",callbacks:{onInitialize:function(){d.startVideo(!0)}}});a.deepAR=d,a.deepAR.callbacks.onVideoStarted=()=>{a.canvasStream=s.captureStream(30),a.webRTCAdaptor.updateVideoTrack(a.canvasStream,a.webRTCAdaptor.publishStreamId,null,!0),a.deepAR.switchEffect(0,"slot",w.DEEP_AR_EFFECTS_URL+r+w.DEEP_AR_EXTENSION)},a.deepAR.downloadFaceTrackingModel(w.DEEP_AR_FOLDER_ROOT_URL+"/models/face/models-68-extreme.bin"),a.deepAR.setVideoElement(a.rawLocalVideo,!0)}else a.deepAR.switchEffect(0,"slot",w.DEEP_AR_EFFECTS_URL+r+w.DEEP_AR_EXTENSION);else y.error("DeepAR API key or DeepAR Model is not set!")}else y.error("VideoEffect is not initialized!")}))()}drawSegmentationMask(e){this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height)}onResults(e){this.renderedFrameCount++,this.effectName==w.BLUR_BACKGROUND?this.drawBlurBackground(e.image,e.segmentationMask,this.backgroundBlurRange):this.effectName==w.VIRTUAL_BACKGROUND?this.drawVirtualBackground(e.image,e.segmentationMask,function(e,t){return t.get?t.get.call(e):t.value}(this,a(this,b,"get"))):this.drawImageDirectly(e.image)}drawImageDirectly(e){this.ctx.save(),this.ctx.globalCompositeOperation="source-over",this.ctx.filter="none",this.ctx.drawImage(e,0,0,e.width,e.height),this.ctx.restore()}drawVirtualBackground(e,t,i){this.ctx.save(),this.ctx.filter="none",this.ctx.clearRect(0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.drawImage(t,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="source-out",this.ctx.drawImage(i,0,0,i.naturalWidth,i.naturalHeight,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="destination-atop",this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.restore()}drawBlurBackground(e,t,i){this.ctx.clearRect(0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="copy",this.ctx.filter="none",this.ctx.filter="blur("+this.edgeBlurRange+"px)",this.drawSegmentationMask(t),this.ctx.globalCompositeOperation="source-in",this.ctx.filter="none",this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.globalCompositeOperation="destination-over",this.ctx.filter="blur("+i+"px)",this.ctx.drawImage(e,0,0,this.effectCanvas.width,this.effectCanvas.height),this.ctx.restore()}}function C(){return this.rawLocalVideo.pause(),null!=this.canvasStream&&this.canvasStream.getVideoTracks().forEach((e=>e.stop())),this.webRTCAdaptor.switchVideoCameraCapture(this.webRTCAdaptor.publishStreamId)}r(w,"DEEPAR","deepar"),r(w,"VIRTUAL_BACKGROUND","virtual-background"),r(w,"BLUR_BACKGROUND","blur-background"),r(w,"NO_EFFECT","no-effect"),r(w,"deepARModelList",["flower_face","Ping_Pong"]),r(w,"DEBUG",!1),r(w,"LOCATE_FILE_URL","https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation"),r(w,"DEEP_AR_FOLDER_ROOT_URL","https://cdn.jsdelivr.net/npm/deepar@4.0.3"),r(w,"DEEP_AR_EFFECTS_URL","../js/external/deepar-effects/"),r(w,"DEEP_AR_EXTENSION",".deepar"),g.register((e=>{var t=new w(e);Object.defineProperty(e,"enableEffect",{value:function(e,i,r){return t.enableEffect(e,i,r)}}),Object.defineProperty(e,"setBackgroundImage",{value:function(e){t.virtualBackgroundImage=e}})}));var k,T=window.log,A="";class E{constructor(e,t,i){r(this,"playOrder",void 0),r(this,"currentPlayType",void 0),r(this,"is360",!1),r(this,"streamId",void 0),r(this,"playType",void 0),r(this,"token",void 0),r(this,"autoPlay",!0),r(this,"mute",!0),r(this,"targetLatency",3),r(this,"subscriberId",void 0),r(this,"subscriberCode",void 0),r(this,"window",void 0),r(this,"containerElement",void 0),r(this,"placeHolderElement",void 0),r(this,"videojsPlayer",void 0),r(this,"dashPlayer",void 0),r(this,"iceServers",void 0),r(this,"iceConnected",void 0),r(this,"errorCalled",void 0),r(this,"aScene",void 0),r(this,"playerListener",void 0),r(this,"webRTCDataListener",void 0),r(this,"tryNextTechTimer",void 0),E.DEFAULT_PLAY_ORDER=["webrtc","hls"],E.DEFAULT_PLAY_TYPE=["mp4","webm"],E.HLS_EXTENSION="m3u8",E.WEBRTC_EXTENSION="webrtc",E.DASH_EXTENSION="mpd",E.STREAMS_FOLDER="streams",E.VIDEO_HTML=A,E.VIDEO_PLAYER_ID="video-player",this.dom=e.document,this.window=e;var a=v("id",this.window.location.search);if(this.containerElement=t,this.placeHolderElement=i,this.errorCalled=!1,this.iceConnected=!1,this.tryNextTechTimer=-1,this.videojsPlayer=null,this.iceServers='[ { "urls": "stun:stun1.l.google.com:19302" } ]',null==a&&null==(a=v("name",this.window.location.search))&&T.warn("Please use id parameter instead of name parameter."),null==a){var n="Stream id is not set.Please add your stream id to the url as a query parameter such as ?id={STREAM_ID} to the url";throw T.error(n),alert(n),new Error(n)}this.streamId=a;var o=v("is360",this.window.location.search);null!=o&&(this.is360="true"==o.toLocaleLowerCase());var s=v("playType",this.window.location.search);this.playType=null!=s?s.split(","):E.DEFAULT_PLAY_TYPE,this.token=v("token",this.window.location.search),void 0===this.token&&(this.token=null);var d=v("autoplay",this.window.location.search);null!=d&&(this.autoPlay="true"==d.toLocaleLowerCase());var c=v("mute",this.window.location.search);null!=c&&(this.mute="true"==c.toLocaleLowerCase());var l=v("targetLatency",this.window.location.search);if(null!=l){var h=Number(l);isNaN(h)?T.warn("targetLatency parameter is not a number. It will be ignored."):this.targetLatency=h}this.subscriberId=v("subscriberId",this.window.location.search),void 0===this.subscriberId&&(this.subscriberId=null),this.subscriberCode=v("subscriberCode",this.window.location.search),null==this.subscriberCode&&(this.subscriberCode=null);var u=v("playOrder",this.window.location.search);this.playOrder=null!=u?u.split(","):E.DEFAULT_PLAY_ORDER,this.loadScripts(),this.setPlayerVisible(!1)}loadScripts(){if(this.playOrder.includes("hls")||this.playOrder.includes("vod")||this.playOrder.includes("webrtc")){var e=this.dom.createElement("link");e.setAttribute("rel","stylesheet"),e.setAttribute("type","text/css"),e.setAttribute("href","css/external/video-js.css"),this.dom.head.appendChild(e);var t=this.dom.createElement("script");t.type="text/javascript",t.src="js/external/video.js",t.async=!1,this.dom.head.appendChild(t),t.onload=()=>{var e=this.dom.createElement("script");e.type="text/javascript",e.src="js/external/videojs-contrib-quality-levels.min.js",this.dom.head.appendChild(e);var t=this.dom.createElement("script");t.type="text/javascript",t.src="js/external/videojs-hls-quality-selector.min.js",this.dom.head.appendChild(t)}}if(this.playOrder.includes("webrtc")){var i=this.dom.createElement("link");i.setAttribute("rel","stylesheet"),i.setAttribute("type","text/css"),i.setAttribute("href","css/videojs-webrtc-plugin.css"),this.dom.head.appendChild(i);var r=this.dom.createElement("script");r.type="text/javascript",r.src="js/videojs-webrtc-plugin.js",r.async=!1,this.dom.head.appendChild(r)}if(this.playOrder.includes("dash")){var a=this.dom.createElement("script");a.type="text/javascript",a.src="js/external/dash.all.min.js",this.dom.head.appendChild(a)}if(this.is360){var n=this.dom.createElement("script");n.type="text/javascript",n.src="js/external/aframe.min.js",this.dom.head.appendChild(n)}}enable360Player(){this.aScene=this.dom.createElement("a-scene");var e=this.dom.getElementsByTagName("video")[0].id;this.aScene.innerHTML='',this.dom.body.appendChild(this.aScene)}setPlayerVisible(e){if(this.containerElement.style.display=e?"block":"none",this.placeHolderElement.style.display=e?"none":"block",this.is360)if(e)this.enable360Player();else if(null!=this.aScene){for(var t=this.dom.getElementsByTagName("a-scene");t.length>0;)this.dom.body.removeChild(t[0]),t=this.dom.getElementsByTagName("a-scene");this.aScene=null}}handleWebRTCInfoMessages(e){"ice_connection_state_changed"==e.info?(T.debug("ice connection state changed to "+e.obj.state),"completed"==e.obj.state||"connected"==e.obj.state?this.iceConnected=!0:"failed"!=e.obj.state&&"disconnected"!=e.obj.state&&"closed"!=e.obj.state||(T.debug("Ice connection is not connected. tryNextTech to replay"),this.tryNextTech())):"closed"==e.info&&(T.debug("Websocket is closed. tryNextTech to replay"),this.tryNextTech())}playWithVideoJS(e,t){var i;if("mp4"==t)i="video/mp4";else if("webm"==t)i="video/webm";else if("mov"==t)i="video/mp4",alert("Browsers do not support to play mov format");else if("avi"==t)i="video/mp4",alert("Browsers do not support to play avi format");else if("m3u8"==t)i="application/x-mpegURL";else if("mpd"==t)i="application/dash+xml";else{if("webrtc"!=t)return void T.warn("Unknown extension: "+t);i="video/webrtc"}var r=this.streamId;this.streamId.endsWith("_adaptive")&&(r=streamId.substring(0,streamId.indexOf("_adaptive"))),this.videojsPlayer=videojs(E.VIDEO_PLAYER_ID,{poster:"previews/"+r+".png",liveui:"m3u8"==t,liveTracker:{trackingThreshold:0},html5:{vhs:{limitRenditionByPlayerDimensions:!1}},controls:!0,class:"video-js vjs-default-skin vjs-big-play-centered",muted:this.mute,preload:"auto",autoplay:this.autoPlay}),this.videojsPlayer.on("error",(e=>{T.warn("There is an error in playback: "+e),this.errorCalled||(this.errorCalled=!0,setTimeout((()=>{this.tryNextTech(),this.errorCalled=!1}),2500))})),"webrtc"==t&&(this.videojsPlayer.on("webrtc-info",((e,t)=>{this.handleWebRTCInfoMessages(t)})),this.videojsPlayer.on("webrtc-error",((e,t)=>{T.warn("error callback: "+JSON.stringify(t)),"no_stream_exist"==t.error||"WebSocketNotConnected"==t.error||"not_initialized_yet"==t.error||"data_store_not_available"==t.error||"highResourceUsage"==t.error||"unauthorized_access"==t.error||"user_blocked"==t.error?this.tryNextTech():"notSetRemoteDescription"==t.error&&(T.warn("notSetRemoteDescription error. Redirecting to HLS player."),this.playIfExists("hls"))})),this.videojsPlayer.on("webrtc-data-received",((e,t)=>{T.warn("webrtc-data-received: "+JSON.stringify(t)),null!=this.webRTCDataListener&&this.webRTCDataListener(t)}))),"m3u8"==t&&(videojs.Vhs.xhr.beforeRequest=e=>{var t=this.getSecurityQueryParams();return e.uri.includes(t)||(e.uri.endsWith("?")||(e.uri=e.uri+"?"),e.uri+=t),T.debug("hls request: "+e.uri),e},this.videojsPlayer.ready((()=>{"function"==typeof this.videojsPlayer.hlsQualitySelector&&this.videojsPlayer.hlsQualitySelector({displayCurrentQuality:!0});var e=this.videojsPlayer.qualityLevels();e.on("addqualitylevel",(function(t){var i=t.qualityLevel;i.height?i.enabled=!0:(e.removeQualityLevel(i),i.enabled=!1)}))}))),"mp4"!=t&&"webm"!=t&&"m3u8"!=t||this.makeVideoJSVisibleWhenReady(),this.videojsPlayer.on("ended",(()=>{T.warn("stream is ended"),this.setPlayerVisible(!1),"vod"!=this.currentPlayType&&(this.iceConnected?this.playIfExists(this.playOrder[0]):"hls"==this.currentPlayType?(this.setPlayerVisible(!1),(this.playOrder[0]="hls")?setTimeout((()=>{this.playIfExists(this.playOrder[0])}),1e4):this.playIfExists(this.playOrder[0])):this.tryNextTech()),null!=this.playerListener&&this.playerListener("ended")})),this.videojsPlayer.on("play",(()=>{this.setPlayerVisible(!0),null!=this.playerListener&&this.playerListener("play")})),this.iceConnected=!1,this.videojsPlayer.src({src:e,type:i,withCredentials:!0,iceServers:this.iceServers,reconnect:!1}),this.autoPlay&&this.videojsPlayer.play().catch((e=>{T.warn("Problem in playback. The error is "+e)}))}makeVideoJSVisibleWhenReady(){this.videojsPlayer.ready((()=>{this.setPlayerVisible(!0)}))}checkStreamExistsViaHttp(e,t,i){var r="";return t.startsWith(e)||(r+=e+"/"),r+=t,null!=i&&""!=i&&(r+="_adaptive."+i),r=this.addSecurityParams(r),fetch(r,{method:"HEAD"}).then((a=>200==a.status?new Promise((function(e,t){e(r)})):(r=e+"/"+t+"."+i,r=this.addSecurityParams(r),fetch(r,{method:"HEAD"}).then((e=>200==e.status?new Promise((function(e,t){e(r)})):(T.warn("No stream found"),new Promise((function(e,t){t("resource_is_not_available")}))))))))}addSecurityParams(e){var t=this.getSecurityQueryParams();return null!=t&&""!=t&&(e+="?"+t),e}tryNextTech(){if(-1==this.tryNextTechTimer){this.destroyDashPlayer(),this.destroyVideoJSPlayer(),this.setPlayerVisible(!1);var e=this.playOrder.indexOf(this.currentPlayType);-1==e||e==this.playOrder.length-1?e=0:e++,this.tryNextTechTimer=setTimeout((()=>{this.tryNextTechTimer=-1,this.playIfExists(this.playOrder[e])}),3e3)}else T.debug("tryNextTech is already scheduled no need to schedule again")}playViaDash(e){this.destroyDashPlayer(),this.dashPlayer=dashjs.MediaPlayer().create(),this.dashPlayer.extend("RequestModifier",(()=>({modifyRequestHeader:function(e,t){return e},modifyRequestURL:e=>{var t="",i=this.getSecurityQueryParams();return e.includes(i)?e:(e.endsWith("?")||(e+="?"),t=e+i,T.warn(t),t)},modifyRequest(e){}}))),this.dashPlayer.updateSettings({streaming:{delay:{liveDelay:this.targetLatency},liveCatchup:{maxDrift:.05,playbackRate:.5,latencyThreshold:60}}}),this.dashPlayer.initialize(this.containerElement.firstChild,e,this.autoPlay),this.dashPlayer.setMute(this.mute),this.dashLatencyTimer=setInterval((()=>{T.warn("live latency: "+this.dashPlayer.getCurrentLiveLatency())}),2e3),this.makeDashPlayerVisibleWhenInitialized(),this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_PLAYING,(e=>{T.warn("playback started"),this.setPlayerVisible(!0),null!=this.playerListener&&this.playerListener("play")})),this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ENDED,(()=>{T.warn("playback ended"),this.destroyDashPlayer(),this.setPlayerVisible(!1),(this.playOrder[0]="dash")?setTimeout((()=>{this.playIfExists(this.playOrder[0])}),1e4):this.playIfExists(this.playOrder[0]),null!=this.playerListener&&this.playerListener("ended")})),this.dashPlayer.on(dashjs.MediaPlayer.events.PLAYBACK_ERROR,(e=>{this.tryNextTech()})),this.dashPlayer.on(dashjs.MediaPlayer.events.ERROR,(e=>{this.tryNextTech()}))}makeDashPlayerVisibleWhenInitialized(){this.dashPlayer.on(dashjs.MediaPlayer.events.STREAM_INITIALIZED,(e=>{T.warn("Stream initialized"),this.setPlayerVisible(!0)}))}destroyDashPlayer(){this.dashPlayer&&(this.dashPlayer.destroy(),this.dashPlayer=null,clearInterval(this.dashLatencyTimer))}destroyVideoJSPlayer(){this.videojsPlayer&&(this.videojsPlayer.dispose(),this.videojsPlayer=null)}playIfExists(e){var i=this;return t((function*(){switch(i.currentPlayType=e,i.destroyVideoJSPlayer(),i.destroyDashPlayer(),i.setPlayerVisible(!1),i.containerElement.innerHTML=E.VIDEO_HTML,T.warn("Try to play the stream "+i.streamId+" with "+i.currentPlayType),i.currentPlayType){case"hls":return i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId,E.HLS_EXTENSION).then((e=>{i.playWithVideoJS(e,E.HLS_EXTENSION),T.warn("incoming stream path: "+e)})).catch((e=>{T.warn("HLS stream resource not available for stream:"+i.streamId+" error is "+e+". Try next play tech"),i.tryNextTech()}));case"dash":return i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId+"/"+i.streamId,E.DASH_EXTENSION).then((e=>{i.playViaDash(e)})).catch((e=>{T.warn("DASH stream resource not available for stream:"+i.streamId+" error is "+e+". Try next play tech"),i.tryNextTech()}));case"webrtc":var t=i.window.location.pathname.substring(0,i.window.location.pathname.lastIndexOf("/")+1),r=i.window.location.hostname+":"+i.window.location.port+t+i.streamId+".webrtc",a="ws://"+r;return location.protocol.startsWith("https")&&(a="wss://"+r),i.playWithVideoJS(i.addSecurityParams(a),E.WEBRTC_EXTENSION);case"vod":var n,o=i.streamId.lastIndexOf(".");return-1!=o?(i.playType[0]="",n=i.streamId.substring(o+1)):n=i.playType[0],i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId,i.playType[0]).then((e=>{i.playWithVideoJS(e,n)})).catch((e=>{T.warn("VOD stream resource not available for stream:"+i.streamId+" and play type "+i.playType[0]+". Error is "+e),i.playType.length>1&&(T.warn("Try next play type which is "+i.playType[1]+"."),i.checkStreamExistsViaHttp(E.STREAMS_FOLDER,i.streamId,i.playType[1]).then((e=>{i.playWithVideoJS(e,i.playType[1])})).catch((e=>{T.warn("VOD stream resource not available for stream:"+i.streamId+" and play type error is "+e)})))}))}}))()}getSecurityQueryParams(){var e="";return null!=this.token&&(e+="&token="+this.token),null!=this.subscriberId&&(e+="&subscriberId="+this.subscriberId),null!=this.subscriberCode&&(e+="&subscriberCode="+this.subscriberCode),e}play(){if(this.streamId.startsWith(E.STREAMS_FOLDER)){var e=this.streamId.lastIndexOf("."),t=this.streamId.substring(e+1);this.playOrder=["vod"],t==E.DASH_EXTENSION?this.playViaDash(this.addSecurityParams(this.streamId),t):this.playWithVideoJS(this.addSecurityParams(this.streamId),t)}else this.playIfExists(this.playOrder[0])}mutePlayer(e){this.mute=e,this.videojsPlayer&&this.videojsPlayer.muted(e),this.dashPlayer&&this.dashPlayer.setMute(e)}isMuted(){return this.mute}addPlayerListener(e){this.playerListener=e}addWebRTCDataListener(e){this.webRTCDataListener=e}sendWebRTCData(e){try{if(this.videojsPlayer&&"webrtc"==this.currentPlayType)return this.videojsPlayer.sendDataViaWebRTC(e),!0;T.warn("Player is not ready or playType is not WebRTC")}catch(e){T.error("An error occurred while sending WebRTC data: ",e)}return!1}}r(E,"DEFAULT_PLAY_ORDER",["webrtc","hls"]),r(E,"DEFAULT_PLAY_TYPE",["mp4","webm"]),r(E,"HLS_EXTENSION","m3u8"),r(E,"WEBRTC_EXTENSION","webrtc"),r(E,"DASH_EXTENSION","mpd"),r(E,"STREAMS_FOLDER","streams"),r(E,"VIDEO_HTML",A),r(E,"VIDEO_PLAYER_ID","video-player");var P=!1;window.startBroadcasting=async function(e){if(console.log("startBroadcasting is called websocket url:"+e.websocketURL+" streamId: "+e.streamId),void 0!==k)throw new Error("Called startBroadcasting while recording is in progress.");let t="",i=1280,r=720;void 0!==e.token&&(t=e.token),void 0!==e.width&&e.width>0&&(i=e.width),void 0!==e.height&&e.height>0&&(r=e.height);const a=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:{max:30}},audio:{channelCount:2,echoCancellation:!1,autoGainControl:!1,noiseSuppression:!1},preferCurrentTab:!0}),n=a.getVideoTracks()[0];console.log("video track settings: ",n.getSettings());const o=a.getAudioTracks()[0];console.log("audio track settings: ",o.getSettings());const s={width:{min:640,ideal:i},height:{min:360,ideal:r},advanced:[{width:i,height:r},{aspectRatio:i/r}],frameRate:{min:15,max:30},resizeMode:"crop-and-scale"};n.applyConstraints(s),k=new g({websocket_url:e.websocketURL,peerconnection_config:{iceServers:[{urls:"stun:stun1.l.google.com:19302"}]},bandwidth:4e3,localStream:a,callback:(i,r)=>{"initialized"==i?(console.log("WebRTC adaptor initialized"),k.publish(e.streamId,t,"","","","",e.driverIp,"")):"publish_started"==i?(console.log("mediapush_publish_started"),P=!0):"publish_finished"==i&&(P=!1),console.log(i)},callbackError:function(e,t){var i=JSON.stringify(e);i=void 0!==t?t:JSON.stringify(e),-1!=e.indexOf("WebSocketNotConnected")?i="WebSocket is disconnected.":-1!=e.indexOf("not_initialized_yet")?i="Server is getting initialized.":-1!=e.indexOf("data_store_not_available")?i="Data store is not available. It's likely that server is initialized or getting closed":-1!=e.indexOf("NotFoundError")?i="Camera or Mic are not found or not allowed in your device":-1!=e.indexOf("NotReadableError")||-1!=e.indexOf("TrackStartError")?i="Camera or Mic are already in use and they cannot be opened. Choose another video/audio source if you have on the page below ":-1!=e.indexOf("OverconstrainedError")||-1!=e.indexOf("ConstraintNotSatisfiedError")?i="There is no device found that fits your video and audio constraints. You may change video and audio constraints":-1!=e.indexOf("NotAllowedError")||-1!=e.indexOf("PermissionDeniedError")?i="You are not allowed to access camera and mic.":-1!=e.indexOf("TypeError")?i="Video/Audio is required":-1!=e.indexOf("getUserMediaIsNotAllowed")?i="You are not allowed to reach devices from an insecure origin, please enable ssl":-1!=e.indexOf("ScreenSharePermissionDenied")?(i="You are not allowed to access screen share",$(".video-source").first().prop("checked",!0)):i=-1!=e.indexOf("UnsecureContext")?"Please Install SSL(https). Camera and mic cannot be opened because of unsecure context. ":-1!=e.indexOf("no_stream_exist")?"There is no active live stream with this id to play":e,void 0!==t&&console.log("error callback: "+e+" message: "+i)}}),window.webRTCAdaptorMediaPush=k},window.stopBroadcasting=function(e){k.stop(e.streamId),k.closeWebSocket()},window.isConnected=function(e){var t=!1;if(P){var i=k.signallingState(e);if(null!=i&&"closed"!=i){var r=k.iceConnectionState(e);null!=r&&"failed"!=r&&"disconnected"!=r&&(t=!0)}}return t}})()})(); \ No newline at end of file diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/EndpointUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/EndpointUnitTest.java index f584bed0..aa05768d 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/EndpointUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/EndpointUnitTest.java @@ -18,4 +18,4 @@ public void testExtraChromeSwitches() { assertEquals("switches", endpoint.getExtraChromeSwitches()); } - } \ No newline at end of file +} \ No newline at end of file diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java index 62ed20ca..2c1edcfe 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java @@ -5,9 +5,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import java.io.File; import java.io.IOException; @@ -20,6 +18,7 @@ import java.util.List; import java.util.Set; +import io.antmedia.datastore.db.types.Broadcast; import org.apache.commons.lang3.StringUtils; import org.junit.BeforeClass; import org.junit.Rule; @@ -405,6 +404,54 @@ public void testStopMediaPush_WhenDriverDoesNotExist_ShouldReturnErrorResult() { assertEquals(expectedResult.getMessage(), result.getMessage()); } - + @Test + public void testValidIP(){ + MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + assertFalse(plugin.isValidIP("test.abc.fd")); + assertFalse(plugin.isValidIP("")); + assertFalse(plugin.isValidIP(null)); + assertTrue(plugin.isValidIP("127.0.0.1")); + assertFalse(plugin.isValidIP("192.168.0.")); + assertFalse(plugin.isValidIP("192..0.1")); + } + @Test + public void testStopRequestForward(){ + String streamId = "stream1"; + MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + doReturn(null).when(plugin).getBroadcast(anyString()); + Result result = plugin.stopMediaPush(streamId); + assertEquals(result.getMessage(),"Driver does not exist for stream id: "+streamId); + + Broadcast broadcast = mock(Broadcast.class); + doReturn(broadcast).when(plugin).getBroadcast(anyString()); + doReturn(null).when(broadcast).getMetaData(); + plugin.stopMediaPush(streamId); + assertEquals(result.getMessage(),"Driver does not exist for stream id: "+streamId); + doReturn("null").when(broadcast).getMetaData(); + plugin.stopMediaPush(streamId); + assertEquals(result.getMessage(),"Driver does not exist for stream id: "+streamId); + + String metaData = "{\"driverIp\":\"54.36..133\"}"; // test isvalid ip + doReturn(metaData).when(broadcast).getMetaData(); + verify(plugin,times(0)).forwardMediaPushStopRequest(anyString(),anyString()); + plugin.stopMediaPush(streamId); + + result.setMessage("Driver does not exist for stream id: " + streamId); + + metaData = "{\"driverIp\":\"54.36.24.133\"}"; + doReturn(metaData).when(broadcast).getMetaData(); + doReturn(false).when(plugin).forwardMediaPushStopRequest(anyString(),anyString()); + plugin.stopMediaPush(streamId); + + result.setMessage("Driver does not exist for stream id: " + streamId); + + metaData = "{\"driverIp\":\"54.36.24.133\"}"; + doReturn(metaData).when(broadcast).getMetaData(); + plugin.stopMediaPush(streamId); + doReturn(true).when(plugin).forwardMediaPushStopRequest(anyString(),anyString()); + verify(plugin,times(2)).forwardMediaPushStopRequest(streamId,"54.36.24.133"); + System.out.println(result.getMessage()); + + } } \ No newline at end of file From 2c0f608611fc6771dbce41155a1dbde934cdd32a Mon Sep 17 00:00:00 2001 From: USAMA Date: Wed, 29 Jan 2025 20:39:12 +0530 Subject: [PATCH 03/14] revert --- MediaPushPlugin/redeploy.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaPushPlugin/redeploy.sh b/MediaPushPlugin/redeploy.sh index e2cfa3c8..0e2f34b3 100755 --- a/MediaPushPlugin/redeploy.sh +++ b/MediaPushPlugin/redeploy.sh @@ -1,8 +1,8 @@ #!/bin/sh AMS_DIR=/usr/local/antmedia/ -AMS_DIR=/home/usama/tem/ant-media-server/ +AMS_DIR=~/softwares/ant-media-server/ -# rm src/main/resources/*.js +rm src/main/resources/*.js cd src/main/js npm install @@ -25,4 +25,4 @@ if [ $OUT -ne 0 ]; then exit $OUT fi cd $AMS_DIR -# ./start-debug.sh +./start-debug.sh From b7fb7f866090206298243e9aa83871a439121619 Mon Sep 17 00:00:00 2001 From: USAMA Date: Thu, 30 Jan 2025 09:59:35 +0530 Subject: [PATCH 04/14] get Ip from Server settings --- .../java/io/antmedia/plugin/MediaPushPlugin.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index cd6a1c13..2ef76708 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -221,18 +221,6 @@ public static boolean isValidURL(String urlString) { } } - public String getPrivateIpAddress() { - if(myPrivateIp == null){ - try { - InetAddress localhost = InetAddress.getLocalHost(); - myPrivateIp = localhost.getHostAddress().trim(); - } catch (Exception e) { - e.printStackTrace(); - } - } - return myPrivateIp; - } - @Override @@ -299,8 +287,8 @@ public Result startMediaPush(String streamIdPar, String websocketUrl, Endpoint e wait.until(ExpectedConditions.jsReturnsValue("return (typeof window.startBroadcasting != 'undefined')")); - String driverIp = getPrivateIpAddress(); - driverIp = "{\"driverIp\":\"" + driverIp + "\"}"; + String driverIp = getApplication().getServerSettings().getHostAddress(); + driverIp = "{\"driverIp\":\"" + driverIp + "\"}"; String startBroadcastingCommand = String.format("window.startBroadcasting({websocketURL:'%s',streamId:'%s',width:%d,height:%d,token:'%s',driverIp:'%s'});", websocketUrl, streamId, width, height, StringUtils.isNotBlank(token) ? token : "",driverIp); From 627e3f55d87a12c028fe9fb9091d257dd6b659d7 Mon Sep 17 00:00:00 2001 From: USAMA Date: Thu, 30 Jan 2025 17:53:24 +0530 Subject: [PATCH 05/14] get port from settings --- .../src/main/java/io/antmedia/plugin/MediaPushPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index 2ef76708..ffdb8096 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -566,8 +566,8 @@ public Broadcast getBroadcast(String streamId) { CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); Gson gson = new Gson(); - String url = "http://"+ "127.0.0.1" +":5080" + applicationContext.getApplicationName() + "/rest/v2/broadcasts/"+ streamId; - logger.info(url); + String url = "http://"+ "127.0.0.1" + ":"+ getApplication().getServerSettings().getDefaultHttpPort() + applicationContext.getApplicationName() + "/rest/v2/broadcasts/"+ streamId; + logger.info(url); HttpUriRequest get = RequestBuilder.get().setUri(url) .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") From 98b371beb5b89bfc5c1b73ecb0ab730d5b6dea5e Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Thu, 30 Jan 2025 19:25:32 +0530 Subject: [PATCH 06/14] revert --- .../java/io/antmedia/plugin/MediaPushPlugin.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index ffdb8096..8c4b5329 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -87,7 +87,6 @@ public class MediaPushPlugin implements ApplicationContextAware, IStreamListener private boolean initialized = false; private ApplicationContext applicationContext; - public String myPrivateIp = null; public Map getDrivers() { return drivers; @@ -100,16 +99,22 @@ public Map getDrivers() { * Extra * https://peter.sh/experiments/chromium-command-line-switches/ */ - private static final List CHROME_DEFAULT_SWITHES = + private static final List CHROME_DEFAULT_SWITHES = Arrays.asList( "--remote-allow-origins=*", "--enable-usermedia-screen-capturing", "--allow-http-screen-capture", + "--disable-infobars", + "--hide-scrollbars", "--auto-accept-this-tab-capture", "--no-sandbox", "--autoplay-policy=no-user-gesture-required", + "--disable-background-media-suspend", + "--disable-gpu-vsync", "--disable-audio-output", - "--disable-background-timer-throttling"); + "--disable-background-timer-throttling", + "--headless=new", + "--start-fullscreen"); public static final int TIMEOUT_IN_SECONDS = 30; @@ -317,8 +322,6 @@ public RemoteWebDriver openDriver(int width, int height, String recordTypeString List extraChromeSwitchList, String streamId, String publisherUrl, String targetUrl) throws IOException { RemoteWebDriver driver; driver = createDriver(width, height, streamId, extraChromeSwitchList); - - driver.get(publisherUrl); driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(TIMEOUT_IN_SECONDS)); driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(TIMEOUT_IN_SECONDS)); @@ -536,7 +539,6 @@ public RemoteWebDriver createDriver(int width, int height, String streamId, List } } - options.addArguments("--disable-blink-features=AutomationControlled"); options.setExperimentalOption("useAutomationExtension", false); options.setExperimentalOption("excludeSwitches", List.of("enable-automation")); options.addArguments(args); From 066f4dfdb5eb866573a9756c0072bcca2c00c173 Mon Sep 17 00:00:00 2001 From: USAMA Date: Mon, 3 Feb 2025 16:09:25 +0530 Subject: [PATCH 07/14] Update test_and_deploy.yml --- .github/workflows/test_and_deploy.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index 2ac839f6..a7ee0298 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -78,15 +78,6 @@ jobs: sleep 20 cd .. - - name: Build and Test Clip Creator - run: | - pushd ClipCreatorPlugin - mvn clean install -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -Dgpg.skip=true - sudo cp target/clip-creator.jar /usr/local/antmedia/plugins - ls /usr/local/antmedia/plugins - sudo service antmedia restart - mvn deploy -DskipTests=false --quiet --settings ../mvn-settings.xml - popd - name: Build and Test Media Push Plugin run: | From ea2bb2e97e2ec38333356bb5ee0d57649b900af7 Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Sun, 9 Feb 2025 23:20:24 +0530 Subject: [PATCH 08/14] fix code covarage --- .github/workflows/test_and_deploy.yml | 9 + .../io/antmedia/plugin/ClipCreatorPlugin.java | 4 +- .../ClipCreatorPluginIntegrationTest.java | 8 +- .../antmedia/test/FilterManagerUnitTest.java | 4 - .../io/antmedia/test/MCUManagerUnitTest.java | 1 - .../HLSMergerPluginIntegrationTest.java | 5 +- .../io/antmedia/plugin/MediaPushPlugin.java | 76 ++----- .../plugin/MediaPushPluginUnitTest.java | 192 +++++++++++++----- 8 files changed, 181 insertions(+), 118 deletions(-) diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index a7ee0298..2ac839f6 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -78,6 +78,15 @@ jobs: sleep 20 cd .. + - name: Build and Test Clip Creator + run: | + pushd ClipCreatorPlugin + mvn clean install -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -Dgpg.skip=true + sudo cp target/clip-creator.jar /usr/local/antmedia/plugins + ls /usr/local/antmedia/plugins + sudo service antmedia restart + mvn deploy -DskipTests=false --quiet --settings ../mvn-settings.xml + popd - name: Build and Test Media Push Plugin run: | diff --git a/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java b/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java index f43edd0d..2960987d 100755 --- a/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java +++ b/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java @@ -175,6 +175,7 @@ public Result startPeriodicRecording(int periodSeconds) vertx.executeBlocking(() -> { + logger.info("startPeriodicRecording#createRecordings ", appName); createRecordings(); return null; }, false); @@ -188,9 +189,8 @@ public Result startPeriodicRecording(int periodSeconds) public void createRecordings() { - List broadcasts = dataStore.getLocalLiveBroadcasts(serverSettings.getHostAddress()); - logger.info("createRecordings for active broadcasts size:{}", broadcasts.size()); + for (Broadcast broadcast : broadcasts) { convertHlsToMp4(broadcast, true); } diff --git a/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java b/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java index 35d7dc90..3b9f01f6 100644 --- a/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java +++ b/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java @@ -7,7 +7,6 @@ import io.antmedia.datastore.db.types.User; import io.antmedia.datastore.db.types.VoD; import io.antmedia.datastore.db.types.Broadcast.PlayListItem; -import io.antmedia.datastore.db.types.BroadcastUpdate; import io.antmedia.muxer.IAntMediaStreamHandler; import io.antmedia.muxer.MuxAdaptor; import io.antmedia.plugin.ClipCreatorPlugin; @@ -289,7 +288,6 @@ public void testPeriodicMp4CreationREST() throws Exception { Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(5, TimeUnit.SECONDS).until(() -> { List voDList2 = callGetVoDList(0,50, streamId); - logger.info("VoD List size: {}", voDList2.size()); return voDList2 != null && voDList2.size() == 2; }); @@ -1069,7 +1067,7 @@ public static Result callUpdateBroadcast(String id, String name, String descript String url = ROOT_SERVICE_URL + "/v2/broadcasts/" + id; HttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); - BroadcastUpdate broadcast = new BroadcastUpdate(); + Broadcast broadcast = new Broadcast(); try { broadcast.setStreamId(id); } catch (Exception e1) { @@ -1086,11 +1084,11 @@ public static Result callUpdateBroadcast(String id, String name, String descript try { Gson gson = new Gson(); - HttpUriRequest put = RequestBuilder.put().setUri(url) + HttpUriRequest post = RequestBuilder.put().setUri(url) .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") .setEntity(new StringEntity(gson.toJson(broadcast))).build(); - HttpResponse response = client.execute(put); + HttpResponse response = client.execute(post); StringBuffer result = readResponse(response); diff --git a/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java b/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java index 1de79f94..94bb6353 100644 --- a/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java +++ b/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java @@ -142,7 +142,6 @@ public void testCheckResultandFilterId() { e.printStackTrace(); fail(e.getMessage()); } - broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); @@ -227,7 +226,6 @@ public void testBugVideoFilterNotWorking(String filterString, String rawFile, in e.printStackTrace(); fail(e.getMessage()); } - broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); @@ -353,7 +351,6 @@ public void testFixVideoPtsInFilter(String filterString, String rawFile, int sou e.printStackTrace(); fail(e.getMessage()); } - broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); @@ -574,7 +571,6 @@ public AVFrame onAudioFrame(String streamId, AVFrame audioFrame) { e.printStackTrace(); fail(e.getMessage()); } - broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); assertEquals("stream1", dataStore.save(broadcast)); diff --git a/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java b/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java index a7c3c510..940568fa 100644 --- a/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java +++ b/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java @@ -131,7 +131,6 @@ public void testMCUWithOtherRooms() throws Exception { } catch (Exception e) { e.printStackTrace(); } - broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); diff --git a/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java b/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java index 3efc470b..f3de2fdb 100644 --- a/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java +++ b/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java @@ -108,7 +108,7 @@ public void testMultiResolutionHLS() { callStopMultiResolutionStream(mergedStreamId); - Awaitility.await().atMost(45, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { + Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { return !testFile(APP_URL+"/streams/" + mergedStreamId+ ".m3u8"); }); @@ -186,8 +186,7 @@ public void testMultiAudioHLS() { callStopMultiResolutionStream(mergedStreamId); - // hls list size is 15 and segment 2 secs, it means it'll be deleted after 30 seconds, have 45 to have some margin - Awaitility.await().atMost(45, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { + Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { return !testFile(APP_URL+"/streams/" + mergedStreamId+ ".m3u8"); }); diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index 8c4b5329..1a552421 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -30,7 +30,6 @@ import java.nio.charset.StandardCharsets; import org.apache.http.entity.StringEntity; import java.util.regex.Pattern; -import java.net.InetAddress; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -65,8 +64,6 @@ import io.antmedia.plugin.api.IStreamListener; import io.antmedia.rest.model.Result; import io.github.bonigarcia.wdm.WebDriverManager; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; @Component(value=IMediaPushPlugin.BEAN_NAME) @@ -85,7 +82,7 @@ public class MediaPushPlugin implements ApplicationContextAware, IStreamListener private boolean initialized = false; - private ApplicationContext applicationContext; + public ApplicationContext applicationContext; public Map getDrivers() { @@ -410,36 +407,37 @@ public boolean isValidIP(String ip) { return Pattern.matches(ipPattern, ip); } - public boolean forwardMediaPushStopRequest(String streamId,String ip){ + public boolean forwardMediaPushStopRequest(String streamId, String ip) { - AntMediaApplicationAdapter appAdapter = getApplication(); - logger.info("forwarding media push stop request to {}",ip); + AntMediaApplicationAdapter appAdapter = getApplication(); + logger.info("forwarding media push stop request to {}", ip); try { CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); - String url = "http://"+ ip + ":"+ appAdapter.getServerSettings().getDefaultHttpPort() + applicationContext.getApplicationName() + "/rest/v1/media-push/stop/"+ streamId; - logger.info(url); + String url = "http://" + ip + ":" + appAdapter.getServerSettings().getDefaultHttpPort() + + applicationContext.getApplicationName() + "/rest/v1/media-push/stop/" + streamId; + logger.info(url); - String jwtToken = JWTFilter.generateJwtToken(appAdapter.getAppSettings().getClusterCommunicationKey(), System.currentTimeMillis() + 5000); - HttpUriRequest post = RequestBuilder.post().setUri(url) - .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .setHeader(TokenFilterManager.TOKEN_HEADER_FOR_NODE_COMMUNICATION, jwtToken) - .setEntity(new StringEntity("{}", StandardCharsets.UTF_8)) - .build(); + String jwtToken = JWTFilter.generateJwtToken(appAdapter.getAppSettings().getClusterCommunicationKey(), + System.currentTimeMillis() + 5000); + HttpUriRequest post = RequestBuilder.post().setUri(url) + .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .setHeader(TokenFilterManager.TOKEN_HEADER_FOR_NODE_COMMUNICATION, jwtToken) + .setEntity(new StringEntity("{}", StandardCharsets.UTF_8)) + .build(); CloseableHttpResponse response = client.execute(post); if (response.getStatusLine().getStatusCode() == 404) { - return false; + return false; + } else if (response.getStatusLine().getStatusCode() == 200) { + return true; } - else if(response.getStatusLine().getStatusCode() == 200){ - return true; - } } catch (Exception e) { e.printStackTrace(); } - return false; - } + return false; + } @Override public Result stopMediaPush(String streamId) { @@ -565,7 +563,6 @@ public static StringBuffer readResponse(HttpResponse response) throws IOExceptio public Broadcast getBroadcast(String streamId) { try { - CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); Gson gson = new Gson(); String url = "http://"+ "127.0.0.1" + ":"+ getApplication().getServerSettings().getDefaultHttpPort() + applicationContext.getApplicationName() + "/rest/v2/broadcasts/"+ streamId; @@ -586,38 +583,7 @@ public Broadcast getBroadcast(String streamId) { else if (response.getStatusLine().getStatusCode() != 200){ throw new Exception("Status code not 200 "); } - Broadcast broadcast = gson.fromJson(result.toString(), Broadcast.class); - return broadcast; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public Broadcast mediaPushStop(String streamId) { - try { - - CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); - Gson gson = new Gson(); - String url = "http://"+ "127.0.0.1" +":5080" + applicationContext.getApplicationName() + "/rest/v2/broadcasts/"+ streamId; - logger.info(url); - - HttpUriRequest get = RequestBuilder.get().setUri(url) - .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .build(); - - CloseableHttpResponse response = client.execute(get); - - StringBuffer result = readResponse(response); - - if (response.getStatusLine().getStatusCode() == 404) { - logger.info("Response to getBroadcast is 404. It means stream is not found or deleted"); - return null; - } - else if (response.getStatusLine().getStatusCode() != 200){ - throw new Exception("Status code not 200 "); - } - Broadcast broadcast = gson.fromJson(result.toString(), Broadcast.class); + Broadcast broadcast = gson.fromJson(result.toString(), Broadcast.class); return broadcast; } catch (Exception e) { e.printStackTrace(); @@ -626,8 +592,6 @@ else if (response.getStatusLine().getStatusCode() != 200){ } - - public AntMediaApplicationAdapter getApplication() { return (AntMediaApplicationAdapter) applicationContext.getBean(AntMediaApplicationAdapter.BEAN_NAME); } diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java index 2c1edcfe..847bf698 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java @@ -2,24 +2,30 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.*; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; +import java.io.*; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.util.Arrays; import java.util.HashMap; -import java.util.List; -import java.util.Set; +import io.antmedia.AntMediaApplicationAdapter; +import io.antmedia.AppSettings; import io.antmedia.datastore.db.types.Broadcast; +import io.antmedia.filter.JWTFilter; +import io.antmedia.filter.TokenFilterManager; +import io.antmedia.settings.ServerSettings; import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.LaxRedirectStrategy; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; @@ -31,9 +37,6 @@ import org.openqa.selenium.InvalidArgumentException; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver.TargetLocator; -import org.openqa.selenium.logging.LogEntries; -import org.openqa.selenium.logging.LogEntry; -import org.openqa.selenium.logging.LogType; import org.openqa.selenium.remote.RemoteWebDriver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +44,9 @@ import io.antmedia.model.Endpoint; import io.antmedia.rest.model.Result; import io.github.bonigarcia.wdm.WebDriverManager; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.CloseableHttpClient; +import org.springframework.context.ApplicationContext; public class MediaPushPluginUnitTest { @@ -70,7 +76,7 @@ public static void beforeClass() @Test public void testCreateDriverWithExtraSwitches() { - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); @@ -96,7 +102,7 @@ public void testCreateDriverWithExtraSwitches() { @Test public void testStartMediaPushWithEndpoint() throws IOException { - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); Endpoint endpoint = new Endpoint(); endpoint.setUrl("http://example.com"); @@ -116,14 +122,14 @@ public void testStartMediaPushWithEndpoint() throws IOException { @Test public void testSendCommand_WhenDriverExists_ShouldExecuteCommand() { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - HashMap drivers = Mockito.mock(HashMap.class); - RemoteWebDriver driver = Mockito.mock(RemoteWebDriver.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + HashMap drivers = mock(HashMap.class); + RemoteWebDriver driver = mock(RemoteWebDriver.class); - Mockito.when(driver.switchTo()).thenReturn(Mockito.mock(TargetLocator.class)); + when(driver.switchTo()).thenReturn(mock(TargetLocator.class)); - JavascriptExecutor js = Mockito.mock(JavascriptExecutor.class); + JavascriptExecutor js = mock(JavascriptExecutor.class); String streamId = "streamId"; String command = "someCommand"; Result expectedResult = new Result(true, streamId, ""); @@ -132,7 +138,7 @@ public void testSendCommand_WhenDriverExists_ShouldExecuteCommand() { when(drivers.containsKey(streamId)).thenReturn(true); when(drivers.get(streamId)).thenReturn(driver); when(js.executeScript(command)).thenReturn(null); - Mockito.doNothing().when(plugin).waitToBeFrameAvailable(Mockito.any()); + doNothing().when(plugin).waitToBeFrameAvailable(Mockito.any()); // Act Result result = plugin.sendCommand(streamId, command); @@ -145,15 +151,15 @@ public void testSendCommand_WhenDriverExists_ShouldExecuteCommand() { @Test public void testSendCommand_WhenDriverDoesNotExist_ShouldReturnErrorResult() { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - HashMap drivers = Mockito.mock(HashMap.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + HashMap drivers = mock(HashMap.class); String streamId = "streamId"; String command = "someCommand"; Result expectedResult = new Result(false, "Driver does not exist for stream id: " + streamId); when(plugin.getDrivers()).thenReturn(drivers); when(drivers.containsKey(streamId)).thenReturn(false); - Mockito.doNothing().when(plugin).waitToBeFrameAvailable(Mockito.any()); + doNothing().when(plugin).waitToBeFrameAvailable(Mockito.any()); // Act @@ -188,9 +194,9 @@ public void testSendCommand() throws IOException { @Test public void testSendCommand_WhenCommandExecutionFails_ShouldReturnErrorResult() { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - HashMap drivers = Mockito.mock(HashMap.class); - RemoteWebDriver driver = Mockito.mock(RemoteWebDriver.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + HashMap drivers = mock(HashMap.class); + RemoteWebDriver driver = mock(RemoteWebDriver.class); String streamId = "streamId"; String command = "someCommand"; Result expectedResult = new Result(false, "Command cannot be executed."); @@ -199,9 +205,9 @@ public void testSendCommand_WhenCommandExecutionFails_ShouldReturnErrorResult() when(drivers.containsKey(streamId)).thenReturn(true); when(drivers.get(streamId)).thenReturn(driver); when(driver.executeScript(command)).thenThrow(new RuntimeException("Command execution failed.")); - Mockito.doNothing().when(plugin).waitToBeFrameAvailable(Mockito.any()); + doNothing().when(plugin).waitToBeFrameAvailable(Mockito.any()); - Mockito.when(driver.switchTo()).thenReturn(Mockito.mock(TargetLocator.class)); + when(driver.switchTo()).thenReturn(mock(TargetLocator.class)); // Act Result result = plugin.sendCommand(streamId, command); @@ -213,7 +219,7 @@ public void testSendCommand_WhenCommandExecutionFails_ShouldReturnErrorResult() @Test public void testStartMediaPush_WhenStreamIdIsEmptyOrNull_ShouldGenerateStreamId() throws IOException { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); String streamId = plugin.checkAndGetStreamId(""); @@ -233,9 +239,9 @@ public void testStartMediaPush_WhenStreamIdIsEmptyOrNull_ShouldGenerateStreamId( @Test public void testStartMediaPush_InvalidUrl_ShouldReturnErrorResult() throws IOException { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - Endpoint endpoint = Mockito.mock(Endpoint.class); - RemoteWebDriver driver = Mockito.mock(RemoteWebDriver.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + Endpoint endpoint = mock(Endpoint.class); + RemoteWebDriver driver = mock(RemoteWebDriver.class); String streamId = "streamId"; String websocketUrl = "websocketUrl"; String url = "invalid_url"; @@ -261,9 +267,9 @@ public void testStartMediaPush_InvalidUrl_ShouldReturnErrorResult() throws IOExc @Test public void testStartMediaPush_WhenDriverExistsForStreamId_ShouldReturnErrorResult() throws IOException { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - Endpoint endpoint = Mockito.mock(Endpoint.class); - RemoteWebDriver driver = Mockito.mock(RemoteWebDriver.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + Endpoint endpoint = mock(Endpoint.class); + RemoteWebDriver driver = mock(RemoteWebDriver.class); String streamId = "streamId"; String websocketUrl = "websocketUrl"; String url = "http://google.com"; @@ -291,8 +297,8 @@ public void testStartMediaPush_WhenDriverExistsForStreamId_ShouldReturnErrorResu @Test public void testStartMediaPush_WhenDriverCreationFails_ShouldReturnErrorResult() throws IOException { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - Endpoint endpoint = Mockito.mock(Endpoint.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + Endpoint endpoint = mock(Endpoint.class); String streamId = "streamId"; String websocketUrl = "ws://test.antmedia.io"; String url = "http://example.com"; @@ -303,7 +309,7 @@ public void testStartMediaPush_WhenDriverCreationFails_ShouldReturnErrorResult() when(endpoint.getWidth()).thenReturn(width); when(endpoint.getHeight()).thenReturn(height); when(plugin.getDrivers()).thenReturn(new HashMap<>()); - Mockito.doThrow(new IOException()).when(plugin).createDriver(width, height, "streamId", null); + doThrow(new IOException()).when(plugin).createDriver(width, height, "streamId", null); // Act Result result = plugin.startMediaPush(streamId, websocketUrl,endpoint.getWidth(), endpoint.getHeight(), endpoint.getUrl(), endpoint.getToken(), null); @@ -315,7 +321,7 @@ public void testStartMediaPush_WhenDriverCreationFails_ShouldReturnErrorResult() @Test public void testGetPublisherUrl() throws InvalidArgumentException, URISyntaxException { - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); String url = plugin.getPublisherHTMLURL("ws://example.antmedia.io"); @@ -329,8 +335,8 @@ public void testGetPublisherUrl() throws InvalidArgumentException, URISyntaxExce @Test public void testStartMediaPush_WhenExecuteScriptTimeoutOccurs_ShouldReturnErrorResult() throws IOException { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - Endpoint endpoint = Mockito.mock(Endpoint.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + Endpoint endpoint = mock(Endpoint.class); String streamId = "streamId"; String websocketUrl = "ws://example.antmedia.io"; String url = "http://example.com"; @@ -360,9 +366,9 @@ public void testStartMediaPush_WhenExecuteScriptTimeoutOccurs_ShouldReturnErrorR @Test public void testStopMediaPush_WhenDriverExists_ShouldStopMediaPushAndReturnSuccessResult() { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - HashMap drivers = Mockito.mock(HashMap.class); - RemoteWebDriver driver = Mockito.mock(RemoteWebDriver.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + HashMap drivers = mock(HashMap.class); + RemoteWebDriver driver = mock(RemoteWebDriver.class); String streamId = "streamId"; Result expectedResult = new Result(true, "Media Push stopped"); @@ -388,8 +394,8 @@ public void testStopMediaPush_WhenDriverExists_ShouldStopMediaPushAndReturnSucce @Test public void testStopMediaPush_WhenDriverDoesNotExist_ShouldReturnErrorResult() { // Arrange - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); - HashMap drivers = Mockito.mock(HashMap.class); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + HashMap drivers = mock(HashMap.class); String streamId = "streamId"; Result expectedResult = new Result(false, "Driver does not exist for stream id: " + streamId, 404); @@ -406,7 +412,7 @@ public void testStopMediaPush_WhenDriverDoesNotExist_ShouldReturnErrorResult() { @Test public void testValidIP(){ - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); assertFalse(plugin.isValidIP("test.abc.fd")); assertFalse(plugin.isValidIP("")); assertFalse(plugin.isValidIP(null)); @@ -415,9 +421,9 @@ public void testValidIP(){ assertFalse(plugin.isValidIP("192..0.1")); } @Test - public void testStopRequestForward(){ + public void testStopRequestForward() throws IOException, URISyntaxException { String streamId = "stream1"; - MediaPushPlugin plugin = Mockito.spy(new MediaPushPlugin()); + MediaPushPlugin plugin = spy(new MediaPushPlugin()); doReturn(null).when(plugin).getBroadcast(anyString()); Result result = plugin.stopMediaPush(streamId); assertEquals(result.getMessage(),"Driver does not exist for stream id: "+streamId); @@ -453,5 +459,97 @@ public void testStopRequestForward(){ verify(plugin,times(2)).forwardMediaPushStopRequest(streamId,"54.36.24.133"); System.out.println(result.getMessage()); + plugin = spy(new MediaPushPlugin()); + + CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class); + HttpClientBuilder builder = mock(HttpClientBuilder.class); + mockStatic(HttpClients.class); + when(HttpClients.custom()).thenReturn(builder); + doReturn(builder).when(builder).setRedirectStrategy((any(LaxRedirectStrategy.class))); + doReturn(mockHttpClient).when(builder).build(); + + AntMediaApplicationAdapter adapter = mock(AntMediaApplicationAdapter.class); + doReturn(adapter).when(plugin).getApplication(); + AppSettings appSettings = mock(AppSettings.class); + doReturn("test").when(appSettings).getClusterCommunicationKey(); + doReturn(appSettings).when(adapter).getAppSettings(); + ServerSettings settings = mock(ServerSettings.class); + doReturn(settings).when(adapter).getServerSettings(); + + doReturn(5080).when(settings).getDefaultHttpPort(); + + mockStatic(JWTFilter.class); + when(JWTFilter.generateJwtToken(anyString(),anyLong())).thenReturn("test"); + + ApplicationContext ctx = mock(ApplicationContext.class); + plugin.applicationContext = ctx; + doReturn("/LiveApp").when(ctx).getApplicationName(); + + URI url = new URI("http://"+ "127.0.0.1" + ":"+ "5080" + "/LiveApp" + "/rest/v1/media-push/stop/"+ streamId); + + CloseableHttpResponse response = mock(CloseableHttpResponse.class); + StatusLine statusLine = mock(StatusLine.class); + doReturn(statusLine).when(response).getStatusLine(); + doReturn(200).when(statusLine).getStatusCode(); + doReturn(response).when(mockHttpClient).execute(any()); + + plugin.forwardMediaPushStopRequest(streamId,"127.0.0.1"); + + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(HttpUriRequest.class); + verify(mockHttpClient).execute(requestCaptor.capture()); + HttpUriRequest capturedRequest = requestCaptor.getValue(); + assertEquals(capturedRequest.getMethod(),"POST"); + assertEquals(capturedRequest.getURI(),url); + assertEquals(capturedRequest.getURI(),url); + Header[] header = capturedRequest.getHeaders(TokenFilterManager.TOKEN_HEADER_FOR_NODE_COMMUNICATION); + assertEquals(header[0].getValue(),"test"); + } + @Test + public void getBroadcastTest() throws URISyntaxException, IOException { + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + String streamId = "stream1"; + + CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class); + HttpClientBuilder builder = mock(HttpClientBuilder.class); + mockStatic(HttpClients.class); + when(HttpClients.custom()).thenReturn(builder); + doReturn(builder).when(builder).setRedirectStrategy((any(LaxRedirectStrategy.class))); + doReturn(mockHttpClient).when(builder).build(); + + AntMediaApplicationAdapter adapter = mock(AntMediaApplicationAdapter.class); + doReturn(adapter).when(plugin).getApplication(); + AppSettings appSettings = mock(AppSettings.class); + doReturn("test").when(appSettings).getClusterCommunicationKey(); + doReturn(appSettings).when(adapter).getAppSettings(); + ServerSettings settings = mock(ServerSettings.class); + doReturn(settings).when(adapter).getServerSettings(); + + doReturn(5080).when(settings).getDefaultHttpPort(); + + ApplicationContext ctx = mock(ApplicationContext.class); + plugin.applicationContext = ctx; + doReturn("/LiveApp").when(ctx).getApplicationName(); + + URI url = new URI("http://"+ "127.0.0.1" + ":"+ "5080" + "/LiveApp" + "/rest/v2/broadcasts/"+ streamId); + CloseableHttpResponse response = mock(CloseableHttpResponse.class); + HttpEntity entity = mock(HttpEntity.class); + String broadcast = "{\"streamId\":\"stream1\",\"status\":\"broadcasting\"}"; + InputStream stream = new ByteArrayInputStream(broadcast.getBytes()); + doReturn(stream).when(entity).getContent(); + doReturn(entity).when(response).getEntity(); + StatusLine statusLine = mock(StatusLine.class); + doReturn(statusLine).when(response).getStatusLine(); + doReturn(200).when(statusLine).getStatusCode(); + doReturn(response).when(mockHttpClient).execute(any()); + + Broadcast broadcast1 = plugin.getBroadcast(streamId); + assertEquals(broadcast1.getStreamId(),streamId); + + ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(HttpUriRequest.class); + verify(mockHttpClient).execute(requestCaptor.capture()); + HttpUriRequest capturedRequest = requestCaptor.getValue(); + assertEquals(capturedRequest.getMethod(),"GET"); + assertEquals(capturedRequest.getURI(),url); + } } \ No newline at end of file From eb32e883f5d3499530ad2dfbdba65b5a964d2c4d Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Sun, 9 Feb 2025 23:52:34 +0530 Subject: [PATCH 09/14] fix code covarage --- .../main/java/io/antmedia/plugin/ClipCreatorPlugin.java | 4 ++-- .../integration/ClipCreatorPluginIntegrationTest.java | 8 +++++--- .../test/java/io/antmedia/test/FilterManagerUnitTest.java | 4 ++++ .../test/java/io/antmedia/test/MCUManagerUnitTest.java | 1 + .../integration/HLSMergerPluginIntegrationTest.java | 5 +++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java b/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java index 2960987d..f43edd0d 100755 --- a/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java +++ b/ClipCreatorPlugin/src/main/java/io/antmedia/plugin/ClipCreatorPlugin.java @@ -175,7 +175,6 @@ public Result startPeriodicRecording(int periodSeconds) vertx.executeBlocking(() -> { - logger.info("startPeriodicRecording#createRecordings ", appName); createRecordings(); return null; }, false); @@ -189,8 +188,9 @@ public Result startPeriodicRecording(int periodSeconds) public void createRecordings() { + List broadcasts = dataStore.getLocalLiveBroadcasts(serverSettings.getHostAddress()); - + logger.info("createRecordings for active broadcasts size:{}", broadcasts.size()); for (Broadcast broadcast : broadcasts) { convertHlsToMp4(broadcast, true); } diff --git a/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java b/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java index 3b9f01f6..35d7dc90 100644 --- a/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java +++ b/ClipCreatorPlugin/src/test/java/io/antmedia/test/integration/ClipCreatorPluginIntegrationTest.java @@ -7,6 +7,7 @@ import io.antmedia.datastore.db.types.User; import io.antmedia.datastore.db.types.VoD; import io.antmedia.datastore.db.types.Broadcast.PlayListItem; +import io.antmedia.datastore.db.types.BroadcastUpdate; import io.antmedia.muxer.IAntMediaStreamHandler; import io.antmedia.muxer.MuxAdaptor; import io.antmedia.plugin.ClipCreatorPlugin; @@ -288,6 +289,7 @@ public void testPeriodicMp4CreationREST() throws Exception { Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(5, TimeUnit.SECONDS).until(() -> { List voDList2 = callGetVoDList(0,50, streamId); + logger.info("VoD List size: {}", voDList2.size()); return voDList2 != null && voDList2.size() == 2; }); @@ -1067,7 +1069,7 @@ public static Result callUpdateBroadcast(String id, String name, String descript String url = ROOT_SERVICE_URL + "/v2/broadcasts/" + id; HttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); - Broadcast broadcast = new Broadcast(); + BroadcastUpdate broadcast = new BroadcastUpdate(); try { broadcast.setStreamId(id); } catch (Exception e1) { @@ -1084,11 +1086,11 @@ public static Result callUpdateBroadcast(String id, String name, String descript try { Gson gson = new Gson(); - HttpUriRequest post = RequestBuilder.put().setUri(url) + HttpUriRequest put = RequestBuilder.put().setUri(url) .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") .setEntity(new StringEntity(gson.toJson(broadcast))).build(); - HttpResponse response = client.execute(post); + HttpResponse response = client.execute(put); StringBuffer result = readResponse(response); diff --git a/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java b/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java index 94bb6353..1de79f94 100644 --- a/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java +++ b/FilterPlugin/src/test/java/io/antmedia/test/FilterManagerUnitTest.java @@ -142,6 +142,7 @@ public void testCheckResultandFilterId() { e.printStackTrace(); fail(e.getMessage()); } + broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); @@ -226,6 +227,7 @@ public void testBugVideoFilterNotWorking(String filterString, String rawFile, in e.printStackTrace(); fail(e.getMessage()); } + broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); @@ -351,6 +353,7 @@ public void testFixVideoPtsInFilter(String filterString, String rawFile, int sou e.printStackTrace(); fail(e.getMessage()); } + broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); @@ -571,6 +574,7 @@ public AVFrame onAudioFrame(String streamId, AVFrame audioFrame) { e.printStackTrace(); fail(e.getMessage()); } + broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); assertEquals("stream1", dataStore.save(broadcast)); diff --git a/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java b/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java index 940568fa..a7c3c510 100644 --- a/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java +++ b/FilterPlugin/src/test/java/io/antmedia/test/MCUManagerUnitTest.java @@ -131,6 +131,7 @@ public void testMCUWithOtherRooms() throws Exception { } catch (Exception e) { e.printStackTrace(); } + broadcast.setUpdateTime(System.currentTimeMillis()); broadcast.setStatus(IAntMediaStreamHandler.BROADCAST_STATUS_BROADCASTING); dataStore.save(broadcast); diff --git a/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java b/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java index f3de2fdb..3efc470b 100644 --- a/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java +++ b/HLSMergerPlugin/src/test/java/io/antmedia/plugin/integration/HLSMergerPluginIntegrationTest.java @@ -108,7 +108,7 @@ public void testMultiResolutionHLS() { callStopMultiResolutionStream(mergedStreamId); - Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { + Awaitility.await().atMost(45, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { return !testFile(APP_URL+"/streams/" + mergedStreamId+ ".m3u8"); }); @@ -186,7 +186,8 @@ public void testMultiAudioHLS() { callStopMultiResolutionStream(mergedStreamId); - Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { + // hls list size is 15 and segment 2 secs, it means it'll be deleted after 30 seconds, have 45 to have some margin + Awaitility.await().atMost(45, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> { return !testFile(APP_URL+"/streams/" + mergedStreamId+ ".m3u8"); }); From d578366a9b7658c2dda11f73ef7037ad33f23315 Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Mon, 10 Feb 2025 00:35:24 +0530 Subject: [PATCH 10/14] fix test cases --- .../io/antmedia/plugin/MediaPushPluginUnitTest.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java index 847bf698..23199d77 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java @@ -33,6 +33,7 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.mockito.ArgumentCaptor; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.openqa.selenium.InvalidArgumentException; import org.openqa.selenium.JavascriptExecutor; @@ -463,7 +464,7 @@ public void testStopRequestForward() throws IOException, URISyntaxException { CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class); HttpClientBuilder builder = mock(HttpClientBuilder.class); - mockStatic(HttpClients.class); + MockedStatic httpClientStaticMock = mockStatic(HttpClients.class); when(HttpClients.custom()).thenReturn(builder); doReturn(builder).when(builder).setRedirectStrategy((any(LaxRedirectStrategy.class))); doReturn(mockHttpClient).when(builder).build(); @@ -478,7 +479,7 @@ public void testStopRequestForward() throws IOException, URISyntaxException { doReturn(5080).when(settings).getDefaultHttpPort(); - mockStatic(JWTFilter.class); + MockedStatic jwtStaticMock = mockStatic(JWTFilter.class); when(JWTFilter.generateJwtToken(anyString(),anyLong())).thenReturn("test"); ApplicationContext ctx = mock(ApplicationContext.class); @@ -503,6 +504,9 @@ public void testStopRequestForward() throws IOException, URISyntaxException { assertEquals(capturedRequest.getURI(),url); Header[] header = capturedRequest.getHeaders(TokenFilterManager.TOKEN_HEADER_FOR_NODE_COMMUNICATION); assertEquals(header[0].getValue(),"test"); + + jwtStaticMock.close(); + httpClientStaticMock.close(); } @Test public void getBroadcastTest() throws URISyntaxException, IOException { @@ -511,7 +515,7 @@ public void getBroadcastTest() throws URISyntaxException, IOException { CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class); HttpClientBuilder builder = mock(HttpClientBuilder.class); - mockStatic(HttpClients.class); + MockedStatic httpClientStaticMock = mockStatic(HttpClients.class); when(HttpClients.custom()).thenReturn(builder); doReturn(builder).when(builder).setRedirectStrategy((any(LaxRedirectStrategy.class))); doReturn(mockHttpClient).when(builder).build(); @@ -550,6 +554,6 @@ public void getBroadcastTest() throws URISyntaxException, IOException { HttpUriRequest capturedRequest = requestCaptor.getValue(); assertEquals(capturedRequest.getMethod(),"GET"); assertEquals(capturedRequest.getURI(),url); - + httpClientStaticMock.close(); } } \ No newline at end of file From 1127f6504e00c927fe8f9fbdca83a7e9af08b568 Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Mon, 10 Feb 2025 02:19:47 +0530 Subject: [PATCH 11/14] fix test cases --- .../io/antmedia/plugin/MediaPushPlugin.java | 7 +++--- .../plugin/MediaPushPluginUnitTest.java | 23 +++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index 1a552421..049d8f11 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -347,7 +347,7 @@ public String checkAndGetStreamId(String streamId) { return streamId; } - private String clearAndQuit(String streamId, RemoteWebDriver driver, Exception e) { + public String clearAndQuit(String streamId, RemoteWebDriver driver, Exception e) { logger.error(ExceptionUtils.getStackTrace(e)); if (driver != null) @@ -434,7 +434,7 @@ public boolean forwardMediaPushStopRequest(String streamId, String ip) { return true; } } catch (Exception e) { - e.printStackTrace(); + logger.error(ExceptionUtils.getStackTrace(e)); } return false; } @@ -463,7 +463,6 @@ public Result stopMediaPush(String streamId) { return result; } } - result.setMessage("Driver does not exist for stream id: " + streamId); return result; } @@ -586,7 +585,7 @@ else if (response.getStatusLine().getStatusCode() != 200){ Broadcast broadcast = gson.fromJson(result.toString(), Broadcast.class); return broadcast; } catch (Exception e) { - e.printStackTrace(); + logger.error(ExceptionUtils.getStackTrace(e)); } return null; } diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java index 23199d77..389f264e 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java @@ -9,6 +9,7 @@ import java.io.*; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -18,6 +19,7 @@ import io.antmedia.filter.JWTFilter; import io.antmedia.filter.TokenFilterManager; import io.antmedia.settings.ServerSettings; +import kotlin.jvm.internal.unsafe.MonitorKt; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; @@ -119,7 +121,7 @@ public void testStartMediaPushWithEndpoint() throws IOException { } - + @Test public void testSendCommand_WhenDriverExists_ShouldExecuteCommand() { // Arrange @@ -499,11 +501,11 @@ public void testStopRequestForward() throws IOException, URISyntaxException { ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(HttpUriRequest.class); verify(mockHttpClient).execute(requestCaptor.capture()); HttpUriRequest capturedRequest = requestCaptor.getValue(); - assertEquals(capturedRequest.getMethod(),"POST"); + assertEquals("POST", capturedRequest.getMethod()); assertEquals(capturedRequest.getURI(),url); assertEquals(capturedRequest.getURI(),url); Header[] header = capturedRequest.getHeaders(TokenFilterManager.TOKEN_HEADER_FOR_NODE_COMMUNICATION); - assertEquals(header[0].getValue(),"test"); + assertEquals("test", header[0].getValue()); jwtStaticMock.close(); httpClientStaticMock.close(); @@ -547,13 +549,24 @@ public void getBroadcastTest() throws URISyntaxException, IOException { doReturn(response).when(mockHttpClient).execute(any()); Broadcast broadcast1 = plugin.getBroadcast(streamId); - assertEquals(broadcast1.getStreamId(),streamId); + assertEquals(streamId, broadcast1.getStreamId()); ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(HttpUriRequest.class); verify(mockHttpClient).execute(requestCaptor.capture()); HttpUriRequest capturedRequest = requestCaptor.getValue(); - assertEquals(capturedRequest.getMethod(),"GET"); + assertEquals("GET", capturedRequest.getMethod()); assertEquals(capturedRequest.getURI(),url); httpClientStaticMock.close(); } + + @Test + public void testDriverExit() throws IOException { + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + RemoteWebDriver driver = plugin.createDriver(1280, 720, "streamId", Arrays.asList("--disable-gpu", "--start-fullscreen")); + driver.get("https://google.com"); + plugin.clearAndQuit("streamId" , driver,new Exception("test")); + verify(driver).quit(); + + } + } \ No newline at end of file From cfc3d7122d603f29495b50c598ea75a0d5309c6f Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Mon, 10 Feb 2025 06:35:23 +0530 Subject: [PATCH 12/14] fix test cases --- .../io/antmedia/plugin/MediaPushPlugin.java | 7 +++- .../plugin/MediaPushPluginUnitTest.java | 41 ++++++++++++++----- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index 049d8f11..fe14b1cf 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -234,6 +234,9 @@ public Result startMediaPush(String streamIdPar, String websocketUrl, int width, return startMediaPush(streamIdPar, websocketUrl, endpoint); } + public WebDriverWait createWebDriverWait(WebDriver driver, int timeoutSeconds) { + return new WebDriverWait(driver, Duration.ofSeconds(timeoutSeconds)); + } @SuppressWarnings("javasecurity:S5334") @Override @@ -280,7 +283,7 @@ public Result startMediaPush(String streamIdPar, String websocketUrl, Endpoint e driver = openDriver(width, height, recordTypeString, extraChromeSwitchList, streamId, publisherUrl, url); - WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(TIMEOUT_IN_SECONDS)); + WebDriverWait wait = createWebDriverWait(driver, TIMEOUT_IN_SECONDS); //there are three methods in javascript side //window.startBroadcasting = startBroadcasting -> gets message json parameter @@ -290,7 +293,7 @@ public Result startMediaPush(String streamIdPar, String websocketUrl, Endpoint e wait.until(ExpectedConditions.jsReturnsValue("return (typeof window.startBroadcasting != 'undefined')")); String driverIp = getApplication().getServerSettings().getHostAddress(); - driverIp = "{\"driverIp\":\"" + driverIp + "\"}"; + driverIp = "{\"driverIp\":\"" + driverIp + "\"}"; String startBroadcastingCommand = String.format("window.startBroadcasting({websocketURL:'%s',streamId:'%s',width:%d,height:%d,token:'%s',driverIp:'%s'});", websocketUrl, streamId, width, height, StringUtils.isNotBlank(token) ? token : "",driverIp); diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java index 389f264e..95dd8408 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java @@ -9,9 +9,9 @@ import java.io.*; import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.function.Function; import io.antmedia.AntMediaApplicationAdapter; import io.antmedia.AppSettings; @@ -19,7 +19,6 @@ import io.antmedia.filter.JWTFilter; import io.antmedia.filter.TokenFilterManager; import io.antmedia.settings.ServerSettings; -import kotlin.jvm.internal.unsafe.MonitorKt; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; @@ -39,8 +38,10 @@ import org.mockito.Mockito; import org.openqa.selenium.InvalidArgumentException; import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver.TargetLocator; import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.ui.WebDriverWait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -121,6 +122,33 @@ public void testStartMediaPushWithEndpoint() throws IOException { } + @Test + public void testStartMediaPushWithWithIP() throws IOException, InterruptedException { + MediaPushPlugin plugin = spy(new MediaPushPlugin()); + String myIp = "192.168.0.1"; + Endpoint endpoint = new Endpoint(); + endpoint.setUrl("http://example.com"); + endpoint.setWidth(1280); + endpoint.setHeight(720); + endpoint.setToken("token"); + endpoint.setExtraChromeSwitches("--disable-gpu,--start-fullscreen"); + + + RemoteWebDriver driver = mock(RemoteWebDriver.class); + doReturn(driver).when(plugin).openDriver(endpoint.getWidth(),endpoint.getHeight(),endpoint.getRecordType(),Arrays.asList("--disable-gpu", "--start-fullscreen"),"streamId","http://example.antmedia.io/media-push/media-push-publisher.html",endpoint.getUrl()); + WebDriverWait wait = mock(WebDriverWait.class); + when(wait.until(any(Function.class))).thenReturn(true); + doReturn(wait).when(plugin).createWebDriverWait(any(WebDriver.class),anyInt()); + + AntMediaApplicationAdapter adapter = mock(AntMediaApplicationAdapter.class); + doReturn(adapter).when(plugin).getApplication(); + ServerSettings settings = mock(ServerSettings.class); + doReturn(settings).when(adapter).getServerSettings(); + doReturn(myIp).when(settings).getHostAddress(); + + plugin.startMediaPush("streamId", "ws://example.antmedia.io", endpoint); + verify(driver).executeScript("window.startBroadcasting({websocketURL:'ws://example.antmedia.io',streamId:'streamId',width:1280,height:720,token:'token',driverIp:'{\"driverIp\":\"192.168.0.1\"}'});"); + } @Test public void testSendCommand_WhenDriverExists_ShouldExecuteCommand() { @@ -559,14 +587,5 @@ public void getBroadcastTest() throws URISyntaxException, IOException { httpClientStaticMock.close(); } - @Test - public void testDriverExit() throws IOException { - MediaPushPlugin plugin = spy(new MediaPushPlugin()); - RemoteWebDriver driver = plugin.createDriver(1280, 720, "streamId", Arrays.asList("--disable-gpu", "--start-fullscreen")); - driver.get("https://google.com"); - plugin.clearAndQuit("streamId" , driver,new Exception("test")); - verify(driver).quit(); - - } } \ No newline at end of file From ac3e5316a53dc632d2b5bc1551579c91bd1ce3ba Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Mon, 10 Feb 2025 07:17:52 +0530 Subject: [PATCH 13/14] fix test cases --- .../io/antmedia/plugin/MediaPushPlugin.java | 83 ++++++++----------- .../plugin/MediaPushPluginUnitTest.java | 16 +++- 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index fe14b1cf..f3508b3a 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -396,19 +396,11 @@ public String getPublisherHTMLURL(String websocketUrl) throws InvalidArgumentExc return publisherHtmlURL; } - public boolean isValidIP(String ip) { - if(ip == null) - return false; - - String ipPattern = - "^(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])\\." + - "(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])\\." + - "(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])\\." + - "(25[0-5]|2[0-4][0-9]|1[0-9]{1,2}|[1-9]?[0-9])$"; - - - return Pattern.matches(ipPattern, ip); - } + public boolean isValidIP(String ip) { + if (ip == null) + return false; + return ip.matches("^((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)$"); + } public boolean forwardMediaPushStopRequest(String streamId, String ip) { @@ -444,59 +436,54 @@ public boolean forwardMediaPushStopRequest(String streamId, String ip) { @Override public Result stopMediaPush(String streamId) { - Result result = new Result(false); - if (!drivers.containsKey(streamId)) { - Broadcast broadcast = getBroadcast(streamId); - - if(broadcast == null){ - logger.warn("Driver does not exist for stream id: {}", streamId); - result.setMessage("Driver does not exist for stream id: " + streamId); - return result; - } - - String metaData = broadcast.getMetaData(); - try { + Result result = new Result(false); + if (!drivers.containsKey(streamId)) { + Broadcast broadcast = getBroadcast(streamId); - if (metaData != null && !metaData.equals("null") && !metaData.isEmpty()){ - JsonObject jsonObject = JsonParser.parseString(metaData).getAsJsonObject(); - String driverIp = jsonObject.get("driverIp").getAsString(); + if (broadcast == null) { + result.setMessage("Driver does not exist for stream id: " + streamId); + return result; + } - if(isValidIP(driverIp) && forwardMediaPushStopRequest(streamId, driverIp)){ - result.setSuccess(true); + String metaData = broadcast.getMetaData(); + try { + if (metaData != null && !metaData.equals("null") && !metaData.isEmpty()) { + JsonObject jsonObject = JsonParser.parseString(metaData).getAsJsonObject(); + String driverIp = jsonObject.get("driverIp").getAsString(); + + if (isValidIP(driverIp) && forwardMediaPushStopRequest(streamId, driverIp)) { + result.setSuccess(true); + return result; + } + } + result.setMessage("Driver does not exist for stream id: " + streamId); + return result; + } catch (Exception e) { + logger.error(ExceptionUtils.getStackTrace(e)); + } return result; - } } - result.setMessage("Driver does not exist for stream id: " + streamId); - return result; - } - catch(Exception e){ - logger.error(e.getStackTrace().toString()); - } - return result; - } - RemoteWebDriver driver = drivers.remove(streamId); recordingMap.remove(streamId); WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(TIMEOUT_IN_SECONDS)); - try - { + try { driver.executeScript("window.stopBroadcasting({" + "streamId:'" + streamId + "'," + "});"); - wait.until(ExpectedConditions.jsReturnsValue("return !window.isConnected('"+streamId+"')")); + wait.until(ExpectedConditions.jsReturnsValue("return !window.isConnected('" + streamId + "')")); result.setSuccess(true); - } - catch(TimeoutException e) { + } catch (TimeoutException e) { logger.error(ExceptionUtils.getStackTrace(e)); - result.setMessage("Timeoutexception occured in stopping the stream. Fortunately, it'll quit the session to stop completely. Error message is " + e.getMessage()); + result.setMessage( + "Timeoutexception occured in stopping the stream. Fortunately, it'll quit the session to stop completely. Error message is " + + e.getMessage()); - } - finally { + } finally { driver.quit(); } return result; diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java index 95dd8408..1750c455 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java @@ -1,14 +1,12 @@ package io.antmedia.plugin; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.io.*; import java.net.URI; import java.net.URISyntaxException; +import java.time.Duration; import java.util.Arrays; import java.util.HashMap; import java.util.function.Function; @@ -421,6 +419,16 @@ public void testStopMediaPush_WhenDriverExists_ShouldStopMediaPushAndReturnSucce //make sure it's removed assertEquals(0, plugin.getDrivers().size()); } + public boolean waituntiltest(){ + return true; + } + @Test + public void testCreateDriverWait(){ + MediaPushPlugin plugin = new MediaPushPlugin(); + WebDriverWait wait = plugin.createWebDriverWait(mock(WebDriver.class),10); + assertNotNull(wait); + wait.withTimeout(Duration.ofSeconds(1)); + } @Test public void testStopMediaPush_WhenDriverDoesNotExist_ShouldReturnErrorResult() { From 38b2328bda7677f953bb7a2d7ef99136fc888688 Mon Sep 17 00:00:00 2001 From: USAMAWIZARD Date: Mon, 17 Feb 2025 20:52:56 +0530 Subject: [PATCH 14/14] get broadcast from datastore --- .../io/antmedia/plugin/MediaPushPlugin.java | 31 +++-------- .../plugin/MediaPushPluginUnitTest.java | 51 +------------------ 2 files changed, 7 insertions(+), 75 deletions(-) diff --git a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java index f3508b3a..6ab4790f 100644 --- a/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java +++ b/MediaPushPlugin/src/main/java/io/antmedia/plugin/MediaPushPlugin.java @@ -58,6 +58,7 @@ import io.antmedia.AntMediaApplicationAdapter; import io.antmedia.filter.JWTFilter; import io.antmedia.RecordType; +import io.antmedia.datastore.db.DataStore; import io.antmedia.datastore.db.types.Broadcast; import io.antmedia.filter.TokenFilterManager; import io.antmedia.model.Endpoint; @@ -551,33 +552,13 @@ public static StringBuffer readResponse(HttpResponse response) throws IOExceptio } public Broadcast getBroadcast(String streamId) { - try { - CloseableHttpClient client = HttpClients.custom().setRedirectStrategy(new LaxRedirectStrategy()).build(); - Gson gson = new Gson(); - String url = "http://"+ "127.0.0.1" + ":"+ getApplication().getServerSettings().getDefaultHttpPort() + applicationContext.getApplicationName() + "/rest/v2/broadcasts/"+ streamId; - logger.info(url); - - HttpUriRequest get = RequestBuilder.get().setUri(url) - .setHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .build(); - - CloseableHttpResponse response = client.execute(get); + AntMediaApplicationAdapter app = getApplication(); + DataStore dataStore = app.getDataStore(); - StringBuffer result = readResponse(response); + if(dataStore == null) + return null; - if (response.getStatusLine().getStatusCode() == 404) { - logger.info("Response to getBroadcast is 404. It means stream is not found or deleted"); - return null; - } - else if (response.getStatusLine().getStatusCode() != 200){ - throw new Exception("Status code not 200 "); - } - Broadcast broadcast = gson.fromJson(result.toString(), Broadcast.class); - return broadcast; - } catch (Exception e) { - logger.error(ExceptionUtils.getStackTrace(e)); - } - return null; + return dataStore.get(streamId); } diff --git a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java index 1750c455..0b4c5164 100644 --- a/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java +++ b/MediaPushPlugin/src/test/java/io/antmedia/plugin/MediaPushPluginUnitTest.java @@ -546,54 +546,5 @@ public void testStopRequestForward() throws IOException, URISyntaxException { jwtStaticMock.close(); httpClientStaticMock.close(); } - @Test - public void getBroadcastTest() throws URISyntaxException, IOException { - MediaPushPlugin plugin = spy(new MediaPushPlugin()); - String streamId = "stream1"; - - CloseableHttpClient mockHttpClient = mock(CloseableHttpClient.class); - HttpClientBuilder builder = mock(HttpClientBuilder.class); - MockedStatic httpClientStaticMock = mockStatic(HttpClients.class); - when(HttpClients.custom()).thenReturn(builder); - doReturn(builder).when(builder).setRedirectStrategy((any(LaxRedirectStrategy.class))); - doReturn(mockHttpClient).when(builder).build(); - - AntMediaApplicationAdapter adapter = mock(AntMediaApplicationAdapter.class); - doReturn(adapter).when(plugin).getApplication(); - AppSettings appSettings = mock(AppSettings.class); - doReturn("test").when(appSettings).getClusterCommunicationKey(); - doReturn(appSettings).when(adapter).getAppSettings(); - ServerSettings settings = mock(ServerSettings.class); - doReturn(settings).when(adapter).getServerSettings(); - - doReturn(5080).when(settings).getDefaultHttpPort(); - - ApplicationContext ctx = mock(ApplicationContext.class); - plugin.applicationContext = ctx; - doReturn("/LiveApp").when(ctx).getApplicationName(); - - URI url = new URI("http://"+ "127.0.0.1" + ":"+ "5080" + "/LiveApp" + "/rest/v2/broadcasts/"+ streamId); - CloseableHttpResponse response = mock(CloseableHttpResponse.class); - HttpEntity entity = mock(HttpEntity.class); - String broadcast = "{\"streamId\":\"stream1\",\"status\":\"broadcasting\"}"; - InputStream stream = new ByteArrayInputStream(broadcast.getBytes()); - doReturn(stream).when(entity).getContent(); - doReturn(entity).when(response).getEntity(); - StatusLine statusLine = mock(StatusLine.class); - doReturn(statusLine).when(response).getStatusLine(); - doReturn(200).when(statusLine).getStatusCode(); - doReturn(response).when(mockHttpClient).execute(any()); - - Broadcast broadcast1 = plugin.getBroadcast(streamId); - assertEquals(streamId, broadcast1.getStreamId()); - - ArgumentCaptor requestCaptor = ArgumentCaptor.forClass(HttpUriRequest.class); - verify(mockHttpClient).execute(requestCaptor.capture()); - HttpUriRequest capturedRequest = requestCaptor.getValue(); - assertEquals("GET", capturedRequest.getMethod()); - assertEquals(capturedRequest.getURI(),url); - httpClientStaticMock.close(); - } - -} \ No newline at end of file +}