UNPKG

sinch-rtc

Version:

Sinch JS SDK for real time communication, voice and IM

1 lines 123 kB
var PAPI,PUBNUB=require("pubnub").init({}),XMLHttpRequest=require("xmlhttprequest").XMLHttpRequest,window=window||global,WRTC=require("wrtc"),navigator=navigator||{mediaDevices:{getUserMedia:function(){return!1},userAgent:""}}||{getUserMedia:function(){return!1},userAgent:""}||{mozGetUserMedia:function(){return!1},userAgent:""}||{webkitGetUserMedia:function(){return!1},userAgent:""},btoa=require("btoa"),atob=require("atob"),localStorage=require("localStorage"),SinchTicketGenerator=require("sinch-ticketgen"),Q=require("q"),SinchVersion=require("../VERSION"),ErrorDomain=(SinchTicketGenerator=require("sinch-ticketgen"),{ErrorDomainNone:-1,ErrorDomainNetwork:0,ErrorDomainCapability:1,ErrorDomainSession:2,ErrorDomainApi:3,ErrorDomainOther:4,ErrorDomainSDK:5,ErrorDomainVerification:7}),ErrorCode={NoneNone:0,NetworkConnectionRefused:1e3,NetworkConnectionTimedOut:1001,NetworkServerError:1002,CapabilityUserNotFound:2e3,CapabilityCapabilityMissing:2001,CapabilityAuthenticationFailed:2002,SessionFailedToInitiateSession:3e3,SessionNoPendingSessionExists:3001,SessionTransferCantBeInitiated:3002,SessionActiveUserLimitReached:3003,ApiApiCallFailed:4e3,OtherInvalidOfflinePayloadTooBig:5e3,OtherInvalidOfflineInvitePayloadFailedToDecode:5001,OtherInvalidOfflineInviteUnknownType:5002,OtherOther:5003,SDKUnexpectedCall:6e3,SDKInternalError:6001,SDKInternalOther:6002,SDKMissingParameter:6003,SDKMissingCallback:6004,VerificationInvalidInput:7001,VerificationServiceError:7002,VerificationIncorrectCode:7003,VerificationFailedToInterceptCode:7004,VerificationUnexpectedInitiateError:7005},sinchAjax=function(e){var t=Q.defer(),i=new XMLHttpRequest;i.onload=function(){if(i.status>=200&&i.status<300){try{i.response=i.response||i.responseText,i.data=JSON.parse(i.response||"{}")}catch(e){console.log("Cant parse JSON"+i.response)}t.resolve(i.data)}else{try{i.response=i.response||i.responseText,i.data=JSON.parse(i.response||"{}")}catch(e){console.log("Cant parse JSON"+i.response)}t.reject(i)}},i.onerror=function(){t.reject(new Error("Unsupported operation "+i.status,i))},i.open(e.method,e.url,!0);for(var n in e.headers)i.setRequestHeader(n,e.headers[n]);return i.send(JSON.stringify(e.data)),t.promise},requestPrototype=function(e,t){var i={method:e.method,headers:{"Content-Type":"application/json; charset=UTF-8",Accept:"application/json, text/plain, */*"}};"GET"!=e.method&&(i.data=t),i.url="";for(var n in e.urlParts){if(":"===e.urlParts[n][0]){var r=e.urlParts[n].slice(1);i.url+=encodeURIComponent((t||{})[r]).replace(/%2B/g,"+").replace(/%40/g,"@")}else i.url+=e.urlParts[n];n<e.urlParts.length-1&&(i.url+="/")}switch(e.auth){case"sign":i.headers=this.signSession(i);break;case"nosign":i.headers=this.signApp(i);break;case"ticket":i.headers=this.signTicket(i),delete i.data.authorization;break;case"signorticket":this._sessionId?i.headers=this.signSession(i):(i.headers=this.signTicket(i),delete i.data.authorization);break;default:throw new Error("Unsupported authentication type: "+e.auth)}if("GET"===e.method&&t&&Object.keys(t).length>0&&!e.hideQueryParams){i.url+="?";for(var s in t)i.url+=encodeURIComponent(s)+"="+encodeURIComponent(t[s])+"&"}return sinchAjax(i)},getUuid=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)})};function Notification(e,t,i,n){this.progress=e/t,this.message=i,this.object=n}function getBrowserInfo(){var e,t=navigator.userAgent,i=t.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i)||t.match(/(applewebkit(?=\/))\/?\s*(\d+)/i)||[];return/trident/i.test(i[1])?"IE "+((e=/\brv[ :]+(\d+)/g.exec(t)||[])[1]||""):"Chrome"===i[1]&&null!=(e=t.match(/\bOPR\/(\d+)/))?"Opera "+e[1]:(i=i[2]?[i[1],i[2]]:[navigator.appName,navigator.appVersion,"-?"],null!=(e=t.match(/version\/(\d+)/i))&&i.splice(1,1,e[1]),i.join("/").substring(0,50))}function getPlatformInfo(){return navigator.platform}function Sinch(e){if(!e)throw new TypeError("Could not create SinchClient, configuration not provided.");if(e.capabilities=e.capabilities||{},"string"!=typeof e.applicationKey)throw new TypeError("Could not create SinchClient, applicationKey is not a string");this.capabilities=e.capabilities,this._appKey=e.applicationKey||"",this._appSecret=e.applicationSecret||void 0,this._sessionId="",this._sessionSecret="",this._logHandler=e.onLogMessage||function(){},this._logMxpHandler=e.onLogMxpMessage||function(){},this._onlineCapability=e.startActiveConnection||e.supportActiveConnection||!1,this._autoStartMxp=e.startActiveConnection||!1,this._expiresIn=e.expiresIn||86400,this._subInstanceId=Math.round(Math.random()*Math.pow(2,32)),this._customStream=e.customStream||void 0,this._supportVideo=e.capabilities.video||!1,this._multiCall=e.capabilities.multiCall||!1,this.applicationKey=this._appKey,this._supportManagedPush=e.supportManagedPush,this._progressTimeout=e.progressTimeout||10500,this.firefox=!1,void 0!==navigator&&(this.firefox=(navigator||{userAgent:""}).userAgent.indexOf("Firefox")>0||(navigator||{vendor:""}).vendor.indexOf("Apple Computer")>0),this._url={base:"https://api.sinch.com/v1/",user:"https://userapi.sinch.com/v1/",portal:"https://portalapi.sinch.com/v1/",reporting:"https://reportingapi.sinch.com/v1/",reporting_v2:"https://reportingapi.sinch.com/v2/",calling:"https://callingapi.sinch.com/v1/",messaging:"https://messagingapi.sinch.com/v1/",verification:"https://verificationapi-v1.sinch.com/verification/v1/"},this.setUrl(e.urlObj||{}),this.loadPAPIUrl(),this.loadTimeDelta(),this.user=new User(this),"messaging"in this.capabilities&&this.capabilities.messaging&&(this.messageClient=new MessageClient(this)),"calling"in this.capabilities&&this.capabilities.calling&&(this.callClient=new CallClient(this,e.customStream)),"stealth"in this.capabilities&&this.capabilities.stealth&&(this.callClient=new CallClient(this,e.customStream))}(PAPI=PAPI||{}).base={getServerTime:{url:"timestamp/",method:"GET",auth:"nosign"},getInstance:{url:"instance",method:"POST",auth:"ticket"},renewInstance:{url:"instance",method:"POST",auth:"sign"},renewSecret:{url:"instances/id/:instanceId/authorization",method:"PUT",auth:"ticket"},getInstances:{url:"instances/id/",method:"GET",auth:"sign"}},(PAPI=PAPI||{}).calling={getConfiguration:{url:"configuration/user",method:"GET",auth:"sign"},placeCall:{url:"calls/:domain",method:"POST",auth:"sign"},callReporting:{url:"calls/:domain/id/:callId",method:"PUT",auth:"sign"},postMedia:{url:"media",method:"POST",auth:"sign"},pushCall:{url:"push",method:"POST",auth:"sign"}},(PAPI=PAPI||{}).messaging={getTransportById:{url:"transport",method:"GET",auth:"sign"},getTransportByParticipants:{url:"transport",method:"POST",auth:"sign"},messageReporting:{url:"report/im",method:"POST",auth:"sign"},pushMessage:{url:"push/messages",method:"POST",auth:"sign"}},(PAPI=PAPI||{}).user={authenticate:{url:"users/email/:email/authentication",method:"POST",auth:"nosign"},authenticateUsername:{url:"users/username/:username/authentication",method:"POST",auth:"nosign"},authenticateNumber:{url:"users/number/:number/authentication",method:"POST",auth:"nosign"},createUser:{url:"users",method:"POST",auth:"nosign"},changePassword:{url:"user/password",method:"PUT",auth:"sign"},updateUser:{url:"user/profile",method:"PATCH",auth:"sign"},getUserProfile:{url:"user/profile",method:"GET",auth:"sign"}},(PAPI=PAPI||{}).verification={verify:{url:"verifications",method:"POST",auth:"nosign"},confirmVerification:{url:"verifications/number/:number",method:"PUT",auth:"nosign"},confirmUserCallout:{url:"verifications",method:"POST",auth:"nosign"},confirmFlashCall:{url:"verifications/number/:number",method:"PUT",auth:"nosign"},queryVerificationById:{url:"verifications/callout/number/:number",method:"GET",hideQueryParams:!0,auth:"nosign"}},Sinch.prototype.loadPAPIUrl=function(){this.PAPI=JSON.parse(JSON.stringify(PAPI));for(var e in PAPI)for(var t in PAPI[e])this.PAPI[e][t].urlParts=(this._url[e]+this.PAPI[e][t].url).split("/"),this[t]=requestPrototype.bind(this,this.PAPI[e][t])},Sinch.prototype.loadTimeDelta=function(){var e=Q.defer();return this.timeDelta?e.resolve():this.getServerTime().then(function(t){var i=new Date(t.timestamp),n=new Date;this.timeDelta=i-n,e.resolve()}.bind(this)).catch(function(t){console.error(t),e.fail(t)}),e.promise},Sinch.prototype.config=function(e){this._appKey=e.appKey||this._appKey,this._sessionId=e.sessionId||this._sessionId,this._sessionSecret=e.sessionSecret||this._sessionSecret,localStorage["SinchSDK-"+this._appKey+"-"+this.user.userId]=this._sessionId},Sinch.prototype.loadSessionId=function(){this._sessionId=localStorage["SinchSDK-"+this._appKey+"-"+this.user.userId]||""},Sinch.prototype.log=function(e,t){t&&t.notify(e),this._logHandler(e)},Sinch.prototype.logMxp=function(e){this._logMxpHandler(e)},Sinch.prototype.setUrl=function(e){this._url.user=e.user||this._url.user,this._url.base=e.base||this._url.base,this._url.portal=e.portal||this._url.portal,this._url.reporting=e.reporting||this._url.reporting,this._url.reporting_v2=e.reporting_v2||this._url.reporting_v2,this._url.calling=e.calling||this._url.calling,this._url.messaging=e.messaging||this._url.messaging,this._url.verification=e.verification||this._url.verification,this.loadPAPIUrl()},Sinch.prototype.terminate=function(){try{this.mxp&&this.mxp.close(),this.mxp.destroy(),this.mxp&&delete this.mxp,this._sessionId="",this._sessionSecret="",this.messageClient&&this.messageClient.destroy()}catch(e){}},Sinch.prototype.stop=function(){console.error("Stop is deprecated, use terminate() instead!"),this.terminate()},Sinch.prototype.adjustedTime=function(){var e=(new Date).getTime();return new Date(e+(this.timeDelta||0)).toISOString()},Sinch.prototype.signSession=function(e){try{var t="";if(void 0!==e.data){var i="string"!=typeof e.data?JSON.stringify(e.data):e.data;t=CryptoJS.MD5(i).toString(CryptoJS.enc.Base64)}e.headers["Content-Type"]=(e.headers["Content-Type"]||"").replace("utf-8","UTF-8").replace("/json;chars","/json; chars"),e.headers["X-Timestamp"]=e.headers["X-Timestamp"]||this.adjustedTime();var n=e.method+"\n"+t+"\n"+(e.headers["Content-Type"]||"")+"\nx-timestamp:"+e.headers["X-Timestamp"]+"\n"+e.url.match(/^https?:\/\/[^\/]+([^#]*)/)[1];if(this._sessionId.length>0&&this._sessionSecret.length>0){var r=CryptoJS.HmacSHA256(CryptoJS.enc.Utf8.parse(n),CryptoJS.enc.Base64.parse(this._sessionSecret)).toString(CryptoJS.enc.Base64);e.headers.Authorization="instance "+this._sessionId+":"+r}else e.headers.Authorization="application "+this._appKey;return e.headers}catch(e){throw e}return null},Sinch.prototype.signTicket=function(e,t){return t=t||e.data.authorization,e.headers=e.headers||{},e.headers.Authorization="user "+t,e.headers["X-Timestamp"]=this.adjustedTime(),e.headers},Sinch.prototype.signApp=function(e){try{return e.headers["X-Timestamp"]=e.headers["X-Timestamp"]||this.adjustedTime(),e.headers.Authorization="application "+this._appKey,e.headers}catch(e){throw e}return null},Sinch.prototype.getSession=function(){return{userId:this.user.userId,sessionId:this._sessionId,sessionSecret:this._sessionSecret,pushNotificationDisplayName:this.user.pushNotificationDisplayName}},Sinch.prototype.newUser=function(e,t,i){var n=Q.defer();return t=t||function(e){return console.info("User successfully created"),e},i=i||function(e){console.error(e)},this.user.create(e).then(t).then(n.resolve).fail(function(e){this.log(e),i(e),n.reject(e)}.bind(this)),n.promise},Sinch.prototype.start=function(e,t,i){var n=Q.defer();if(t=t||function(){this.log(new Notification(0,1,"SinchClient started"))}.bind(this),i=i||function(e){console.error(e)},this.started){var r=new Error("Sinch client already started");i(r),n.reject(r)}else e&&(this.user.pushNotificationDisplayName=e.pushNotificationDisplayName),this.started=!0,this.loadTimeDelta().then(function(e){return this.log(new Notification(0,5,"Get authentication token"),n),this.user.authenticate(e)}.bind(this,e),e).then(function(e){return this.loadSessionId(),e}.bind(this)).then(function(e){return this.log(new Notification(1,5,"Get instance using auth token"),n),e&&e.sessionId&&e.sessionSecret?this.user.resumeSession(e):this.user.initSessKeySecret()}.bind(this)).fail(function(e){if(40400===((e||{response:{}}).response||{}).errorCode)return this.log(new Notification(1,5,"Invalid instance. Will try again without any pre-set instance ID."),n),this._sessionId="",this.user.initSessKeySecret();throw e}.bind(this)).then(function(){return this.log(new Notification(2,5,"Get MXP configuration"),n),this.user.getMXPConf()}.bind(this)).then(function(){this.log(new Notification(3,5,"Create MXP object"),n),this.mxp=new MXP(this)}.bind(this)).then(function(){if(this._autoStartMxp&&(void 0!==this.messageClient||void 0!==this.callClient))return this.log(new Notification(4,5,"Will start active connection"),n),this.startActiveConnection();this.log(new Notification(4,5,"Will NOT start active connection. This will prevent IM and incoming data calls."),n)}.bind(this)).then(t).then(function(){this.log(new Notification(5,5,"Successfully started SinchClient"),n),n.resolve()}.bind(this)).fail(function(e){this.started=!1,this._sessionId="",this._sessionSecret="",this.log(e),i(e),n.reject(e)}.bind(this));return n.promise},Sinch.prototype.getMessageClient=function(){if("messaging"in this.capabilities&&this.capabilities.messaging)return this.messageClient;throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"No messaging capability, not possible to retrieve messageClient")},Sinch.prototype.getCallClient=function(){if("calling"in this.capabilities&&this.capabilities.calling)return this.callClient;throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"No calling capability, not possible to retrieve callClient")},Sinch.prototype.createSmsVerification=function(e,t){return new Verification(this,e,t,"sms")},Sinch.prototype.createCalloutVerification=function(e,t){return new CalloutVerification(this,e,t)},Sinch.prototype.createFlashCallVerification=function(e,t){return new Verification(this,e,t,"flashcall")},Sinch.prototype.createVerification=function(e,t,i){return new Verification(this,e,t,i.toLowerCase())},Sinch.prototype.startActiveConnection=function(){if(this._onlineCapability&&this.started)return this.log(new Notification(4,5,"Manually starting active connection")),this.mxp.init();if(!this._onlineCapability)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,'No online capability, can not start active connection. Set configuration option "supportActiveConnection" to "true" when instantiating the SinchClient');this._autoStartMxp=!0},Sinch.prototype.stopActiveConnection=function(){if(this._onlineCapability)return this.log(new Notification(4,5,"Manually closing active connection")),this.mxp.close();throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,'No online capability, can not start active connection. Set configuration option "supportActiveConnection" to "true" when instantiating the SinchClient')},Sinch.prototype.getVersion=function(){try{return SinchVersion.version[1]}catch(e){return"dev"}},Sinch.prototype.onnotification=function(e,t){};var SinchClient=Sinch;WRTC=WRTC||{};function Call(e,t,i){this.sinch=e,this.eventListeners=[],this.peerConnections={},this.callId=i||getUuid(),this.callDomain="None",this.callOutbound=void 0,this.fromId="",this.toId="",this.webRtcConfig={iceServers:[{urls:["stun:23.21.150.121","stun:stun.l.google.com:19302"]}]};var n=navigator.userAgent.match(/Chrom[e|ium]\/([0-9]+)\./),r=!!n&&parseInt(n[1],10),s=navigator.userAgent.match(/Firefox\/([0-9]+)\./),o=!!s&&parseInt(s[1],10);(r>=48||o>=42)&&(this.sinch.log(new Notification(0,1,"Chrome >= 48 or FF >= 42 detected, will generate certificate manually for better compatibility")),PeerConnection.generateCertificate({name:"ECDSA",namedCurve:"P-256"}).then(function(e){this.sinch.log(new Notification(0,1,"New certificate generated and configured!")),this.webRtcConfig.certificates=[e]}.bind(this))),this.outgoingStream=void 0,this.incomingStream=void 0,this.earlymedia=void 0,this.callState=CallState.INITIATING,this.callEndCause=CallEndCause.NONE,this.timeProgressing=null,this.timeEstablished=null,this.timeEnded=null,this.error=null,this.autoAnswer=!1,this.autoHangup=!1,this.videoSupport=t||!1,this.clientMap={},this.activeInstance=void 0,this.dataChannels={},this.proxyUrl=void 0,this.customHeaders=void 0,this.joinBuffer={};var a={onCallEnded:function(e){this.sinch.mxp.unsubscribe("signalPubNub")}.bind(this)};this.addEventListener(a);var c="web",l="0";try{c=getBrowserInfo().split("/")[0],l=getBrowserInfo().split("/")[1]}catch(e){}var h={onCallEnded:function(t){var i=t.getDetails();if(i.startedTime){var n={callId:t.callId,domain:t.callDomain,outbound:t.callOutbound,fromId:t.fromId,toId:t.toId,callTime:new Date(i.startedTime).toISOString(),duration:i.duration,setupDuration:(t.timeEstablished-t.timeProgressing)/1e3||0,result:t.callEndCause,deviceInformation:{ModelId:getPlatformInfo()||"unknown",OSName:c,OSVersion:l,SDKPlatform:"js",SDKPlatformVersion:e.getVersion()}};t.sinch.callReporting(n).fail(function(){console.error("Could not report call!")})}t.ffIceTimer&&clearInterval(t.ffIceTimer)}};this.addEventListener(h)}function CallDetails(e){this.endCause=e.endCause,this.endedTime=e.endedTime,this.error=e.error,this.establishedTime=e.establishedTime,this.startedTime=e.startedTime,this.duration=e.duration}function CallClient(e,t){if(!(e instanceof Sinch))throw new Error("CallClient can't be instantiated, use getCallClient in an SinchClient instance");var i=navigator.userAgent.toLowerCase();if(i.indexOf("msie")>-1||/Edge/.test(i))throw new Error("SinchClient can't be started with calling capability. Browser not supported.");this.sinch=e,this.eventListeners=[],this.callBuffert={},this.localMediaStream=void 0,this.incomingCallCustomStream=t,this.groupChannel=void 0}PeerConnection=window.RTCPeerConnection||window.mozRTCPeerConnection||window.webkitRTCPeerConnection||WRTC.RTCPeerConnection,SessionDescription=window.RTCSessionDescription||window.mozRTCSessionDescription||window.webkitRTCSessionDescription||WRTC.RTCSessionDescription,IceCandidate=window.RTCIceCandidate||window.mozRTCIceCandidate||WRTC.RTCIceCandidate,Call.prototype.addEventListener=function(e){this.eventListeners.push(e)},Call.prototype.removeEventListener=function(e){this.eventListeners.splice(this.eventListeners.indexOf(e),1)},Call.prototype.setStream=function(e){this.outgoingStream=e,this.execListener("onLocalStream",e)},Call.prototype.execListener=function(e,t){this.eventListeners.forEach(function(i){try{return i[e]&&i[e](this,t)}catch(t){var n=new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error executing listener: "+e,t);throw console.error(n),n}}.bind(this))},Call.prototype.setEndCause=function(e){this.callEndCause===CallEndCause.NONE&&(this.callEndCause=e)},Call.prototype.setParticipants=function(e,t){this.callOutbound=e==this.sinch.user.userId,this.toId=t,this.fromId=e},Call.prototype.progress=function(e){if(this.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainOther,ErrorCode.OtherOther,"Progress: Invalid call state for progressing",Call);this.sinch.log(new Notification(0,1,"Call changing state to PROGRESSING")),this.timeProgressing=new Date,this.callState=CallState.PROGRESSING,e&&this.execListener("onCallProgressing"),this.autoAnswer&&this.answer(),this.autoHangup&&this.hangup()},Call.prototype.establish=function(){this.callState==CallState.PROGRESSING?(this.sinch.log(new Notification(0,1,"Call changing state to ESTABLISHED")),this.cleanPeerConnections(!1),"connection"!=this.callDomain&&this.unmute(),this.timeEstablished=new Date,this.callState=CallState.ESTABLISHED,this.execListener("onCallEstablished")):console.log("Call state not in PROGRESSING, cant process second JOIN")},Call.prototype.mxpAck=function(e){if(this.sinch.log(new Notification(0,1,"Call ACK Received",e)),this.callState!=CallState.INITIATING&&this.callState!=CallState.PROGRESSING)throw new SinchError(ErrorDomain.ErrorDomainOther,ErrorCode.OtherOther,"Invalid call state for processing Ack",Call);this.clientMap[e.getSenderId()]=this.clientMap[e.getSenderId()]||e.getFrom(),this.processRTCAnswer(e).then(function(){"yes"===(e.decrypted.nvps||{}).earlymedia?(this.activeInstance=e.getSenderId(),this.progress(!1),this.establish(),this.earlymedia=!0):this.progress(!0),this.joinBuffer[e.getSenderId()]&&(this.sinch.log(new Notification(0,1,"Buffered JOIN was detected for this Ack, will immediatley process & remove.")),this.mxpJoin(this.joinBuffer[e.getSenderId()]),delete this.joinBuffer[e.getSenderId()])}.bind(this))},Call.prototype.processRTCAnswer=function(e){var t=Q.defer(),i=this.getPeerConnectionInstance(e.getSenderId());return i.setRelayUrl(this.relayUrl),null==i.offer?(this.sinch.log(new Notification(0,1,"Send deny to instance: "+i.offer)),this.sinch.mxp.callDeny(this,i.instanceId).fail(function(e){}),t.resolve()):this.callState!=CallState.ENDED&&"media"!=e.decrypted.bt&&null!=e.decrypted.bd?i.setRemoteDescription(new SessionDescription(JSON.parse(e.decrypted.bd))).then(function(){t.resolve()}.bind(this)):t.resolve(),t.promise},Call.prototype.sendCancel=function(e,t){setTimeout(function(){this.setEndCause(e),this.error=new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,t),this.sinch.mxp.callCancel(this).fail(function(e){throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error sending call Cancel")}),this.callFailure()}.bind(this),2e3)},Call.prototype.mxpPeerEventSdp=function(e){if(this.callState==CallState.INITIATING||this.callState==CallState.PROGRESSING)this.disableIce=!0,this.processRTCAnswer(e);else if(this.callState==CallState.ESTABLISHED){var t=JSON.parse(e.decrypted.bd),i=new SessionDescription(t),n=this.getPeerConnectionInstance(e.getSenderId());"offer"==t.type?(this.sinch.log(new Notification(0,3,"Got renegotiation SDP Offer",t)),n.setRemoteDescription(i).then(function(){this.sinch.log(new Notification(1,3,"Successfully configured SDP Offer.",t)),n.createAnswer().then(function(t){this.sinch.log(new Notification(2,3,"Successfully created SDP Answer.",t)),this.sinch.mxp.callTxPeerEventSDP(this,t,e.getSenderId()).fail(function(e){throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error sending SDP Answer")})}.bind(this)).fail(function(e){console.error("Major error in creating answer",e)})}.bind(this),function(e){throw this.sendCancel(CallEndCause.FAILURE,e),new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error setting remote SDP")}.bind(this))):"answer"==t.type&&(this.sinch.log(new Notification(0,2,"Got renegotiation SDP Answer",t)),n.setRemoteDescription(RTCdescription,function(){this.sinch.log(new Notification(1,2,"Configured incoming SDP Answer",t))}.bind(this),function(e){throw this.sendCancel(CallEndCause.FAILURE,e),new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error setting remote SDP")}))}},Call.prototype.mxpInjectIce=function(e){if(this.callState!=CallState.ENDED){this.sinch.log(new Notification(0,2,"Recieved ICE Candidate from B",e));var t=JSON.parse(e.decrypted.bd);t.candidate=t.cand||t.candidate,t.sdpMLineIndex=t.sdpMLI||t.sdpMLineIndex,this.getPeerConnectionInstance(e.getSenderId()).addRemoteIceCandidate(t)}},Call.prototype.mxpJoin=function(e){if(this.sinch.log(new Notification(0,1,"Call JOIN Received",e)),this.activeInstance&&this.activeInstance!=e.getSenderId())throw console.error("Can not process JOIN, call in session after previous JOIN"),new SinchError(ErrorDomain.ErrorDomainSession,ErrorCode.SessionActiveUserLimitReached,"Can not process JOIN, call in session after previous JOIN");var t=e.getSenderId();this.callState==CallState.INITIATING?(this.sinch.log(new Notification(0,1,"JOIN received before ACK. Will cache JOIN to process after ACK.")),this.joinBuffer[t]=e):Q.fcall(function(){var t=Q.defer(),i=this.getPeerConnectionInstance(e.getSenderId());return"sdp"===e.decrypted.bt&&e.decrypted.bd&&!i.hasRemoteDescription()?i.setRemoteDescription(new SessionDescription(JSON.parse(e.decrypted.bd))).then(function(){this.sinch.log(new Notification(1,2,"Configured incoming SDP Join",e.decrypted.bd)),t.resolve()}.bind(this)).fail(function(e){throw this.sendCancel(CallEndCause.FAILURE,e),new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error setting remote SDP")}):t.resolve(),t.promise}.bind(this)).then(function(){if(this.callState!=CallState.PROGRESSING&&!this.earlymedia)throw console.error("Can not process JOIN, call in unexpected state. Call state: "+this.getState()),new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Can not process JOIN, call in unexpected state.");this.activeInstance=e.getSenderId(),this.sinch.mxp.callJoined(this).then(function(){this.sinch.log(new Notification(0,1,"Successfully sent JOINED",this)),this.earlymedia||this.establish()}.bind(this)).fail(function(e){console.error("Unhandled error in call.mxpJoin.",e)})}.bind(this)).fail(function(e){console.error("Error processing JOIN",e)})},Call.prototype.mxpJoined=function(e){(this.sinch.log(new Notification(0,1,"Call JOINED Received",e)),this.callState==CallState.INITIATING||this.callState==CallState.PROGRESSING)?JSON.parse(e.decrypted.bd).fi!=this.sinch._sessionId+":"+this.sinch._subInstanceId?(this.setEndCause(CallEndCause.OTHER_DEVICE_ANSWERED),this.mxpHangup()):this.callState==CallState.PROGRESSING&&this.establish():console.log("Call state already ESTABLISHED (or ENDED), cant process second JOIN")},Call.prototype.mxpHangup=function(e){this.callState!=CallState.ENDED&&(this.sinch.log(new Notification(0,1,"Call HANGUP Received",e)),this.callState==CallState.ESTABLISHED?this.setEndCause(CallEndCause.HUNG_UP):this.setEndCause(CallEndCause.CANCELED),this.timeEnded=new Date,this.callState=CallState.ENDED,this.execListener("onCallEnded"),this.cleanPeerConnections(!0))},Call.prototype.cleanPeerConnections=function(e){for(var t in this.peerConnections)this.peerConnections[t]&&(e||t!=this.activeInstance)&&(this.peerConnections[t].close(),delete this.peerConnections[t])},Call.prototype.mxpDeny=function(e){if(this.callState!=CallState.ENDED){if(this.sinch.log(new Notification(0,1,"Call DENIED Received",e)),this.setEndCause(CallEndCause.DENIED),"error/json"==e.decrypted.bt){this.error=new SinchError(ErrorDomain.ErrorDomainApi,ErrorCode.ApiApiCallFailed,"");var t=JSON.parse(e.decrypted.bd);for(var i in t)this.error[i]=t[i];this.error.message=t.code+" "+t.reason,this.error.mxp=e.decrypted}this.callState==CallState.INITIATING?(this.autoHangup=!0,this.progress(!0)):"no"==(e.decrypted.nvps||{}).denyall?this.mxpHangup():this.hangup()}},Call.prototype.mxpCancel=function(e){if(this.callState!=CallState.ENDED){this.sinch.log(new Notification(0,1,"Call CANCEL Received",e)),this.timeEnded=new Date,this.callState=CallState.ENDED;Date.now();this.setEndCause(CallEndCause.CANCELED),this.execListener("onCallEnded"),this.cleanPeerConnections(!0)}},Call.prototype.mxpFail=function(e){if(this.sinch.log(new Notification(0,1,"Call FAILURE Received",e)),"message"==e.decrypted.bt)this.error=new SinchError(ErrorDomain.ErrorDomainApi,ErrorCode.ApiApiCallFailed,""),this.error.message=e.decrypted.bd,this.error.mxp=e.decrypted;else if("error/json"==e.decrypted.bt){this.error=new SinchError(ErrorDomain.ErrorDomainApi,ErrorCode.ApiApiCallFailed,"");var t=JSON.parse(e.decrypted.bd);for(var i in t)this.error[i]=t[i];this.error.message=t.code+" "+t.reason,this.error.mxp=e.decrypted}this.callFailure()},Call.prototype.callFailure=function(){this.timeEnded=new Date,this.callState=CallState.ENDED,this.setEndCause(CallEndCause.FAILURE),this.execListener("onCallEnded"),this.cleanPeerConnections(!0)},Call.prototype.addEventListenerPrototype=function(e){e.onOpen&&(this.onopen=e.onOpen),e.onClose&&(this.onclose=e.onClose),e.onMessage&&(this.onmessage=e.onMessage)},Call.prototype.setCallTimeouts=function(e,t){setTimeout(function(){this.pushService&&this.pushService.push(!0,this.callState)?this.progress(!0):this.callState==CallState.INITIATING&&(this.sinch.log(new Notification(0,1,"Call PROGRESSING timeout. Will hangup call.",this)),this.setEndCause(CallEndCause.TIMEOUT),this.hangup())}.bind(this),e),setTimeout(function(){this.callState==CallState.PROGRESSING&&(this.sinch.log(new Notification(0,1,"Call ESTABLISHED timeout. Will hangup call.",this)),this.setEndCause(CallEndCause.NO_ANSWER),this.hangup())}.bind(this),t)},Call.prototype.getCallObject=function(e,t){var i={cli:"",destination:{type:{pstn:"number",data:"username",conference:"username",connection:"username",sip:"username"}[t],endpoint:e},callId:this.callId,mediaChannels:["audio"],subinstanceId:this.sinch._subInstanceId,headers:{p2p:"yes"},domain:{pstn:"pstn",data:"data",conference:"conference",connection:"data",sip:"sip"}[t]};return this.sinch._supportVideo&&i.mediaChannels.push("video"),this.customHeaders&&(i.headers.ph=JSON.stringify(this.customHeaders)),"connection"==t&&(i.headers.nomedia=!0),i},Call.prototype.getPeerConnectionInstance=function(e){if(e&&this.peerConnections[""])return this.peerConnections[e]=this.peerConnections[""],delete this.peerConnections[""],this.peerConnections[e].updateInstanceId(e),this.peerConnections[e];var t=e||"";return this.peerConnections[t]||(this.peerConnections[t]=new PeerConnectionInstance(e,this.webRtcConfig,this.outgoingStream,this)),this.peerConnections[t]},Call.prototype.createInstances=function(e){if(!e)return null;for(var t={},i=0;i<e.length;++i)t[e[i].instanceId]={},t[e[i].instanceId].capabilities=e[i].capabilities;return t},Call.prototype.getPlaceCallResponse=function(e){return{body:e.body||e.Body,signalChannel:e.signalChannel||e.SignalChannel,instances:e.instances||e.Instances,encryptionKey:e.encryptionKey||e.EncryptionKey}},Call.prototype.placeCall=function(e,t){var i=Q.defer();this.callDomain=t,this.setParticipants(this.sinch.user.userId,e),this.setCallTimeouts(this.sinch._progressTimeout||TIMEOUT_CALLPROGRESSING,TIMEOUT_CALLESTABLISHED);var n=this.getCallObject(e,t);return this.peerConnection=this.getPeerConnectionInstance(null),this.peerConnection.createOffer({offerToReceiveAudio:!0,offerToReceiveVideo:this.videoSupport}).then(function(t){this.originalOffer=t,n.sdp=t,this.sinch.placeCall(n).then(function(t){var n=this.getPlaceCallResponse(t);this.sinch.log(new Notification(0,1,"Successfully initiated call, waiting for MXP signalling.",n)),this.instances=this.createInstances(n.instances),void 0!==n.signalChannel&&null!==n.signalChannel&&(this.clientMap.virtual={fs:n.signalChannel,fu:e}),this.sinch._supportManagedPush?(this.pushService=new PushService(this.sinch,this.instances,this.callId),this.pushService.push(!1,this.callState)):this.pushService=null,this.relayUrl=n.body.replace(/(\r\n|\n|\r)/gm,""),this.sinch.mxp.configureMxpSession(this.callId,n.encryptionKey,n.body),i.resolve()}.bind(this)).fail(function(e){this.error=new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,JSON.parse(e.response).message),this.callFailure(),i.reject(error)}.bind(this))}.bind(this),function(e){console.error("Failed to generate SDP Offer"),console.error(e)}),i.promise},Call.prototype.updateSdp=function(e){for(var t=e.split("\n"),i="",n=!1,r=!1,s=0;s<t.length;++s)t[s].length>0&&!t[s].startsWith("a=crypto:1")&&(i=i+t[s]+"\n"),t[s].length>0&&t[s].startsWith("a=mid:")&&(r=!0),t[s].length>0&&t[s].startsWith("a=group:BUNDLE")&&(n=!0);return n||(i+="a=group:BUNDLE audio\n"),r||(i+="a=mid:audio\n"),i},Call.prototype.ackIncomingCall=function(e){var t=Q.defer();this.sinch.log(new Notification(0,1,"Incoming call",this)),this.setCallTimeouts(TIMEOUT_CALLPROGRESSING,TIMEOUT_CALLESTABLISHED);var i=JSON.parse(e.decrypted.nvps.sdp);i.sdp=this.updateSdp(i.sdp),this.sinch.log(new Notification(0,1,"Received SDP offer from B",i));var n=new SessionDescription(i);return this.peerConnection=this.getPeerConnectionInstance(e.getSenderId()),this.peerConnection.setRelayUrl(e.decrypted.bd),this.peerConnection.setRemoteDescription(n).then(function(){this.sinch.log(new Notification(1,3,"Successfully configured sdp offer.",i)),this.peerConnection.createAnswer().then(function(t){this.progress(!1),this.sinch.log(new Notification(2,3,"Header detected, p2p, will proceed with direct peer connection!.",e)),this.sinch.mxp.sendSdpAnswer(this,t).fail(function(e){throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error sending SDP Answer")})}.bind(this),function(e){console.error("Major error in creating answer",e)})}.bind(this),function(e){throw this.sendCancel(CallEndCause.FAILURE,e),new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error setting remote SDP")}.bind(this)),t.promise},Call.prototype.answer=function(){if(this.sinch.log(new Notification(0,1,"Answer call initiated, to answer()",this)),this.callState==CallState.PROGRESSING)this.mediaObj?this.sinch.postMedia(this.mediaObj).then(function(e){var t="audio:ISAC/0.0.0.0/"+e.proxyid+"/"+e.ip+":"+e.port;this.sinch.mxp.joinIncomingCall(this,t).then(function(){this.sinch.log(new Notification(3,3,"Successfully sent updated proxy information in Ack to caller",t))}.bind(this)).fail(function(e){throw console.error(e),new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Could not send Ack to Old with MEDIA answer")})}.bind(this)).fail(function(e){throw console.error(e),new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Could not send Answer to v1/media")}):this.sinch.mxp.joinIncomingCall(this).fail(function(e){throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error sending JOIN (pickup phone).")});else if("undefined"==typeof outgoingStream)this.sinch.log(new Notification(0,1,"Outgoing stream undefined, perhaps early answer. Will set auto answer for future automatic answer.")),this.autoAnswer=!0;else{if(this.callState==CallState.ENDED||this.callState==CallState.ESTABLISHED)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Call in invalid state to answer.");this.sinch.log(new Notification(0,1,"Stream defined and state in initializing or progressing. Setting auto answer for later retry.")),this.autoAnswer=!0}},Call.prototype.openDataChannel=function(e){return void 0===this.dataChannels[e]&&(this.dataChannels[e]=this.getPeerConnectionInstance(this.activeInstance).createDataChannel(e,{reliable:!1}),this.dataChannels[e].addEventListener=this.addEventListenerPrototype.bind(this.dataChannels[e]),this.execListener("onDataChannelAdded",this.dataChannels[e])),this.dataChannels[e]},Call.prototype.hangup=function(){if(this.hangupRetries=(this.hangupRetries||0)+1,this.callState==CallState.ESTABLISHED)this.sinch.mxp.callHangup(this).fail(function(e){throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error sending call Hangup")}),this.mxpHangup();else if(!this.callOutbound||this.callState!=CallState.PROGRESSING&&this.callState!=CallState.INITIATING)if(this.callOutbound||this.callState!=CallState.PROGRESSING&&this.callState!=CallState.INITIATING){if(this.callState==CallState.ENDED)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Call already ended");this.mxpHangup()}else this.callState==CallState.PROGRESSING?(this.sinch.mxp.callDeny(this).fail(function(e){throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error sending call Deny")}),this.setEndCause(CallEndCause.DENIED),this.mxpHangup()):this.autoHangup=!0;else Object.keys(this.clientMap).length>0||this.hangupRetries>5?(this.sinch.mxp.callCancel(this).fail(function(e){throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error sending call Cancel")}),this.mxpHangup()):(this.sinch.log(new Notification(0,1,"Can not hang up call at this time. Will try again in 0.5 seconds (max five retries).")),setTimeout(this.hangup.bind(this),500))},Call.prototype.getCallId=function(){return this.callId},Call.prototype.getDetails=function(){return new CallDetails({endCause:this.callEndCause,endedTime:this.timeEnded,error:this.error,establishedTime:this.timeEstablished,startedTime:this.timeProgressing,duration:this.timeEstablished?(this.timeEnded-this.timeEstablished)/1e3:0})},Call.prototype.getDirection=function(){return this.callOutbound?1:0},Call.prototype.getRemoteUserId=function(){return this.getDirection()?this.toId:this.fromId},Call.prototype.getState=function(){return Object.keys(CallState).filter(function(e){return CallState[e]===this.callState}.bind(this))[0]},Call.prototype.getEndCause=function(){return Object.keys(CallEndCause).filter(function(e){return CallEndCause[e]===this.callEndCause}.bind(this))[0]},Call.prototype.getHeaders=function(){return this.customHeaders},Call.prototype.sendDTMF=function(e){if(this.activeInstance&&!this.DTMFsender){var t=this.getPeerConnectionInstance(this.activeInstance);t.getSenders?this.DTMFsender=t.getSenders()[0].dtmf:(console.warn("Your browser doesn't support DTMF tone building"),this.DTMFsender=t.createDTMFSender(this.outgoingStream.getAudioTracks()[0]))}return this.DTMFsender&&this.DTMFsender.insertDTMF(e)},Call.prototype.mute=function(){if(this.callState!=CallState.ESTABLISHED&&this.callState!=CallState.PROGRESSING&&this.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Call not in ESTABLISHED state.");this.sinch.log(new Notification(0,1,"Call was muted using mute()."));for(var e=this.outgoingStream.getAudioTracks(),t=0;t<e.length;t++)e[t].enabled=!1},Call.prototype.unmute=function(){if(this.callState!=CallState.ESTABLISHED&&this.callState!=CallState.PROGRESSING&&this.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Call not in ESTABLISHED state.");this.sinch.log(new Notification(0,1,"Call was un-muted using unmute()."));for(var e=this.outgoingStream.getAudioTracks(),t=0;t<e.length;t++)e[t].enabled=!0},navigator.mediaDevices&&(navigator.mediaDevices.getUserMedia=navigator.mediaDevices.getUserMedia||navigator.getUserMedia||navigator.mozGetUserMedia||navigator.webkitGetUserMedia),CallClient.prototype.addEventListener=function(e){this.eventListeners.push(e)},CallClient.prototype.removeEventListener=function(e){this.eventListeners.splice(this.eventListeners.indexOf(e),1)},CallClient.prototype.execListener=function(e,t){var i=0;return this.eventListeners.forEach(function(n){return i++,n[e]&&n[e](t)}.bind(this)),i},CallClient.prototype.initStream=function(e,t){var i=Q.defer(),n=!(!this.sinch._supportVideo||t)&&{mandatory:{maxWidth:320,maxHeight:240}};return void 0!==e?(this.sinch.log(new Notification(0,1,"Will wire customStream into call",e)),i.resolve(e)):void 0===this.localMediaStream?(this.sinch.log(new Notification(0,1,"Will retrieve new Mic for stream")),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia({video:n,audio:!0}).then(function(e){this.localMediaStream=e,i.resolve(this.localMediaStream)}).catch(function(e){console.error("Error retrieving media stream",e)})):(this.sinch.log(new Notification(0,1,"Will retrieve cached Mic for stream",this.localMediaStream)),i.resolve(this.localMediaStream)),i.promise},CallClient.prototype.alreadyInCall=function(){if(this.sinch._multiCall)return!1;for(var e in this.callBuffert)if(this.callBuffert[e].callState==CallState.PROGRESSING||this.callBuffert[e].callState==CallState.ESTABLISHED)return!0},CallClient.prototype.handleIncomingCall=function(e){this.sinch.log(new Notification(0,1,"Will handle incoming call",e));var t,i=new Call(this.sinch,this.sinch._supportVideo,e.mxpSessionId);(e.decrypted.nvps||{}).nomedia?i.callDomain="connection":i.callDomain="data",i.setParticipants(e.decrypted.fu,this.sinch.user.userId),i.customHeaders=JSON.parse((e.decrypted.nvps||{}).ph||"{}"),this.sinch.mxp.configureMxpSession(i.callId,e.decrypted.nvps.key,e.decrypted.bd),i.clientMap[e.getSenderId()]=e.getFrom(),this.callBuffert[i.callId]=i,this.alreadyInCall()?(this.sinch.log(new Notification(0,1,"Already in a call, will hangup incoming call.",e)),this.sinch.mxp.subscribe("signalPubNub").then(function(){this.sinch.mxp.callDeny(i)}.bind(this))):this.execListener("onIncomingCall",i)?("connection"==i.callDomain?(t=Q.defer(),t.resolve(null),t.promise):this.initStream(this.incomingCallCustomStream)).then(function(t){return this.execListener("onMediaStream",t),this.sinch.mxp.subscribe("signalPubNub").then(function(){(e.decrypted.nvps||{}).nomedia||i.setStream(t),i.activeInstance=e.getSenderId(),i.proxyUrl=e.decrypted.bd.replace(/(\r\n|\n|\r)/gm,""),i.ackIncomingCall(e).catch(function(e){console.error("Error handling incoming call",e)})}.bind(this))}.bind(this)):this.sinch.log(new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKMissingCallback,"Missing handler, onIncomingCall."))},CallClient.prototype.callUser=function(e,t,i){this.sinch.log(new Notification(0,1,"CallUser method called",e));var n=new Call(this.sinch,this.sinch._supportVideo);return n.customHeaders=t,this.initStream(i).then(function(t){return this.sinch.mxp.subscribe("signalPubNub").then(function(){if(n.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error executing user call. Incorrect call state.");n.setStream(t),n.placeCall(e,"data"),this.callBuffert[n.callId]=n}.bind(this))}.bind(this)),n},CallClient.prototype.callSip=function(e,t,i){this.sinch.log(new Notification(0,1,"CallSip method called",e));var n=new Call(this.sinch);return n.customHeaders=t,this.initStream(i).then(function(t){return this.sinch.mxp.subscribe("signalPubNub").then(function(){if(n.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error executing user call. Incorrect call state.");n.setStream(t),n.placeCall(e,"sip"),this.callBuffert[n.callId]=n}.bind(this))}.bind(this)),n},CallClient.prototype.connect=function(e,t){this.sinch.log(new Notification(0,1,"connect method called",e));var i=new Call(this.sinch);return i.customHeaders=t,this.sinch.mxp.subscribe("signalPubNub").then(function(){if(i.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error executing connect. Incorrect call state.");i.placeCall(e,"connection"),this.callBuffert[i.callId]=i}.bind(this)),i},CallClient.prototype.callPhoneNumber=function(e,t,i){this.sinch.log(new Notification(0,1,"CallPhoneNumber method called",e));var n=new Call(this.sinch);return n.customHeaders=t,this.initStream(i,!0).then(function(t){return this.sinch.mxp.subscribe("signalPubNub").then(function(){if(n.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error executing user call. Incorrect call state.");n.setStream(t),n.placeCall(e,"pstn"),this.callBuffert[n.callId]=n}.bind(this))}.bind(this)),n},CallClient.prototype.callConference=function(e,t,i){if(this.sinch.log(new Notification(0,1,"CallConference method called",e)),!(e=""+e)||e.length>64)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKMissingParameter,"Invalid conferenceId. Must be alphanumeric string less than 64 characters in length.");var n=new Call(this.sinch);return n.customHeaders=t,this.initStream(i,!0).then(function(t){return this.sinch.mxp.subscribe("signalPubNub").then(function(){if(n.callState!=CallState.INITIATING)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Error executing user call. Incorrect call state.");n.setStream(t),n.placeCall(e,"conference"),this.callBuffert[n.callId]=n}.bind(this))}.bind(this)),n},CallClient.prototype.callGroup=function(e){if(this.sinch.log(new Notification(0,1,"callRoom method called, for group",e)),void 0!==this.groupChannel)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Can not call room, already in a room");if(!this.sinch._multiCall)throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKInternalOther,"Can not call room, multiCall capability not specified");return this.groupChannel=e,new GroupCall(this.sinch,e)};var PeerConnection,SessionDescription,IceCandidate,CallState={INITIATING:0,PROGRESSING:1,ESTABLISHED:2,ENDED:3,TRANSFERRING:4},CallEndCause={NONE:0,TIMEOUT:1,CANCELED:6,DENIED:2,FAILURE:4,HUNG_UP:5,NO_ANSWER:3,OTHER_DEVICE_ANSWERED:7,TIMEOUT:1,TRANSFERRED:8},TIMEOUT_CALLPROGRESSING=10500,TIMEOUT_CALLESTABLISHED=45e3,CallHelper=function(){};function CalloutVerification(e,t,i){if(!(e instanceof Sinch))throw new SinchError(ErrorDomain.ErrorDomainVerification,ErrorCode.VerificationInvalidInput,"Invalid input to constructor. VerificationClient can not be instantiated, use createSmsVerification in an SinchClient instance",error);if(void 0===t||0==t.toString().length)throw new SinchError(ErrorDomain.ErrorDomainVerification,ErrorCode.VerificationInvalidInput,"Invalid input to constructor. Valid phone number required (E.164 format ideally)",t);this.sinch=e,this.number=t||null,this.custom=i||null,this.flagVerified=!1}function FlashCallVerification(e,t,i){if(!(e instanceof Sinch))throw new SinchError(ErrorDomain.ErrorDomainVerification,ErrorCode.VerificationInvalidInput,"Invalid input to constructor. VerificationClient can not be instantiated, use createSmsVerification in an SinchClient instance",error);if(void 0===t||0==t.toString().length)throw new SinchError(ErrorDomain.ErrorDomainVerification,ErrorCode.VerificationInvalidInput,"Invalid input to constructor. Valid phone number required (E.164 format ideally)",t);this.sinch=e,this.number=t||null,this.custom=i||null,this.flagVerified=!1}function GroupCall(e,t){this.sinch=e,this.callClient=e.callClient,this.groupChannel=t,this.eventListeners=[],this.callBuffert=[],this.callListeners={onCallProgressing:function(e){this.sinch.log(new Notification(0,1,"Call progressing",e))}.bind(this),onCallEstablished:function(e){this.sinch.log(new Notification(0,1,"Call established",e)),this.execListener("onGroupRemoteCallAdded",e)}.bind(this),onCallEnded:function(e){this.sinch.log(new Notification(0,1,"Call ended",e)),this.execListener("onGroupRemoteCallRemoved",e)}.bind(this)},this.groupListener={onIncomingCall:function(e){e.addEventListener(this.callListeners),setTimeout(function(){e.answer()},450*Object.keys(this.callBuffert).length+Math.random())}.bind(this)},this.callClient.addEventListener(this.groupListener),this.sinch.callClient.initStream().then(function(e){this.sinch.log(new Notification(0,1,"Media stream successfully created",e)),this.execListener("onGroupLocalMediaAdded",e),this.sinch.mxp.broadcastPubNub.publish({channel:t,message:this.sinch.user.userId}),this.sinch.mxp.subscribeNotificationChannel(t)}.bind(this)),this.sinch.onnotification=function(e,i){t==e&&i!=this.sinch.user.userId&&(this.sinch.log(new Notification(0,1,"Will call user in group, after random timeout",i)),setTimeout(function(){var e=this.callClient.callUser(i);this.callBuffert.push(e),e.addEventListener(this.callListeners)}.bind(this),300+Math.round(500*Math.random())))}.bind(this)}function Message(e,t){if(this.delivered=[],this.direction=!t,e instanceof MXPMessageObj){this.messageId=e.mxpSessionId;var i=JSON.parse(e.decrypted.bd);this.textBody=i.t,this.recipientIds=e.recipientIds,this.senderId=e.decrypted.fu;try{this.headers=e.decrypted.nvps.ph}catch(e){}this.timestamp=new Date}else{if(!(e instanceof Object))throw new SinchError(ErrorDomain.ErrorDomainSDK,ErrorCode.SDKMissingParameter,"Unsupported message parameters",e);this.messageId=getUuid(),this.recipientIds=e.recipientIds,this.textBody=e.textBody,this.senderId=e.senderId,this.headers=e.publicHeaders,this.timestamp=new Date}}function MessageDeliveryInfo(e,t){this.messageId=t,this.recipientId=e,this.timestamp=new Date}function MessageClient(e){if(!(e instanceof Sinch))throw new Error("MessageClient can't be instantiated, use getMessageClient in an SinchClient instance");this.sinch=e,this.eventListeners=[],this.messageBuffert={},this.ackBuffert={},this.onMessageDelivered=[],this.emptyLog(),this.messageLogInterval=setInterval(this.commitLog.bind(this),3e4)}CallHelper.generateIceCandidate=function(e,t){return"candidate:"+(""+Math.random()).substring(2,7)+" 1 UDP 2130706431 "+e+" "+t+" typ relay raddr 0.0.0.0 rport 0 generation 0\r\n"},CallHelper.generateRelayCandidate=function(e,t,i){var n=e.candidate.split(" ");return-1!=n.indexOf("srflx")&&"udp"==n[2].toLowerCase()?new IceCandidate({candidate:["candidate:"+(""+Math.random()).substring(2,7),n[1],n[2].toUpperCase(),Math.round(n[3]/10),t,i,"typ","relay","raddr",n[4],"rport",n[5],"generation",0].join(" "),sdpMLineIndex:"number"==typeof e.sdpMLI?e.sdpMLI:e.sdpMLineIndex||0,sdpMid:e.sdpMid}):null},CalloutVerification.prototype.initiate=function(e,t){var i=Q.defer();if(this.flagVerified){var n=new SinchError(ErrorDomain.ErrorDomainVerification,ErrorCode.VerificationUnexpectedInitiateError,"Verification already verified, can't perform another callout.");i.reject(n)}else{var r={identity:{type:"number",endpoint:this.number},custom:this.custom,method:"callout",metadata:{os:getBrowserInfo(),platform:getPlatformInfo(),sdk:"js/"+this.sinch.getVersion()}};this.sinch.log(new Notification(0,1,"Will initiate callout verification using object",r)),this.sinch.confirmUserCallout(r).then(function(n){var r=this;r.sinch.log(new Notification(0,1,"Successfully initiated callout verification with response",n));var s=0,o=function(){r.sinch.queryVerificationById({number:r.number}).then(function(a){switch(r.sinch.log(new Notification(0,1,"Poll result after "+s+"s",a)),a.status){case"SUCCESSFUL":r.sinch.log(new Notification(0,1,"Successfully verified number after "+s+"s")),e&&e(),i.resolve();break;case"PENDING":if(s+=n.callout.pollingInterval,n.callout.pollingInterval>0&&s<n.callout.stopPollingAfter)window.setTimeout(o,1e3*n.callout.pollingInterval);else{var c=new SinchError(ErrorDomain.ErrorDomainVerification,ErrorCode.Verif