forked from muaz-khan/RTCMultiConnection
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRTCMultiConnection.min.js
executable file
·7 lines (6 loc) · 127 KB
/
RTCMultiConnection.min.js
1
2
3
4
5
6
7
// Last time updated at Tuesday, December 22nd, 2015, 4:53:02 PM
!function(){function RTCMultiSession(connection,callbackForSignalingReady){function onDataChannelMessage(e){return e.data.checkingPresence&&connection.channels[e.userid]?void connection.channels[e.userid].send({presenceDetected:!0}):e.data.presenceDetected&&connection.peers[e.userid]?void(connection.peers[e.userid].connected=!0):void("text"===e.data.type?textReceiver.receive(e.data,e.userid,e.extra):connection.autoTranslateText?(e.original=e.data,connection.Translator.TranslateText(e.data,function(translatedText){e.data=translatedText,connection.onmessage(e)})):connection.onmessage(e))}function onNewSession(session){return connection.skipOnNewSession||(session.session||(session.session={}),session.extra||(session.extra={}),connection.sessionid&&session.sessionid!=connection.sessionid)?void 0:connection.onNewSession?(session.join=function(forceSession){if(!forceSession)return connection.join(session);for(var f in forceSession)session.session[f]=forceSession[f];var isDontCaptureUserMedia=connection.dontCaptureUserMedia;connection.dontCaptureUserMedia=!1,connection.captureUserMedia(function(){connection.dontCaptureUserMedia=!0,connection.join(session),connection.dontCaptureUserMedia=isDontCaptureUserMedia},forceSession)},session.extra||(session.extra={}),connection.onNewSession(session)):void connection.join(session)}function updateSocketForLocalStreams(socket){for(var i=0;i<connection.localStreamids.length;i++){var streamid=connection.localStreamids[i];connection.streams[streamid]&&connection.streams[streamid].sockets.push(socket)}}function newPrivateSocket(_config){function waitUntilRemoteStreamStartsFlowing(args){return isMobileDevice||isPluginRTC||isNull(connection.waitUntilRemoteStreamStartsFlowing)||!connection.waitUntilRemoteStreamStartsFlowing?afterRemoteStreamStartedFlowing(args):(args.numberOfTimes||(args.numberOfTimes=0),args.numberOfTimes++,args.mediaElement.readyState<=HTMLMediaElement.HAVE_CURRENT_DATA||args.mediaElement.paused||args.mediaElement.currentTime<=0?args.numberOfTimes>=60?socket.send({failedToReceiveRemoteVideo:!0,streamid:args.stream.streamid}):void setTimeout(function(){log("Waiting for incoming remote stream to be started flowing: "+args.numberOfTimes+" seconds."),waitUntilRemoteStreamStartsFlowing(args)},900):afterRemoteStreamStartedFlowing(args))}function initFakeChannel(){if(connection.fakeDataChannels&&!connection.channels[_config.userid]&&!connection.session.data){var fakeChannel={send:function(data){socket.send({fakeData:data})},readyState:"open"};connection.channels[_config.userid]={channel:fakeChannel,send:function(data){this.channel.send(data)}},peerConfig.onopen(fakeChannel)}}function afterRemoteStreamStartedFlowing(args){var mediaElement=args.mediaElement,session=args.session,stream=args.stream;stream.onended=function(){streamedObject.mediaElement&&!streamedObject.mediaElement.parentNode&&document.getElementById(stream.streamid)&&(streamedObject.mediaElement=document.getElementById(stream.streamid)),onStreamEndedHandler(streamedObject,connection)};var streamedObject={mediaElement:mediaElement,stream:stream,streamid:stream.streamid,session:session||connection.session,blobURL:isPluginRTC?"":mediaElement.mozSrcObject?URL.createObjectURL(stream):mediaElement.src,type:"remote",extra:_config.extra,userid:_config.userid,isVideo:isPluginRTC?!!session.video:!!stream.isVideo,isAudio:isPluginRTC?!!session.audio&&!session.video:!!stream.isAudio,isScreen:!!stream.isScreen,isInitiator:!!_config.isInitiator,rtcMultiConnection:connection,socket:socket};if(connection.streams[stream.streamid]=connection._getStream(streamedObject),connection.onstream(streamedObject),!isEmpty(args.preMuted)&&(args.preMuted.audio||args.preMuted.video)){var fakeObject=merge({},streamedObject);fakeObject.session=merge(fakeObject.session,args.preMuted),fakeObject.isAudio=!!fakeObject.session.audio&&!fakeObject.session.video,fakeObject.isVideo=!!fakeObject.session.video,fakeObject.isScreen=!1,connection.onmute(fakeObject)}log("on:add:stream",streamedObject),onSessionOpened(),connection.onspeaking&&initHark({stream:stream,streamedObject:streamedObject,connection:connection})}function onChannelOpened(channel){_config.channel=channel,connection.channels[_config.userid]={channel:_config.channel,send:function(data){connection.send(data,this.channel)}},connection.onopen({extra:_config.extra,userid:_config.userid,channel:channel});for(var q in connection.fileQueue)connection.send(connection.fileQueue[q],channel);isData(connection.session)&&onSessionOpened(),connection.partOfScreen&&connection.partOfScreen.sharing&&connection.peers[_config.userid].sharePartOfScreen(connection.partOfScreen)}function updateSocket(){socket.userid!=_config.userid&&(socket.userid=_config.userid,sockets[_config.socketIndex]=socket,connection.numberOfConnectedUsers++,connection.peers[_config.userid]={socket:socket,peer:peer,userid:_config.userid,extra:_config.extra,userinfo:_config.userinfo,addStream:function(session00){connection.addStream(session00,this.socket)},removeStream:function(streamid){return connection.streams[streamid]?(this.peer.connection.removeStream(connection.streams[streamid].stream),void this.renegotiate()):warn("No such stream exists. Stream-id:",streamid)},renegotiate:function(stream,session){connection.renegotiate(stream,session)},changeBandwidth:function(bandwidth){if(!bandwidth)throw"You MUST pass bandwidth object.";if(isString(bandwidth))throw"Pass object for bandwidth instead of string; e.g. {audio:10, video:20}";this.peer.bandwidth=bandwidth,this.socket.send({changeBandwidth:!0,bandwidth:bandwidth})},sendCustomMessage:function(message){this.socket.send({customMessage:!0,message:message})},onCustomMessage:function(message){log('Received "private" message from',this.userid,isString(message)?message:toStr(message))},drop:function(dontSendMessage){for(var stream in connection.streams)-1==connection._skip.indexOf(stream)&&(stream=connection.streams[stream],stream.userid==connection.userid&&"local"==stream.type&&(this.peer.connection.removeStream(stream.stream),onStreamEndedHandler(stream,connection)),"remote"==stream.type&&stream.userid==this.userid&&onStreamEndedHandler(stream,connection));!dontSendMessage&&this.socket.send({drop:!0})},hold:function(holdMLine){return"answer"==peer.prevCreateType?void this.socket.send({unhold:!0,holdMLine:holdMLine||"both",takeAction:!0}):(this.socket.send({hold:!0,holdMLine:holdMLine||"both"}),this.peer.hold=!0,void this.fireHoldUnHoldEvents({kind:holdMLine,isHold:!0,userid:connection.userid,remoteUser:this.userid}))},unhold:function(holdMLine){return"answer"==peer.prevCreateType?void this.socket.send({unhold:!0,holdMLine:holdMLine||"both",takeAction:!0}):(this.socket.send({unhold:!0,holdMLine:holdMLine||"both"}),this.peer.hold=!1,void this.fireHoldUnHoldEvents({kind:holdMLine,isHold:!1,userid:connection.userid,remoteUser:this.userid}))},fireHoldUnHoldEvents:function(e){var isHold=e.isHold,kind=e.kind,userid=e.remoteUser||e.userid;for(var stream in connection.streams)-1==connection._skip.indexOf(stream)&&(stream=connection.streams[stream],stream.userid==userid&&(isHold&&connection.onhold(merge({kind:kind},stream)),isHold||connection.onunhold(merge({kind:kind},stream))))},redial:function(){for(var stream in connection.streams)-1==connection._skip.indexOf(stream)&&(stream=connection.streams[stream],stream.userid==this.userid&&"remote"==stream.type&&onStreamEndedHandler(stream,connection));log("ReDialing..."),socket.send({recreatePeer:!0}),peer=new PeerConnection,peer.create("offer",peerConfig)},sharePartOfScreen:function(args){function partOfScreenCapturer(){return that.stopPartOfScreenSharing?(that.stopPartOfScreenSharing=!1,void(connection.onpartofscreenstopped&&connection.onpartofscreenstopped())):that.pausePartOfScreenSharing?(connection.onpartofscreenpaused&&connection.onpartofscreenpaused(),setTimeout(partOfScreenCapturer,args.interval||200)):void capturePartOfScreen({element:args.element,connection:connection,callback:function(screenshot){if(!connection.channels[that.userid])throw"No such data channel exists.";screenshot!=lastScreenshot&&(lastScreenshot=screenshot,connection.channels[that.userid].send({screenshot:screenshot,isPartOfScreen:!0})),!args.once&&setTimeout(partOfScreenCapturer,args.interval||200)}})}var that=this,lastScreenshot="";partOfScreenCapturer()},getConnectionStats:function(callback,interval){function invoker(){RTCPeerConnection.prototype.getConnectionStats=window.getConnectionStats,peer.connection&&peer.connection.getConnectionStats(callback,interval)}if(!callback)throw"callback is mandatory.";window.getConnectionStats?invoker():loadScript(connection.resources.getConnectionStats,invoker)},takeSnapshot:function(callback){takeSnapshot({userid:this.userid,connection:connection,callback:callback})}})}function onSessionOpened(){if(connection.isInitiator&&getLength(participants)&&getLength(participants)<=connection.maxParticipantsAllowed&&(connection.session.oneway||connection.session.broadcast||defaultSocket.send({sessionid:connection.sessionid,newParticipant:_config.userid||socket.channel,userData:{userid:_config.userid||socket.channel,extra:_config.extra}})),"chrome"==_config.userinfo.browser&&!_config.renegotiatedOnce)for(var rSession in connection.renegotiatedSessions)_config.renegotiatedOnce=!0,connection.renegotiatedSessions[rSession]&&connection.renegotiatedSessions[rSession].stream&&connection.peers[_config.userid].renegotiate(connection.renegotiatedSessions[rSession].stream,connection.renegotiatedSessions[rSession].session)}function socketResponse(response){if(!isRMSDeleted&&response.userid!=connection.userid){if(response.sdp){_config.userid=response.userid,_config.extra=response.extra||{},_config.renegotiate=response.renegotiate,_config.streaminfo=response.streaminfo,_config.isInitiator=response.isInitiator,_config.userinfo=response.userinfo;var sdp=JSON.parse(response.sdp);"offer"==sdp.type&&(peerConfig.preferSCTP=!!response.preferSCTP,connection.fakeDataChannels=!!response.fakeDataChannels),initFakeChannel(),sdpInvoker(sdp,response.labels)}if(response.candidate&&peer&&peer.addIceCandidate(JSON.parse(response.candidate)),response.streamid&&(rtcMultiSession.streamids||(rtcMultiSession.streamids={}),rtcMultiSession.streamids[response.streamid]||(rtcMultiSession.streamids[response.streamid]=response.streamid,connection.onstreamid(response))),response.mute||response.unmute)if(response.promptMuteUnmute){if(!connection.privileges.canMuteRemoteStream)return void connection.onstatechange({userid:response.userid,extra:response.extra,name:"mute-request-denied",reason:response.userid+' tried to mute your stream; however "privileges.canMuteRemoteStream" is "false".'});connection.streams[response.streamid]&&(response.mute&&!connection.streams[response.streamid].muted&&connection.streams[response.streamid].mute(response.session),response.unmute&&connection.streams[response.streamid].muted&&connection.streams[response.streamid].unmute(response.session))}else{var streamObject={};connection.streams[response.streamid]&&(streamObject=connection.streams[response.streamid]);var session=response.session,fakeObject=merge({},streamObject);fakeObject.session=session,fakeObject.isAudio=!!fakeObject.session.audio&&!fakeObject.session.video,fakeObject.isVideo=!!fakeObject.session.video,fakeObject.isScreen=!!fakeObject.session.screen,response.mute&&connection.onmute(fakeObject||response),response.unmute&&connection.onunmute(fakeObject||response)}if(response.isVolumeChanged&&(log("Volume of stream: "+response.streamid+" has changed to: "+response.volume),connection.streams[response.streamid])){var mediaElement=connection.streams[response.streamid].mediaElement;mediaElement&&(mediaElement.volume=response.volume)}if(response.stopped&&connection.streams[response.streamid]&&onStreamEndedHandler(connection.streams[response.streamid],connection),response.promptStreamStop){if(!connection.privileges.canStopRemoteStream)return void connection.onstatechange({userid:response.userid,extra:response.extra,name:"stop-request-denied",reason:response.userid+' tried to stop your stream; however "privileges.canStopRemoteStream" is "false".'});warn("Remote stream has been manually stopped!"),connection.streams[response.streamid]&&connection.streams[response.streamid].stop()}if(response.left){if(isFirefox){var userLeft=response.userid;for(var stream in connection.streams)stream=connection.streams[stream],stream.userid==userLeft&&(connection.stopMediaStream(stream),onStreamEndedHandler(stream,connection))}if(peer&&peer.connection&&("closed"!=peer.connection.signalingState&&-1==peer.connection.iceConnectionState.search(/disconnected|failed/gi)&&peer.connection.close(),peer.connection=null),participants[response.userid]&&delete participants[response.userid],response.closeEntireSession)return connection.onSessionClosed(response),void connection.leave();connection.remove(response.userid),onLeaveHandler({userid:response.userid,extra:response.extra||{},entireSessionClosed:!!response.closeEntireSession},connection)}if(response.playRoleOfBroadcaster&&(response.extra&&(connection.extra=merge(connection.extra,response.extra)),response.participants&&(participants=response.participants,participants[connection.userid]&&delete participants[connection.userid],sockets[0]&&sockets[0].userid==response.userid&&(delete sockets[0],sockets=swap(sockets)),socketObjects[response.userid]&&delete socketObjects[response.userid]),setTimeout(connection.playRoleOfInitiator,2e3)),response.changeBandwidth){if(!connection.peers[response.userid])throw"No such peer exists.";connection.peers[response.userid].peer.bandwidth=response.bandwidth,connection.peers[response.userid].renegotiate()}if(response.customMessage){if(!connection.peers[response.userid])throw"No such peer exists.";if(response.message.ejected){if(connection.sessionDescriptions[connection.sessionid].userid!=response.userid)throw"only initiator can eject a user.";connection.leave(),connection.onSessionClosed({userid:response.userid,extra:response.extra||_config.extra,isEjected:!0})}else connection.peers[response.userid].onCustomMessage(response.message)}if(response.drop){if(!connection.peers[response.userid])throw"No such peer exists.";connection.peers[response.userid].drop(!0),connection.peers[response.userid].renegotiate(),connection.ondrop(response.userid)}if(response.hold||response.unhold){if(!connection.peers[response.userid])throw"No such peer exists.";if(response.takeAction)return void connection.peers[response.userid][response.hold?"hold":"unhold"](response.holdMLine);connection.peers[response.userid].peer.hold=!!response.hold,connection.peers[response.userid].peer.holdMLine=response.holdMLine,socket.send({isRenegotiate:!0}),connection.peers[response.userid].fireHoldUnHoldEvents({kind:response.holdMLine,isHold:!!response.hold,userid:response.userid})}response.isRenegotiate&&connection.peers[response.userid].renegotiate(null,connection.peers[response.userid].peer.session),response.fakeData&&peerConfig.onmessage(response.fakeData),response.recreatePeer&&(peer=new PeerConnection),response.failedToReceiveRemoteVideo&&(log("Remote peer hasn't received stream: "+response.streamid+". Renegotiating..."),connection.peers[response.userid]&&connection.peers[response.userid].renegotiate()),response.redial&&connection.peers[response.userid]&&("disconnected"!=connection.peers[response.userid].peer.connection.iceConnectionState&&(_config.redialing=!1),"disconnected"!=connection.peers[response.userid].peer.connection.iceConnectionState||_config.redialing||(_config.redialing=!0,warn("Peer connection is closed.",toStr(connection.peers[response.userid].peer.connection),"ReDialing.."),connection.peers[response.userid].redial()))}}function sdpInvoker(sdp,labels){function createAnswer(){peer.recreateAnswer(sdp,session,function(_sdp,streaminfo){sendsdp({sdp:_sdp,socket:socket,streaminfo:streaminfo}),connection.detachStreams=[]})}if("answer"==sdp.type)return peer.setRemoteDescription(sdp),void updateSocket();if(!_config.renegotiate&&"offer"==sdp.type)return peerConfig.offerDescription=sdp,peerConfig.session=connection.session,peer||(peer=new PeerConnection),peer.create("answer",peerConfig),void updateSocket();var session=_config.renegotiate;if(detachMediaStream(labels,peer.connection),session.oneway||isData(session))createAnswer(),delete _config.renegotiate;else{if(_config.capturing)return;_config.capturing=!0,connection.captureUserMedia(function(stream){_config.capturing=!1,peer.addStream(stream),connection.renegotiatedSessions[JSON.stringify(_config.renegotiate)]={session:_config.renegotiate,stream:stream},delete _config.renegotiate,createAnswer()},_config.renegotiate)}}var socketConfig={channel:_config.channel,onmessage:socketResponse,onopen:function(_socket){_socket&&(socket=_socket),isofferer&&!peer&&(peerConfig.session=connection.session,peer||(peer=new PeerConnection),peer.create("offer",peerConfig)),_config.socketIndex=socket.index=sockets.length,socketObjects[socketConfig.channel]=socket,sockets[_config.socketIndex]=socket,updateSocketForLocalStreams(socket),socket.__push||(socket.__push=socket.send,socket.send=function(message){message.userid=message.userid||connection.userid,message.extra=message.extra||connection.extra||{},socket.__push(message)})}};socketConfig.callback=function(_socket){socket=_socket,socketConfig.onopen()};var socket=connection.openSignalingChannel(socketConfig);socket&&socketConfig.onopen(socket);var peer,isofferer=_config.isofferer,peerConfig={onopen:onChannelOpened,onicecandidate:function(candidate){if(!connection.candidates)throw"ICE candidates are mandatory.";if(!connection.iceProtocols)throw"At least one must be true; UDP or TCP.";var iceCandidates=connection.candidates,stun=iceCandidates.stun,turn=iceCandidates.turn;if(isNull(iceCandidates.reflexive)||(stun=iceCandidates.reflexive),isNull(iceCandidates.relay)||(turn=iceCandidates.relay),(iceCandidates.host||!candidate.candidate.match(/a=candidate.*typ host/g))&&!(!turn&&candidate.candidate.match(/a=candidate.*typ relay/g)||!stun&&candidate.candidate.match(/a=candidate.*typ srflx/g))){var protocol=connection.iceProtocols;(protocol.udp||!candidate.candidate.match(/a=candidate.* udp/g))&&(protocol.tcp||!candidate.candidate.match(/a=candidate.* tcp/g))&&(window.selfNPObject||(window.selfNPObject=candidate),socket&&socket.send({candidate:JSON.stringify({candidate:candidate.candidate,sdpMid:candidate.sdpMid,sdpMLineIndex:candidate.sdpMLineIndex})}))}},onmessage:function(data){if(data){var abToStr=ab2str(data);if(-1!=abToStr.indexOf('"userid":'))abToStr=JSON.parse(abToStr),onDataChannelMessage(abToStr);else if(data instanceof ArrayBuffer||data instanceof DataView){if(!connection.enableFileSharing)throw'It seems that receiving data is either "Blob" or "File" but file sharing is disabled.';if(!rtcMultiSession.fileBufferReader){var that=this;return void initFileBufferReader(connection,function(fbr){rtcMultiSession.fileBufferReader=fbr,that.onmessage(data)})}var fileBufferReader=rtcMultiSession.fileBufferReader;return void fileBufferReader.convertToObject(data,function(chunk){return chunk.maxChunks||chunk.readyForNextChunk?chunk.readyForNextChunk?void fileBufferReader.getNextChunk(chunk.uuid,function(nextChunk,isLastChunk,extra){rtcMultiSession.send(nextChunk)}):void fileBufferReader.addChunk(chunk,function(promptNextChunk){rtcMultiSession.send(promptNextChunk)}):void connection.onmessage({data:chunk,userid:_config.userid,extra:_config.extra})})}}},onaddstream:function(stream,session){function eventListener(){setTimeout(function(){mediaElement.muted=!1,afterRemoteStreamStartedFlowing({mediaElement:mediaElement,session:session,stream:stream,preMuted:preMuted})},3e3),mediaElement.removeEventListener("play",eventListener)}if(session=session||_config.renegotiate||connection.session,!isData(session)){session.screen&&(session.audio||session.video)&&(_config.gotAudioOrVideo?(session.audio=!1,session.video=!1):(_config.gotAudioOrVideo=!0,session.screen=!1));var preMuted={};if(_config.streaminfo){var streaminfo=_config.streaminfo.split("----"),strInfo=JSON.parse(streaminfo[streaminfo.length-1]);isIE||(stream.streamid=strInfo.streamid,stream.isScreen=!!strInfo.isScreen,stream.isVideo=!!strInfo.isVideo,stream.isAudio=!!strInfo.isAudio,preMuted=strInfo.preMuted),streaminfo.pop(),_config.streaminfo=streaminfo.join("----")}var mediaElement=createMediaElement(stream,merge({remote:!0},session));return connection.setDefaultEventsForMediaElement&&connection.setDefaultEventsForMediaElement(mediaElement,stream.streamid),isPluginRTC||stream.getVideoTracks().length?void waitUntilRemoteStreamStartsFlowing({mediaElement:mediaElement,session:session,stream:stream,preMuted:preMuted}):mediaElement.addEventListener("play",eventListener,!1)}},onremovestream:function(stream){stream&&stream.streamid?(stream=connection.streams[stream.streamid],stream&&(log("on:stream:ended via on:remove:stream",stream),onStreamEndedHandler(stream,connection))):log("on:remove:stream",stream)},onclose:function(e){e.extra=_config.extra,e.userid=_config.userid,connection.onclose(e),connection.channels[e.userid]&&delete connection.channels[e.userid]},onerror:function(e){e.extra=_config.extra,e.userid=_config.userid,connection.onerror(e)},oniceconnectionstatechange:function(event){log("oniceconnectionstatechange",toStr(event)),peer.connection&&"connected"==peer.connection.iceConnectionState&&"complete"==peer.connection.iceGatheringState&&"stable"==peer.connection.signalingState&&1==connection.numberOfConnectedUsers&&connection.onconnected({userid:_config.userid,extra:_config.extra,peer:connection.peers[_config.userid],targetuser:_config.userinfo}),!connection.isInitiator&&peer.connection&&"connected"==peer.connection.iceConnectionState&&"complete"==peer.connection.iceGatheringState&&"stable"==peer.connection.signalingState&&1==connection.numberOfConnectedUsers&&connection.onstatechange({userid:_config.userid,extra:_config.extra,name:"connected-with-initiator",reason:"ICE connection state seems connected; gathering state is completed; and signaling state is stable."}),connection.peers[_config.userid]&&connection.peers[_config.userid].oniceconnectionstatechange&&connection.peers[_config.userid].oniceconnectionstatechange(event),connection.peers[_config.userid]&&"failed"==connection.peers[_config.userid].peer.connection.iceConnectionState&&connection.onfailed({userid:_config.userid,extra:_config.extra,peer:connection.peers[_config.userid],targetuser:_config.userinfo}),connection.peers[_config.userid]&&"disconnected"==connection.peers[_config.userid].peer.connection.iceConnectionState&&(!peer.connection.renegotiate&&connection.ondisconnected({userid:_config.userid,extra:_config.extra,peer:connection.peers[_config.userid],targetuser:_config.userinfo}),peer.connection.renegotiate=!1),connection.autoReDialOnFailure&&connection.peers[_config.userid]&&("disconnected"!=connection.peers[_config.userid].peer.connection.iceConnectionState&&(_config.redialing=!1),"disconnected"!=connection.peers[_config.userid].peer.connection.iceConnectionState||_config.redialing||(_config.redialing=!0,warn("Peer connection is closed.",toStr(connection.peers[_config.userid].peer.connection),"ReDialing.."),connection.peers[_config.userid].socket.send({redial:!0}),connection.streams.remove({remote:!0,userid:_config.userid})))},onsignalingstatechange:function(event){log("onsignalingstatechange",toStr(event))},attachStreams:connection.dontAttachStream?[]:connection.attachStreams,iceServers:connection.iceServers,rtcConfiguration:connection.rtcConfiguration,bandwidth:connection.bandwidth,sdpConstraints:connection.sdpConstraints,optionalArgument:connection.optionalArgument,disableDtlsSrtp:connection.disableDtlsSrtp,dataChannelDict:connection.dataChannelDict,preferSCTP:connection.preferSCTP,onSessionDescription:function(sessionDescription,streaminfo){sendsdp({sdp:sessionDescription,socket:socket,streaminfo:streaminfo})},trickleIce:connection.trickleIce,processSdp:connection.processSdp,sendStreamId:function(stream){socket&&socket.send({streamid:stream.streamid,isScreen:!!stream.isScreen,isAudio:!!stream.isAudio,isVideo:!!stream.isVideo})},rtcMultiConnection:connection};connection.playRoleOfInitiator=function(){connection.dontCaptureUserMedia=!0,connection.open(),sockets=swap(sockets),connection.dontCaptureUserMedia=!1},connection.askToShareParticipants=function(){defaultSocket&&defaultSocket.send({askToShareParticipants:!0})},connection.shareParticipants=function(args){var message={joinUsers:participants,userid:connection.userid,extra:connection.extra};args&&(args.dontShareWith&&(message.dontShareWith=args.dontShareWith),args.shareWith&&(message.shareWith=args.shareWith)),defaultSocket.send(message)}}function detachMediaStream(labels,peer){if(labels)for(var i=0;i<labels.length;i++){var label=labels[i];connection.streams[label]&&peer.removeStream(connection.streams[label].stream)}}function sendsdp(e){e.socket.send({sdp:JSON.stringify({sdp:e.sdp.sdp,type:e.sdp.type}),renegotiate:e.renegotiate?e.renegotiate:!1,streaminfo:e.streaminfo||"",labels:e.labels||[],preferSCTP:!!connection.preferSCTP,fakeDataChannels:!!connection.fakeDataChannels,isInitiator:!!connection.isInitiator,userinfo:{browser:isFirefox?"firefox":"chrome"}})}function onNewParticipant(response){var channel=response.newParticipant;if(channel&&!participants[channel]&&channel!=connection.userid){var new_channel=connection.token();newPrivateSocket({channel:new_channel,extra:response.userData?response.userData.extra:response.extra,userid:response.userData?response.userData.userid:response.userid}),defaultSocket.send({participant:!0,targetUser:channel,channel:new_channel})}}function clearSession(){connection.numberOfConnectedUsers--;var alertMessage={left:!0,extra:connection.extra||{},userid:connection.userid,sessionid:connection.sessionid};connection.isInitiator&&(connection.autoCloseEntireSession?alertMessage.closeEntireSession=!0:sockets[0]&&sockets[0].send({playRoleOfBroadcaster:!0,userid:connection.userid,extra:connection.extra,participants:participants})),sockets.forEach(function(socket,i){socket.send(alertMessage),socketObjects[socket.channel]&&delete socketObjects[socket.channel],delete sockets[i]}),sockets=swap(sockets),connection.refresh(),webAudioMediaStreamSources.forEach(function(mediaStreamSource){mediaStreamSource.disconnect()}),webAudioMediaStreamSources=[]}function onSignalingReady(){rtcMultiSession.signalingReady||(rtcMultiSession.signalingReady=!0,setTimeout(callbackForSignalingReady,1e3),connection.isInitiator||defaultSocket&&defaultSocket.send({searchingForRooms:!0}))}function joinParticipants(joinUsers){for(var user in joinUsers)participants[joinUsers[user]]||onNewParticipant({sessionid:connection.sessionid,newParticipant:joinUsers[user],userid:connection.userid,extra:connection.extra})}function getDefaultSocketRef(){return connection.openSignalingChannel({onmessage:function(response){if(!isRMSDeleted&&response.userid!=connection.userid){if(response.sessionid&&response.userid&&(connection.sessionDescriptions[response.sessionid]||(connection.numberOfSessions++,connection.sessionDescriptions[response.sessionid]=response,connection.isAcceptNewSession&&(connection.dontOverrideSession||(connection.session=response.session),onNewSession(response)))),response.newParticipant&&!connection.isAcceptNewSession&&rtcMultiSession.broadcasterid===response.userid&&response.newParticipant!=connection.userid&&onNewParticipant(response),getLength(participants)<connection.maxParticipantsAllowed&&response.targetUser==connection.userid&&response.participant){if(connection.peers[response.userid]&&!connection.peers[response.userid].peer)return delete participants[response.userid],delete connection.peers[response.userid],connection.isAcceptNewSession=!0,acceptRequest(response);participants[response.userid]||acceptRequest(response)}if(response.acceptedRequestOf==connection.userid&&connection.onstatechange({userid:response.userid,extra:response.extra,name:"request-accepted",reason:response.userid+" accepted your participation request."}),response.rejectedRequestOf==connection.userid&&connection.onstatechange({userid:response.userid,extra:response.extra,name:"request-rejected",reason:response.userid+" rejected your participation request."}),response.customMessage)if(response.message.drop){connection.ondrop(response.userid),connection.attachStreams=[];for(var stream in connection.streams)-1==connection._skip.indexOf(stream)&&(stream=connection.streams[stream],"local"==stream.type?(connection.detachStreams.push(stream.streamid),onStreamEndedHandler(stream,connection)):onStreamEndedHandler(stream,connection));response.message.renegotiate&&connection.renegotiate()}else connection.onCustomMessage&&connection.onCustomMessage(response.message);if(connection.isInitiator&&response.searchingForRooms&&defaultSocket&&defaultSocket.send({sessionDescription:connection.sessionDescription,responseFor:response.userid}),response.sessionDescription&&response.responseFor==connection.userid){var sessionDescription=response.sessionDescription;connection.sessionDescriptions[sessionDescription.sessionid]||(connection.numberOfSessions++,connection.sessionDescriptions[sessionDescription.sessionid]=sessionDescription)}connection.isInitiator&&response.askToShareParticipants&&defaultSocket&&connection.shareParticipants({shareWith:response.userid}),response.shareWith==connection.userid&&response.dontShareWith!=connection.userid&&response.joinUsers&&joinParticipants(response.joinUsers),!response.shareWith&&response.joinUsers&&(response.dontShareWith?connection.userid!=response.dontShareWith&&joinParticipants(response.joinUsers):joinParticipants(response.joinUsers)),response.messageFor==connection.userid&&response.presenceState&&("checking"==response.presenceState&&(defaultSocket.send({messageFor:response.userid,presenceState:"available",_config:response._config}),log("participant asked for availability")),"available"==response.presenceState&&(rtcMultiSession.presenceState="available",connection.onstatechange({userid:"browser",extra:{},name:"room-available",reason:"Initiator is available and room is active."}),joinSession(response._config))),response.donotJoin&&response.messageFor==connection.userid&&log(response.userid,"is not joining your room."),response.isDisconnectSockets&&(log("Disconnecting your sockets because initiator also disconnected his sockets."),connection.disconnect())}},callback:function(socket){socket&&this.onopen(socket)},onopen:function(socket){socket&&(defaultSocket=socket),onSignalingReady&&onSignalingReady(),rtcMultiSession.defaultSocket=defaultSocket,defaultSocket.__push||(defaultSocket.__push=defaultSocket.send,defaultSocket.send=function(message){message.userid=message.userid||connection.userid,message.extra=message.extra||connection.extra||{},defaultSocket.__push(message)})}})}function setDirections(){var userMaxParticipantsAllowed=0;256!=connection.maxParticipantsAllowed&&(userMaxParticipantsAllowed=connection.maxParticipantsAllowed),"one-way"==connection.direction&&(connection.session.oneway=!0),"one-to-one"==connection.direction&&(connection.maxParticipantsAllowed=1),"one-to-many"==connection.direction&&(connection.session.broadcast=!0),"many-to-many"==connection.direction&&(connection.maxParticipantsAllowed&&1!=connection.maxParticipantsAllowed||(connection.maxParticipantsAllowed=256)),userMaxParticipantsAllowed&&1!=connection.maxParticipantsAllowed&&(connection.maxParticipantsAllowed=userMaxParticipantsAllowed)}function joinSession(_config,skipOnStateChange){if(!rtcMultiSession.donotJoin||rtcMultiSession.donotJoin!=_config.sessionid){connection.dontOverrideSession||(connection.session=_config.session||{}),rtcMultiSession.broadcasterid=_config.userid,_config.sessionid&&(connection.sessionid=_config.sessionid),connection.isAcceptNewSession=!1;var channel=getRandomString();newPrivateSocket({channel:channel,extra:_config.extra||{},userid:_config.userid
});var offers={};if(connection.attachStreams.length){var stream=connection.attachStreams[connection.attachStreams.length-1];stream.getAudioTracks&&stream.getAudioTracks().length&&(offers.audio=!0),stream.getVideoTracks().length&&(offers.video=!0)}log(isEmpty(offers)?"Seems data-only connection.":toStr(offers)),connection.onstatechange({userid:_config.userid,extra:{},name:"connecting-with-initiator",reason:"Checking presence of the initiator; and the room."}),defaultSocket.send({participant:!0,channel:channel,targetUser:_config.userid,session:connection.session,offers:{audio:!!offers.audio,video:!!offers.video}}),connection.skipOnNewSession=!1,invokeMediaCaptured(connection)}}function acceptRequest(response){if(rtcMultiSession.requestsFrom||(rtcMultiSession.requestsFrom={}),!rtcMultiSession.requestsFrom[response.userid]){var obj={userid:response.userid,extra:response.extra,channel:response.channel||response.userid,session:response.session||connection.session};if(response.offers){log(response.offers.audio&&response.offers.video?"target user has both audio/video streams.":response.offers.audio&&!response.offers.video?"target user has only audio stream.":!response.offers.audio&&response.offers.video?"target user has only video stream.":"target user has no stream; it seems one-way streaming or data-only connection.");var mandatory=connection.sdpConstraints.mandatory;isNull(mandatory.OfferToReceiveAudio)&&(connection.sdpConstraints.mandatory.OfferToReceiveAudio=!!response.offers.audio),isNull(mandatory.OfferToReceiveVideo)&&(connection.sdpConstraints.mandatory.OfferToReceiveVideo=!!response.offers.video),log("target user's SDP has?",toStr(connection.sdpConstraints.mandatory))}rtcMultiSession.requestsFrom[response.userid]=obj,connection.onRequest&&connection.isInitiator?connection.onRequest(obj):_accept(obj)}}function _accept(e){return rtcMultiSession.captureUserMediaOnDemand?(rtcMultiSession.captureUserMediaOnDemand=!1,void connection.captureUserMedia(function(){_accept(e),invokeMediaCaptured(connection)})):(log("accepting request from",e.userid),participants[e.userid]=e.userid,void newPrivateSocket({isofferer:!0,userid:e.userid,channel:e.channel,extra:e.extra||{},session:e.session||connection.session}))}var socketObjects={},sockets=[],rtcMultiSession=this,participants={};!rtcMultiSession.fileBufferReader&&connection.session.data&&connection.enableFileSharing&&initFileBufferReader(connection,function(fbr){rtcMultiSession.fileBufferReader=fbr});var textReceiver=new TextReceiver(connection);connection.remove=function(userid){rtcMultiSession.requestsFrom&&rtcMultiSession.requestsFrom[userid]&&delete rtcMultiSession.requestsFrom[userid],connection.peers[userid]&&(connection.peers[userid].peer&&connection.peers[userid].peer.connection&&("closed"!=connection.peers[userid].peer.connection.signalingState&&connection.peers[userid].peer.connection.close(),connection.peers[userid].peer.connection=null),delete connection.peers[userid]),participants[userid]&&delete participants[userid];for(var stream in connection.streams)stream=connection.streams[stream],stream.userid==userid&&(onStreamEndedHandler(stream,connection),delete connection.streams[stream]);socketObjects[userid]&&delete socketObjects[userid]},connection.refresh=function(){connection.isInitiator&&connection.socket&&connection.socket.remove&&connection.socket.remove(),participants={};for(var i=0;i<connection.attachStreams.length;i++)connection.stopMediaStream(connection.attachStreams[i]);currentUserMediaRequest={streams:[],mutex:!1,queueRequests:[]},rtcMultiSession.isOwnerLeaving=!0,connection.isInitiator=!1,connection.isAcceptNewSession=!0,connection.attachMediaStreams=[],connection.sessionDescription=null,connection.sessionDescriptions={},connection.localStreamids=[],connection.preRecordedMedias={},connection.snapshots={},connection.numberOfConnectedUsers=0,connection.numberOfSessions=0,connection.attachStreams=[],connection.detachStreams=[],connection.fileQueue={},connection.channels={},connection.renegotiatedSessions={};for(var peer in connection.peers)peer!=connection.userid&&delete connection.peers[peer];for(var stream in connection.streams)-1==connection._skip.indexOf(stream)&&(onStreamEndedHandler(connection.streams[stream],connection),delete connection.streams[stream]);socketObjects={},sockets=[],participants={}},connection.reject=function(userid){isString(userid)||(userid=userid.userid),defaultSocket.send({rejectedRequestOf:userid}),connection.remove(userid)},rtcMultiSession.leaveHandler=function(e){return connection.leaveOnPageUnload?isNull(e.keyCode)?clearSession():void(116==e.keyCode&&clearSession()):void 0},listenEventHandler("beforeunload",rtcMultiSession.leaveHandler),listenEventHandler("keyup",rtcMultiSession.leaveHandler),rtcMultiSession.onLineOffLineHandler=function(){navigator.onLine?rtcMultiSession.isOffLine&&(rtcMultiSession.isOffLine=!navigator.onLine):rtcMultiSession.isOffLine=!0},listenEventHandler("load",rtcMultiSession.onLineOffLineHandler),listenEventHandler("online",rtcMultiSession.onLineOffLineHandler),listenEventHandler("offline",rtcMultiSession.onLineOffLineHandler);var defaultSocket=getDefaultSocketRef();rtcMultiSession.defaultSocket=defaultSocket,defaultSocket&&onSignalingReady&&setTimeout(onSignalingReady,2e3),connection.session.screen&&loadScreenFrame(),connection.getExternalIceServers&&loadIceFrame(function(iceServers){connection.iceServers=connection.iceServers.concat(iceServers)}),0==connection.log&&connection.skipLogs(),connection.onlog&&(log=warn=error=function(){var log={},index=0;Array.prototype.slice.call(arguments).forEach(function(argument){log[index++]=toStr(argument)}),toStr=function(str){return str},connection.onlog(log)}),this.initSession=function(args){function transmit(){defaultSocket&&getLength(participants)<connection.maxParticipantsAllowed&&!rtcMultiSession.isOwnerLeaving&&defaultSocket.send(connection.sessionDescription),connection.transmitRoomOnce||rtcMultiSession.isOwnerLeaving||setTimeout(transmit,connection.interval||3e3)}rtcMultiSession.isOwnerLeaving=!1,setDirections(),participants={},rtcMultiSession.isOwnerLeaving=!1,isNull(args.transmitRoomOnce)||(connection.transmitRoomOnce=args.transmitRoomOnce),args.dontTransmit||transmit()},this.joinSession=function(_config){function contactInitiator(){defaultSocket.send({messageFor:_config.userid,presenceState:rtcMultiSession.presenceState,_config:{userid:_config.userid,extra:_config.extra||{},sessionid:_config.sessionid,session:_config.session||!1}})}function checker(){"checking"==rtcMultiSession.presenceState&&(warn("Unable to reach initiator. Trying again..."),contactInitiator(),setTimeout(function(){"checking"==rtcMultiSession.presenceState&&(connection.onstatechange({userid:_config.userid,extra:_config.extra||{},name:"room-not-available",reason:"Initiator seems absent. Waiting for someone to open the room."}),connection.isAcceptNewSession=!0,setTimeout(checker,2e3))},2e3))}return defaultSocket?(_config=_config||{},participants={},rtcMultiSession.presenceState="checking",connection.onstatechange({userid:_config.userid,extra:_config.extra||{},name:"detecting-room-presence",reason:"Checking presence of the room."}),contactInitiator(),void setTimeout(checker,3e3)):setTimeout(function(){warn("Default-Socket is not yet initialized."),rtcMultiSession.joinSession(_config)},1e3)},connection.donotJoin=function(sessionid){rtcMultiSession.donotJoin=sessionid;var session=connection.sessionDescriptions[sessionid];session&&(defaultSocket.send({donotJoin:!0,messageFor:session.userid,sessionid:sessionid}),participants={},connection.isAcceptNewSession=!0,connection.sessionid=null)},this.send=function(message,_channel){if(message instanceof ArrayBuffer||message instanceof DataView||(message=str2ab({extra:connection.extra,userid:connection.userid,data:message})),_channel)return void("open"==_channel.readyState&&_channel.send(message));for(var dataChannel in connection.channels){var channel=connection.channels[dataChannel].channel;"open"==channel.readyState&&channel.send(message)}},this.leave=function(){clearSession()},this.addStream=function(e){function addStream(_peer){var socket=_peer.socket;if(!socket)return void warn(_peer,"doesn't has socket.");if(updateSocketForLocalStreams(socket),!_peer||!_peer.peer)throw"No peer to renegotiate.";var peer=_peer.peer;e.stream&&(peer.attachStreams||(peer.attachStreams=[]),peer.attachStreams.push(e.stream)),detachMediaStream(connection.detachStreams,peer.connection),e.stream&&(session.audio||session.video||session.screen)&&peer.addStream(e.stream),peer.recreateOffer(session,function(sdp,streaminfo){sendsdp({sdp:sdp,socket:socket,renegotiate:session,labels:connection.detachStreams,streaminfo:streaminfo}),connection.detachStreams=[]})}var session=e.renegotiate;if(connection.renegotiatedSessions[JSON.stringify(e.renegotiate)]||(connection.renegotiatedSessions[JSON.stringify(e.renegotiate)]={session:e.renegotiate,stream:e.stream}),e.socket)e.socket.userid!=connection.userid&&addStream(connection.peers[e.socket.userid]);else for(var peer in connection.peers)peer!=connection.userid&&addStream(connection.peers[peer])},connection.request=function(userid,extra){connection.captureUserMedia(function(){newPrivateSocket({channel:connection.userid,extra:extra||{},userid:userid}),defaultSocket.send({participant:!0,targetUser:userid})})},connection.accept=function(e){arguments.length>1&&isString(arguments[0])&&(e={},arguments[0]&&(e.userid=arguments[0]),arguments[1]&&(e.extra=arguments[1]),arguments[2]&&(e.channel=arguments[2])),connection.captureUserMedia(function(){_accept(e)})};var isRMSDeleted=!1;this.disconnect=function(){if(this.isOwnerLeaving=!0,!connection.keepStreamsOpened){for(var streamid in connection.localStreams)connection.localStreams[streamid].stop();connection.localStreams={},currentUserMediaRequest={streams:[],mutex:!1,queueRequests:[]}}connection.isInitiator&&defaultSocket.send({isDisconnectSockets:!0}),connection.refresh(),rtcMultiSession.defaultSocket=defaultSocket=null,isRMSDeleted=!0,connection.ondisconnected({userid:connection.userid,extra:connection.extra,peer:connection.peers[connection.userid],isSocketsDisconnected:!0}),connection.close(),window.removeEventListener("beforeunload",rtcMultiSession.leaveHandler),window.removeEventListener("keyup",rtcMultiSession.leaveHandler),delete this,log("Disconnected your sockets, peers, streams and everything except RTCMultiConnection object.")}}function convertToAudioStream(mediaStream){if(!mediaStream)throw"MediaStream is mandatory.";if(mediaStream.getVideoTracks&&!mediaStream.getVideoTracks().length)return mediaStream;var context=new AudioContext,mediaStreamSource=context.createMediaStreamSource(mediaStream),destination=context.createMediaStreamDestination();return mediaStreamSource.connect(destination),webAudioMediaStreamSources.push(mediaStreamSource),destination.stream}function getRandomString(){if(window.crypto&&crypto.getRandomValues&&-1==navigator.userAgent.indexOf("Safari")){for(var a=window.crypto.getRandomValues(new Uint32Array(3)),token="",i=0,l=a.length;l>i;i++)token+=a[i].toString(36);return token}return(Math.random()*(new Date).getTime()).toString(36).replace(/\./g,"")}function isData(session){return!session.audio&&!session.video&&!session.screen&&session.data}function isNull(obj){return"undefined"==typeof obj}function isString(obj){return"string"==typeof obj}function isEmpty(session){var length=0;for(var s in session)length++;return 0==length}function ab2str(buf){var result="";try{result=String.fromCharCode.apply(null,new Uint16Array(buf))}catch(e){}return result}function str2ab(str){isString(str)||(str=JSON.stringify(str));for(var buf=new ArrayBuffer(2*str.length),bufView=new Uint16Array(buf),i=0,strLen=str.length;strLen>i;i++)bufView[i]=str.charCodeAt(i);return buf}function swap(arr){for(var swapped=[],length=arr.length,i=0;length>i;i++)arr[i]&&arr[i]!==!0&&swapped.push(arr[i]);return swapped}function forEach(obj,callback){for(var item in obj)callback(obj[item],item)}function log(){console.log(arguments)}function error(){console.error(arguments)}function warn(){console.warn(arguments)}function toStr(obj){return JSON.stringify(obj,function(key,value){return value&&value.sdp?(log(value.sdp.type," ",value.sdp.sdp),""):value}," ")}function getLength(obj){var length=0;for(var o in obj)o&&length++;return length}function createMediaElement(stream,session){var mediaElement=document.createElement(stream.isAudio?"audio":"video");if(mediaElement.id=stream.streamid,isPluginRTC){var body=document.body||document.documentElement;return body.insertBefore(mediaElement,body.firstChild),setTimeout(function(){Plugin.attachMediaStream(mediaElement,stream)},1e3),Plugin.attachMediaStream(mediaElement,stream)}return mediaElement[isFirefox?"mozSrcObject":"src"]=isFirefox?stream:(window.URL||window.webkitURL).createObjectURL(stream),mediaElement.controls=!0,mediaElement.autoplay=!!session.remote,mediaElement.muted=session.remote?!1:!0,isFirefox&&mediaElement.addEventListener("ended",function(){stream.onended()},!1),mediaElement.play(),mediaElement}function onStreamEndedHandler(streamedObject,connection){(!streamedObject.mediaElement||streamedObject.mediaElement.parentNode)&&(onStreamEndedHandlerFiredFor[streamedObject.streamid]||(onStreamEndedHandlerFiredFor[streamedObject.streamid]=streamedObject,connection.onstreamended(streamedObject)))}function onLeaveHandler(event,connection){onLeaveHandlerFiredFor[event.userid]||(onLeaveHandlerFiredFor[event.userid]=event,connection.onleave(event))}function takeSnapshot(args){function _takeSnapshot(video){var canvas=document.createElement("canvas");canvas.width=video.videoWidth||video.clientWidth,canvas.height=video.videoHeight||video.clientHeight;var context=canvas.getContext("2d");context.drawImage(video,0,0,canvas.width,canvas.height),connection.snapshots[userid]=canvas.toDataURL("image/png"),args.callback&&args.callback(connection.snapshots[userid])}var userid=args.userid,connection=args.connection;if(args.mediaElement)return _takeSnapshot(args.mediaElement);for(var stream in connection.streams)stream=connection.streams[stream],stream.userid==userid&&stream.stream&&stream.stream.getVideoTracks&&stream.stream.getVideoTracks().length&&_takeSnapshot(stream.mediaElement)}function invokeMediaCaptured(connection){connection.onMediaCaptured&&(connection.onMediaCaptured(),delete connection.onMediaCaptured)}function merge(mergein,mergeto){if(mergein||(mergein={}),!mergeto)return mergein;for(var item in mergeto)mergein[item]=mergeto[item];return mergein}function loadScript(src,onload){var script=document.createElement("script");script.src=src,script.onload=function(){log("loaded resource:",src),onload&&onload()},document.documentElement.appendChild(script)}function capturePartOfScreen(args){var connection=args.connection,element=args.element;if(!window.html2canvas)return loadScript(connection.resources.html2canvas,function(){capturePartOfScreen(args)});if(isString(element)&&(element=document.querySelector(element),element||(element=document.getElementById(element))),!element)throw"HTML DOM Element is not accessible!";html2canvas(element,{onrendered:function(canvas){args.callback(canvas.toDataURL())}})}function initFileBufferReader(connection,callback){function _private(chunk){return chunk.userid=chunk.extra.userid,chunk}if(!window.FileBufferReader)return void loadScript(connection.resources.FileBufferReader,function(){initFileBufferReader(connection,callback)});var fileBufferReader=new FileBufferReader;fileBufferReader.onProgress=function(chunk){connection.onFileProgress(_private(chunk),chunk.uuid)},fileBufferReader.onBegin=function(file){connection.onFileStart(_private(file))},fileBufferReader.onEnd=function(file){connection.onFileEnd(_private(file))},callback(fileBufferReader)}function loadScreenFrame(skip){if(DetectRTC.screen.extensionid==ReservedExtensionID&&!loadedScreenFrame){if(!skip)return loadScreenFrame(!0);loadedScreenFrame=!0;var iframe=document.createElement("iframe");iframe.onload=function(){iframe.isLoaded=!0,log("Screen Capturing frame is loaded.")},iframe.src="https://www.webrtc-experiment.com/getSourceId/",iframe.style.display="none",(document.body||document.documentElement).appendChild(iframe),screenFrame={postMessage:function(){return iframe.isLoaded?void iframe.contentWindow.postMessage({captureSourceId:!0},"*"):void setTimeout(screenFrame.postMessage,100)}}}}function loadIceFrame(callback,skip){if(!loadedIceFrame){if(!skip)return loadIceFrame(callback,!0);loadedIceFrame=!0;var iframe=document.createElement("iframe");iframe.onload=function(){function iFrameLoaderCallback(event){event.data&&event.data.iceServers&&(callback(event.data.iceServers),window.removeEventListener("message",iFrameLoaderCallback))}iframe.isLoaded=!0,listenEventHandler("message",iFrameLoaderCallback),iframe.contentWindow.postMessage("get-ice-servers","*")},iframe.src="https://cdn.webrtc-experiment.com/getIceServers/",iframe.style.display="none",(document.body||document.documentElement).appendChild(iframe)}}function muteOrUnmute(e){var stream=e.stream,root=e.root,session=e.session||{},enabled=e.enabled;if(session.audio||session.video||(session=isString(session)?{audio:!0,video:!0}:merge(session,{audio:!0,video:!0})),session.type){if("remote"==session.type&&"remote"!=root.type)return;if("local"==session.type&&"local"!=root.type)return}if(log(enabled?"Muting":"UnMuting","session",toStr(session)),"local"==root.type&&session.audio&&stream.getAudioTracks){var audioTracks=stream.getAudioTracks()[0];audioTracks&&(audioTracks.enabled=!enabled)}if("local"==root.type&&(session.video||session.screen)&&stream.getVideoTracks){var videoTracks=stream.getVideoTracks()[0];videoTracks&&(videoTracks.enabled=!enabled)}if(root.sockets.forEach(function(socket){"local"==root.type&&socket.send({streamid:root.streamid,mute:!!enabled,unmute:!enabled,session:session}),"remote"==root.type&&socket.send({promptMuteUnmute:!0,streamid:root.streamid,mute:!!enabled,unmute:!enabled,session:session})}),"remote"!=root.type){var fakeObject=merge({},root);fakeObject.session=session,fakeObject.isAudio=!!fakeObject.session.audio&&!fakeObject.session.video,fakeObject.isVideo=!!fakeObject.session.video,fakeObject.isScreen=!!fakeObject.session.screen,enabled&&(stream.preMuted={audio:stream.getAudioTracks().length&&!stream.getAudioTracks()[0].enabled,video:stream.getVideoTracks().length&&!stream.getVideoTracks()[0].enabled},root.rtcMultiConnection.onmute(fakeObject)),enabled||(stream.preMuted={},root.rtcMultiConnection.onunmute(fakeObject))}}function initHark(args){if(!window.hark)return void loadScript(args.connection.resources.hark,function(){initHark(args)});var connection=args.connection,streamedObject=args.streamedObject,stream=args.stream,options={},speechEvents=hark(stream,options);speechEvents.on("speaking",function(){connection.onspeaking&&connection.onspeaking(streamedObject)}),speechEvents.on("stopped_speaking",function(){connection.onsilence&&connection.onsilence(streamedObject)}),speechEvents.on("volume_change",function(volume,threshold){connection.onvolumechange&&connection.onvolumechange(merge({volume:volume,threshold:threshold},streamedObject))})}function getUserMedia(options){function streaming(stream,returnBack,streamid){streamid||(streamid=getRandomString()),connection.localStreams[streamid]=stream;var video=options.video;video&&(video[isFirefox?"mozSrcObject":"src"]=isFirefox?stream:(window.URL||window.webkitURL).createObjectURL(stream),video.play()),options.onsuccess(stream,returnBack,idInstance,streamid),currentUserMediaRequest.streams[idInstance]={stream:stream,streamid:streamid},currentUserMediaRequest.mutex=!1,currentUserMediaRequest.queueRequests.length&&getUserMedia(currentUserMediaRequest.queueRequests.shift())}if(isPluginRTC)return Plugin.getUserMedia?Plugin.getUserMedia(options.constraints||{audio:!0,video:!0},options.onsuccess,options.onerror):void setTimeout(function(){getUserMedia(options)},1e3);if(currentUserMediaRequest.mutex===!0)return void currentUserMediaRequest.queueRequests.push(options);currentUserMediaRequest.mutex=!0;var connection=options.connection,mediaConstraints=options.mediaConstraints||{},videoConstraints="boolean"==typeof mediaConstraints.video?mediaConstraints.video:mediaConstraints.video||mediaConstraints,audioConstraints="boolean"==typeof mediaConstraints.audio?mediaConstraints.audio:mediaConstraints.audio||defaultConstraints,n=navigator,hints=options.constraints||{audio:defaultConstraints,video:defaultConstraints};hints.video&&hints.video.mozMediaSource&&(videoConstraints={}),1==hints.video&&(hints.video=defaultConstraints),1==hints.audio&&(hints.audio=defaultConstraints),"boolean"==typeof audioConstraints&&hints.audio&&(hints.audio=audioConstraints),"boolean"==typeof videoConstraints&&hints.video&&(hints.video=videoConstraints);var audioMandatoryConstraints=audioConstraints.mandatory;isEmpty(audioMandatoryConstraints)||(hints.audio.mandatory=merge(hints.audio.mandatory,audioMandatoryConstraints));var videoMandatoryConstraints=videoConstraints.mandatory;if(videoMandatoryConstraints){var mandatory={};if(videoMandatoryConstraints.minWidth&&(mandatory.minWidth=videoMandatoryConstraints.minWidth),videoMandatoryConstraints.minHeight&&(mandatory.minHeight=videoMandatoryConstraints.minHeight),videoMandatoryConstraints.maxWidth&&(mandatory.maxWidth=videoMandatoryConstraints.maxWidth),videoMandatoryConstraints.maxHeight&&(mandatory.maxHeight=videoMandatoryConstraints.maxHeight),videoMandatoryConstraints.minAspectRatio&&(mandatory.minAspectRatio=videoMandatoryConstraints.minAspectRatio),videoMandatoryConstraints.maxFrameRate&&(mandatory.maxFrameRate=videoMandatoryConstraints.maxFrameRate),videoMandatoryConstraints.minFrameRate&&(mandatory.minFrameRate=videoMandatoryConstraints.minFrameRate),mandatory.minWidth&&mandatory.minHeight){var allowed=["1920:1080","1280:720","960:720","640:360","640:480","320:240","320:180"];(-1==allowed.indexOf(mandatory.minWidth+":"+mandatory.minHeight)||-1==allowed.indexOf(mandatory.maxWidth+":"+mandatory.maxHeight))&&error('The min/max width/height constraints you passed "seems" NOT supported.',toStr(mandatory)),(mandatory.minWidth>mandatory.maxWidth||mandatory.minHeight>mandatory.maxHeight)&&error("Minimum value must not exceed maximum value.",toStr(mandatory)),mandatory.minWidth>=1280&&mandatory.minHeight>=720&&warn("Enjoy HD video! min/"+mandatory.minWidth+":"+mandatory.minHeight+", max/"+mandatory.maxWidth+":"+mandatory.maxHeight)}hints.video.mandatory=merge(hints.video.mandatory,mandatory)}videoMandatoryConstraints&&(hints.video.mandatory=merge(hints.video.mandatory,videoMandatoryConstraints)),videoConstraints.optional&&videoConstraints.optional instanceof Array&&videoConstraints.optional.length&&(hints.video.optional=hints.video.optional?hints.video.optional.concat(videoConstraints.optional):videoConstraints.optional),audioConstraints.optional&&audioConstraints.optional instanceof Array&&audioConstraints.optional.length&&(hints.audio.optional=hints.audio.optional?hints.audio.optional.concat(audioConstraints.optional):audioConstraints.optional),hints.video.mandatory&&!isEmpty(hints.video.mandatory)&&connection._mediaSources.video&&(hints.video.optional.forEach(function(video,index){video.sourceId==connection._mediaSources.video&&delete hints.video.optional[index]}),hints.video.optional=swap(hints.video.optional),hints.video.optional.push({sourceId:connection._mediaSources.video})),hints.audio.mandatory&&!isEmpty(hints.audio.mandatory)&&connection._mediaSources.audio&&(hints.audio.optional.forEach(function(audio,index){audio.sourceId==connection._mediaSources.audio&&delete hints.audio.optional[index]}),hints.audio.optional=swap(hints.audio.optional),hints.audio.optional.push({sourceId:connection._mediaSources.audio})),hints.video&&!hints.video.mozMediaSource&&hints.video.optional&&hints.video.mandatory&&!hints.video.optional.length&&isEmpty(hints.video.mandatory)&&(hints.video=!0),isMobileDevice&&(hints={audio:!!hints.audio,video:!!hints.video}),log("invoked getUserMedia with constraints:",toStr(hints));var idInstance=JSON.stringify(hints);currentUserMediaRequest.streams[idInstance]?streaming(currentUserMediaRequest.streams[idInstance].stream,!0,currentUserMediaRequest.streams[idInstance].streamid):(n.getMedia=n.webkitGetUserMedia||n.mozGetUserMedia,n.getMedia(hints,streaming,function(error){options.onerror(error,hints)}))}function setSdpConstraints(config){var sdpConstraints,sdpConstraints_mandatory={OfferToReceiveAudio:!!config.OfferToReceiveAudio,OfferToReceiveVideo:!!config.OfferToReceiveVideo};return sdpConstraints={mandatory:sdpConstraints_mandatory,optional:[{VoiceActivityDetection:!1}]},navigator.mozGetUserMedia&&firefoxVersion>34&&(sdpConstraints={OfferToReceiveAudio:!!config.OfferToReceiveAudio,OfferToReceiveVideo:!!config.OfferToReceiveVideo}),sdpConstraints}function PeerConnection(){return{create:function(type,options){merge(this,options);var self=this;return this.type=type,this.init(),this.attachMediaStreams(),isFirefox&&this.session.data?(this.session.data&&"offer"==type&&this.createDataChannel(),this.getLocalDescription(type),this.session.data&&"answer"==type&&this.createDataChannel()):self.getLocalDescription(type),this},getLocalDescription:function(createType){function createDescription(){self.connection["offer"==createType?"createOffer":"createAnswer"](function(sessionDescription){sessionDescription.sdp=self.serializeSdp(sessionDescription.sdp,createType),self.connection.setLocalDescription(sessionDescription),self.trickleIce&&self.onSessionDescription(sessionDescription,self.streaminfo),"offer"==sessionDescription.type&&log("offer sdp",sessionDescription.sdp),self.prevCreateType=createType},self.onSdpError,self.constraints)}log("(getLocalDescription) peer createType is",createType),this.session.inactive&&isNull(this.rtcMultiConnection.waitUntilRemoteStreamStartsFlowing)&&(this.rtcMultiConnection.waitUntilRemoteStreamStartsFlowing=!1);var self=this;"answer"==createType?this.setRemoteDescription(this.offerDescription,createDescription):createDescription()},serializeSdp:function(sdp,createType){if(sdp=this.processSdp(sdp),isFirefox)return sdp;if(this.session.inactive&&!this.holdMLine&&(this.hold=!0,(this.session.screen||this.session.video)&&this.session.audio?this.holdMLine="both":this.session.screen||this.session.video?this.holdMLine="video":this.session.audio&&(this.holdMLine="audio")),sdp=this.setBandwidth(sdp),"both"==this.holdMLine){if(this.hold)this.prevSDP=sdp,sdp=sdp.replace(/a=sendonly|a=recvonly|a=sendrecv/g,"a=inactive");else if(this.prevSDP&&!this.session.inactive&&(sdp=this.prevSDP,35>=chromeVersion))return sdp}else if("audio"==this.holdMLine||"video"==this.holdMLine){sdp=sdp.split("m=");var audio="",video="";sdp[1]&&0==sdp[1].indexOf("audio")&&(audio="m="+sdp[1]),sdp[2]&&0==sdp[2].indexOf("audio")&&(audio="m="+sdp[2]),sdp[1]&&0==sdp[1].indexOf("video")&&(video="m="+sdp[1]),sdp[2]&&0==sdp[2].indexOf("video")&&(video="m="+sdp[2]),"audio"==this.holdMLine&&(this.hold?(this.prevSDP=sdp[0]+audio+video,sdp=sdp[0]+audio.replace(/a=sendonly|a=recvonly|a=sendrecv/g,"a=inactive")+video):this.prevSDP&&(sdp=this.prevSDP)),"video"==this.holdMLine&&(this.hold?(this.prevSDP=sdp[0]+audio+video,sdp=sdp[0]+audio+video.replace(/a=sendonly|a=recvonly|a=sendrecv/g,"a=inactive")):this.prevSDP&&(sdp=this.prevSDP))}return!this.hold&&this.session.inactive&&(sdp="offer"==createType?sdp.replace(/a=setup:passive|a=setup:active|a=setup:holdconn/g,"a=setup:actpass"):sdp.replace(/a=setup:actpass|a=setup:passive|a=setup:holdconn/g,"a=setup:active"),sdp=sdp.replace(/a=inactive/g,"a=sendrecv")),sdp},init:function(){function returnSDP(){return self.returnedSDP?void(self.returnedSDP=!1):(self.returnedSDP=!0,void self.onSessionDescription(self.connection.localDescription,self.streaminfo))}this.setConstraints(),this.connection=new RTCPeerConnection(this.iceServers,this.optionalArgument),this.session.data&&(log("invoked: createDataChannel"),this.createDataChannel()),this.connection.onicecandidate=function(event){return event.candidate?void(self.trickleIce&&self.onicecandidate(event.candidate)):void(self.trickleIce||returnSDP())},this.connection.onaddstream=function(e){log("onaddstream",isPluginRTC?e.stream:toStr(e.stream)),self.onaddstream(e.stream,self.session)},this.connection.onremovestream=function(e){self.onremovestream(e.stream)},this.connection.onsignalingstatechange=function(){self.connection&&self.oniceconnectionstatechange({iceConnectionState:self.connection.iceConnectionState,iceGatheringState:self.connection.iceGatheringState,signalingState:self.connection.signalingState})},this.connection.oniceconnectionstatechange=function(){self.connection&&(self.oniceconnectionstatechange({iceConnectionState:self.connection.iceConnectionState,iceGatheringState:self.connection.iceGatheringState,signalingState:self.connection.signalingState}),self.trickleIce||"complete"==self.connection.iceGatheringState&&(log("iceGatheringState",self.connection.iceGatheringState),returnSDP()))};var self=this},setBandwidth:function(sdp){if(isMobileDevice||isFirefox||!this.bandwidth)return sdp;var bandwidth=this.bandwidth;return this.session.screen&&(bandwidth.screen?bandwidth.screen<300&&warn("It seems that you are using wrong bandwidth value for screen. Screen sharing is expected to fail."):warn("It seems that you are not using bandwidth for screen. Screen sharing is expected to fail.")),bandwidth.screen&&this.session.screen&&(sdp=sdp.replace(/b=AS([^\r\n]+\r\n)/g,""),sdp=sdp.replace(/a=mid:video\r\n/g,"a=mid:video\r\nb=AS:"+bandwidth.screen+"\r\n")),(bandwidth.audio||bandwidth.video||bandwidth.data)&&(sdp=sdp.replace(/b=AS([^\r\n]+\r\n)/g,"")),bandwidth.audio&&(sdp=sdp.replace(/a=mid:audio\r\n/g,"a=mid:audio\r\nb=AS:"+bandwidth.audio+"\r\n")),bandwidth.video&&(sdp=sdp.replace(/a=mid:video\r\n/g,"a=mid:video\r\nb=AS:"+(this.session.screen?bandwidth.screen:bandwidth.video)+"\r\n")),bandwidth.data&&!this.preferSCTP&&(sdp=sdp.replace(/a=mid:data\r\n/g,"a=mid:data\r\nb=AS:"+bandwidth.data+"\r\n")),sdp},setConstraints:function(){var sdpConstraints=setSdpConstraints({OfferToReceiveAudio:!!this.session.audio,OfferToReceiveVideo:!!this.session.video||!!this.session.screen});if(this.sdpConstraints.mandatory&&(sdpConstraints=setSdpConstraints(this.sdpConstraints.mandatory)),this.constraints=sdpConstraints,this.constraints&&log("sdp-constraints",toStr(this.constraints)),this.optionalArgument={optional:this.optionalArgument.optional||[],mandatory:this.optionalArgument.mandatory||{}},this.preferSCTP||this.optionalArgument.optional.push({RtpDataChannels:!0}),log("optional-argument",toStr(this.optionalArgument)),isNull(this.iceServers))this.iceServers=null;else{var iceCandidates=this.rtcMultiConnection.candidates,stun=iceCandidates.stun,turn=iceCandidates.turn,host=iceCandidates.host;isNull(iceCandidates.reflexive)||(stun=iceCandidates.reflexive),isNull(iceCandidates.relay)||(turn=iceCandidates.relay),host||stun||!turn?host||stun||turn||(this.rtcConfiguration.iceTransports="none"):this.rtcConfiguration.iceTransports="relay",this.iceServers={iceServers:this.iceServers,iceTransports:this.rtcConfiguration.iceTransports}}log("rtc-configuration",toStr(this.iceServers))},onSdpError:function(e){var message=toStr(e);message&&-1!=message.indexOf("RTP/SAVPF Expects at least 4 fields")&&(message="It seems that you are trying to interop RTP-datachannels with SCTP. It is not supported!"),error("onSdpError:",message)},onSdpSuccess:function(){log("sdp success")},onMediaError:function(err){error(toStr(err))},setRemoteDescription:function(sessionDescription,onSdpSuccess){if(!sessionDescription)throw"Remote session description should NOT be NULL.";if(this.connection){log("setting remote description",sessionDescription.type,sessionDescription.sdp);var self=this;this.connection.setRemoteDescription(new RTCSessionDescription(sessionDescription),onSdpSuccess||this.onSdpSuccess,function(error){
-1==error.search(/STATE_SENTINITIATE|STATE_INPROGRESS/gi)&&self.onSdpError(error)})}},addIceCandidate:function(candidate){function onAddIceCandidate(iceCandidate){self.connection.addIceCandidate(iceCandidate,function(){log("added:",candidate.sdpMid,candidate.candidate)},function(){error("onIceFailure",arguments,candidate.candidate)})}var self=this;isPluginRTC?RTCIceCandidate(candidate,function(iceCandidate){onAddIceCandidate(iceCandidate)}):onAddIceCandidate(new RTCIceCandidate(candidate))},createDataChannel:function(channelIdentifier){if(!this.channels||!this.channels.length){var self=this;this.channels||(this.channels=[]);var dataChannelDict={};this.dataChannelDict&&(dataChannelDict=this.dataChannelDict),isChrome&&!this.preferSCTP&&(dataChannelDict.reliable=!1),log("dataChannelDict",toStr(dataChannelDict)),("answer"==this.type||isFirefox)&&(this.connection.ondatachannel=function(event){self.setChannelEvents(event.channel)}),(isChrome&&"offer"==this.type||isFirefox)&&this.setChannelEvents(this.connection.createDataChannel(channelIdentifier||"channel",dataChannelDict))}},setChannelEvents:function(channel){var self=this;channel.binaryType="arraybuffer",this.dataChannelDict.binaryType&&(channel.binaryType=this.dataChannelDict.binaryType),channel.onmessage=function(event){self.onmessage(event.data)};var numberOfTimes=0;channel.onopen=function(){channel.push=channel.send,channel.send=function(data){if("disconnected"!=self.connection.iceConnectionState&&-1==channel.readyState.search(/closing|closed/g)&&-1!=channel.readyState.search(/connecting|open/g)){if("connecting"==channel.readyState)return numberOfTimes++,setTimeout(function(){if(!(20>numberOfTimes))throw"Number of times exceeded to wait for WebRTC data connection to be opened.";channel.send(data)},1e3);try{channel.push(data)}catch(e){if(numberOfTimes++,warn("Data transmission failed. Re-transmitting..",numberOfTimes,toStr(e)),numberOfTimes>=20)throw"Number of times exceeded to resend data packets over WebRTC data channels.";setTimeout(function(){channel.send(data)},100)}}},self.onopen(channel)},channel.onerror=function(event){self.onerror(event)},channel.onclose=function(event){self.onclose(event)},this.channels.push(channel)},addStream:function(stream){stream.streamid||isIE||(stream.streamid=getRandomString()),log("attaching stream:",stream.streamid,isPluginRTC?stream:toStr(stream)),this.connection.addStream(stream),this.sendStreamId(stream),this.getStreamInfo()},attachMediaStreams:function(){for(var streams=this.attachStreams,i=0;i<streams.length;i++)this.addStream(streams[i])},getStreamInfo:function(){this.streaminfo="";for(var streams=this.connection.getLocalStreams(),i=0;i<streams.length;i++)0==i?this.streaminfo=JSON.stringify({streamid:streams[i].streamid||"",isScreen:!!streams[i].isScreen,isAudio:!!streams[i].isAudio,isVideo:!!streams[i].isVideo,preMuted:streams[i].preMuted||{}}):this.streaminfo+="----"+JSON.stringify({streamid:streams[i].streamid||"",isScreen:!!streams[i].isScreen,isAudio:!!streams[i].isAudio,isVideo:!!streams[i].isVideo,preMuted:streams[i].preMuted||{}})},recreateOffer:function(renegotiate,callback){log("recreating offer"),this.type="offer",this.session=renegotiate,this.onSessionDescription=callback,this.getStreamInfo(),this.session.data&&this.createDataChannel(),this.getLocalDescription("offer")},recreateAnswer:function(sdp,session,callback){log("recreating answer"),this.type="answer",this.session=session,this.onSessionDescription=callback,this.offerDescription=sdp,this.getStreamInfo(),this.session.data&&this.createDataChannel(),this.getLocalDescription("answer")}}}function invokeSaveAsDialog(fileUrl,fileName){var hyperlink=document.createElement("a");hyperlink.href=fileUrl,hyperlink.target="_blank",hyperlink.download=fileName||fileUrl,navigator.mozGetUserMedia&&(hyperlink.onclick=function(){(document.body||document.documentElement).removeChild(hyperlink)},(document.body||document.documentElement).appendChild(hyperlink));var evt=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!0});hyperlink.dispatchEvent(evt),navigator.mozGetUserMedia||URL.revokeObjectURL(hyperlink.href)}function TextReceiver(connection){function receive(data,userid,extra){var uuid=data.uuid;if(content[uuid]||(content[uuid]=[]),content[uuid].push(data.message),data.last){var message=content[uuid].join("");data.isobject&&(message=JSON.parse(message));var receivingTime=(new Date).getTime(),latency=receivingTime-data.sendingTime,e={data:message,userid:userid,extra:extra,latency:latency};message.preRecordedMediaChunk?(connection.preRecordedMedias[message.streamerid]||connection.shareMediaFile(null,null,message.streamerid),connection.preRecordedMedias[message.streamerid].onData(message.chunk)):connection.autoTranslateText?(e.original=e.data,connection.Translator.TranslateText(e.data,function(translatedText){e.data=translatedText,connection.onmessage(e)})):message.isPartOfScreen?connection.onpartofscreen(message):connection.onmessage(e),delete content[uuid]}}var content={};return{receive:receive}}function listenEventHandler(eventName,eventHandler){window.removeEventListener(eventName,eventHandler),window.addEventListener(eventName,eventHandler,!1)}function setDefaults(connection){function updateLabel(progress,label){if(-1!=progress.position){var position=+progress.position.toFixed(2).split(".")[1]||100;label.innerHTML=position+"%"}}connection.userid=getRandomString(),connection.session={audio:!0,video:!0},connection.maxParticipantsAllowed=256,connection.direction="many-to-many",connection.mediaConstraints={mandatory:{},optional:[],audio:{mandatory:{},optional:[]},video:{mandatory:{},optional:[]}},connection.candidates={host:!0,stun:!0,turn:!0},connection.sdpConstraints={},connection.sdpConstraints.mandatory={OfferToReceiveAudio:!0,OfferToReceiveVideo:!0},connection.privileges={canStopRemoteStream:!1,canMuteRemoteStream:!1},connection.iceProtocols={tcp:!0,udp:!0},connection.preferSCTP=isFirefox||chromeVersion>=32?!0:!1,connection.chunkInterval=isFirefox||chromeVersion>=32?100:500,connection.chunkSize=isFirefox||chromeVersion>=32?13e3:1e3,connection.fakeDataChannels=!1,connection.waitUntilRemoteStreamStartsFlowing=null,connection.leaveOnPageUnload=!0,connection.getExternalIceServers=isChrome,connection.UA={isFirefox:isFirefox,isChrome:isChrome,isMobileDevice:isMobileDevice,version:isChrome?chromeVersion:firefoxVersion,isNodeWebkit:isNodeWebkit,isSafari:isSafari,isIE:isIE,isOpera:isOpera},connection.fileQueue={},connection.renegotiatedSessions={},connection.channels={},connection.extra={},connection.bandwidth={screen:300},connection.caniuse={RTCPeerConnection:DetectRTC.isWebRTCSupported,getUserMedia:!!navigator.webkitGetUserMedia||!!navigator.mozGetUserMedia,AudioContext:DetectRTC.isAudioContextSupported,ScreenSharing:DetectRTC.isScreenCapturingSupported,RtpDataChannels:DetectRTC.isRtpDataChannelsSupported,SctpDataChannels:DetectRTC.isSctpDataChannelsSupported},connection.snapshots={},connection._mediaSources={},connection.devices={},connection.language="en",connection.autoTranslateText=!1,connection.googKey="AIzaSyCgB5hmFY74WYB-EoWkhr9cAGr6TiTHrEE",connection.localStreamids=[],connection.localStreams={},connection.preRecordedMedias={},connection.attachStreams=[],connection.detachStreams=[],connection.optionalArgument={optional:[{DtlsSrtpKeyAgreement:!0},{googImprovedWifiBwe:!0},{googScreencastMinBitrate:300}],mandatory:{}},connection.dataChannelDict={},connection.dontAttachStream=!1,connection.dontCaptureUserMedia=!1,connection.preventSSLAutoAllowed=!1,connection.autoReDialOnFailure=!0,connection.isInitiator=!1,connection.DetectRTC=DetectRTC,connection.trickleIce=!0,connection.sessionDescriptions={},connection.sessionDescription=null,connection.resources={RecordRTC:"https://cdn.webrtc-experiment.com/RecordRTC.js",PreRecordedMediaStreamer:"https://cdn.webrtc-experiment.com/PreRecordedMediaStreamer.js",customGetUserMediaBar:"https://cdn.webrtc-experiment.com/navigator.customGetUserMediaBar.js",html2canvas:"https://cdn.webrtc-experiment.com/screenshot.js",hark:"https://cdn.webrtc-experiment.com/hark.js",firebase:"https://cdn.webrtc-experiment.com/firebase.js",firebaseio:"https://webrtc-experiment.firebaseIO.com/",muted:"https://cdn.webrtc-experiment.com/images/muted.png",getConnectionStats:"https://cdn.webrtc-experiment.com/getConnectionStats.js",FileBufferReader:"https://cdn.webrtc-experiment.com/FileBufferReader.js"},connection.body=document.body||document.documentElement,connection.peers={},connection.firebase="chat",connection.numberOfSessions=0,connection.numberOfConnectedUsers=0,connection.enableFileSharing=!0,connection.autoSaveToDisk=!1,connection.processSdp=function(sdp){return sdp},connection.onmessage=function(e){log("onmessage",toStr(e))},connection.onopen=function(e){log("Data connection is opened between you and",e.userid)},connection.onerror=function(e){error(onerror,toStr(e))},connection.onclose=function(e){warn("onclose",toStr(e)),connection.streams.remove({userid:e.userid})};var progressHelper={};connection.onFileStart=function(file){var div=document.createElement("div");div.title=file.name,div.innerHTML="<label>0%</label> <progress></progress>",connection.body.insertBefore(div,connection.body.firstChild),progressHelper[file.uuid]={div:div,progress:div.querySelector("progress"),label:div.querySelector("label")},progressHelper[file.uuid].progress.max=file.maxChunks},connection.onFileProgress=function(chunk){var helper=progressHelper[chunk.uuid];helper&&(helper.progress.value=chunk.currentPosition||chunk.maxChunks||helper.progress.max,updateLabel(helper.progress,helper.label))},connection.onFileEnd=function(file){progressHelper[file.uuid]&&(progressHelper[file.uuid].div.innerHTML='<a href="'+file.url+'" target="_blank" download="'+file.name+'">'+file.name+"</a>"),(connection.onFileSent||connection.onFileReceived)&&(connection.onFileSent&&connection.onFileSent(file,file.uuid),connection.onFileReceived&&connection.onFileReceived(file.name,file))},connection.onstream=function(e){connection.body.insertBefore(e.mediaElement,connection.body.firstChild)},connection.onstreamended=function(e){if(log("onStreamEndedHandler:",e),!e.mediaElement)return warn("Event.mediaElement is undefined",e);if(!e.mediaElement.parentNode){if(e.mediaElement=document.getElementById(e.streamid),!e.mediaElement)return warn("Event.mediaElement is undefined",e);if(!e.mediaElement.parentNode)return warn("Event.mediElement.parentNode is null.",e)}e.mediaElement.parentNode.removeChild(e.mediaElement)},connection.onSessionClosed=function(session){session.isEjected?warn(session.userid,"ejected you."):warn("Session has been closed.",session)},connection.onmute=function(e){e.isVideo&&e.mediaElement&&(e.mediaElement.pause(),e.mediaElement.setAttribute("poster",e.snapshot||connection.resources.muted)),e.isAudio&&e.mediaElement&&(e.mediaElement.muted=!0)},connection.onunmute=function(e){e.isVideo&&e.mediaElement&&(e.mediaElement.play(),e.mediaElement.removeAttribute("poster")),e.isAudio&&e.mediaElement&&(e.mediaElement.muted=!1)},connection.onleave=function(e){log("onleave",toStr(e))},connection.token=getRandomString,connection.peers[connection.userid]={drop:function(){connection.drop()},renegotiate:function(){},addStream:function(){},hold:function(){},unhold:function(){},changeBandwidth:function(){},sharePartOfScreen:function(){}},connection._skip=["stop","mute","unmute","_private","_selectStreams","selectFirst","selectAll","remove"],connection.streams={mute:function(session){this._private(session,!0)},unmute:function(session){this._private(session,!1)},_private:function(session,enabled){function _muteOrUnMute(stream,session,isMute){session.local&&"local"!=stream.type||session.remote&&"remote"!=stream.type||!(session.isScreen&&!stream.isScreen||session.isAudio&&!stream.isAudio||session.isVideo&&!stream.isVideo||(isMute?!stream.mute(session):!stream.unmute(session)))}if(!session||isString(session))for(var stream in this)-1==connection._skip.indexOf(stream)&&this[stream]._private(session,enabled);else for(var stream in this)-1==connection._skip.indexOf(stream)&&_muteOrUnMute(this[stream],session,enabled)},stop:function(type){function _stopStream(_stream,config){config.userid&&_stream.userid!=config.userid||config.local&&"local"!=_stream.type||config.remote&&"remote"!=_stream.type||(config.screen&&_stream.isScreen&&_stream.stop(),config.audio&&_stream.isAudio&&_stream.stop(),config.video&&_stream.isVideo&&_stream.stop(),config.audio||config.video||config.screen||_stream.stop())}var _stream;for(var stream in this)if(-1==connection._skip.indexOf(stream))if(_stream=this[stream],type)if(isString(type)){var config={};config[type]=!0,_stopStream(_stream,config)}else _stopStream(_stream,type);else _stream.stop()},remove:function(type){function _stopAndRemoveStream(_stream,config){config.userid&&_stream.userid!=config.userid||config.local&&"local"!=_stream.type||config.remote&&"remote"!=_stream.type||(config.screen&&_stream.isScreen&&endStream(_stream),config.audio&&_stream.isAudio&&endStream(_stream),config.video&&_stream.isVideo&&endStream(_stream),config.audio||config.video||config.screen||endStream(_stream))}function endStream(_stream){onStreamEndedHandler(_stream,connection),delete connection.streams[_stream.streamid]}var _stream;for(var stream in this)if(-1==connection._skip.indexOf(stream))if(_stream=this[stream],type)if(isString(type)){var config={};config[type]=!0,_stopAndRemoveStream(_stream,config)}else _stopAndRemoveStream(_stream,type);else _stopAndRemoveStream(_stream,{local:!0,remote:!0})},selectFirst:function(args){return this._selectStreams(args,!1)},selectAll:function(args){return this._selectStreams(args,!0)},_selectStreams:function(args,all){if(!args||isString(args)||isEmpty(args))throw"Invalid arguments.";isNull(args.local)&&isNull(args.remote)&&isNull(args.userid)&&(args.local=args.remote=!0),args.isAudio||args.isVideo||args.isScreen||(args.isAudio=args.isVideo=args.isScreen=!0);var selectedStreams=[];for(var stream in this)-1==connection._skip.indexOf(stream)&&(stream=this[stream])&&(args.local&&"local"==stream.type||args.remote&&"remote"==stream.type||args.userid&&stream.userid==args.userid)&&(args.isVideo&&stream.isVideo&&selectedStreams.push(stream),args.isAudio&&stream.isAudio&&selectedStreams.push(stream),args.isScreen&&stream.isScreen&&selectedStreams.push(stream));return all?selectedStreams:selectedStreams[0]}};var iceServers=[];iceServers.push({url:"stun:stun.l.google.com:19302"}),iceServers.push({url:"stun:stun.anyfirewall.com:3478"}),iceServers.push({url:"turn:turn.bistri.com:80",credential:"homeo",username:"homeo"}),iceServers.push({url:"turn:turn.anyfirewall.com:443?transport=tcp",credential:"webrtc",username:"webrtc"}),connection.iceServers=iceServers,connection.rtcConfiguration={iceServers:null,iceTransports:"all",peerIdentity:!1},connection.media={min:function(width,height){connection.mediaConstraints.video&&(connection.mediaConstraints.video.mandatory||(connection.mediaConstraints.video.mandatory={}),connection.mediaConstraints.video.mandatory.minWidth=width,connection.mediaConstraints.video.mandatory.minHeight=height)},max:function(width,height){connection.mediaConstraints.video&&(connection.mediaConstraints.video.mandatory||(connection.mediaConstraints.video.mandatory={}),connection.mediaConstraints.video.mandatory.maxWidth=width,connection.mediaConstraints.video.mandatory.maxHeight=height)}},connection._getStream=function(event){function muteOrUnmuteLocally(session,isPause,mediaElement){if(mediaElement){var lastPauseState=mediaElement.onpause,lastPlayState=mediaElement.onplay;mediaElement.onpause=mediaElement.onplay=function(){},isPause?mediaElement.pause():mediaElement.play(),mediaElement.onpause=lastPauseState,mediaElement.onplay=lastPlayState}}var resultingObject=merge({sockets:event.socket?[event.socket]:[]},event);return resultingObject.stop=function(){var self=this;if(self.sockets.forEach(function(socket){"local"==self.type&&socket.send({streamid:self.streamid,stopped:!0}),"remote"==self.type&&socket.send({promptStreamStop:!0,streamid:self.streamid})}),"remote"!=self.type){var stream=self.stream;stream&&self.rtcMultiConnection.stopMediaStream(stream)}},resultingObject.mute=function(session){this.muted=!0,this._private(session,!0)},resultingObject.unmute=function(session){this.muted=!1,this._private(session,!1)},resultingObject._private=function(session,enabled){return session&&!isNull(session.sync)&&0==session.sync?void muteOrUnmuteLocally(session,enabled,this.mediaElement):void muteOrUnmute({root:this,session:session,enabled:enabled,stream:this.stream})},resultingObject.startRecording=function(session){var self=this;return session||(session={audio:!0,video:!0}),isString(session)&&(session={audio:"audio"==session,video:"video"==session}),window.RecordRTC?(log("started recording session",session),self.videoRecorder=self.audioRecorder=null,isFirefox?session.video?self.videoRecorder=RecordRTC(self.stream,{type:"video"}):session.audio&&(self.audioRecorder=RecordRTC(self.stream,{type:"audio"})):isChrome&&(session.video&&(self.videoRecorder=RecordRTC(self.stream,{type:"video"})),session.audio&&(self.audioRecorder=RecordRTC(self.stream,{type:"audio"}))),self.audioRecorder&&self.audioRecorder.startRecording(),void(self.videoRecorder&&self.videoRecorder.startRecording())):loadScript(self.rtcMultiConnection.resources.RecordRTC,function(){self.startRecording(session)})},resultingObject.stopRecording=function(callback,session){session||(session={audio:!0,video:!0}),isString(session)&&(session={audio:"audio"==session,video:"video"==session}),log("stopped recording session",session);var self=this;session.audio&&self.audioRecorder?self.audioRecorder.stopRecording(function(){session.video&&self.videoRecorder?self.videoRecorder.stopRecording(function(){callback({audio:self.audioRecorder.getBlob(),video:self.videoRecorder.getBlob()})}):callback({audio:self.audioRecorder.getBlob()})}):session.video&&self.videoRecorder&&self.videoRecorder.stopRecording(function(){callback({video:self.videoRecorder.getBlob()})})},resultingObject.takeSnapshot=function(callback){takeSnapshot({mediaElement:this.mediaElement,userid:this.userid,connection:connection,callback:callback})},resultingObject.streamObject=resultingObject,resultingObject},connection.set=function(properties){for(var property in properties)this[property]=properties[property];return this},connection.onMediaError=function(event){error("name",event.name),error("constraintName",toStr(event.constraintName)),error("message",event.message),error("original session",event.session)},connection.takeSnapshot=function(userid,callback){takeSnapshot({userid:userid,connection:connection,callback:callback})},connection.saveToDisk=function(blob,fileName){blob.size&&blob.type?FileSaver.SaveToDisk(URL.createObjectURL(blob),fileName||blob.name||blob.type.replace("/","-")+blob.type.split("/")[1]):FileSaver.SaveToDisk(blob,fileName)},connection.selectDevices=function(device1,device2){function select(device){device&&(connection._mediaSources[device.kind]=device.id)}device1&&select(this.devices[device1]),device2&&select(this.devices[device2])},connection.getDevices=function(callback){return DetectRTC.MediaDevices.length?(DetectRTC.MediaDevices.forEach(function(device){connection.devices[device.deviceId]=device}),void(callback&&callback(connection.devices))):setTimeout(function(){connection.getDevices(callback)},1e3)},connection.getMediaDevices=connection.enumerateDevices=function(callback){if(!callback)throw"callback is mandatory.";connection.getDevices(function(){callback(connection.DetectRTC.MediaDevices)})},connection.onCustomMessage=function(message){log("Custom message",message)},connection.ondrop=function(droppedBy){log("Media connection is dropped by "+droppedBy)},connection.drop=function(config){config=config||{},connection.attachStreams=[];for(var stream in connection.streams)-1==connection._skip.indexOf(stream)&&(stream=connection.streams[stream],"local"==stream.type?(connection.detachStreams.push(stream.streamid),onStreamEndedHandler(stream,connection)):onStreamEndedHandler(stream,connection));connection.sendCustomMessage({drop:!0,dontRenegotiate:isNull(config.renegotiate)?!0:config.renegotiate})},connection.Translator={TranslateText:function(text,callback){var newScript=document.createElement("script");newScript.type="text/javascript";var sourceText=encodeURIComponent(text),randomNumber="method"+connection.token();window[randomNumber]=function(response){response.data&&response.data.translations[0]&&callback&&callback(response.data.translations[0].translatedText),response.error&&"Daily Limit Exceeded"==response.error.message&&(warn('Text translation failed. Error message: "Daily Limit Exceeded."'),callback(text))};var source="https://www.googleapis.com/language/translate/v2?key="+connection.googKey+"&target="+(connection.language||"en-US")+"&callback=window."+randomNumber+"&q="+sourceText;newScript.src=source,document.getElementsByTagName("head")[0].appendChild(newScript)}},connection.setDefaultEventsForMediaElement=function(mediaElement,streamid){mediaElement.onpause=function(){connection.streams[streamid]&&!connection.streams[streamid].muted&&connection.streams[streamid].mute()},mediaElement.onplay=function(){connection.streams[streamid]&&connection.streams[streamid].muted&&connection.streams[streamid].unmute()};var volumeChangeEventFired=!1;mediaElement.onvolumechange=function(){volumeChangeEventFired||(volumeChangeEventFired=!0,connection.streams[streamid]&&setTimeout(function(){var root=connection.streams[streamid];connection.streams[streamid].sockets.forEach(function(socket){socket.send({streamid:root.streamid,isVolumeChanged:!0,volume:mediaElement.volume})}),volumeChangeEventFired=!1},2e3))}},connection.onMediaFile=function(e){log("onMediaFile",e),connection.body.appendChild(e.mediaElement)},connection.shareMediaFile=function(file,video,streamerid){return streamerid=streamerid||connection.token(),PreRecordedMediaStreamer?PreRecordedMediaStreamer.shareMediaFile({file:file,video:video,streamerid:streamerid,connection:connection}):(loadScript(connection.resources.PreRecordedMediaStreamer,function(){connection.shareMediaFile(file,video,streamerid)}),streamerid)},connection.onpartofscreen=function(e){var image=document.createElement("img");image.src=e.screenshot,connection.body.appendChild(image)},connection.skipLogs=function(){log=error=warn=function(){}},connection.hold=function(mLine){for(var peer in connection.peers)connection.peers[peer].hold(mLine)},connection.onhold=function(track){log("onhold",track),"audio"!=track.kind&&(track.mediaElement.pause(),track.mediaElement.setAttribute("poster",track.screenshot||connection.resources.muted)),"audio"==track.kind&&(track.mediaElement.muted=!0)},connection.unhold=function(mLine){for(var peer in connection.peers)connection.peers[peer].unhold(mLine)},connection.onunhold=function(track){log("onunhold",track),"audio"!=track.kind&&(track.mediaElement.play(),track.mediaElement.removeAttribute("poster")),"audio"!=track.kind&&(track.mediaElement.muted=!1)},connection.sharePartOfScreen=function(args){function partOfScreenCapturer(){(!connection.partOfScreen||connection.partOfScreen.sharing)&&capturePartOfScreen({element:args.element,connection:connection,callback:function(screenshot){if(screenshot!=lastScreenshot){lastScreenshot=screenshot;for(var channel in connection.channels)connection.channels[channel].send({screenshot:screenshot,isPartOfScreen:!0})}!args.once&&setTimeout(partOfScreenCapturer,args.interval||200)}})}var lastScreenshot="";partOfScreenCapturer(),connection.partOfScreen=merge({sharing:!0},args)},connection.pausePartOfScreenSharing=function(){for(var peer in connection.peers)connection.peers[peer].pausePartOfScreenSharing=!0;connection.partOfScreen&&(connection.partOfScreen.sharing=!1)},connection.resumePartOfScreenSharing=function(){for(var peer in connection.peers)connection.peers[peer].pausePartOfScreenSharing=!1;connection.partOfScreen&&(connection.partOfScreen.sharing=!0)},connection.stopPartOfScreenSharing=function(){for(var peer in connection.peers)connection.peers[peer].stopPartOfScreenSharing=!0;connection.partOfScreen&&(connection.partOfScreen.sharing=!1)},connection.takeScreenshot=function(element,callback){if(!element||!callback)throw"Invalid number of arguments.";if(!window.html2canvas)return loadScript(connection.resources.html2canvas,function(){connection.takeScreenshot(element)});if(isString(element)&&(element=document.querySelector(element),element||(element=document.getElementById(element))),!element)throw"HTML Element is inaccessible!";html2canvas(element,{onrendered:function(canvas){callback(canvas.toDataURL())}})},connection.onScreenCapturingExtensionAvailable=function(){log("It seems that screen capturing extension is installed and available on your system!")},!isPluginRTC&&DetectRTC.screen.onScreenCapturingExtensionAvailable&&(DetectRTC.screen.onScreenCapturingExtensionAvailable=function(){connection.onScreenCapturingExtensionAvailable()}),connection.changeBandwidth=function(bandwidth){for(var peer in connection.peers)connection.peers[peer].changeBandwidth(bandwidth)},connection.convertToAudioStream=function(mediaStream){convertToAudioStream(mediaStream)},connection.onstatechange=function(state){log("on:state:change ("+state.userid+"):",state.name+":",state.reason||"")},connection.onfailed=function(event){event.peer.numOfRetries||(event.peer.numOfRetries=0),event.peer.numOfRetries++,error("ICE connectivity check is failed. Renegotiating peer connection."),event.peer.numOfRetries<2&&event.peer.renegotiate(),event.peer.numOfRetries>=2&&(event.peer.numOfRetries=0)},connection.onconnected=function(event){log("Peer connection has been established between you and",event.userid)},connection.ondisconnected=function(event){error("Peer connection seems has been disconnected between you and",event.userid),isEmpty(connection.channels)||connection.channels[event.userid]&&(connection.channels[event.userid].send({checkingPresence:!0}),setTimeout(function(){return connection.peers[event.userid].connected?void delete connection.peers[event.userid].connected:(connection.streams.remove({remote:!0,userid:event.userid}),void connection.remove(event.userid))},3e3))},connection.onstreamid=function(event){log("got remote streamid",event.streamid,"from",event.userid)},connection.stopMediaStream=function(mediaStream){if(!mediaStream)throw"MediaStream argument is mandatory.";if(connection.keepStreamsOpened)return void(mediaStream.onended&&mediaStream.onended());connection.localStreams[mediaStream.streamid]&&delete connection.localStreams[mediaStream.streamid],isFirefox&&mediaStream.onended&&mediaStream.onended();var checkForMediaStreamTrackStop=Boolean((mediaStream.getAudioTracks||mediaStream.getVideoTracks)&&(mediaStream.getAudioTracks()[0]&&!mediaStream.getAudioTracks()[0].stop||mediaStream.getVideoTracks()[0]&&!mediaStream.getVideoTracks()[0].stop));return!mediaStream.getAudioTracks||checkForMediaStreamTrackStop?void(mediaStream.stop&&mediaStream.stop()):(mediaStream.getAudioTracks().length&&mediaStream.getAudioTracks()[0].stop&&mediaStream.getAudioTracks().forEach(function(track){track.stop()}),void(mediaStream.getVideoTracks().length&&mediaStream.getVideoTracks()[0].stop&&mediaStream.getVideoTracks().forEach(function(track){track.stop()})))},connection.changeBandwidth=function(bandwidth){if(!bandwidth||isString(bandwidth)||isEmpty(bandwidth))throw'Invalid "bandwidth" arguments.';forEach(connection.peers,function(peer){peer.peer.bandwidth=bandwidth}),connection.renegotiate()},connection.openSignalingChannel=function(config){if(!window.Firebase)return loadScript(connection.resources.firebase,function(){connection.openSignalingChannel(config)});var channel=config.channel||connection.channel;connection.firebase&&(connection.resources.firebaseio=connection.resources.firebaseio.replace("//chat.","//"+connection.firebase+"."));var firebase=new Firebase(connection.resources.firebaseio+channel);firebase.channel=channel,firebase.on("child_added",function(data){config.onmessage(data.val())}),firebase.send=function(data){for(var prop in data)(isNull(data[prop])||"function"==typeof data[prop])&&(data[prop]=!1);this.push(data)},connection.socket||(connection.socket=firebase),firebase.onDisconnect().remove(),setTimeout(function(){config.callback(firebase)},1)},connection.Plugin=Plugin}window.RMCDefaultChannel=location.href.replace(/\/|:|#|\?|\$|\^|%|\.|`|~|!|\+|@|\[|\||]|\|*. /g,"").split("\n").join("").split("\r").join(""),window.RTCMultiConnection=function(channel){function initRTCMultiSession(onSignalingReady){return screenFrame&&loadScreenFrame(),rtcMultiSession?onSignalingReady():void(rtcMultiSession=new RTCMultiSession(connection,onSignalingReady))}function joinSession(session,joinAs){if(isString(session)&&(connection.skipOnNewSession=!0),!rtcMultiSession)return log("Signaling channel is not ready. Connecting..."),void initRTCMultiSession(function(){log("Signaling channel is connected. Joining the session again..."),setTimeout(function(){joinSession(session,joinAs)},1e3)});if(isString(session)){if(!connection.sessionDescriptions[session])return setTimeout(function(){log("Session-Descriptions not found. Rechecking.."),joinSession(session,joinAs)},1e3);session=connection.sessionDescriptions[session]}if(joinAs)return captureUserMedia(function(){session.oneway=!0,joinSession(session)},joinAs);if(!session||!session.userid||!session.sessionid){error("missing arguments",arguments);var error='Invalid data passed over "connection.join" method.';throw connection.onstatechange({userid:"browser",extra:{},name:"Unexpected data detected.",reason:error}),error}connection.dontOverrideSession||(connection.session=session.session);var extra=connection.extra||session.extra||{};session.oneway||isData(session)?rtcMultiSession.joinSession(session,extra):captureUserMedia(function(){rtcMultiSession.joinSession(session,extra)})}function captureUserMedia(callback,_session,dontCheckChromExtension){function onIFrameCallback(event){if(event.data&&event.data.chromeMediaSourceId){window.removeEventListener("message",onIFrameCallback);var sourceId=event.data.chromeMediaSourceId;if(DetectRTC.screen.sourceId=sourceId,DetectRTC.screen.chromeMediaSource="desktop","PermissionDeniedError"==sourceId){var mediaStreamError={message:"https:"==location.protocol?"User denied to share content of his screen.":SCREEN_COMMON_FAILURE,name:"PermissionDeniedError",constraintName:screen_constraints,session:session};return currentUserMediaRequest.mutex=!1,DetectRTC.screen.sourceId=null,connection.onMediaError(mediaStreamError)}captureUserMedia(callback,_session)}event.data&&event.data.chromeExtensionStatus&&(warn("Screen capturing extension status is:",event.data.chromeExtensionStatus),DetectRTC.screen.chromeMediaSource="screen",captureUserMedia(callback,_session,!0))}function _captureUserMedia(forcedConstraints,forcedCallback,isRemoveVideoTracks,dontPreventSSLAutoAllowed){if(connection.onstatechange({userid:"browser",extra:{},name:"fetching-usermedia",reason:"About to capture user-media with constraints: "+toStr(forcedConstraints)}),connection.preventSSLAutoAllowed&&!dontPreventSSLAutoAllowed&&isChrome)return navigator.customGetUserMediaBar?void navigator.customGetUserMediaBar(forcedConstraints,function(){_captureUserMedia(forcedConstraints,forcedCallback,isRemoveVideoTracks,!0)},function(){connection.onMediaError({name:"PermissionDeniedError",message:"User denied permission.",constraintName:forcedConstraints,session:session})}):void loadScript(connection.resources.customGetUserMediaBar,function(){_captureUserMedia(forcedConstraints,forcedCallback,isRemoveVideoTracks,dontPreventSSLAutoAllowed)});var mediaConfig={onsuccess:function(stream,returnBack,idInstance,streamid){onStreamSuccessCallback(stream,returnBack,idInstance,streamid,forcedConstraints,forcedCallback,isRemoveVideoTracks,screen_constraints,constraints,session);
},onerror:function(e,constraintUsed){if(isFirefox&&"PERMISSION_DENIED"==e&&(e={message:"",name:"PermissionDeniedError",constraintName:constraintUsed,session:session}),isFirefox&&constraintUsed.video&&constraintUsed.video.mozMediaSource)return mediaStreamError={message:Firefox_Screen_Capturing_Warning,name:e.name||"PermissionDeniedError",constraintName:constraintUsed,session:session},void connection.onMediaError(mediaStreamError);if(isString(e))return connection.onMediaError({message:"Unknown Error",name:e,constraintName:constraintUsed,session:session});if(e.name&&("PermissionDeniedError"==e.name||"DevicesNotFoundError"==e.name)){var mediaStreamError="Either: ";mediaStreamError+="\n Media resolutions are not permitted.",mediaStreamError+="\n Another application is using same media device.",mediaStreamError+="\n Media device is not attached or drivers not installed.",mediaStreamError+="\n You denied access once and it is still denied.",e.message&&e.message.length&&(mediaStreamError+="\n "+e.message),mediaStreamError={message:mediaStreamError,name:e.name,constraintName:constraintUsed,session:session},connection.onMediaError(mediaStreamError),isChrome&&(session.audio||session.video)&&DetectRTC.load(function(){session.audio&&!DetectRTC.hasMicrophone&&(warn("It seems that you have no microphone attached to your device/system."),session.audio=session.audio=!1,session.video||(alert("It seems that you are capturing microphone and there is no device available or access is denied. Reloading..."),location.reload())),session.video&&!DetectRTC.hasWebcam&&(warn("It seems that you have no webcam attached to your device/system."),session.video=session.video=!1,session.audio||(alert("It seems that you are capturing webcam and there is no device available or access is denied. Reloading..."),location.reload())),DetectRTC.hasMicrophone||DetectRTC.hasWebcam?connection.getUserMediaPromptedOnce||(connection.getUserMediaPromptedOnce=!0,captureUserMedia(callback,session)):(alert("It seems that either both microphone/webcam are not available or access is denied. Reloading..."),location.reload())})}if(e.name&&"ConstraintNotSatisfiedError"==e.name){var mediaStreamError="Either: ";mediaStreamError+="\n You are prompting unknown media resolutions.",mediaStreamError+="\n You are using invalid media constraints.",e.message&&e.message.length&&(mediaStreamError+="\n "+e.message),mediaStreamError={message:mediaStreamError,name:e.name,constraintName:constraintUsed,session:session},connection.onMediaError(mediaStreamError)}session.screen&&(isFirefox?error(Firefox_Screen_Capturing_Warning):"https:"!==location.protocol?isNodeWebkit||"file:"!=location.protocol&&"http:"!=location.protocol||error("You cannot use HTTP or file protocol for screen capturing. You must either use HTTPs or chrome extension page or Node-Webkit page."):error('Unable to detect actual issue. Maybe "deprecated" screen capturing flag was not set using command line or maybe you clicked "No" button or maybe chrome extension returned invalid "sourceId". Please install chrome-extension: http://bit.ly/webrtc-screen-extension')),currentUserMediaRequest.mutex=!1;var idInstance=JSON.stringify(constraintUsed);currentUserMediaRequest.streams[idInstance]&&delete currentUserMediaRequest.streams[idInstance]},mediaConstraints:connection.mediaConstraints||{}};mediaConfig.constraints=forcedConstraints||constraints,mediaConfig.connection=connection,getUserMedia(mediaConfig)}var session=_session||connection.session;if(isEmpty(session))return void(callback&&callback());if(connection.dontCaptureUserMedia)return callback();if(isData(session)||!connection.isInitiator&&session.oneway)return connection.attachStreams=[],callback();var constraints={audio:session.audio?{mandatory:{},optional:[{chromeRenderToAssociatedSink:!0}]}:!1,video:!!session.video};if(connection._mediaSources.audio&&constraints.audio.optional.push({sourceId:connection._mediaSources.audio}),connection._mediaSources.video&&(constraints.video={optional:[{sourceId:connection._mediaSources.video}]}),!session.screen&&!constraints.audio&&!constraints.video)return callback();var screen_constraints={audio:!1,video:{mandatory:{chromeMediaSource:DetectRTC.screen.chromeMediaSource,maxWidth:screen.width>1920?screen.width:1920,maxHeight:screen.height>1080?screen.height:1080},optional:[]}};if(isFirefox&&session.screen){if("https:"!==location.protocol)return error(SCREEN_COMMON_FAILURE);warn(Firefox_Screen_Capturing_Warning),screen_constraints.video=merge(screen_constraints.video.mandatory,{mozMediaSource:"window",mediaSource:"window"}),constraints.audio&&(screen_constraints.audio=!0,constraints={}),delete screen_constraints.video.chromeMediaSource}if(session.screen){if(isChrome&&DetectRTC.screen.extensionid!=ReservedExtensionID&&(useCustomChromeExtensionForScreenCapturing=!0),isChrome&&!useCustomChromeExtensionForScreenCapturing&&!dontCheckChromExtension&&!DetectRTC.screen.sourceId)return listenEventHandler("message",onIFrameCallback),screenFrame||loadScreenFrame(),void screenFrame.postMessage();if(isChrome&&useCustomChromeExtensionForScreenCapturing&&!dontCheckChromExtension&&"screen"==DetectRTC.screen.chromeMediaSource&&DetectRTC.screen.extensionid)return DetectRTC.screen.extensionid==ReservedExtensionID&&-1==document.domain.indexOf("webrtc-experiment.com")?captureUserMedia(callback,_session,!0):(log("checking if chrome extension is installed."),void DetectRTC.screen.getChromeExtensionStatus(function(status){"installed-enabled"==status&&(DetectRTC.screen.chromeMediaSource="desktop"),captureUserMedia(callback,_session,!0),log("chrome extension is installed?","desktop"==DetectRTC.screen.chromeMediaSource)}));if(isChrome&&useCustomChromeExtensionForScreenCapturing&&"desktop"==DetectRTC.screen.chromeMediaSource&&!DetectRTC.screen.sourceId)return void DetectRTC.screen.getSourceId(function(sourceId){if("PermissionDeniedError"==sourceId){var mediaStreamError={message:"User denied to share content of his screen.",name:"PermissionDeniedError",constraintName:screen_constraints,session:session};return currentUserMediaRequest.mutex=!1,DetectRTC.screen.chromeMediaSource="desktop",connection.onMediaError(mediaStreamError)}return"No-Response"==sourceId?(error("Chrome extension seems not available. Make sure that manifest.json#L16 has valid content-script matches pointing to your URL."),DetectRTC.screen.chromeMediaSource="screen",captureUserMedia(callback,_session,!0)):void captureUserMedia(callback,_session,!0)});isChrome&&"desktop"==DetectRTC.screen.chromeMediaSource&&(screen_constraints.video.mandatory.chromeMediaSourceId=DetectRTC.screen.sourceId);var _isFirstSession=isFirstSession;_captureUserMedia(screen_constraints,constraints.audio||constraints.video?function(){_isFirstSession&&(isFirstSession=!0),_captureUserMedia(constraints,callback)}:callback)}else _captureUserMedia(constraints,callback,session.audio&&!session.video)}function onStreamSuccessCallback(stream,returnBack,idInstance,streamid,forcedConstraints,forcedCallback,isRemoveVideoTracks,screen_constraints,constraints,session){streamid||(streamid=getRandomString()),connection.onstatechange({userid:"browser",extra:{},name:"usermedia-fetched",reason:"Captured user media using constraints: "+toStr(forcedConstraints)}),isRemoveVideoTracks&&(stream=convertToAudioStream(stream)),connection.localStreamids.push(streamid),stream.onended=function(){streamedObject.mediaElement&&!streamedObject.mediaElement.parentNode&&document.getElementById(stream.streamid)&&(streamedObject.mediaElement=document.getElementById(stream.streamid)),connection.attachStreams.forEach(function(_stream,index){_stream==stream&&(delete connection.attachStreams[index],connection.attachStreams=swap(connection.attachStreams))}),onStreamEndedHandler(streamedObject,connection),connection.streams[streamid]&&connection.removeStream(streamid);var _stream=connection.streams[streamid];_stream&&_stream.sockets.length&&_stream.sockets.forEach(function(socket){socket.send({streamid:_stream.streamid,stopped:!0})}),currentUserMediaRequest.mutex=!1,currentUserMediaRequest.streams[idInstance]&&delete currentUserMediaRequest.streams[idInstance],DetectRTC.screen.sourceId=null},isIE||(stream.streamid=streamid,stream.isScreen=forcedConstraints==screen_constraints,stream.isVideo=forcedConstraints==constraints&&!!constraints.video,stream.isAudio=forcedConstraints==constraints&&!!constraints.audio&&!constraints.video,stream.preMuted={audio:stream.getAudioTracks().length&&!stream.getAudioTracks()[0].enabled,video:stream.getVideoTracks().length&&!stream.getVideoTracks()[0].enabled});var mediaElement=createMediaElement(stream,session);mediaElement.muted=!0;var streamedObject={stream:stream,streamid:streamid,mediaElement:mediaElement,blobURL:mediaElement.mozSrcObject?URL.createObjectURL(stream):mediaElement.src,type:"local",userid:connection.userid,extra:connection.extra,session:session,isVideo:!!stream.isVideo,isAudio:!!stream.isAudio,isScreen:!!stream.isScreen,isInitiator:!!connection.isInitiator,rtcMultiConnection:connection};isFirstSession&&connection.attachStreams.push(stream),isFirstSession=!1,connection.streams[streamid]=connection._getStream(streamedObject),returnBack||connection.onstream(streamedObject),connection.setDefaultEventsForMediaElement&&connection.setDefaultEventsForMediaElement(mediaElement,streamid),forcedCallback&&forcedCallback(stream,streamedObject),connection.onspeaking&&initHark({stream:stream,streamedObject:streamedObject,connection:connection})}var rtcMultiSession,connection=this;connection.channel=channel||RMCDefaultChannel,connection.isAcceptNewSession=!0,connection.open=function(args){connection.isAcceptNewSession=!1,connection.isInitiator=!0;var dontTransmit=!1;return args&&(isString(args)?connection.sessionid=args:(isNull(args.transmitRoomOnce)||(connection.transmitRoomOnce=args.transmitRoomOnce),isNull(args.dontTransmit)||(dontTransmit=args.dontTransmit),isNull(args.sessionid)||(connection.sessionid=args.sessionid))),connection.socket&&connection.socket.remove&&connection.socket.remove(),connection.sessionid||(connection.sessionid=connection.channel),connection.sessionDescription={sessionid:connection.sessionid,userid:connection.userid,session:connection.session,extra:connection.extra},connection.sessionDescriptions[connection.sessionDescription.sessionid]||(connection.numberOfSessions++,connection.sessionDescriptions[connection.sessionDescription.sessionid]=connection.sessionDescription),initRTCMultiSession(function(){rtcMultiSession.captureUserMediaOnDemand=args?!!args.captureUserMediaOnDemand:!1,args&&args.onMediaCaptured&&(connection.onMediaCaptured=args.onMediaCaptured),rtcMultiSession.captureUserMediaOnDemand||captureUserMedia(function(){rtcMultiSession.initSession({sessionDescription:connection.sessionDescription,dontTransmit:dontTransmit}),invokeMediaCaptured(connection)}),rtcMultiSession.captureUserMediaOnDemand&&rtcMultiSession.initSession({sessionDescription:connection.sessionDescription,dontTransmit:dontTransmit})}),connection.sessionDescription},connection.connect=function(sessionid){return sessionid&&(connection.sessionid=sessionid),initRTCMultiSession(function(){log("Signaling channel is ready.")}),this},connection.join=joinSession,connection.send=function(data,_channel){if(connection.numberOfConnectedUsers<=0)return void setTimeout(function(){connection.send(data,_channel)},1e3);if(!data)throw"No file, data or text message to share.";if(data instanceof Array&&!isNull(data[0].size)&&!isNull(data[0].type))for(var i=0;i<data.length;i++)data[i].size&&data[i].type&&connection.send(data[i],_channel);else if(isNull(data.size)||isNull(data.type))TextSender.send({text:data,channel:rtcMultiSession,_channel:_channel,connection:connection});else{if(!connection.enableFileSharing)throw'"enableFileSharing" boolean MUST be "true" to support file sharing.';if(!rtcMultiSession.fileBufferReader)return void initFileBufferReader(connection,function(fbr){rtcMultiSession.fileBufferReader=fbr,connection.send(data,_channel)});var extra=merge({userid:connection.userid},data.extra||connection.extra);rtcMultiSession.fileBufferReader.readAsArrayBuffer(data,function(uuid){rtcMultiSession.fileBufferReader.getNextChunk(uuid,function(nextChunk,isLastChunk,extra){_channel?_channel.send(nextChunk):rtcMultiSession.send(nextChunk)})},extra)}},connection.disconnect=function(){rtcMultiSession&&rtcMultiSession.disconnect(),rtcMultiSession=null};var isFirstSession=!0;connection.captureUserMedia=captureUserMedia,connection.leave=function(userid){return rtcMultiSession?(isFirstSession=!0,userid?void connection.eject(userid):void rtcMultiSession.leave()):void 0},connection.eject=function(userid){if(!connection.isInitiator)throw"Only session-initiator can eject a user.";if(!connection.peers[userid])throw"You ejected invalid user.";connection.peers[userid].sendCustomMessage({ejected:!0})},connection.close=function(){connection.autoCloseEntireSession=!0,connection.leave()},connection.renegotiate=function(stream,session){return connection.numberOfConnectedUsers<=0?void setTimeout(function(){connection.renegotiate(stream,session)},1e3):void rtcMultiSession.addStream({renegotiate:session||merge({oneway:!0},connection.session),stream:stream})},connection.attachExternalStream=function(stream,isScreen){var constraints={};stream.getAudioTracks&&stream.getAudioTracks().length&&(constraints.audio=!0),stream.getVideoTracks&&stream.getVideoTracks().length&&(constraints.video=!0);var screen_constraints={video:{chromeMediaSource:"fake"}},forcedConstraints=isScreen?screen_constraints:constraints;onStreamSuccessCallback(stream,!1,"",null,forcedConstraints,!1,!1,screen_constraints,constraints,constraints)},connection.addStream=function(session,socket){function addStream(stream){rtcMultiSession.addStream({stream:stream,renegotiate:session||connection.session,socket:socket})}if(connection.numberOfConnectedUsers<=0)return void setTimeout(function(){connection.addStream(session,socket)},1e3);if(session){var isOneWayStreamFromParticipant;!connection.isInitiator&&session.oneway&&(session.oneway=!1,isOneWayStreamFromParticipant=!0),captureUserMedia(function(stream){isOneWayStreamFromParticipant&&(session.oneway=!0),addStream(stream)},session)}else addStream()},connection.removeStream=function(streamid,dontRenegotiate){function _detachStream(_stream,config){config.local&&"local"!=_stream.type||config.remote&&"remote"!=_stream.type||(config.screen&&_stream.isScreen&&connection.detachStreams.push(_stream.streamid),config.audio&&_stream.isAudio&&connection.detachStreams.push(_stream.streamid),config.video&&_stream.isVideo&&connection.detachStreams.push(_stream.streamid),config.audio||config.video||config.screen||connection.detachStreams.push(_stream.streamid),-1!=connection.detachStreams.indexOf(_stream.streamid)&&(log("removing stream",_stream.streamid),onStreamEndedHandler(_stream,connection),config.stop&&connection.stopMediaStream(_stream.stream)))}if(connection.numberOfConnectedUsers<=0)return void setTimeout(function(){connection.removeStream(streamid,dontRenegotiate)},1e3);if(streamid||(streamid="all"),!isString(streamid)||-1!=streamid.search(/all|audio|video|screen/gi)){for(var stream in connection.streams)if(-1==connection._skip.indexOf(stream))if(_stream=connection.streams[stream],"all"==streamid)_detachStream(_stream,{audio:!0,video:!0,screen:!0});else if(isString(streamid)){var config={};config[streamid]=!0,_detachStream(_stream,config)}else _detachStream(_stream,streamid);return void(!dontRenegotiate&&connection.detachStreams.length&&connection.renegotiate())}var stream=connection.streams[streamid];return stream?(connection.detachStreams.push(stream.streamid),log("removing stream",stream.streamid),onStreamEndedHandler(stream,connection),void(dontRenegotiate||connection.renegotiate())):warn("No such stream exists. Stream-id:",streamid)},connection.switchStream=function(session){return connection.numberOfConnectedUsers<=0?void setTimeout(function(){connection.switchStream(session)},1e3):(connection.removeStream("all",!0),void connection.addStream(session))},connection.sendCustomMessage=function(message){return rtcMultiSession&&rtcMultiSession.defaultSocket?void rtcMultiSession.defaultSocket.send({customMessage:!0,message:message}):setTimeout(function(){connection.sendCustomMessage(message)},1e3)},setDefaults(connection)};var webAudioMediaStreamSources=[],isOpera=!!window.opera||navigator.userAgent.indexOf(" OPR/")>=0,isFirefox="undefined"!=typeof window.InstallTrigger,isSafari=Object.prototype.toString.call(window.HTMLElement).indexOf("Constructor")>0,isChrome=!!window.chrome&&!isOpera,isIE=!!document.documentMode,isPluginRTC=isSafari||isIE,isMobileDevice=!!navigator.userAgent.match(/Android|iPhone|iPad|iPod|BlackBerry|IEMobile/i),isNodeWebkit=!!(window.process&&"object"==typeof window.process&&window.process.versions&&window.process.versions["node-webkit"]);window.MediaStream=window.MediaStream||window.webkitMediaStream,window.AudioContext=window.AudioContext||window.webkitAudioContext;var chromeVersion=50,matchArray=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);isChrome&&matchArray&&matchArray[2]&&(chromeVersion=parseInt(matchArray[2],10));var firefoxVersion=50;matchArray=navigator.userAgent.match(/Firefox\/(.*)/),isFirefox&&matchArray&&matchArray[1]&&(firefoxVersion=parseInt(matchArray[1],10));var console=window.console||{log:function(){},error:function(){},warn:function(){}};if(isChrome||isFirefox||isSafari)var log=console.log.bind(console),error=console.error.bind(console),warn=console.warn.bind(console);var screenFrame,loadedScreenFrame,loadedIceFrame,onStreamEndedHandlerFiredFor={},onLeaveHandlerFiredFor={},Firefox_Screen_Capturing_Warning='Make sure that you are using Firefox Nightly and you enabled: media.getusermedia.screensharing.enabled flag from about:config page. You also need to add your domain in "media.getusermedia.screensharing.allowed_domains" flag. If you are using WinXP then also enable "media.getusermedia.screensharing.allow_on_old_platforms" flag. NEVER forget to use "only" HTTPs for screen capturing!',SCREEN_COMMON_FAILURE="HTTPs i.e. SSL-based URI is mandatory to use screen capturing.",ReservedExtensionID="ajhifddimkapgcifgcodmmfdlknahffk",useCustomChromeExtensionForScreenCapturing=-1!=document.domain.indexOf("webrtc-experiment.com");attachEventListener=function(video,type,listener,useCapture){video.addEventListener(type,listener,useCapture)};var Plugin=window.PluginRTC||{};window.onPluginRTCInitialized=function(pluginRTCObject){Plugin=pluginRTCObject,MediaStreamTrack=Plugin.MediaStreamTrack,RTCPeerConnection=Plugin.RTCPeerConnection,RTCIceCandidate=Plugin.RTCIceCandidate,RTCSessionDescription=Plugin.RTCSessionDescription,log(isPluginRTC?"Java-Applet":"ActiveX","plugin has been loaded.")},isEmpty(Plugin)||window.onPluginRTCInitialized(Plugin),isPluginRTC&&loadScript("https://cdn.webrtc-experiment.com/Plugin.EveryWhere.js");var MediaStream=window.MediaStream;"undefined"==typeof MediaStream&&"undefined"!=typeof webkitMediaStream&&(MediaStream=webkitMediaStream),"undefined"==typeof MediaStream||"stop"in MediaStream.prototype||(MediaStream.prototype.stop=function(){this.getAudioTracks().forEach(function(track){track.stop()}),this.getVideoTracks().forEach(function(track){track.stop()})});var RTCPeerConnection,defaultConstraints={mandatory:{},optional:[]},currentUserMediaRequest={streams:[],mutex:!1,queueRequests:[]},RTCSessionDescription=window.RTCSessionDescription||window.mozRTCSessionDescription,RTCIceCandidate=window.RTCIceCandidate||window.mozRTCIceCandidate;"undefined"!=typeof mozRTCPeerConnection?RTCPeerConnection=mozRTCPeerConnection:"undefined"!=typeof webkitRTCPeerConnection?RTCPeerConnection=webkitRTCPeerConnection:"undefined"!=typeof window.RTCPeerConnection?RTCPeerConnection=window.RTCPeerConnection:console.error("WebRTC 1.0 (RTCPeerConnection) API seems NOT available in this browser.");var FileSaver={SaveToDisk:invokeSaveAsDialog},TextSender={send:function(config){function sendText(textMessage,text){var data={type:"text",uuid:uuid,sendingTime:sendingTime};textMessage&&(text=textMessage,data.packets=parseInt(text.length/packetSize)),text.length>packetSize?data.message=text.slice(0,packetSize):(data.message=text,data.last=!0,data.isobject=isobject),channel.send(data,_channel),textToTransfer=text.slice(data.message.length),textToTransfer.length&&setTimeout(function(){sendText(null,textToTransfer)},connection.chunkInterval||100)}var connection=config.connection;if(config.text instanceof ArrayBuffer||config.text instanceof DataView)return config.channel.send(config.text,config._channel);var channel=config.channel,_channel=config._channel,initialText=config.text,packetSize=connection.chunkSize||1e3,textToTransfer="",isobject=!1;isString(initialText)||(isobject=!0,initialText=JSON.stringify(initialText));var uuid=getRandomString(),sendingTime=(new Date).getTime();sendText(initialText)}};!function(){"use strict";function getBrowserInfo(){var nameOffset,verOffset,ix,nAgt=(navigator.appVersion,navigator.userAgent),browserName=navigator.appName,fullVersion=""+parseFloat(navigator.appVersion),majorVersion=parseInt(navigator.appVersion,10);return-1!==(verOffset=nAgt.indexOf("Opera"))?(browserName="Opera",fullVersion=nAgt.substring(verOffset+6),-1!==(verOffset=nAgt.indexOf("Version"))&&(fullVersion=nAgt.substring(verOffset+8))):-1!==(verOffset=nAgt.indexOf("MSIE"))?(browserName="IE",fullVersion=nAgt.substring(verOffset+5)):-1!==(verOffset=nAgt.indexOf("Chrome"))?(browserName="Chrome",fullVersion=nAgt.substring(verOffset+7)):-1!==(verOffset=nAgt.indexOf("Safari"))?(browserName="Safari",fullVersion=nAgt.substring(verOffset+7),-1!==(verOffset=nAgt.indexOf("Version"))&&(fullVersion=nAgt.substring(verOffset+8))):-1!==(verOffset=nAgt.indexOf("Firefox"))?(browserName="Firefox",fullVersion=nAgt.substring(verOffset+8)):(nameOffset=nAgt.lastIndexOf(" ")+1)<(verOffset=nAgt.lastIndexOf("/"))&&(browserName=nAgt.substring(nameOffset,verOffset),fullVersion=nAgt.substring(verOffset+1),browserName.toLowerCase()===browserName.toUpperCase()&&(browserName=navigator.appName)),isEdge&&(browserName="Edge",fullVersion=parseInt(navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)[2],10)),-1!==(ix=fullVersion.indexOf(";"))&&(fullVersion=fullVersion.substring(0,ix)),-1!==(ix=fullVersion.indexOf(" "))&&(fullVersion=fullVersion.substring(0,ix)),majorVersion=parseInt(""+fullVersion,10),isNaN(majorVersion)&&(fullVersion=""+parseFloat(navigator.appVersion),majorVersion=parseInt(navigator.appVersion,10)),{fullVersion:fullVersion,version:majorVersion,name:browserName}}function DetectLocalIPAddress(callback){getIPs(function(ip){callback(ip.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/)?"Local: "+ip:"Public: "+ip)})}function getIPs(callback){function handleCandidate(candidate){var ipRegex=/([0-9]{1,3}(\.[0-9]{1,3}){3})/,ipAddress=ipRegex.exec(candidate)[1];void 0===ipDuplicates[ipAddress]&&callback(ipAddress),ipDuplicates[ipAddress]=!0}var ipDuplicates={},RTCPeerConnection=window.RTCPeerConnection||window.mozRTCPeerConnection||window.webkitRTCPeerConnection,useWebKit=!!window.webkitRTCPeerConnection;if(!RTCPeerConnection){var iframe=document.getElementById("iframe");if(!iframe)throw"NOTE: you need to have an iframe in the page right above the script tag.";var win=iframe.contentWindow;RTCPeerConnection=win.RTCPeerConnection||win.mozRTCPeerConnection||win.webkitRTCPeerConnection,useWebKit=!!win.webkitRTCPeerConnection}var servers,mediaConstraints={optional:[{RtpDataChannels:!0}]};useWebKit&&(servers={iceServers:[{urls:"stun:stun.services.mozilla.com"}]},"undefined"!=typeof DetectRTC&&DetectRTC.browser.isFirefox&&DetectRTC.browser.version<=38&&(servers[0]={url:servers[0].urls}));var pc=new RTCPeerConnection(servers,mediaConstraints);pc.onicecandidate=function(ice){ice.candidate&&handleCandidate(ice.candidate.candidate)},pc.createDataChannel(""),pc.createOffer(function(result){pc.setLocalDescription(result,function(){},function(){})},function(){}),setTimeout(function(){var lines=pc.localDescription.sdp.split("\n");lines.forEach(function(line){0===line.indexOf("a=candidate:")&&handleCandidate(line)})},1e3)}function checkDeviceSupport(callback){return!navigator.enumerateDevices&&window.MediaStreamTrack&&window.MediaStreamTrack.getSources&&(navigator.enumerateDevices=window.MediaStreamTrack.getSources.bind(window.MediaStreamTrack)),!navigator.enumerateDevices&&navigator.enumerateDevices&&(navigator.enumerateDevices=navigator.enumerateDevices.bind(navigator)),navigator.enumerateDevices?(MediaDevices=[],void navigator.enumerateDevices(function(devices){devices.forEach(function(_device){var device={};for(var d in _device)device[d]=_device[d];var skip;MediaDevices.forEach(function(d){d.id===device.id&&(skip=!0)}),skip||("audio"===device.kind&&(device.kind="audioinput"),"video"===device.kind&&(device.kind="videoinput"),device.deviceId||(device.deviceId=device.id),device.id||(device.id=device.deviceId),device.label||(device.label="Please invoke getUserMedia once.",isHTTPs||(device.label="HTTPs is required to get label of this "+device.kind+" device.")),("audioinput"===device.kind||"audio"===device.kind)&&(hasMicrophone=!0),"audiooutput"===device.kind&&(hasSpeakers=!0),("videoinput"===device.kind||"video"===device.kind)&&(hasWebcam=!0),MediaDevices.push(device))}),"undefined"!=typeof DetectRTC&&(DetectRTC.MediaDevices=MediaDevices,DetectRTC.hasMicrophone=hasMicrophone,DetectRTC.hasSpeakers=hasSpeakers,DetectRTC.hasWebcam=hasWebcam),callback&&callback()})):void(callback&&callback())}var navigator=window.navigator;navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&(navigator.enumerateDevices=function(callback){navigator.mediaDevices.enumerateDevices().then(callback)}),"undefined"!=typeof navigator?("undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia)):navigator={getUserMedia:function(){}};var isMobileDevice=!!navigator.userAgent.match(/Android|iPhone|iPad|iPod|BlackBerry|IEMobile/i),isEdge=!(-1===navigator.userAgent.indexOf("Edge")||!navigator.msSaveOrOpenBlob&&!navigator.msSaveBlob),isMobile={Android:function(){return navigator.userAgent.match(/Android/i)},BlackBerry:function(){return navigator.userAgent.match(/BlackBerry/i)},iOS:function(){return navigator.userAgent.match(/iPhone|iPad|iPod/i)},Opera:function(){return navigator.userAgent.match(/Opera Mini/i)},Windows:function(){return navigator.userAgent.match(/IEMobile/i)},any:function(){return isMobile.Android()||isMobile.BlackBerry()||isMobile.iOS()||isMobile.Opera()||isMobile.Windows()},getOsName:function(){var osName="Unknown OS";return isMobile.Android()&&(osName="Android"),isMobile.BlackBerry()&&(osName="BlackBerry"),isMobile.iOS()&&(osName="iOS"),isMobile.Opera()&&(osName="Opera Mini"),isMobile.Windows()&&(osName="Windows"),osName}},osName="Unknown OS";isMobile.any()?osName=isMobile.getOsName():(-1!==navigator.appVersion.indexOf("Win")&&(osName="Windows"),-1!==navigator.appVersion.indexOf("Mac")&&(osName="MacOS"),-1!==navigator.appVersion.indexOf("X11")&&(osName="UNIX"),-1!==navigator.appVersion.indexOf("Linux")&&(osName="Linux"));var isCanvasSupportsStreamCapturing=!1,isVideoSupportsStreamCapturing=!1;["captureStream","mozCaptureStream","webkitCaptureStream"].forEach(function(item){item in document.createElement("canvas")&&(isCanvasSupportsStreamCapturing=!0),item in document.createElement("video")&&(isVideoSupportsStreamCapturing=!0)});var MediaDevices=[],canEnumerate=!1;"undefined"!=typeof MediaStreamTrack&&"getSources"in MediaStreamTrack?canEnumerate=!0:navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&(canEnumerate=!0);var hasMicrophone=canEnumerate,hasSpeakers=canEnumerate,hasWebcam=canEnumerate;checkDeviceSupport();var DetectRTC={};DetectRTC.browser=getBrowserInfo(),DetectRTC.browser["is"+DetectRTC.browser.name]=!0;var isHTTPs="https:"===location.protocol,isWebRTCSupported=(!!(window.process&&"object"==typeof window.process&&window.process.versions&&window.process.versions["node-webkit"]),!1);["webkitRTCPeerConnection","mozRTCPeerConnection","RTCIceGatherer"].forEach(function(item){item in window&&(isWebRTCSupported=!0)}),DetectRTC.isWebRTCSupported=isWebRTCSupported,DetectRTC.isORTCSupported="undefined"!=typeof RTCIceGatherer;var isScreenCapturingSupported=!1;DetectRTC.browser.isChrome&&DetectRTC.browser.version>=35?isScreenCapturingSupported=!0:DetectRTC.browser.isFirefox&&DetectRTC.browser.version>=34&&(isScreenCapturingSupported=!0),isHTTPs||(isScreenCapturingSupported=!1),DetectRTC.isScreenCapturingSupported=isScreenCapturingSupported;var webAudio={};["AudioContext","webkitAudioContext","mozAudioContext","msAudioContext"].forEach(function(item){webAudio.isSupported&&webAudio.isCreateMediaStreamSourceSupported||item in window&&(webAudio.isSupported=!0,"createMediaStreamSource"in window[item].prototype&&(webAudio.isCreateMediaStreamSourceSupported=!0))}),DetectRTC.isAudioContextSupported=webAudio.isSupported,DetectRTC.isCreateMediaStreamSourceSupported=webAudio.isCreateMediaStreamSourceSupported;var isRtpDataChannelsSupported=!1;DetectRTC.browser.isChrome&&DetectRTC.browser.version>31&&(isRtpDataChannelsSupported=!0),DetectRTC.isRtpDataChannelsSupported=isRtpDataChannelsSupported;var isSCTPSupportd=!1;if(DetectRTC.browser.isFirefox&&DetectRTC.browser.version>28?isSCTPSupportd=!0:DetectRTC.browser.isChrome&&DetectRTC.browser.version>25?isSCTPSupportd=!0:DetectRTC.browser.isOpera&&DetectRTC.browser.version>=11&&(isSCTPSupportd=!0),DetectRTC.isSctpDataChannelsSupported=isSCTPSupportd,DetectRTC.isMobileDevice=isMobileDevice,DetectRTC.isWebSocketsSupported="WebSocket"in window&&2===window.WebSocket.CLOSING,DetectRTC.isWebSocketsBlocked="Checking",DetectRTC.isWebSocketsSupported){var websocket=new WebSocket("wss://echo.websocket.org:443/");websocket.onopen=function(){DetectRTC.isWebSocketsBlocked=!1,DetectRTC.loadCallback&&DetectRTC.loadCallback()},websocket.onerror=function(){DetectRTC.isWebSocketsBlocked=!0,DetectRTC.loadCallback&&DetectRTC.loadCallback()}}var isGetUserMediaSupported=!1;navigator.getUserMedia?isGetUserMediaSupported=!0:navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&(isGetUserMediaSupported=!0),DetectRTC.browser.isChrome&&DetectRTC.browser.version>=47&&!isHTTPs&&(DetectRTC.isGetUserMediaSupported="Requires HTTPs"),DetectRTC.isGetUserMediaSupported=isGetUserMediaSupported,DetectRTC.osName=osName,DetectRTC.isCanvasSupportsStreamCapturing=isCanvasSupportsStreamCapturing,DetectRTC.isVideoSupportsStreamCapturing=isVideoSupportsStreamCapturing,DetectRTC.DetectLocalIPAddress=DetectLocalIPAddress,DetectRTC.load=function(callback){this.loadCallback=callback,checkDeviceSupport(callback)},DetectRTC.MediaDevices=MediaDevices,DetectRTC.hasMicrophone=hasMicrophone,DetectRTC.hasSpeakers=hasSpeakers,DetectRTC.hasWebcam=hasWebcam;var isSetSinkIdSupported=!1;"setSinkId"in document.createElement("video")&&(isSetSinkIdSupported=!0),DetectRTC.isSetSinkIdSupported=isSetSinkIdSupported;var isRTPSenderReplaceTracksSupported=!1;DetectRTC.browser.isFirefox?"getSenders"in mozRTCPeerConnection.prototype&&(isRTPSenderReplaceTracksSupported=!0):DetectRTC.browser.isChrome&&"getSenders"in webkitRTCPeerConnection.prototype&&(isRTPSenderReplaceTracksSupported=!0),DetectRTC.isRTPSenderReplaceTracksSupported=isRTPSenderReplaceTracksSupported;var isRemoteStreamProcessingSupported=!1;DetectRTC.browser.isFirefox&&DetectRTC.browser.version>38&&(isRemoteStreamProcessingSupported=!0),DetectRTC.isRemoteStreamProcessingSupported=isRemoteStreamProcessingSupported;var isApplyConstraintsSupported=!1;"undefined"!=typeof MediaStreamTrack&&"applyConstraints"in MediaStreamTrack.prototype&&(isApplyConstraintsSupported=!0),DetectRTC.isApplyConstraintsSupported=isApplyConstraintsSupported;var isMultiMonitorScreenCapturingSupported=!1;DetectRTC.browser.isFirefox&&DetectRTC.browser.version>=43&&(isMultiMonitorScreenCapturingSupported=!0),
DetectRTC.isMultiMonitorScreenCapturingSupported=isMultiMonitorScreenCapturingSupported,window.DetectRTC=DetectRTC}();var screenCallback;DetectRTC.screen={chromeMediaSource:"screen",extensionid:ReservedExtensionID,getSourceId:function(callback){function onstatus(status){return"installed-enabled"==status?(screenCallback=callback,void window.postMessage("get-sourceId","*")):(DetectRTC.screen.chromeMediaSource="screen",void callback("No-Response"))}if(!callback)throw'"callback" parameter is mandatory.';DetectRTC.screen.status?onstatus(DetectRTC.screen.status):DetectRTC.screen.getChromeExtensionStatus(onstatus)},onMessageCallback:function(data){if(isString(data)||data.sourceId){if(log("chrome message",data),"PermissionDeniedError"==data){if(DetectRTC.screen.chromeMediaSource="PermissionDeniedError",screenCallback)return screenCallback("PermissionDeniedError");throw new Error("PermissionDeniedError")}"rtcmulticonnection-extension-loaded"==data&&(DetectRTC.screen.chromeMediaSource="desktop",DetectRTC.screen.onScreenCapturingExtensionAvailable&&(DetectRTC.screen.onScreenCapturingExtensionAvailable(),DetectRTC.screen.onScreenCapturingExtensionAvailable=null)),data.sourceId&&(DetectRTC.screen.sourceId=data.sourceId,screenCallback&&screenCallback(DetectRTC.screen.sourceId))}},getChromeExtensionStatus:function(extensionid,callback){function _callback(status){DetectRTC.screen.status=status,callback(status)}if(isFirefox)return _callback("not-chrome");2!=arguments.length&&(callback=extensionid,extensionid=this.extensionid);var image=document.createElement("img");image.src="chrome-extension://"+extensionid+"/icon.png",image.onload=function(){DetectRTC.screen.chromeMediaSource="screen",window.postMessage("are-you-there","*"),setTimeout(function(){_callback("screen"==DetectRTC.screen.chromeMediaSource?"desktop"==DetectRTC.screen.chromeMediaSource?"installed-enabled":"installed-disabled":"installed-enabled")},2e3)},image.onerror=function(){_callback("not-installed")}}},window.addEventListener||(window.addEventListener=function(el,eventName,eventHandler){el.attachEvent&&el.attachEvent("on"+eventName,eventHandler)}),window.addEventListener("message",function(event){event.origin==window.location.origin&&DetectRTC.screen.onMessageCallback(event.data)})}();