From 7095b97ef8fa95fba42e824fd13fa4d10972fce9 Mon Sep 17 00:00:00 2001 From: yuyujulin Date: Mon, 2 Sep 2024 22:30:17 +0800 Subject: [PATCH] test --- examples/2.click_to_call_phone/config.js | 5 + examples/2.click_to_call_phone/favicon.png | Bin 0 -> 3930 bytes examples/2.click_to_call_phone/phone.css | 15 + examples/2.click_to_call_phone/phone.html | 70 + examples/2.click_to_call_phone/phone.js | 226 + examples/2.click_to_call_phone/usage_1.html | 20 + examples/2.click_to_call_phone/usage_2.html | 59 + examples/2.click_to_call_phone/usage_3.html | 149 + examples/4.phone_prototype/config.js | 141 + examples/4.phone_prototype/images/favicon.png | Bin 0 -> 3930 bytes .../4.phone_prototype/images/in_green.png | Bin 0 -> 668 bytes examples/4.phone_prototype/images/in_red.png | Bin 0 -> 616 bytes .../4.phone_prototype/images/old-phone.jpg | Bin 0 -> 27521 bytes .../4.phone_prototype/images/out_green.png | Bin 0 -> 644 bytes examples/4.phone_prototype/images/out_red.png | Bin 0 -> 568 bytes examples/4.phone_prototype/index.html | 307 + examples/4.phone_prototype/phone.css | 130 + examples/4.phone_prototype/phone.js | 2859 ++ examples/4.phone_prototype/sounds/bell.mp3 | Bin 0 -> 16741 bytes examples/4.phone_prototype/sounds/ring1.mp3 | Bin 0 -> 737304 bytes examples/4.phone_prototype/sounds/ring2.mp3 | Bin 0 -> 77323 bytes examples/favicon.png | Bin 0 -> 5018 bytes examples/service-worker.js | 31 + examples/tutorial.html | 3550 +++ js/LICENSE | 51 + js/ac_webrtc.min.js | 16 + js/ac_webrtc_and_utils_es5.min.js | 16 + js/acapi.1.19.0.js | 2517 ++ js/acapi.1.19.0_es5.js | 2884 ++ js/citrix_ac_webrtc.min.js | 16 + js/jssip.js | 25822 ++++++++++++++++ js/tracer.js | 204 + js/utils.js | 1930 ++ js/utils_es5.js | 2455 ++ 34 files changed, 43473 insertions(+) create mode 100644 examples/2.click_to_call_phone/config.js create mode 100644 examples/2.click_to_call_phone/favicon.png create mode 100644 examples/2.click_to_call_phone/phone.css create mode 100644 examples/2.click_to_call_phone/phone.html create mode 100644 examples/2.click_to_call_phone/phone.js create mode 100644 examples/2.click_to_call_phone/usage_1.html create mode 100644 examples/2.click_to_call_phone/usage_2.html create mode 100644 examples/2.click_to_call_phone/usage_3.html create mode 100644 examples/4.phone_prototype/config.js create mode 100644 examples/4.phone_prototype/images/favicon.png create mode 100644 examples/4.phone_prototype/images/in_green.png create mode 100644 examples/4.phone_prototype/images/in_red.png create mode 100644 examples/4.phone_prototype/images/old-phone.jpg create mode 100644 examples/4.phone_prototype/images/out_green.png create mode 100644 examples/4.phone_prototype/images/out_red.png create mode 100644 examples/4.phone_prototype/index.html create mode 100644 examples/4.phone_prototype/phone.css create mode 100644 examples/4.phone_prototype/phone.js create mode 100644 examples/4.phone_prototype/sounds/bell.mp3 create mode 100644 examples/4.phone_prototype/sounds/ring1.mp3 create mode 100644 examples/4.phone_prototype/sounds/ring2.mp3 create mode 100644 examples/favicon.png create mode 100644 examples/service-worker.js create mode 100644 examples/tutorial.html create mode 100644 js/LICENSE create mode 100644 js/ac_webrtc.min.js create mode 100644 js/ac_webrtc_and_utils_es5.min.js create mode 100644 js/acapi.1.19.0.js create mode 100644 js/acapi.1.19.0_es5.js create mode 100644 js/citrix_ac_webrtc.min.js create mode 100644 js/jssip.js create mode 100644 js/tracer.js create mode 100644 js/utils.js create mode 100644 js/utils_es5.js diff --git a/examples/2.click_to_call_phone/config.js b/examples/2.click_to_call_phone/config.js new file mode 100644 index 0000000..ad05b7e --- /dev/null +++ b/examples/2.click_to_call_phone/config.js @@ -0,0 +1,5 @@ +let serverConfig = { + domain: 'audiocodes.com', + addresses: ['wss://webrtclab.audiocodes.com'], + iceServers: ['74.125.140.127:19302', '74.125.143.127:19302'] +} \ No newline at end of file diff --git a/examples/2.click_to_call_phone/favicon.png b/examples/2.click_to_call_phone/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..58842a70e8bc582976157d33a3385bd7aef41ef7 GIT binary patch literal 3930 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 literal 0 HcmV?d00001 diff --git a/examples/2.click_to_call_phone/phone.css b/examples/2.click_to_call_phone/phone.css new file mode 100644 index 0000000..52deafa --- /dev/null +++ b/examples/2.click_to_call_phone/phone.css @@ -0,0 +1,15 @@ + #panels { + max-width: 500px; + } + + .panel, + #local_video, + #remote_video { + display: none; + } + + #hangup_btn, + #cancel_outgoing_call_btn { + background-color: lightpink; + border-color: lightpink; + } \ No newline at end of file diff --git a/examples/2.click_to_call_phone/phone.html b/examples/2.click_to_call_phone/phone.html new file mode 100644 index 0000000..d37c5a0 --- /dev/null +++ b/examples/2.click_to_call_phone/phone.html @@ -0,0 +1,70 @@ + + + + + + Click to call + + + + + + + + + + + + + + +
+
+ + +
+
+

Thank you

+
+
+
+ calling +

+

+
+ +
+
+ +
+
+
+ open call +

+
+ +
+ +
+
+
+
+
+ +
+ + +
+ + + \ No newline at end of file diff --git a/examples/2.click_to_call_phone/phone.js b/examples/2.click_to_call_phone/phone.js new file mode 100644 index 0000000..23172a0 --- /dev/null +++ b/examples/2.click_to_call_phone/phone.js @@ -0,0 +1,226 @@ +'use strict'; + +/* + Tutorial + Simple click-to-Call phone + + URL parameters: + 'call' call to user name (or phone number). Must be set. + 'caller' caller user name. Optional (default 'Anonymous') + 'callerDN' caller display name. Optional (default 'Anonymous') + 'server' Optional. Replace default SBC server address (from config.js) to the parameter value. + */ + +let phone = new AudioCodesUA(); // phone API +let activeCall = null; // not null, if exists active call +let callTo; // call to user + +// Run when document is ready +function documentIsReady() { + phone.setAcLogger(ac_log); + phone.setJsSipLogger(console.log); + + ac_log(`------ Date: ${new Date().toDateString()} -------`); + ac_log(`AudioCodes WebRTC SDK. Simple click-to-call`); + ac_log(`SDK: ${phone.version()}`); + ac_log(`SIP: ${JsSIP.C.USER_AGENT}`); + ac_log(`Browser: ${phone.getBrowserName()} Internal name: ${phone.getBrowser()}`); + + // Check WebRTC support. + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + let noWebRTC = 'WebRTC API is not supported in this browser !'; + guiError(noWebRTC); + ac_log(noWebRTC); + return; + } + + // Get call parameters from URL + callTo = getParameter('call'); + if (callTo === null) { + let missedCallParameter = 'Missed "call" parameter in URL'; + guiError(missedCallParameter); + ac_log(missedCallParameter); + return; + } + + // For testing. Replace default SBC address to some other. + let server = getParameter('server', null); + if (server !== null) { + serverConfig.addresses = [server]; + } + + guiInit(); + + // Check devices: microphone must exists, camera is optional + // Note: the method implementation moved to phone API. + phone.checkAvailableDevices() + .then(() => { + let caller = getParameter('caller', 'Anonymous'); + let callerDN = getParameter('callerDN', 'Anonymous'); + initSipStack({ user: caller, displayName: callerDN, password: '' }); + }) + .catch((e) => { + ac_log('error', e); + guiError(e); + }) +} + +function ac_log() { + let args = [].slice.call(arguments) + console.log.apply(console, ['%c' + args[0]].concat(['color: BlueViolet;'], args.slice(1))); +} + +function getParameter(name, defValue = null) { + let s = window.location.search.split('&' + name + '=')[1]; + if (!s) s = window.location.search.split('?' + name + '=')[1]; + return s !== undefined ? decodeURIComponent(s.split('&')[0]) : defValue; +} + +function initSipStack(account) { + phone.setServerConfig(serverConfig.addresses, serverConfig.domain, serverConfig.iceServers); + phone.setAccount(account.user, account.displayName, account.password); + + // Set phone API listeners + phone.setListeners({ + loginStateChanged: function (isLogin, cause) { + switch (cause) { + case "connected": + ac_log('phone>>> loginStateChanged: connected'); + guiMakeCall(callTo); + break; + case "disconnected": + ac_log('phone>>> loginStateChanged: disconnected'); + if (phone.isInitialized()) // after deinit() phone will disconnect SBC. + guiError('Cannot connect to SBC server'); + break; + case "login failed": + ac_log('phone>>> loginStateChanged: login failed'); + break; + case "login": + ac_log('phone>>> loginStateChanged: login'); + break; + case "logout": + ac_log('phone>>> loginStateChanged: logout'); + break; + } + }, + + outgoingCallProgress: function (call, response) { + ac_log('phone>>> outgoing call progress'); + document.getElementById('outgoing_call_progress').innerText = 'dzzz dzzz'; + }, + + callTerminated: function (call, message, cause, redirectTo) { + ac_log(`phone>>> call terminated callback, cause=${cause}`); + if (call !== activeCall) { + ac_log('terminated no active call'); + return; + } + activeCall = null; + guiWarning('Call terminated: ' + cause); + phone.deinit(); // Disconnect from SBC server. + guiShowPanel('call_terminated_panel'); + }, + + callConfirmed: function (call, message, cause) { + ac_log('phone>>> callConfirmed'); + guiInfo(''); + let remoteVideo = document.getElementById('remote_video'); + let vs = remoteVideo.style; + vs.display = 'block'; + vs.width = vs.height = call.hasReceiveVideo() ? 'auto' : 0; + guiShowPanel('call_established_panel'); + }, + + callShowStreams: function (call, localStream, remoteStream) { + ac_log('phone>>> callShowStreams'); + let remoteVideo = document.getElementById('remote_video'); + remoteVideo.srcObject = remoteStream; // to play audio and optional video + }, + + incomingCall: function (call, invite) { + ac_log('phone>>> incomingCall'); + call.reject(); + }, + + callHoldStateChanged: function (call, isHold, isRemote) { + ac_log('phone>>> callHoldStateChanged ' + isHold ? 'hold' : 'unhold'); + } + }); + + guiInfo('Connecting...'); + phone.init(false); +} + +function onBeforeUnload() { + phone !== null && phone.isInitialized() && phone.deinit(); +} + +function guiInit() { + window.addEventListener('beforeunload', onBeforeUnload); + document.getElementById('cancel_outgoing_call_btn').onclick = guiHangup; + document.getElementById('hangup_btn').onclick = guiHangup; + document.getElementById('mute_audio_btn').onclick = guiMuteAudio; +} + +function guiMakeCall(callTo) { + if (activeCall !== null) + throw 'Already exists active call'; + document.getElementById('outgoing_call_user').innerText = callTo; + document.getElementById('outgoing_call_progress').innerText = ''; + document.getElementById('call_established_user').innerText = callTo; + guiInfo(''); + guiShowPanel('outgoing_call_panel'); + activeCall = phone.call(phone.AUDIO, callTo); // Note: Can be used audio or video call. +} + +function guiHangup() { + if (activeCall !== null) { + activeCall.terminate(); + activeCall = null; + } +} + +function guiMuteAudio() { + let muted = activeCall.isAudioMuted(); + activeCall.muteAudio(!muted); + document.getElementById('mute_audio_btn').value = !muted ? 'Unmute' : 'Mute'; +} + +//--------------- Status line ------- +function guiError(text) { guiStatus(text, 'Pink'); } + +function guiWarning(text) { guiStatus(text, 'Gold'); } + +function guiInfo(text) { guiStatus(text, 'Aquamarine'); } + +function guiStatus(text, color) { + let line = document.getElementById('status_line'); + line.setAttribute('style', `background-color: ${color}`); + line.innerHTML = text; +} +//--------------- Show or hide element ------- +function guiShow(id) { + document.getElementById(id).style.display = 'block'; +} + +function guiHide(id) { + document.getElementById(id).style.display = 'none'; +} + +function guiIsHidden(id) { + let elem = document.getElementById(id); + let display = window.getComputedStyle(elem).getPropertyValue('display'); + return display === 'none'; +} + +function guiShowPanel(activePanel) { + const panels = ['call_terminated_panel', 'outgoing_call_panel', 'call_established_panel']; + for (let panel of panels) { + if (panel === activePanel) { + guiShow(panel); + } else { + guiHide(panel); + } + } +} \ No newline at end of file diff --git a/examples/2.click_to_call_phone/usage_1.html b/examples/2.click_to_call_phone/usage_1.html new file mode 100644 index 0000000..72863cc --- /dev/null +++ b/examples/2.click_to_call_phone/usage_1.html @@ -0,0 +1,20 @@ + + + + + + + + + + Click to call SantaClaus + + \ No newline at end of file diff --git a/examples/2.click_to_call_phone/usage_2.html b/examples/2.click_to_call_phone/usage_2.html new file mode 100644 index 0000000..1684cdb --- /dev/null +++ b/examples/2.click_to_call_phone/usage_2.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + +
+
+ +
+ Server: +

Call to:
+
+ +
+ + + \ No newline at end of file diff --git a/examples/2.click_to_call_phone/usage_3.html b/examples/2.click_to_call_phone/usage_3.html new file mode 100644 index 0000000..e3c5932 --- /dev/null +++ b/examples/2.click_to_call_phone/usage_3.html @@ -0,0 +1,149 @@ + + + + + + + + + + + + + +
+
+ +
+
+
+ + + + \ No newline at end of file diff --git a/examples/4.phone_prototype/config.js b/examples/4.phone_prototype/config.js new file mode 100644 index 0000000..3836379 --- /dev/null +++ b/examples/4.phone_prototype/config.js @@ -0,0 +1,141 @@ +let DefaultServerConfig = { + domain: 'southtestwebrtc.aicccloud.com', + addresses: ['wss://southtestwebrtc.aicccloud.com:65061'], + iceServers: [], + version: '9-May-2022' +} + +let DefaultPhoneConfig = { + reconnectIntervalMin: 2, // Minimum interval between WebSocket reconnection attempts. (seconds) + reconnectIntervalMax: 30, // Maximum interval between WebSocket reconnection attempts (seconds) + registerExpires: 600, // SIP registration expiry time (seconds) + useSessionTimer: false, // Enable Session Timers (as per RFC 4028) + pingInterval: 20, // Keep alive ping interval, 0 value means don't send pings. (seconds) + pongTimeout: true, // Close and reopen websocket when pong timeout detected + timerThrottlingBestEffort: true, // Action if timer throttling detected (for Chrome increase ping interval) + pongReport: 1, // if 0 not print, otherwise each N pongs print min and max pong delay + pongDist: true, // Print to console log also pong delay distribution. + keepAliveBeep: 0, // To prevent intensive timer throttling in Chrome play periodically beeps. + restoreCall: true, // Restore call if HTML page was reloaded during call. + restoreServer: true, // After page reload arise priority of previously connected SBC + restoreCallMaxDelay: 20, // Maximum interval to restore call (seconds) + dtmfUseWebRTC: true, // Send DTMF using RTP as per RFC2833 (otherwise use SIP INFO) + dtmfDuration: null, // Duration of the DTMF tone (milliseconds) Default is 250 + dtmfInterToneGap: null, // Interval between two DTMF tones (milliseconds) Default is 250 + avoidTwoWayHold: true, // If call in remote hold, disable local hold button to avoid 2 way holds. + enableAddVideo: true, // Enable to call remote side to add video stream. + addLoggerTimestamp: true, // Always add timestamp string to log. + useWebrtcTracer: false, // Use advanced WebRTC methods logging tools. + audioAutoAnswerNoSdp: true, // Use audio for auto answer to incoming INVITE without SDP + switchSbcAtInvite5xx: true, // When outgoing call answer 5xx switch to alternative SBC and re-call. + networkPriority: undefined, // DSCP network priority: undefined (don't modify) or 'high', 'medium', 'low', 'very-low' + useServiceWorkerNotification: true, // Use service worker to incoming call notification (Chrome, Firefox) + // SDK modes and fixes. + modes: { + ice_timeout_fix: 2000, // ICE gathering timeout (milliseconds) + chrome_rtp_timeout_fix: 23, // Workaround of https://bugs.chromium.org/p/chromium/issues/detail?id=982793 + sbc_ha_pairs_mode: undefined, // After SBC disconnection try reconnect to the same URL. + ringing_header_mode: 'Allow-Events: talk,hold,conference' // Extra header(s) to response 180. // Only for multiple SBC HA pairs configuration. + }, + // Set browser constraints. + constraints: { + chrome: { audio: { echoCancellation: true } }, + firefox: { audio: { echoCancellation: true } }, + safari: { audio: { echoCancellation: true } }, + "safari|ios": { audio: { echoCancellation: true } } + }, + + /* Change codec priority. Remove codecs. + codecFilter: { + audio: { + remove: ['isac'], + priority: ['opus', 'pcma', 'pcmu'], + }, + video: { + priority: ['vp9', 'vp8'] + } + }, + */ + + version: '29-May-2022' +} + +let DefaultUserPref = { + hideLocalVideo: false, // when open remote video hide local video. + videoSize: 'Small', // Micro, X Tiny, Tiny, X Small, Small, Medium, X Medium, Large, X Large, XX Large, Huge, Default, Custom + answeringMachine: { // For compatibility with phone prototype with answering machine. + use: true, + startDelay: 10, + recordDuration: 20, + newRecord: false, + forceNoMicrophone: false, + }, + + videoCustom: { + local: { + size: 'Tiny', + top: 'auto', + left: 'auto' + }, + remote: { + size: 'Small', + top: 'auto', + left: 'auto' + } + }, + conference: { + layout: 'compact', + fps: 10, + size: 'Small' + }, + devicesExact: false, + + version: '30-May-2022' +} + +let SoundConfig = { + generateTones: { + // Phone ringing, busy and other tones vary in different countries. + // Please see: https://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf + + /* Germany + ringingTone: [{ f: 425, t: 1.0 }, { t: 4.0 }], + busyTone: [{ f: 425, t: 0.48 }, { t: 0.48 }], + disconnectTone: [{ f: 425, t: 0.48 }, { t: 0.48 }], + autoAnswerTone: [{ f: 425, t: 0.3 }] + */ + + /* France + ringingTone: [{f:400, t:1.5}, {t:3.5}], + busyTone: [{ f: 400, t: 0.5 }, { t: 0.5 }], + disconnectTone: [{ f: 400, t: 0.5 }, { t: 0.5 }], + autoAnswerTone: [{ f: 400, t: 0.3 }] + */ + + /* Great Britain */ + ringingTone: [{ f: [400, 450], t: 0.4 }, { t: 0.2 }, { f: [400, 450], t: 0.4 }, { t: 2.0 }], + busyTone: [{ f: 400, t: 0.375 }, { t: 0.375 }], + disconnectTone: [{ f: 400, t: 0.375 }, { t: 0.375 }], + autoAnswerTone: [{ f: 400, t: 0.3 }], + + /* keep alive unaudible sound */ + keepAliveTone: [{f: 20000, t: 0.1}] + }, + downloadSounds: [ + { ring: 'ring1' }, // incoming call sound. + { r_ring: 'ring1' }, // for ringer if used the same sound, use it with different sound name. + 'bell' + ], + play: { + outgoingCallProgress: { name: 'ringingTone', loop: true, volume: 0.2 }, + busy: { name: 'busyTone', volume: 0.2, repeat: 4 }, + disconnect: { name: 'disconnectTone', volume: 0.2, repeat: 3 }, + autoAnswer: { name: 'autoAnswerTone', volume: 0.2 }, + incomingCall: { name: 'ring', loop: true, volume: 1.0 }, + incomingCallRinger: { name: 'r_ring', loop: true, volume: 1.0 }, + incomingMessage: { name: 'bell', volume: 1.0 }, + dtmf: { volume: 0.15 }, + keepAliveBeep: { name: 'keepAliveTone', volue: 0.01 } + }, + version: '24-Jul-2022' +} \ No newline at end of file diff --git a/examples/4.phone_prototype/images/favicon.png b/examples/4.phone_prototype/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..58842a70e8bc582976157d33a3385bd7aef41ef7 GIT binary patch literal 3930 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 literal 0 HcmV?d00001 diff --git a/examples/4.phone_prototype/images/in_green.png b/examples/4.phone_prototype/images/in_green.png new file mode 100644 index 0000000000000000000000000000000000000000..6e4f10b77908c900b4403d3cb9953ab669ccac59 GIT binary patch literal 668 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%0DG6vp91t44U=Lcq)>VfnC=mGYyACE6** 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 literal 0 HcmV?d00001 diff --git a/examples/4.phone_prototype/images/out_green.png b/examples/4.phone_prototype/images/out_green.png new file mode 100644 index 0000000000000000000000000000000000000000..9e7753be29c3b0ac4cf6aeb53461d9cf3349d522 GIT binary patch literal 644 zcmV-~0( zK~zY`?Up}i6LA#Bzb^?wMQJpY1RQ!7>RyM^QQN6b{#+c3i#j+YaKY8g;R5NXI2GKa zy>5lJ#5IcsXSrOqD^zS~Yd{*F%NgSJe!u(OHHt$Y-17VVcpu*P{kaER**`K$^0;W5 zf`}e5v+;)$B9ED!!&+}=YT#0{oCi>0<|+~8Rd1R3n21^cHhjxHP7N+K%ZmWE0T>CD z^Z-2eEw?LskWtCX%S5=C5UmKT}19Vcy^1=6oXMV^u5bo;WAQj54q8=E#ZzP(8!xsc|Vh_rIs*tGF}@ZrLF zXZT4~XoglF$K`kJ#_EOhqw^zeADJ}J&hkDA+1mhsy|a(wyRScce+L|fKI}ii)3?vY zId^|}+P-q3viFGSzAp63*5`4~u?~#BpR1;rr;6A~3Y{#tVdq2@q$33feKv^BNk$6Q zu)$;x%O+O~!0X9_Vdn%(SjF8t3u&OgeX9RX!B3(KV17!oy6;=A5nI*4<{)H}CzV(> z4I|shx7;p|__FW;k66gI5S`V>Ng;b5fKaVIy31ZQ_+~YvZTXg4pZa literal 0 HcmV?d00001 diff --git a/examples/4.phone_prototype/images/out_red.png b/examples/4.phone_prototype/images/out_red.png new file mode 100644 index 0000000000000000000000000000000000000000..bd5e952b01d49ea1762ef6fce3753da3187d1ebc GIT binary patch literal 568 zcmV-80>}M{P)NP#Kyo3_AD#jxgK=pTPPAt_&oyvJhh8j;~l-(Di8(-X2fVEbvRx!$D4AaCgO$wzFJCzDS zvzg?633Qd;M;8pkE74V~#T7sL!U!+89b`3Y&iIVO5TM@r4)H<@x$L zFEsJYg5o1F0uHxyS9_L}N7|~6CI?$7c}9s + + + + + WebRTC single call phone + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+
+ Server + + + +
+ +
+ Account + + + + +
+ +
+ +
+ +
+
+
+ Devices + + Microphone
+ +
+
+
+ + Speaker
+ +
+
+
+ + Camera
+ +
+
+
+ + Secondary ringer
+ +
+
+ + Exact +
+
+ +
+ + + + + + + + +
+
+ call +
+ + + +
+
+
+ + +
+ + +
+ call log +
    +
+
+
+ +
+
+ calling +

+

+
+ +
+
+ +
+
+ incoming call +

+
+ + + + +
+
+
+ +
+
+ redirect call +
+ + +
+
+
+ +
+
+ blind call transfer +
+ + +
+
+
+ +
+
+
+ open call +

+
+ +
+ + + + + + + + + + + + + Hide local video + Video size + + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
123
456
789
*0#
+
+
+ +
+ +
+ send message +
+ to: +
+ +
+ +
+
+ +
+ messages + +
    +
+
+
+ +
+ +
+ settings +
+ to user: + event:
+ accept: + content-type:
+ expires:
+
+
+ +
+ subscribe +
+
+ +
+ +
+
+
+ notify +
+
+ +
+
+
+
+ +
+ + +
+ + + \ No newline at end of file diff --git a/examples/4.phone_prototype/phone.css b/examples/4.phone_prototype/phone.css new file mode 100644 index 0000000..d3f4fb1 --- /dev/null +++ b/examples/4.phone_prototype/phone.css @@ -0,0 +1,130 @@ + #panels { + max-width: 500px; + } + + .panel, + #dtmf_keypad { + display: none; + } + + #setting .server { + background: lightgray; + } + + #setting .account { + background: #A5ECEC; + } + + #call_log_ul { + list-style: none; + overflow-y: auto; + height: 80%; + padding-left: 10px; + } + /* call log */ + + #call_log_ul li:before { + content: ''; + display: inline-block; + background-size: 1.1em; + height: 1.1em; + width: 1.1em; + margin-right: 10px; + } + + #call_log_ul li.in_red:before { + background-image: url("images/in_red.png"); + } + + #call_log_ul li.in_green:before { + background-image: url("images/in_green.png"); + } + + #call_log_ul li.out_red:before { + background-image: url("images/out_red.png"); + } + + #call_log_ul li.out_green:before { + background-image: url("images/out_green.png"); + } + + #call_log_ul li { + background: #f6f3f3; + margin: 5px 0 5px 0; + } + /* Messages */ + #message_ul { + list-style: none; + height: 50vh; + overflow-y: auto; + padding-left: 10px; + } + /* DTMF keypad */ + + #keypad_table { + font-family: Verdana, Arial, Helvetica, sans-serif; + text-align: center; + margin: 10px auto; + } + + #keypad_table tr td { + vertical-align: middle; + text-align: center; + border: 1px solid #000000; + font-size: 18px; + font-weight: bold; + width: 40px; + height: 30px; + cursor: pointer; + background-color: #666666; + color: #CCCCCC; + } + + #keypad_table tr td:hover { + background-color: #999999; + color: #FFFF00; + } + + #hangup_btn, + #cancel_outgoing_call_btn, + #reject_btn { + background-color: lightpink; + border-color: lightpink; + } + + #accept_audio_btn, + #accept_recvonly_video_btn, + #accept_video_btn { + background-color: lightgreen; + border-color: lightgreen; + } + + #redirect_btn { + background-color: lightskyblue; + border-color: lightskyblue; + } + + #message_btn.new_message { + color: crimson; + } + + .incoming_message { + color:darkviolet; + } + + .outgoing_message { + color: green; + } + + #notification_permission_btn { + display: none; + } + + .mark_invalid:invalid { + color: red; + } + + #devices_done_btn { + margin-right: 20px; + } + \ No newline at end of file diff --git a/examples/4.phone_prototype/phone.js b/examples/4.phone_prototype/phone.js new file mode 100644 index 0000000..3ac82db --- /dev/null +++ b/examples/4.phone_prototype/phone.js @@ -0,0 +1,2859 @@ +'use strict'; + +/* + Tutorial + Single call phone prototype + + This is example of AudioCodes WebRTC API usage. + The API is similar for Browser, Android and IPhone. + For browser the API is implemented as wrapper of open source JsSIP library. + GUI is simplified, and built in pure javascript (without framework). + + Implemented: + + - Persistent user account, user preferences, phone and server configuration in browser local storage. + - SIP server registration. + - Outgoing call. + - Incoming call (answer, reject, redirect). + - Incoming call desktop notification. + - Hide/show local video view during open call (saved in user preferences) + - Select video view size (saved in user preferences) + - Mute audio, mute video. + - Call hold/un-hold. + - Send DTMF. + - Redial last call. + - Persistent call log history in browser indexed database. + - Server connection keep-alive, detection connectivity failure. + - Restore call after page reloading. + - Use the previously connected server after page reloading. + - Custom logger function. + - Sound playing: incoming call ring, ringing-tone, busy-tone, terminated-tone, dtmf tones. + - Support of Chrome WebAudio autoplay policy + - Blind call transfer (transferor and transferee). + (transferee code supports also receiving attended transfer REFER) + - Incoming call custom header usage (Alert-Info example) + - Incoming call with Replaces header + - Receiving SIP NOTIFY in/out of dialog (in dialog NOTIFY talk example) + - Sending/Receiving out of dialog SIP MESSAGE (text messages example) + - Sending/receiving in dialog SIP INFO (JSON data example) + - Answer with receive only video. + - Start sending/receiving video in audio call. Stop sending video. + - Sound customization using file config.js + - Partial support iOS Safari + - For outgoing call and 5xx response - switch to alternative SBC and re-call + - Screen Sharing + - Added support of header: x-genesys-calluuid (Genesys server support example) + - Added special support of Firefox incoming call notification permission request. + - Restoration the previously connected server using X-AudioCodes-SBC-FQDN header. + - Added DSCP network priority + - Added stop receive video + - Added service-worker incoming call notification. + - Added SUBSCRIBE/NOTIFY dialog + - Added setCodecFilter and printUsedCodecs() to check used codecs. + - Added microphone, speaker, camera selection + + Igor Kolosov AudioCodes 2022 + Last edit: 20-Jun-2023 + */ + +// Global variables +let phone = new AudioCodesUA(); // phone API +let hasCamera = false; // If computer has camera. +let callLogDb = new CallLogDb(100); // last call logs indexeddb. Set max records number. +let messageDb = new MessageDb(100); // last incoming text messages. Set max records number. +let userAccount; // { user: '', password: '', displayName: '', authUser: ''} +let userPref; // User preferences (mostly GUI) +let phoneConfig; // Default from site setting, or custom if user is changed it. +let serverConfig; // Default from site setting, or custom if user is changed it. +let desktopNotification = { rsw: null, basic: null } // incoming call notification +let activeCall = null; // not null, if exists active call +let transferCall = null; // transfer recipient outgoing call. +let audioPlayer = new AudioPlayer2(); // Play ring, ringback & busy tones. +let ac_log = console.log; // Phone logger function. +let recallAfterSwitchingSbc = null; // Switching SBC and re-calling after initial INVITE 5xx response. +let serverLocalAddress; // set by optional REGISTER OK header: X-AudioCodes-SBC-FQDN +let screenSharingStream = null; +let keepAliveBeepJob = null; +let subscriber = null; // client subscribe dialog +let notifier = null; // server subscribe dialog +let devices = new SelectDevices(); +let remoteVideoDeviceId = ''; + +const videoSizesSeq = ['Micro', 'X Tiny', 'Tiny', 'X Small', 'Small', 'Medium', 'X Medium', 'Large', 'X Large', 'XX Large', 'Huge']; +const videoSizes = { + 'Default': { width: '', height: '' }, + 'Micro': { width: '60px', height: '45px' }, + 'X Tiny': { width: '90px', height: '70px' }, + 'Tiny': { width: '120px', height: '90px' }, + 'X Small': { width: '160px', height: '120px' }, + 'Small': { width: '240px', height: '180px' }, + 'Medium': { width: '320px', height: '240px' }, + 'X Medium': { width: '400px', height: '300px' }, + 'Large': { width: '480px', height: '360px' }, + 'X Large': { width: '640px', height: '480px' }, + 'XX Large': { width: '800px', height: '600px' }, + 'Huge': { width: '960px', height: '720px' }, +}; + +function documentIsReady() { + // Load configurations + serverConfig = guiLoadServerConfig(); + phoneConfig = guiLoadPhoneConfig(); + userPref = guiLoadUserPref(); + devices.load(guiLoadSelectedDevices()); + + // Set logger + if (!serverConfig.logger) { + setConsoleLoggers(); + startPhone(); + } else { + setWebsocketLoggers(serverConfig.logger) + .catch((e) => { + setConsoleLoggers(); + ac_log('Cannot connect to logger server', e); + }) + .finally(() => { + startPhone(); + }) + } +} + +function startPhone() { + ac_log(`------ Date: ${new Date().toDateString()} -------`); + ac_log(`AudioCodes WebRTC SDK. Single call phone prototype`); + ac_log(`SDK: ${phone.version()}`); + ac_log(`SIP: ${JsSIP.C.USER_AGENT}`); + ac_log(`Browser: ${phone.getBrowserName()} Internal name: ${phone.getBrowser()}|${phone.getOS()}`); + + if (navigator.connection) { + let str = ''; + try { + let nc = navigator.connection; + if (nc.type) str += ' type=' + nc.type; + if (nc.effectiveType) str += ' etype=' + nc.effectiveType; + if (nc.downlink) str += ' downlink=' + nc.downlink + ' Mbps'; + if (nc.downlinkMax) str += ' downlinkMax=' + nc.downlinkMax + ' Mbps'; + if (nc.rtt) str += ' rtt=' + nc.rtt + ' ms'; + } catch (e) { + str += ' [error]'; + } + ac_log('Network connection:' + str); + } + + devices.setDevices(true, + [{ name: 'microphone', kind: 'audioinput' }, + { name: 'camera', kind: 'videoinput' }, + { name: 'speaker', kind: 'audiooutput' }, + { name: 'ringer', kind: 'audiooutput' }]); + + devices.enumerate(false) + .then(() => { + let str = 'devices: selected'; + for (let name of devices.names) { + if (devices.getNumber(name) > 1) { + str += `\n${name}: "${devices.getSelected(name).label}"`; + } + } + ac_log(str); + + /* + // print devices list + for (let name of devices.names) { + let device = devices.getDevice(name); + let str = `--- ${name} selected=${device.index}\n`; + for (let ix = 0; ix < device.list.length; ix++) + str += `${ix}: ${JSON.stringify(device.list[ix])}\n`; + ac_log(str); + } + */ + + for (let name of devices.names) + guiFillDeviceList(name); + + setDeviceIds(); + + startPhone2() + }); +} + +function startPhone2() { + audioPlayer.init({ logger: ac_log }); + + guiInit(); + + // Set selected ring instead default. + if (userPref.selectedRing) { + ac_log('Set preferred ring for incoming call: ' + userPref.selectedRing); + SoundConfig.downloadSounds[0] = { ring: userPref.selectedRing }; + } + + // Prepare audio data + audioPlayer.downloadSounds('sounds/', SoundConfig.downloadSounds) + .then(() => { + let tones = Object.assign({}, SoundConfig.generateTones, audioPlayer.dtmfTones); + return audioPlayer.generateTonesSuite(tones); + }) + .then(() => { + ac_log('audioPlayer: sounds are ready:', audioPlayer.sounds); + }); + + callLogDb.open() + .then(() => { + ac_log('call-log db: open'); + return callLogDb.load(); + }) + .then(() => { + ac_log('call-log db: loaded', callLogDb.list.length); + for (let entry of callLogDb.list) { + guiAddLog(entry); + } + }) + .catch(e => { + ac_log('call-log db open/load error', e); + }); + + messageDb.open() + .then(() => { + ac_log('message db: open'); + return messageDb.load(); + }) + .then(() => { + ac_log('message db: loaded', messageDb.list.length); + for (let entry of messageDb.list) { + guiAddMessage(entry); + } + }) + .catch(e => { + ac_log('message db open/load error', e); + }); + // Check WebRTC support + // Check available devices (microphone must exists, camera is optional) + phone.checkAvailableDevices() + .then((camera) => { + hasCamera = camera; + guiSetCamera(); + ac_log(`hasCamera=${hasCamera}`); + }) + .catch((e) => { + ac_log('Warning: missed micropone/speaker', e); + throw e; + }) + .then(() => { + guiSetServerFields(serverConfig); + + // Account can be null, if was not saved in local storage before + userAccount = guiLoadAccount(); + if (userAccount) { + guiSetAcountFields(userAccount); + initSipStack(userAccount); + } else { + throw 'Please set user, display-name and password, and optional authorization name.'; + } + }) + .catch((e) => { + ac_log('error', e); + guiError(e); + guiShowPanel('setting_panel'); + }) +} + +function createTimestamp(date = null) { + if (date === null) + date = new Date(); + let h = date.getHours(); + let m = date.getMinutes(); + let s = date.getSeconds(); + let ms = date.getMilliseconds(); + return ((h < 10) ? '0' + h : h) + ':' + ((m < 10) ? '0' + m : m) + ':' + ((s < 10) ? '0' + s : s) + '.' + ('00' + ms).slice(-3) + ' '; +} + +function createDateTimestamp(date = null) { + function lz(n) { return n < 10 ? '0' + n : '' + n; } + if (date === null) + date = new Date(); + let yr = date.getFullYear().toString(); + let mh = date.getMonth() + 1; + let d = date.getDate(); + let h = date.getHours(); + let m = date.getMinutes(); + return yr + '-' + lz(mh) + '-' + lz(d) + ' ' + lz(h) + ':' + lz(m); +} + +function setConsoleLoggers() { + let useTimestamp = phoneConfig.addLoggerTimestamp; + let useColor = ['chrome', 'firefox', 'safari'].includes(phone.getBrowser()); + + ac_log = function () { + let args = [].slice.call(arguments); + let firstArg = [(useTimestamp ? createTimestamp() : '') + (useColor ? '%c' : '') + args[0]]; + if (useColor) firstArg = firstArg.concat(['color: BlueViolet;']); + console.log.apply(console, firstArg.concat(args.slice(1))); + }; + let js_log = function () { + let args = [].slice.call(arguments); + let firstArg = [(useTimestamp ? createTimestamp() : '') + args[0]]; + console.log.apply(console, firstArg.concat(args.slice(1))); + }; + + phone.setAcLogger(ac_log); + phone.setJsSipLogger(js_log); +} + +function setWebsocketLoggers(url) { + return new Promise((resolve, reject) => { + let ws = new WebSocket('wss://' + url, 'wslog'); + ws.onopen = () => { resolve(ws); } + ws.onerror = (e) => { reject(e); } + }) + .then(ws => { + const log = function () { + let args = [].slice.call(arguments); + let msg = [createTimestamp() + args[0]].concat(args.slice(1)).join(); + if (ws.readyState === WebSocket.OPEN) { + ws.send(msg + '\n'); + } else { + console.log(msg); + } + }; + ac_log(`Sending log to "${url}"`); + ac_log = log; + phone.setAcLogger(log); + phone.setJsSipLogger(log); + }) +} + +function initSipStack(account) { + // If page is reloaded, try reconnect previously connected SBC server + let data = sessionStorage.getItem('phoneRestoreServer'); + if (data !== null) { + sessionStorage.removeItem('phoneRestoreServer'); + if (phoneConfig.restoreServer) { + let restoreServer = JSON.parse(data); + let delay = Math.ceil(Math.abs(restoreServer.time - new Date().getTime()) / 1000); + if (delay <= phoneConfig.restoreCallMaxDelay) { + if (restoreServer.isLocal) { + serverConfig.addresses.unshift(restoreServer.address); + } + let ix = searchServerAddress(serverConfig.addresses, restoreServer.address); + if (ix !== -1) { + ac_log('Page reloading, raise priority of previously connected server: "' + restoreServer.address + '"'); + serverConfig.addresses[ix] = [restoreServer.address, 1000]; + } else { + ac_log('Cannot find previously connected server: ' + restoreServer.address + ' in configuration'); + } + } + } + } + + // If an optional TURN server is used, set a username and password for it. + // + // Note: Please don't set TURN password in config.js, because everyone can read it ! + // Note: TURN server user name and password can be obtained via REST API request, or entered by user. + // To keep this example simple, we'll assume that the TURN server is configured + // to use the same user names and passwords as the SIP server. + for (let server of serverConfig.iceServers) { + if (typeof server === 'string') + continue; + let url = Array.isArray(server.urls) ? server.urls[0] : server.urls; + if (url.startsWith('turn:')) { + // Set TURN user name and password. Don't override if already set. + if (server.username === undefined) + server.username = (account.authUser !== '') ? account.authUser : account.user; + if (server.credential === undefined) + server.credential = account.password; + } + } + + phone.setServerConfig(serverConfig.addresses, serverConfig.domain, serverConfig.iceServers); + phone.setAccount(account.user, account.displayName, account.password, account.authUser); + + // Setting phone options + phone.setReconnectIntervals(phoneConfig.reconnectIntervalMin, phoneConfig.reconnectIntervalMax); + phone.setRegisterExpires(phoneConfig.registerExpires); + phone.setUseSessionTimer(phoneConfig.useSessionTimer); + phone.setBrowsersConstraints(phoneConfig.constraints); + phone.setWebSocketKeepAlive(phoneConfig.pingInterval, phoneConfig.pongTimeout, phoneConfig.timerThrottlingBestEffort, phoneConfig.pongReport, phoneConfig.pongDist); + phone.setDtmfOptions(phoneConfig.dtmfUseWebRTC, phoneConfig.dtmfDuration, phoneConfig.dtmfInterToneGap); + phone.setEnableAddVideo(phoneConfig.enableAddVideo); + phone.setNetworkPriority(phoneConfig.networkPriority); + phone.setCodecFilter(phoneConfig.codecFilter); + + // Set some strings to testing. Please don't use them in production. + phone.setUserAgent(`AudioCodes WebRTC SDK. Single call phone prototype ${phone.version()} ${phone.getBrowserName()}`); + phone.setRegisterExtraHeaders(['X-SBC: AudioCodes Mediant']); + + devices.addDeviceChangeListener((e) => { + ac_log('Devices: device change event', e); + }); + + // Set phone API listeners + phone.setListeners({ + loginStateChanged: function (isLogin, cause, response) { + switch (cause) { + case "connected": + // after this can be called 'login', but better use init(autoLogin=true) + ac_log('phone>>> loginStateChanged: connected'); + break; + case "disconnected": + ac_log('phone>>> loginStateChanged: disconnected'); + guiError('SBC server: disconnected'); + if (activeCall === null) // if no active call + guiShowPanel('setting_panel'); + break; + case "login failed": + ac_log('phone>>> loginStateChanged: login failed'); + guiError('SBC server: login failed'); + guiShowPanel('setting_panel'); + break; + case "login": + ac_log('phone>>> loginStateChanged: login'); + serverLocalAddress = response.getHeader('X-AudioCodes-SBC-FQDN'); + + let url = serverLocalAddress ? serverLocalAddress : phone.getServerAddress(); + if (url.startsWith('wss://')) + url = url.substring(6); + guiInfo(`"${phone.getAccount().user}" is logged in "${url}"`); + + let restoreData = sessionStorage.getItem('phoneRestoreCall'); + if (restoreData !== null) { + sessionStorage.removeItem('phoneRestoreCall'); + } + if (activeCall !== null && activeCall.isEstablished()) { + ac_log('Re-login done, active call exists (SBC might have switched over to secondary)'); + guiShowPanel('call_established_panel'); + } else if (restoreData !== null && phoneConfig.restoreCall && guiRestoreCall(restoreData)) { + ac_log('Call is restored after page reloading'); + } else if (recallAfterSwitchingSbc !== null) { + ac_log('phone: switched SBC: re-call...'); + guiMakeCallTo(recallAfterSwitchingSbc.callTo, recallAfterSwitchingSbc.videoOptions); + recallAfterSwitchingSbc = null; + } else { + guiShowPanel('dialer_panel'); + } + break; + case "logout": + ac_log('phone>>> loginStateChanged: logout'); + guiInfo('SBC server: logout'); + if (recallAfterSwitchingSbc !== null) { + ac_log('phone: switching SBC...'); + break; + } + if (activeCall === null || !activeCall.isEstablished()) { // if no active call + guiShowPanel('setting_panel'); + break; + } + } + }, + + /* + * Optional callback. Incoming re-INVITE request. + * Called twice: the 1st incoming re-INVITE (start=true), + * the 2nd after send OK (start=false) + */ + callIncomingReinvite: function (call, start, request) { + if (start) { + // Check screen sharing optional SIP header + call.data['screen-sharing-header'] = request.getHeader('x-screen-sharing'); + + //-------------- X-Genesys-CallUUID --------------- + let genesysId = request.getHeader('x-genesys-calluuid'); + if (genesysId) { + ac_log('Genesys UUID=' + genesysId); + if (genesysId !== call.data['_genesys_uuid']) { + call.data['_genesys_uuid'] = genesysId; + if (call.isLocalHold()) { + ac_log('Incoming re-INVITE: genesys ID changed & local hold.'); + call.data['_genesys_uuid_changed'] = true; + } + } + } + //-------------- X-Genesys-CallUUID --------------- + return; + } + //-------------- X-Genesys-CallUUID --------------- + if (call.data['_genesys_uuid_changed']) { + call.data['_genesys_uuid_changed'] = false; + ac_log('Incoming re-INVITE/Send OK genesys ID changed & local hold.=> unhold !'); + call.hold(false); + } + //------------- End of X-Genesys-CallUUID ------------ + + ac_log('phone>>> call incoming reinvite, video current: ' + call.getVideoState() + ' enabled: ' + call.getEnabledVideoState()); + // Other side may start or stop send video. + guiShowVideoControls(call); + setEnableReceiveVideoButton(); + let remoteVideo = document.getElementById('remote_video'); + setVideoElementVisibility(remoteVideo, call.hasReceiveVideo()); + + // Screen sharing. + // Here can be some GUI manipulations. (e.g. bigger video size) + let screenSharingHeader = call.data['screen-sharing-header']; + if (call.hasReceiveVideo() && screenSharingHeader === 'on') { + ac_log('phone: remote screen shown: on'); + guiInfo('remote screen shown: On'); + } else if (screenSharingHeader === 'off') { + ac_log('remote screen shown: off'); + guiInfo('remote screen shown: Off'); + } + }, + + /* + * Optional callback. Call transferor notification + * + * state=0 in progress (REFER accepted or NOTIFY 1xx) + * state=-1 failed (REFER rejected or NOTIFY with >= 300) + * state=1 success (NOTIFY 2xx) + */ + transferorNotification: function (call, state) { + switch (state) { + case 0: + ac_log('phone>>> transferor: transfer in progress...'); + guiWarning('call transfer in progress...'); + break; + + case -1: + ac_log('phone>>> transferor: transfer failed'); + guiHold(false); // un-hold active call + document.getElementById('blind_transfer_btn').disabled = false; + guiError('call transfer failed'); + break; + + case 1: + ac_log('phone>>> transferor: transfer is successful'); + guiInfo('call transfer is successful'); + activeCall.data['terminated_transferred'] = true; + guiHangup(); // terminate active call + break; + } + }, + + /* + * Optional callback for call transferee + * Accept or reject incoming REFER. + */ + transfereeRefer: function (call, refer) { + if (transferCall === null) { + ac_log('phone>>> transferee incoming REFER: accepted'); + return true; + } else { + ac_log('phone>>> transferee incoming REFER: rejected, because other transfer in progress'); + return false; + } + }, + + /* + * Optional callback for call transferee + * Created new outgoing call according the incoming REFER. + * + * Note: Transferee uses 2 calls at the same time: + * call that receive REFER, and created new outgoing call + */ + transfereeCreatedCall: function (call) { + ac_log('phone>>> transferee created call', call); + transferCall = call; // Used until call will be established + + guiInfo('call transferring to ' + call.data['_user']); + + // create new call log record + let time = call.data['_create_time'].getTime(); + let logRecord = { + id: callLogDb.createId(time), + time: time, + duration: -1, + incoming: false, + user: call.data['_user'], + display_name: call.data['_display_name'] + }; + + call.data['log_record'] = logRecord; + guiAddLog(logRecord, 'call_log_ul'); + callLogDb.add(logRecord) + .then(() => { + ac_log('call-log db: added'); + }) + .catch((e) => { + ac_log('call-log db: add error', e); + }); + }, + + outgoingCallProgress: function (call, response) { + ac_log('phone>>> outgoing call progress'); + if (call === transferCall) + return; + document.getElementById('outgoing_call_progress').innerText = 'dzzz dzzz'; + if (response.body) { + call.data['outgoingCallProgress_played'] = true; // If the 18x respone includes SDP, the server plays sound + } else if (!call.data['outgoingCallProgress_played']) { + call.data['outgoingCallProgress_played'] = true; // To prevent duplicate playing. + audioPlayer.play(SoundConfig.play.outgoingCallProgress); + } + }, + + callTerminated: function (call, message, cause, redirectTo) { + if (call.data['terminated_transferred']) + cause = 'call transfer is successful'; + else if (call.data['terminated_replaced']) + cause = 'call is replaced'; + ac_log(`phone>>> call terminated callback, cause=${cause}`); + + let logRecord = call.data['log_record']; + + // update call log duration + if (call.wasAccepted()) { // sent or received SIP 2xx response + logRecord.duration = call.duration(); + guiUpdateLog(logRecord); + callLogDb.update(logRecord) + .then(() => { + ac_log('call-log db: updated'); + }) + .catch((e) => { + ac_log('call-log db: update error', e); + }); + } + + // print call log record to console + let str = new Date(logRecord.time).toLocaleDateString('en-GB', { + day: 'numeric', + month: 'short', + year: 'numeric', + hour12: false, + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }); + str += logRecord.incoming ? ' in ' : ' out ' + str += logRecord.user; + if (logRecord.display_name) + str += ' "' + logRecord.display_name + '"'; + str += logRecord.duration >= 0 ? ' ' + logRecord.duration + ' sec' : ' failed'; + ac_log('Call log: ', str); + + if (call === transferCall) { + ac_log('terminated transfer call'); + transferCall = null; + return; + } + + // Incoming call during active call or call that receive REFER. + if (call !== activeCall) { + ac_log('terminated no active call'); + return; + } + + activeCall = null; + + // update GUI + guiWarning('Call terminated: ' + cause); + guiShowPanel('dialer_panel'); + guiClearVideoView(); + guiNotificationClose(); + audioPlayer.stop(); + if (cause !== 'Redirected' && recallAfterSwitchingSbc === null) { + if (call.isOutgoing() && !call.wasAccepted()) { + audioPlayer.play(SoundConfig.play.busy); + } else { + audioPlayer.play(SoundConfig.play.disconnect); + } + } + + if (cause === 'Redirected') { + ac_log('Redirect call to ' + redirectTo); + guiMakeCallTo(redirectTo, call.hasEnabledSendVideo() ? phone.VIDEO : phone.AUDIO); + return; + } + + // 5xx response to initial outgoing INVITE + if (call.isOutgoing() && !call.wasAccepted()) { + let statusCode = (message && message.status_code) ? message.status_code : 0; + if (statusCode >= 500 && statusCode < 600 && phoneConfig.switchSbcAtInvite5xx) { + if (phone.getNumberOfSBC() === 1) { + ac_log('phone: Cannot switch to other SBC, because set single SBC'); + } else { + ac_log('phone: Outgoing call response 5xx. Switching SBC and re-call'); + recallAfterSwitchingSbc = { + callTo: call.data['_user'], + videoOptions: call.hasEnabledSendVideo() ? phone.VIDEO : phone.AUDIO + }; + phone.switchSBC(); + } + } + } + }, + + callConfirmed: function (call, message, cause) { + ac_log('phone>>> callConfirmed'); + // update call log duration + let logRecord = call.data['log_record']; + logRecord.duration = 0; // zero duration means call is established + guiUpdateLog(logRecord); + callLogDb.update(logRecord) + .then(() => { + ac_log('call-log db: updated'); + }) + .catch((e) => { + ac_log('call-log db: update error', e); + }); + + //-------------- X-Genesys-CallUUID --------------- + let genesysId = message !== null ? message.getHeader('x-genesys-calluuid') : undefined; + if (genesysId) { + ac_log('Genesys UUID=' + genesysId); + call.data['_genesys_uuid'] = genesysId; + } + //-------------- End of X-Genesys-CallUUID -------- + + guiInfo(''); + if (call === transferCall) { + guiInfo('call transferred') + ac_log('transfer call is established. Set it as active call'); + activeCall = call; + transferCall = null; + + // Set user name + let user = call.data['_user']; + let dn = call.data['_display_name']; // optional + let caller = dn ? `"${dn}" ${user}` : user; + document.getElementById('call_established_user').innerText = caller; + } + audioPlayer.stop(); + + // Show/hide video controls and local video + let remoteVideo = document.getElementById('remote_video'); + setVideoElementVisibility(remoteVideo, call.hasReceiveVideo()); + guiShowVideoControls(call); + setEnableReceiveVideoButton(); + guiShowLocalVideo(call.hasSendVideo() && !userPref.hideLocalVideo); + + if (call.data['open_replaced']) { + guiInfo('call is replaced'); + } + + let screenSharingBtn = document.getElementById('screen_sharing_btn'); + screenSharingBtn.value = 'Start screen sharing'; + screenSharingBtn.disabled = false; + + let sendVideoBtn = document.getElementById('send_video_btn'); + sendVideoBtn.value = call.hasEnabledSendVideo() ? 'Stop sending video' : 'Start sending video'; + sendVideoBtn.disabled = !hasCamera; + + // restore button values to initial state + document.getElementById('hold_btn').value = 'Hold'; + document.getElementById('hold_btn').disabled = false; + document.getElementById('mute_audio_btn').value = 'Mute'; + document.getElementById('mute_video_btn').value = 'Mute video'; + document.getElementById('blind_transfer_btn').disabled = false; + + // for restored call restore hold or mute state if need. + let restore = activeCall.data['restoreCall']; + if (restore) { + if (restore.hold !== '') { + if (restore.hold.includes('remote')) { + ac_log('Restore remote hold'); + guiWarning('Remote HOLD'); + activeCall.setRemoteHoldState(); + } + if (restore.hold.includes('local')) { + ac_log('Restore local hold'); + guiHold(true); + } + } else if (restore.mute !== '') { + if (restore.mute.includes('audio')) { + ac_log('Restore mute audio'); + guiMuteAudio(); + } + if (restore.mute.includes('video')) { + ac_log('Restore mute video'); + guiMuteVideo(); + } + } + if (restore.screenSharing) { + ac_log('Restore screen sharing'); + guiToggleScreenSharing(); + } + } + guiShowPanel('call_established_panel'); + }, + + callShowStreams: function (call, localStream, remoteStream) { + if (call === transferCall) { + ac_log('phone>>> callShowStreams (transfer call)'); + return; + } + ac_log('phone>>> callShowStreams'); + + audioPlayer.stop(); + + printStreamsParameters(); + + let remoteVideo = document.getElementById('remote_video'); + setRemoteVideoSinkId(remoteVideo) + .catch((e) => { + ac_log(`Warning: remove video HTMLVideoElement.setSinkId(): "${e.message}" [Used default browser speaker]`, e); + }) + .finally(() => { + remoteVideo.srcObject = remoteStream; + }); + }, + + incomingCall: function (call, invite, replacedCall, hasSDP) { + ac_log('phone>>> incomingCall', call, invite, replacedCall, hasSDP); + call.data['incoming_invite_hasSDP'] = hasSDP; + + // create new call log record + let time = call.data['_create_time'].getTime(); + let logRecord = { + id: callLogDb.createId(time), + time: time, + duration: -1, + incoming: true, + user: call.data['_user'], + display_name: call.data['_display_name'] + }; + call.data['log_record'] = logRecord; + guiAddLog(logRecord); + callLogDb.add(logRecord) + .then(() => { + ac_log('call-log db: added'); + }) + .catch((e) => { + ac_log('call-log db: add error', e); + }); + + // If received INVITE with Replaces header + if (replacedCall !== null) { + ac_log('phone: incomingCall, INVITE with Replaces'); + + // close the replaced call. + replacedCall.data['terminated_replaced'] = true; + replacedCall.terminate(); + + // auto answer to replaces call. + activeCall = call; + activeCall.data['open_replaced'] = true; + + let videoOption = replacedCall.hasVideo() ? phone.VIDEO : (replacedCall.hasReceiveVideo() ? phone.RECVONLY_VIDEO : phone.AUDIO); + activeCall.answer(videoOption); + return; + } + + // Check if exists other active call + if (activeCall !== null) { + ac_log('Reject incoming call, because we during other call'); + call.reject(); + return; + } + + // Incoming call + guiInfo(''); + activeCall = call; + + // Can be used custom header in incoming INVITE + // ------ begin of Alert-Info auto answer example ---- + // JsSIP parse Alert-Info as raw string. We use custom parser defined in utils.js + let alertInfo = new AlertInfo(invite); + ac_log(`alert-info header ${alertInfo.exists() ? ' exists' : 'does not exist'}`); + if (alertInfo.hasAutoAnswer()) { + ac_log(`alert-info delay=${alertInfo.getDelay()}`); // currently ignored + ac_log('*** Used Alert-Info Auto answer ***'); + audioPlayer.play(SoundConfig.play.autoAnswer); + + let videoOption; + if (activeCall.data['incoming_invite_hasSDP']) { + videoOption = activeCall.hasVideo() ? (hasCamera ? phone.VIDEO : phone.RECVONLY_VIDEO) : phone.AUDIO; + } else { + videoOption = phoneConfig.audioAutoAnswerNoSdp ? phone.AUDIO : phone.VIDEO; + } + guiAnswerCall(videoOption); + return; + } + //------ end of Alert-Info auto answer example ---- + + //-------------- X-Genesys-CallUUID --------------- + let genesysId = invite.getHeader('x-genesys-calluuid'); + if (genesysId) { + ac_log('Genesys UUID=' + genesysId); + call.data['_genesys_uuid'] = genesysId; + } + //------------ End of X-Genesys-CallUUID ---------- + + audioPlayer.play(SoundConfig.play.incomingCall); + + // If set ringer deviceId, playing parallel in 'ringer' device. + audioPlayer.playRing(SoundConfig.play.incomingCallRinger); + + let user = call.data['_user']; + let dn = call.data['_display_name']; // optional + let caller = dn ? `"${dn}" ${user}` : user; + + document.getElementById('incoming_call_user').innerText = caller; + document.getElementById('call_established_user').innerText = caller; + document.getElementById('accept_video_btn').disabled = !hasCamera || !call.hasVideo(); + document.getElementById('accept_recvonly_video_btn').disabled = !call.hasVideo(); + guiShowPanel('incoming_call_panel'); + guiNotificationShow(caller); + }, + + /* + * Here isHold, and isRemote arguments described hold event. + * + * For example arguments can be isHold=false isRemote=true + * It means that remote phone remove its hold. + * But phone can still be in local hold. + * + * So recommended within the callback check + * call.isRemoteHold() and call.isLocalHold(). + */ + callHoldStateChanged: function (call, isHold, isRemote) { + if (call === transferCall) { + ac_log('phone>>> callHoldStateChanged (transfer call)'); + return; + } + ac_log('phone>>> callHoldStateChanged'); + + let remoteHold = call.isRemoteHold(); + let localHold = call.isLocalHold(); + if (remoteHold && localHold) { + guiWarning('Remote & Local HOLD'); + } else if (remoteHold && !localHold) { + guiWarning('Remote HOLD'); + } else if (!remoteHold && localHold) { + guiWarning('Local HOLD'); + } else { + guiInfo('Unhold done'); + } + + // Update hold button + if (!isRemote) { + document.getElementById('hold_btn').value = isHold ? 'Unhold' : 'Hold'; + } + if (!localHold && isRemote && phoneConfig.avoidTwoWayHold) { + document.getElementById('hold_btn').disabled = remoteHold; + } + }, + + /* + * Optional callback. Incoming SIP NOTIFY (in or out of dialog) + * Can be used for any events. + * Returns true - process the NOTIFY, false - use default JsSIP processing + * + * Here for example supported in dialog NOTIFY events: "talk" and "hold". + */ + incomingNotify: function (call, eventName, from, contentType, body, request) { + ac_log(`phone>>> incoming NOTIFY "${eventName}"`, call, from, contentType, body); + if (call === null) { // out of dialog NOTIFY + if (eventName === 'vq') { // voice quality event + let vq = getXVoiceQuality(request); + if (vq) { + ac_log(`NOTIFY: "X-VoiceQuality" header: score="${vq.score}", color="${vq.color}"`); + } else { + ac_log('NOTIFY: missing "X-VoiceQuality" header'); + } + return true; + } else { + return false; + } + } + if (eventName !== 'talk' && eventName !== 'hold' && eventName !== 'dtmf') + return false; // skip unsupported events + if (activeCall === null) + return false; // skip illegal state. + + if (eventName === 'talk') { + if (!activeCall.isEstablished() && !activeCall.isOutgoing()) { + ac_log('incoming NOTIFY "talk": answer call'); + audioPlayer.play(SoundConfig.play.autoAnswer); + let videoOption; + if (activeCall.data['incoming_invite_hasSDP']) { + videoOption = activeCall.hasVideo() ? (hasCamera ? phone.VIDEO : phone.RECVONLY_VIDEO) : phone.AUDIO; + } else { + videoOption = phoneConfig.audioAutoAnswerNoSdp ? phone.AUDIO : phone.VIDEO; + } + guiAnswerCall(videoOption); + } else if (activeCall.isEstablished() && activeCall.isLocalHold()) { + ac_log('incoming NOTIFY "talk": un-hold call'); + guiHold(false); + } else { + ac_log('incoming NOTIFY "talk": ignored'); + } + } else if (eventName === 'hold') { + if (activeCall.isEstablished() && !activeCall.isLocalHold()) { + ac_log('incoming NOTIFY "hold": set call on hold'); + guiHold(true); + } else { + ac_log('incoming NOTIFY "hold": ignored'); + } + } else if (eventName === 'dtmf') { + ac_log('incoming NOTIFY "dtmf" body="' + body + '"'); + body = body.trim().toLowerCase(); + if (body.startsWith('signal=')) { + let str = body.substring(7); + for (let key of str) { + activeCall.sendDTMF(key); + } + } + } + return true; + }, + + /* + * Optional callback. Incoming SIP MESSAGE (out of dialog) + */ + incomingMessage: function (call, from, contentType, body, request) { + ac_log('phone>>> incoming MESSAGE', from, contentType, body); + let time = new Date(); + let message = { + id: callLogDb.createId(time), + incoming: true, + time: time, + user: from.user, + display_name: from.displayName, + host: from.host, + contentType: contentType, + body: body + }; + + if (guiIsHidden('message_panel')) { // If message_panel is not used + // visual message notification + if (!userPref.newMessages) + userPref.newMessages = 0; + userPref.newMessages++; + guiStoreUserPref(userPref); + let button = document.getElementById('message_btn'); + button.innerText = `Messages (${userPref.newMessages} new)`; + button.classList.add('new_message'); + } + audioPlayer.play(SoundConfig.play.incomingMessage); + + guiAddMessage(message); + + messageDb.add(message) + .then(() => { + ac_log('message db: added'); + }) + .catch((e) => { + ac_log('message db: add error', e); + }); + }, + + /* + * Optional callback. Incoming SIP INFO (in dialog) + */ + incomingInfo: function (call, from, contentType, body, request) { + ac_log('phone>>> incoming INFO', call, from, contentType, body); + }, + + /* + * Optional callback. Screen sharing is ended. + * Called when: + * 1. called method call.stopScreenSharing + * 2. stopped by browser built-in screen-sharing pop up window. + * 3. call with screen-sharing is terminated. Will be called before callTerminated() + */ + callScreenSharingEnded: function (call, stream) { + ac_log('phone>>> callScreenSharingEnded', call); + // send video and screen sharing use the same video track, we use it for screen + // sharing or for sending video. + let screenSharingBtn = document.getElementById('screen_sharing_btn'); + let sendVideoBtn = document.getElementById('send_video_btn'); + screenSharingBtn.value = 'Start screen sharing'; + screenSharingBtn.disabled = false; + sendVideoBtn.value = call.hasSendVideo() ? 'Stop sending video' : 'Start sending video'; + sendVideoBtn.disabled = !hasCamera; + phone.closeScreenSharing(screenSharingStream); + setEnableReceiveVideoButton(); + screenSharingStream = null; + }, + + /* + * Optional callback. Incoming SUBSCRIBE (out of dialog) + * return 0 - dialog successfully created. + * >0 - failure. Send response with the SIP code. + */ + incomingSubscribe(subscribe, eventName, accepts) { + // Check incoming SUBSCRIBE + let ourEventName = document.querySelector('#subscribe_test_setting_form [name=event_name]').value.trim(); + let ourContentType = document.querySelector('#subscribe_test_setting_form [name=content_type]').value.trim(); + + // Check event type + if (!eventName || eventName !== ourEventName) { + guiWarning(`receive SUBSCRIBE: Event: ${eventName} We support Event: ${ourEventName}`); + return 489; // send SIP response 489 "Bad Event" + } + // Check if accept header includes our content-type + if (!accepts || !accepts.some(v => v.includes(ourContentType))) { + guiWarning(`receive SUBSCRIBE: Accept: ${accepts} We support Content-Type: ${ourContentType}`); + return 406; // send SIP response 406 "Not Acceptable" + } + try { + createNotifier(subscribe); + } catch (e) { + guiWarning('Cannot create server subscribe dialog'); + ac_log('Cannot create server subscribe dialog', e); + return 400; // send SIP response 400 "Bad Request" + } + return 0; // Don't send SIP response, created dialog will send it. + } + }); + + // Request permission to use desktop notification (for incoming call) + if (window.Notification && Notification.permission === 'default') { + if (phone.browser === 'firefox') { + // Special for Firefox: + // If Notification.requestPermission() is not called from the user driven event, + // the notification permission pop-up window will not be shown, and instead a special icon will be added to the address bar. + // The pop-up window will be shown when you click this icon. + // Another possibility: to show a special button and call the method Notification.requestPermission() when this button + // is pressed. In the case notification permission pop-up window will be shown. + document.getElementById('notification_permission_btn').onclick = guiRequestNotificationPermission; + guiShow('notification_permission_btn'); + } else { + guiRequestNotificationPermission(); + } + } + + // Use service worker to incoming call notification. + if (phoneConfig.useServiceWorkerNotification) + registerServiceWorker(); + + // API modes and browser issues workarounds + phone.setModes(phoneConfig.modes); + + guiInfo('Logging...'); + + // Initialize SIP, establish connection to SBC. + phone.init(true); // autoLogin=true, so after SBC connection is established, automatically send SIP REGISTER. +} + +// Search server address in array of addresses +function searchServerAddress(addresses, searchAddress) { + searchAddress = searchAddress.toLowerCase(); + for (let ix = 0; ix < addresses.length; ix++) { + let data = addresses[ix]; // can be address or [address, priority] + let address = data instanceof Array ? data[0] : data; + if (address.toLowerCase() === searchAddress) + return ix; + } + return -1; +} + +function setVideoElementVisibility(videoElement, isVisible) { + videoElement.style.display = 'block'; + if (isVisible) { + let size = userPref.videoSize; + if (size === 'Custom') { + let isLocal = videoElement === document.getElementById('local_video'); + size = isLocal ? userPref.videoCustom.local.size : userPref.videoCustom.remote.size; + } + guiSetVideoSize(videoElement, size); + } else { + videoElement.style.width = videoElement.style.height = '0px'; + } +} + +/* + Print call information for debugging. Using SDK. + */ +async function printStreamsParameters() { + if (activeCall === null) { + ac_log('activeCall is null'); + return; + } + // Current video state set according answer SDP (hold answer will be ignored) + ac_log('Video State current: ' + activeCall.getVideoState() + ' enabled: ' + activeCall.getEnabledVideoState()); + + // WebRTC tracks + let li = await phone.getWR().stream.getInfo(activeCall.getRTCLocalStream()); + let ri = await phone.getWR().stream.getInfo(activeCall.getRTCRemoteStream()); + ac_log(`Enabled Tracks: local ${li} remote ${ri}`) + + // WebRTC transceivers + let ti = await phone.getWR().connection.getTransceiversInfo(activeCall.getRTCPeerConnection()); + ac_log(`Transceivers: ${ti}`); +} + + +/* + Print call statistics for debugging. Using SDK + */ +function printCallStats() { + if (activeCall === null) { + ac_log('activeCall is null'); + return; + } + let conn = activeCall.getRTCPeerConnection(); + + conn.getStats(null) + .then(report => { + report.forEach(now => { + let str = now.type; + str += ' {'; + let first = true; + for (let key of Object.keys(now)) { + if (first) first = false; + else str += ','; + str += (key + '=' + now[key]); + } + str += '} \r\n'; + ac_log(str); + }); + }) +} + +// Note: don't work immediatelly after call established, +// because getStats missed 'inbound-rtp', 'outbound-rtp', 'codec' +// Repeat after a few seconds +async function printUsedCodecs() { + if (activeCall === null) { + ac_log('activeCall is null'); + return; + } + let conn = activeCall.getRTCPeerConnection(); + + let stats = await conn.getStats(); + let reports = {}; + stats.forEach(entry => { + let type = entry.type; + if (['inbound-rtp', 'outbound-rtp', 'codec'].includes(type)) { + if (!reports[type]) + reports[type] = []; + reports[type].push(Object.assign({}, entry)); + } + }); + + try { + let audioIn = getCodec(reports, 'inbound-rtp', 'audio'); + let audioOut = getCodec(reports, 'outbound-rtp', 'audio'); + let videoIn = getCodec(reports, 'inbound-rtp', 'video'); + let videoOut = getCodec(reports, 'outbound-rtp', 'video'); + ac_log(`audio in: ${audioIn ? audioIn : '-'}`); + ac_log(`audio out: ${audioOut ? audioOut : '-'}`); + if (videoIn || videoOut) { + ac_log(`video in: ${videoIn ? videoIn : '-'}`); + ac_log(`video out: ${videoOut ? videoOut : '-'}`); + } + } catch (e) { + ac_log('Cannot detect codec. Repeat after a few seconds', e); + } +} + +function getCodec(reports, report, mediaType) { + let rtps = reports[report]; + if (!rtps) + throw `Missed "${report}" stats`; + let foundRtp = null; + for (let rtp of rtps) { + if (rtp.mediaType === mediaType) { + foundRtp = rtp; + break; + } + } + if (!foundRtp) + return undefined; + let searchId = foundRtp.codecId; + if (!searchId) + return undefined; + let codecs = reports['codec']; + if (!codecs) + throw 'Missed "codec" stats'; + for (let codec of codecs) { + if (codec.id === searchId) { + let name = codec.mimeType; + name = name.substring(6).toUpperCase(); + if (codec.sdpFmtpLine) + name += '#' + codec.sdpFmtpLine; + return name; + } + } + throw `Not found "codec" id=="${searchId}"`; +} + +function onBeforeUnload() { + guiNotificationClose(); // If was notification on desktop, remove it. + + if (phone === null || !phone.isInitialized()) + return; + + if (activeCall != null) { + // If used restoreCall phone mode, save to local storage data + // to restore the call after page reloading + if (activeCall.isEstablished() && phoneConfig.restoreCall) { + let data = { + callTo: activeCall.data['_user'], + video: activeCall.getVideoState(), // sendrecv, sendonly, recvonly, inactive + replaces: activeCall.getReplacesHeader(), + time: new Date().getTime(), + hold: `${activeCall.isLocalHold() ? 'local' : ''}${activeCall.isRemoteHold() ? 'remote' : ''}`, + mute: `${activeCall.isAudioMuted() ? 'audio' : ''}${activeCall.isVideoMuted() ? 'video' : ''}` + } + if (activeCall.isScreenSharing()) { + data.screenSharing = true; + data.video = activeCall.doesScreenSharingReplaceCamera() ? 'sendrecv' : 'inactive'; + } + sessionStorage.setItem('phoneRestoreCall', JSON.stringify(data)); + } else { + // Send SIP BYE + activeCall.terminate(); + } + } + + // Save connected server address to restore after page reloading + let serverAddress = phone.getServerAddress(); + if (serverAddress !== null || serverLocalAddress !== undefined) { + let data = { + time: new Date().getTime(), + address: serverLocalAddress ? 'wss:/' + serverLocalAddress.trim() : serverAddress, + isLocal: serverLocalAddress !== undefined + } + sessionStorage.setItem('phoneRestoreServer', JSON.stringify(data)); + } + + // Send un-SUBSCRIBE if subscription dialog exists. + if (subscriber !== null) { + subscriber.terminate(); + } + + // Send final NOTIFY if notifier dialog exists. + if (notifier !== null) { + notifier.terminate(); + } + + // Send SIP unREGISTER + phone.logout(); +} + +/* + * Simple GUI + */ +function guiInit() { + window.addEventListener('beforeunload', onBeforeUnload); + + document.getElementById('send_video_btn').onclick = guiToggleSendVideo; + if (phone.isScreenSharingSupported()) { + document.getElementById('screen_sharing_btn').onclick = guiToggleScreenSharing; + } else { + ac_log('Warning: screen sharing is not supported'); + guiHide('screen_sharing_btn'); + } + document.getElementById('enable_sound_btn').onclick = guiEnableSound; + + // pressing enter key leads to audio call. + document.querySelector('#call_form [name=call_to]').addEventListener("keydown", function (ev) { + if (ev.keyCode === 13) { + ev.preventDefault(); + guiMakeCall(phone.AUDIO); + } + }); + + document.getElementById('login_btn').onclick = function () { + let user = document.querySelector('#setting [name=user]').value || ''; + let authUser = document.querySelector('#setting [name=auth_user]').value || ''; + let password = document.querySelector('#setting [name=password]').value || ''; + let displayName = document.querySelector('#setting [name=display_name]').value || ''; + + user = user.trim(); + authUser = authUser.trim(); + password = password.trim(); + displayName = displayName.trim(); + + let account = { + user: user, + authUser: authUser, + password: password, + displayName: displayName + }; + guiStoreAccount(account); + + try { + let domain = document.querySelector('#setting [name=sip_domain]').value; + let addresses = document.querySelector('#setting [name=sip_addresses]').value; + let iceServers = document.querySelector('#setting [name=ice_servers]').value; + + domain = domain.trim(); + addresses = addresses.trim(); + iceServers = iceServers.trim(); + + if (iceServers === '') + iceServers = '[]'; + + let conf = { + domain: domain, + addresses: JSON.parse(addresses), + iceServers: JSON.parse(iceServers) + }; + guiStoreServerConfig(conf); + + // if user name was changed, clear call log and then reload page + let sameUserAsWas = userAccount && 'user' in userAccount && userAccount.user === user; + if (sameUserAsWas) { + ac_log('user name is not changed'); + location.reload(); + } else { + ac_log('user name is changed, clear the user databases'); + callLogDb.clear() + .then(() => { + return messageDb.clear(); + }) + .finally(() => { + location.reload(); + }) + } + } catch (e) { + ac_log('Store settings error', e); + guiError('Please fix settings'); + } + } + + document.getElementById('info_btn').onclick = function () { + printStreamsParameters(); + let conn = activeCall.getRTCPeerConnection(); + ac_log('connection', conn); + } + + document.getElementById('stats_btn').onclick = function () { + printCallStats(); + } + + document.getElementById('codecs_btn').onclick = function () { + printUsedCodecs(); + } + + document.getElementById('blind_transfer_btn').onclick = function () { + guiShowPanel('transfer_call_panel'); + } + + document.getElementById('do_transfer_btn').onclick = guiDoTransferCall; + + document.getElementById('settings_btn').onclick = function () { + guiShowPanel('setting_panel'); + } + + document.getElementById('devices_btn').onclick = function () { + devices.enumerate(true) + .catch((e) => { + ac_log('getUserMedia() exception', e); + }) + .finally(() => { + for (let name of devices.names) + guiFillDeviceList(name); + + guiShowPanel('devices_panel'); + }); + } + + document.getElementById('devices_exact_ckb').checked = userPref.devicesExact; + + document.getElementById('devices_done_btn').onclick = function () { + // set selected in GUI devices. + for (let name of devices.names) { + let selectElement = document.querySelector(`#devices [name=${name}]`); + let index = selectElement.selectedIndex; + if (index !== -1) { // -1 indicates that no element is selected + let n = selectElement.options[index].value; + devices.setSelectedIndex(name, parseInt(n)); + } + } + + let str = 'Devices done: selected'; + for (let name of devices.names) { + if (devices.getNumber(name) > 1) { + str += `\n${name}: "${devices.getSelected(name).label}"`; + } + } + ac_log(str); + + /* + // print device list + for (let name of devices.names) { + let device = devices.getDevice(name); + let str = `--- ${name} selected=${device.index}\n`; + for (let ix = 0; ix < device.list.length; ix++) + str += `${ix}: ${JSON.stringify(device.list[ix])}\n`; + ac_log(str); + } + */ + + userPref.devicesExact = document.getElementById('devices_exact_ckb').checked; + guiStoreUserPref(userPref); + guiStoreSelectedDevices(devices.store()); + + setDeviceIds(); + + guiShowPanel('dialer_panel'); + } + + document.getElementById('call_log_btn').onclick = function () { + guiEnableSound(); + guiShowPanel('call_log_panel'); + } + + document.getElementById('redial_last_call_btn').onclick = function () { + guiRedialLastCall(); + } + + document.getElementById('call_log_return_btn').onclick = function () { + guiShowPanel('dialer_panel'); + } + + document.getElementById('call_log_clear_btn').onclick = function () { + guiClearLog(); + callLogDb.clear() + .then(() => { + ac_log('call-log db: cleared'); + }) + .catch(e => { + ac_log('call-log db: clear error', e) + }); + } + + document.getElementById('audio_call_btn').onclick = function () { guiMakeCall(phone.AUDIO); } + document.getElementById('video_call_btn').onclick = function () { guiMakeCall(phone.VIDEO); } + document.getElementById('accept_audio_btn').onclick = function () { guiAnswerCall(phone.AUDIO); } + document.getElementById('accept_recvonly_video_btn').onclick = function () { guiAnswerCall(phone.RECVONLY_VIDEO); } + document.getElementById('accept_video_btn').onclick = function () { guiAnswerCall(phone.VIDEO); } + document.getElementById('reject_btn').onclick = guiRejectCall; + document.getElementById('redirect_btn').onclick = guiRedirectCall; + document.getElementById('do_redirect_btn').onclick = guiDoRedirectCall; + document.getElementById('cancel_outgoing_call_btn').onclick = guiHangup; + document.getElementById('hangup_btn').onclick = guiHangup; + document.getElementById('hold_btn').onclick = guiToggleHold; + document.getElementById('send_reinvite_btn').onclick = guiSendReInvite; + document.getElementById('enable_receive_video_btn').onclick = guiEnableReceiveVideo; + document.getElementById('send_info_btn').onclick = guiSendInfo; + document.getElementById('mute_audio_btn').onclick = guiMuteAudio; + document.getElementById('mute_video_btn').onclick = guiMuteVideo; + document.getElementById('hide_local_video_ckb').onclick = guiToggleLocalVideo; + document.getElementById('hide_local_video_ckb').checked = userPref.hideLocalVideo; + document.getElementById('video_size_select').onchange = guiVideoSizeChanged; + document.getElementById('keypad_btn').onclick = guiToggleDTMFKeyPad; + document.getElementById('call_log_ul').onclick = guiClickOnCallLog; + guiSetVideoSizeControl(userPref.videoSize); + guiVideoSizeChanged(false); + + document.getElementById('message_btn').onclick = guiMessage; + document.getElementById('send_message_btn').onclick = guiSendMessage; + if (userPref.newMessages && userPref.newMessages > 0) { + let button = document.getElementById('message_btn'); + button.innerText = `Messages (${userPref.newMessages} new)`; + button.classList.add('new_message'); + } + + document.getElementById('message_return_btn').onclick = function () { guiShowPanel('dialer_panel'); } + document.getElementById('message_clear_btn').onclick = function () { + guiClearMessages(); + messageDb.clear() + .then(() => { + ac_log('message db: cleared'); + }) + .catch(e => { + ac_log('message db: clear error', e) + }); + } + + document.getElementById('subscribe_btn').onclick = guiSubscribePanel; + document.getElementById('subscribe_return_btn').onclick = function () { guiInfo(''); guiShowPanel('dialer_panel'); } + document.getElementById('send_init_subscribe_btn').onclick = guiSendInitSubscribe; + document.getElementById('send_next_subscribe_btn').onclick = guiSendNextSubscribe; + document.getElementById('send_unsubscribe_btn').onclick = guiSendUnsubscribe; + document.getElementById('send_notify_btn').onclick = guiSendNotify; + document.getElementById('send_final_notify_btn').onclick = guiSendFinalNotify; + document.getElementById('send_initial_and_next_subscribe_btn').onclick = guiSendInitAndNextSubscribe; + + // For Chrome only + if (phoneConfig.keepAliveBeep > 0 && phone.getBrowser() === 'chrome') { + document.addEventListener('visibilitychange', () => { + if (document.hidden) { + ac_log('Phone: page is hidden: start sending keep alive beep'); + if (audioPlayer.isDisabled()) { + ac_log('Warning: cannot play keep alive beep, because sound is not enabled'); + return; + } + keepAliveBeepJob = setInterval(() => { + audioPlayer.playShortSound(SoundConfig.play.keepAliveBeep); + }, phoneConfig.keepAliveBeep * 1000); + } else { + ac_log('Phone: page is visible: stop sending keep alive beep'); + if (keepAliveBeepJob) + clearInterval(keepAliveBeepJob); + } + }); + } +} + +/* + * Support of Chrome Audio Policy. + * Important: work only when called in GUI event callback (likes button click) + */ +function guiEnableSound() { + if (!audioPlayer.isDisabled()) + return; + ac_log('Let enable sound...'); + audioPlayer.enable() + .then(() => { + ac_log('Sound is enabled') + guiHide('enable_sound_btn'); + }) + .catch((e) => { + ac_log('Cannot enable sound', e); + }); +} + +function guiSetCamera() { + document.getElementById('video_call_btn').disabled = !hasCamera; +} + +function guiAnswerCall(videoOption) { + guiEnableSound(); + guiNotificationClose(); + + // restore button values to initial state + document.getElementById('hold_btn').value = 'Hold'; + document.getElementById('mute_audio_btn').value = 'Mute'; + document.getElementById('mute_video_btn').value = 'Mute video'; + + guiShowPanel('call_established_panel'); + + // Some values to testing. Please don't use in production. + let extraHeaders = ['X-Greeting: You are welcome !'] + activeCall.answer(videoOption, extraHeaders); +} + +// Find last outgoing call from call log history, and set it in dialer +function guiRedialLastCall() { + guiEnableSound(); + let callTo = document.querySelector('#call_form [name=call_to]'); + for (let index = callLogDb.list.length - 1; index >= 0; index--) { + let logRecord = callLogDb.list[index]; + if (!logRecord.incoming) { + callTo.value = logRecord.user; + break; + } + } + callTo.focus(); +} + +// Try to restore call terminated by page reloading +function guiRestoreCall(restoreData) { + let restore = JSON.parse(restoreData); + let delay = Math.ceil(Math.abs(restore.time - new Date().getTime()) / 1000); + if (delay > phoneConfig.restoreCallMaxDelay) { + ac_log('No restore call, delay is too long (' + delay + ' seconds)'); + return false; + } + ac_log('Trying to restore call', restore); + document.getElementById('outgoing_call_user').innerText = restore.callTo; + document.getElementById('outgoing_call_progress').innerText = ''; + document.getElementById('call_established_user').innerText = restore.callTo; + let videoOption = hasCamera && (restore.video === 'sendrecv' || restore.video === 'sendonly') ? phone.VIDEO : phone.AUDIO; + guiMakeCallTo(restore.callTo, videoOption, ['Replaces: ' + restore.replaces], { 'restoreCall': restore }); + return true; +} + +function guiMakeCall(videoOption) { + guiEnableSound(); + if (activeCall !== null) + throw 'Already exists active call'; + let callTo = document.querySelector('#call_form [name=call_to]').value.trim(); + if (callTo === '') + return; + document.querySelector('#call_form [name=call_to]').value = ''; + document.getElementById('outgoing_call_user').innerText = callTo; + document.getElementById('outgoing_call_progress').innerText = ''; + document.getElementById('call_established_user').innerText = callTo; + guiMakeCallTo(callTo, videoOption); +} + +function guiMakeCallTo(callTo, videoOption, extraHeaders = null, extraData = null) { + document.getElementById('local_video').style.display = 'block'; + document.getElementById('remote_video').style.display = 'block'; + + guiInfo(''); + guiShowPanel('outgoing_call_panel'); + + // Some extra headers to testing. Please don't use the test strings in production ! + if (!extraHeaders) { + extraHeaders = ['X-Greeting: Nice to see you!']; + } + + activeCall = phone.call(videoOption, callTo, extraHeaders); + if (extraData !== null) { + Object.assign(activeCall.data, extraData); + } + + // create new call log record + let time = activeCall.data['_create_time'].getTime(); + let logRecord = { + id: callLogDb.createId(time), + time: time, + duration: -1, + incoming: false, + user: activeCall.data['_user'], + display_name: activeCall.data['_display_name'] + }; + + activeCall.data['log_record'] = logRecord; + guiAddLog(logRecord, 'call_log_ul'); + callLogDb.add(logRecord) + .then(() => { + ac_log('call-log db: added'); + }) + .catch((e) => { + ac_log('call-log db: add error', e); + }); +} + +function guiRejectCall() { + guiEnableSound(); + guiNotificationClose(); + if (activeCall !== null) { + activeCall.reject(); + activeCall = null; + } + guiShowPanel('dialer_panel'); +} + +function guiRedirectCall() { + guiEnableSound(); + audioPlayer.stop(); + guiNotificationClose(); + guiShowPanel('redirect_call_panel'); +} + +function guiDoRedirectCall() { + let redirectTo = document.querySelector('#redirect_form [name=redirect_to]').value.trim(); + if (redirectTo === '') { + guiRejectCall(); + return; + } + if (activeCall !== null) { + activeCall.redirect(redirectTo); + activeCall = null; + } + guiShowPanel('dialer_panel'); +} + +function guiDoTransferCall() { + let transferTo = document.querySelector('#transfer_form [name=transfer_to]').value.trim(); + guiShowPanel('call_established_panel'); + if (transferTo !== '') { + document.getElementById('blind_transfer_btn').disabled = true; + blindTransfer(transferTo); + } +} + +async function blindTransfer(transferTo) { + ac_log('blind transfer ' + transferTo); + + // wait until active call be on hold + while (activeCall !== null && !activeCall.isLocalHold()) { + try { + await guiHold(true); + } catch (e) { + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + if (activeCall === null) + return; + // To prevent user un-hold call during call transfer + document.getElementById('hold_btn').disabled = true; + + // send REFER + activeCall.sendRefer(transferTo); +} + +function guiHangup() { + guiEnableSound(); + guiNotificationClose(); + if (activeCall !== null) { + activeCall.terminate(); + activeCall = null; + } + guiShowPanel('dialer_panel'); +} + +function guiClearVideoView() { + document.getElementById('local_video').srcObject = null; + document.getElementById('remote_video').srcObject = null; +} + +/* + * Start/Stop sending video + */ +function guiToggleSendVideo() { + if (activeCall === null) { + ac_log('send video: no active call'); + return; + } + guiInfo(''); + let sendVideoBtn = document.getElementById('send_video_btn'); + if (!activeCall.hasEnabledSendVideo()) { + sendVideoBtn.disabled = true; + activeCall.startSendingVideo() + .then(() => { + sendVideoBtn.value = 'Stop sending video'; + guiShowVideoControls(activeCall); + guiShowLocalVideo(!userPref.hideLocalVideo); + let remoteVideo = document.getElementById('remote_video'); + setVideoElementVisibility(remoteVideo, activeCall.hasReceiveVideo()); + setEnableReceiveVideoButton(); + }) + .catch((e) => { + ac_log('start sending video failure', e); + }) + .finally(() => { + sendVideoBtn.disabled = false; + }); + } else { + sendVideoBtn.disabled = true; + activeCall.stopSendingVideo() + .then(() => { + sendVideoBtn.value = 'Start sending video'; + guiShowVideoControls(activeCall); + guiShowLocalVideo(false); + let remoteVideo = document.getElementById('remote_video'); + setVideoElementVisibility(remoteVideo, activeCall.hasReceiveVideo()); + setEnableReceiveVideoButton(); + }) + .catch((e) => { + ac_log('stop sending video failure', e); + }) + .finally(() => { + sendVideoBtn.disabled = false; + }); + } +} + +function guiToggleHold() { + if (activeCall === null) { + ac_log('toggle hold: no active call'); + return; + } + guiHold(!activeCall.isLocalHold()); +} + +// Start/stop screen sharing. To screen sharing used the same video track as for sending video. +async function guiToggleScreenSharing() { + if (activeCall === null) { + ac_log('guiToggleScreenSharing: no active call'); + return; + } + let screenSharingBtn = document.getElementById('screen_sharing_btn'); + let sendVideoBtn = document.getElementById('send_video_btn'); + guiInfo(''); + if (!activeCall.isScreenSharing()) { + return Promise.resolve() + .then(() => { + if (screenSharingStream === null) { + return phone.openScreenSharing() + .then(stream => { + screenSharingStream = stream; + }); + } + }) + .then(() => { + screenSharingBtn.disabled = true; + sendVideoBtn.value = 'Start sending video'; + sendVideoBtn.disabled = true; + return activeCall.startScreenSharing(screenSharingStream); + }) + .then(() => { + screenSharingBtn.value = 'Stop screen sharing'; + sendVideoBtn.value = 'Start sending video'; + sendVideoBtn.disabled = true; + setEnableReceiveVideoButton(); + // Optional check if other side receive the video. + if (!activeCall.hasSendVideo()) { + ac_log('Warning: Currently other side does not accept the screen sharing video'); + guiWarning('Currently other side does not accept the screen sharing video'); + } + }) + .catch((e) => { + sendVideoBtn.disabled = !hasCamera; + ac_log('guiScreenSharing: error: ' + e); + }) + .finally(() => { + screenSharingBtn.disabled = false; + }); + } else { + // Note: GUI updated in callScreenSharingEnded callback + return activeCall.stopScreenSharing(); + } +} + +function guiSendReInvite() { + if (activeCall === null) { + ac_log('send re-INVITE: no active call'); + return; + } + activeCall.sendReInvite(); +} + +function setEnableReceiveVideoButton() { + if (activeCall !== null) + document.getElementById('enable_receive_video_btn').value = (activeCall.hasEnabledReceiveVideo() ? 'Disable' : 'Enable') + ' receive video'; +} + +function guiEnableReceiveVideo() { + if (activeCall === null) { + ac_log('enable receive video: no active call'); + return; + } + let receive = activeCall.hasEnabledReceiveVideo(); + let hasTransceiver = activeCall.enableReceiveVideo(!receive); + setEnableReceiveVideoButton(); + if (hasTransceiver) { + activeCall.sendReInvite({ showStreams: true }); + } +} + +function guiSendInfo() { + // Send data using in-dialog SIP INFO + if (activeCall === null) { + ac_log('send INFO: no active call'); + return; + } + let data = { + location: 'Haifa', + attractions: ['Bahai Gardens', 'Carmelite Monastery', 'Beaches', 'Hecht Museum'] + }; + activeCall.sendInfo(JSON.stringify(data), 'application/json'); +} + +function guiHold(hold) { + ac_log('guiHold set ' + hold); + document.getElementById('hold_btn').disabled = true; + return activeCall.hold(hold) + .catch(() => { + ac_log('hold/unhold - failure'); + }) + .finally(() => { + document.getElementById('hold_btn').disabled = false; + }); +} + +function guiSendDTMF(key) { + if (activeCall != null) { + audioPlayer.play(Object.assign({ 'name': key }, SoundConfig.play.dtmf)); + activeCall.sendDTMF(key); + } +} + +function guiToggleDTMFKeyPad() { + if (guiIsHidden('dtmf_keypad')) { + ac_log('show DTMF keypad'); + document.getElementById('keypad_btn').value = 'Close keypad'; + guiShow('dtmf_keypad'); + } else { + ac_log('hide DTMF keypad'); + document.getElementById('keypad_btn').value = 'Keypad'; + guiHide('dtmf_keypad'); + } +} + +function guiMuteAudio() { + let muted = activeCall.isAudioMuted(); + activeCall.muteAudio(!muted); + document.getElementById('mute_audio_btn').value = !muted ? 'Unmute' : 'Mute'; +} + +function guiMuteVideo() { + let muted = activeCall.isVideoMuted(); + activeCall.muteVideo(!muted); + document.getElementById('mute_video_btn').value = !muted ? 'Unmute video' : 'Mute video'; +} + +function guiToggleLocalVideo() { + let hide = userPref.hideLocalVideo = document.getElementById('hide_local_video_ckb').checked; + userPref.hideLocalVideo = hide; + guiStoreUserPref(userPref); + guiShowLocalVideo(!hide); +} + +function guiShowLocalVideo(show) { + ac_log(`${show ? 'show' : 'hide'} local video`); + if (activeCall === null) { + ac_log('activeCall is null'); + return; + } + let localVideo = document.getElementById('local_video'); + localVideo.volume = 0.0; + localVideo.mute = true; + setVideoElementVisibility(localVideo, show); + if (show) { + localVideo.srcObject = activeCall.getRTCLocalStream(); + } else { + localVideo.srcObject = null; + } +} + +function guiShowVideoControls(call) { + let send = call.hasSendVideo(); + let receive = call.hasReceiveVideo(); + let videoControls = document.getElementById('video_controls_span'); + let muteVideoBtn = document.getElementById('mute_video_btn'); + videoControls.style.display = (send || receive) ? 'inline' : 'none'; + muteVideoBtn.disabled = !send; +} + +// Video size. Preset or custom. +function guiSetVideoSizeControl(selectedSize) { + let options = document.getElementById('video_size_select') + // Set selected property in options + for (let i = 0; i < options.length; i++) { + let option = options[i]; + option.selected = (option.value === selectedSize); + } +} + +function guiVideoSizeChanged(save = true) { + let size = document.getElementById('video_size_select').value; + if (size === 'Reset Custom') { + userPref.videoCustom = { + local: { + size: 'Tiny', + top: 'auto', + left: 'auto' + }, + remote: { + size: 'Small', + top: 'auto', + left: 'auto' + } + }; + size = 'Custom'; + guiSetVideoSizeControl(size); + } + + let localVideo = document.getElementById('local_video'); + let remoteVideo = document.getElementById('remote_video'); + + let isCustom = (size === 'Custom'); + guiSetVideoStyles(isCustom); + guiUseMouse(isCustom); + + if (isCustom) { + if (localVideo.style.height !== '0px') { + let lpref = userPref.videoCustom.local; + guiSetVideoSize(localVideo, lpref.size); + guiSetVideoPos(localVideo, lpref.left, lpref.top); + } + + let rpref = userPref.videoCustom.remote; + guiSetVideoSize(remoteVideo, rpref.size); + guiSetVideoPos(remoteVideo, rpref.left, rpref.top); + } else { + if (localVideo.style.height !== '0px') { + guiSetVideoSize(localVideo, size); + } + guiSetVideoSize(remoteVideo, size); + } + + if (save) { + userPref.videoSize = size; + guiStoreUserPref(userPref); + } +} + +function guiSetVideoSize(video, size) { + let s = videoSizes[size]; + video.style.width = s.width; + video.style.height = s.height; + video.dataset.size = size; // used to mouse size changing +} + +function guiSetVideoPos(video, left, top) { + video.style.left = left; + video.style.top = top; +} + +// In custom mode, video controls can overlap one other. +function guiSetVideoStyles(isCustom) { + let localVideo = document.getElementById('local_video'); + let remoteVideo = document.getElementById('remote_video'); + localVideo.style.position = isCustom ? 'absolute' : 'static'; + remoteVideo.style.position = isCustom ? 'absolute' : 'static'; + remoteVideo.style['z-index'] = isCustom ? -1 : 'auto'; + if (!isCustom) { + localVideo.left = localVideo.top = remoteVideo.left = remoteVideo.top = 'auto'; + } +} + +/* + * In 'custom' size mode,let use mouse to drag video panel, and mouse wheel to change video panel size. + */ +let mousedata = { localVideo: null, video: null, x0: null, y0: null, left: null, top: null }; + +function guiUseMouse(use) { + let localVideo = document.getElementById('local_video'); + let remoteVideo = document.getElementById('remote_video'); + document.removeEventListener('mousemove', eventMouseMove); + document.removeEventListener('mouseup', eventMouseUp); + localVideo.removeEventListener('wheel', eventMouseWheel, { passive: true }); + remoteVideo.removeEventListener('wheel', eventMouseWheel, { passive: true }); + localVideo.removeEventListener('mousedown', eventMouseDown); + remoteVideo.removeEventListener('mousedown', eventMouseDown); + if (!use) + return; + localVideo.addEventListener('wheel', eventMouseWheel, { passive: true }); + remoteVideo.addEventListener('wheel', eventMouseWheel, { passive: true }); + localVideo.addEventListener('mousedown', eventMouseDown); + remoteVideo.addEventListener('mousedown', eventMouseDown); + mousedata.localVideo = localVideo; +} + +function eventMouseDown(e) { + mousedata.video = e.currentTarget; // video used in mousemove and mouseup events. + ac_log(`mousedown: start dragging ${mousedata.video === mousedata.localVideo ? 'local' : 'remote'} video`); + document.addEventListener('mouseup', eventMouseUp); + document.addEventListener('mousemove', eventMouseMove); + mousedata.x0 = e.clientX; // save initial values + mousedata.y0 = e.clientY; + mousedata.left = mousedata.video.offsetLeft; + mousedata.top = mousedata.video.offsetTop; +} + +function eventMouseMove(e) { + mousedata.video.style.left = (mousedata.left + e.clientX - mousedata.x0) + 'px'; + mousedata.video.style.top = (mousedata.top + e.clientY - mousedata.y0) + 'px'; +} + +function eventMouseUp() { + ac_log('mouseup: stop dragging'); + document.removeEventListener('mousemove', eventMouseMove); + document.removeEventListener('mouseup', eventMouseUp); + let pref = (mousedata.video === mousedata.localVideo) ? userPref.videoCustom.local : userPref.videoCustom.remote; + pref.left = mousedata.video.style.left; + pref.top = mousedata.video.style.top; + guiStoreUserPref(userPref); +} + +function eventMouseWheel(e) { + let video = e.currentTarget; + let size = video.dataset.size; + let increase = e.deltaY < 0; + let newSize = changeVideoSize(increase, size); + ac_log(`mousewheel: ${video === mousedata.localVideo ? 'local' : 'remote'} video: size: ${size} -> ${newSize}`); + if (!newSize) + return; // cannot change size anymore + guiSetVideoSize(video, newSize); + let pref = (video === mousedata.localVideo) ? userPref.videoCustom.local : userPref.videoCustom.remote; + pref.size = newSize; + guiStoreUserPref(userPref); +} + +function changeVideoSize(increase, size) { + let ix = videoSizesSeq.findIndex((str) => size === str); + if (ix === -1) return null; + ix += increase ? 1 : -1; + return ix >= 0 && ix < videoSizesSeq.length ? videoSizesSeq[ix] : null; +} + + +//----------------- Local storage load/store ---------------------- +function guiLoadAccount() { return storageLoadConfig('phoneAccount'); } + +function guiStoreAccount(value) { storageSaveConfig('phoneAccount', value); } + +function guiLoadServerConfig() { return storageLoadConfig('phoneServerConfig', DefaultServerConfig); } + +function guiStoreServerConfig(value) { storageSaveConfig('phoneServerConfig', value, DefaultServerConfig); } + +function guiLoadPhoneConfig() { return storageLoadConfig('phoneConfig', DefaultPhoneConfig, true, true); } + +function guiLoadUserPref() { return storageLoadConfig('phoneUserPref', DefaultUserPref, false, false); } + +function guiStoreUserPref(value) { storageSaveConfig('phoneUserPref', value, DefaultUserPref); } + +function guiLoadSelectedDevices() { return storageLoadConfig('phoneSelectedDevices'); } + +function guiStoreSelectedDevices(value) { storageSaveConfig('phoneSelectedDevices', value); } + +//----------- set server and account fields in HTML ------------ +function guiSetServerFields(server_config) { + document.querySelector('#setting [name=sip_domain]').value = server_config.domain; + document.querySelector('#setting [name=sip_addresses]').value = JSON.stringify(server_config.addresses); + // An empty array seems strange to a non-programmer ;-) + let ice = JSON.stringify(server_config.iceServers); + if (ice === '[]') + ice = ''; + document.querySelector('#setting [name=ice_servers]').value = ice; +} + +function guiSetAcountFields(account) { + document.querySelector('#setting [name=user]').value = account.user; + document.querySelector('#setting [name=password]').value = account.password; + document.querySelector('#setting [name=display_name]').value = account.displayName; + document.querySelector('#setting [name=auth_user]').value = account.authUser; +} + +//------------- Set status line -------------------- +function guiError(text) { guiStatus(text, 'Pink'); } + +function guiWarning(text) { guiStatus(text, 'Gold'); } + +function guiInfo(text) { guiStatus(text, 'Aquamarine'); } + +function guiStatus(text, color) { + let line = document.getElementById('status_line'); + line.setAttribute('style', `background-color: ${color}`); + line.innerHTML = text; +} + +//--------------- Show or hide element ------- +function guiShow(id) { + document.getElementById(id).style.display = 'block'; +} + +function guiHide(id) { + document.getElementById(id).style.display = 'none'; +} + +function guiIsHidden(id) { + let elem = document.getElementById(id); + // Instead elem.style.display, because display set via CSS. + let display = window.getComputedStyle(elem).getPropertyValue('display'); + return display === 'none'; +} + +//--------------- Show active panel and hide others ---------------- +function guiShowPanel(activePanel) { + const panels = ['setting_panel', 'devices_panel', 'dialer_panel', 'call_log_panel', + 'outgoing_call_panel', 'incoming_call_panel', 'call_established_panel', + 'redirect_call_panel', 'transfer_call_panel', 'message_panel', 'subscribe_panel' + ]; + for (let panel of panels) { + if (panel === activePanel) { + guiShow(panel); + } else { + guiHide(panel); + } + } + // special settings for some panels. + switch (activePanel) { + case 'dialer_panel': + if (!audioPlayer.isDisabled()) + guiHide('enable_sound_btn'); + break; + } +} + +//-------- Desktop notification (for incoming call) --------- +function registerServiceWorker() { + if (!navigator.serviceWorker) { + ac_log('phone: The browser does not support Service Worker'); + return; + } + return navigator.serviceWorker.register('../service-worker.js', { scope: '.' }) + .then(rsw => { + if (typeof rsw.showNotification !== 'function' || typeof rsw.getNotifications !== 'function') { + ac_log('phone: Warning: serviceWorker.showNotification() is not implemented !'); + rsw.unregister(); + return; + } + ac_log('phone: service worker registered'); + desktopNotification.rsw = rsw; + navigator.serviceWorker.addEventListener('message', serviceWorkerAction); + }); +} + +function serviceWorkerAction(e) { + if (e.data.type === 'answer') { + if (e.data.action === 'accept') { + let videoOption; + if (activeCall.data['incoming_invite_hasSDP']) { + videoOption = activeCall.hasVideo() ? (hasCamera ? phone.VIDEO : phone.RECVONLY_VIDEO) : phone.AUDIO; + } else { + videoOption = phoneConfig.audioAutoAnswerNoSdp ? phone.AUDIO : phone.VIDEO; + } + guiAnswerCall(videoOption); + } else if (e.data.action === 'reject') { + guiRejectCall(); + } + } +} + +function guiRequestNotificationPermission() { + guiHide('notification_permission_btn'); + Notification.requestPermission(); +} + +function guiNotificationShow(caller) { + if (!window.Notification) + return; + if (Notification.permission !== "granted") + return; + if (desktopNotification.rsw) { + guiNotificationShowSW(caller); + } else { + guiNotificationShowBasic(caller); + } +} + +function guiNotificationShowSW(caller) { + let options = { + image: 'images/old-phone.jpg', + actions: [ + { action: 'accept', title: 'Accept' /*, icon:'images/in_green.png' */ }, + { action: 'reject', title: 'Reject' /*, icon: 'images/in_red.png'*/ }, + ], + } + ac_log('show notification [service worker]'); + desktopNotification.rsw.showNotification("Calling " + caller, options); +} + +function guiNotificationShowBasic(caller) { + guiNotificationClose(); + try { + const options = { + image: 'images/old-phone.jpg', + requireInteraction: true + } + ac_log('show notification [basic]'); + desktopNotification.basic = new Notification("Calling " + caller, options); + ac_log('desktopNotification created'); + desktopNotification.basic.onclick = function (event) { + event.target.close(); + desktopNotification.basic = null; + } + } catch (e) { + ac_log('cannot create Notification', e); + } +} + +function guiNotificationClose() { + if (desktopNotification.rsw) { + desktopNotification.rsw.getNotifications() + .then(notifications => { + for (let notification of notifications) { + ac_log('desktopNofification.close() [service worker]'); + notification.close(); + } + }); + } else { + if (desktopNotification.basic) { + desktopNotification.basic.close(); + desktopNotification.basic = null; + ac_log('desktopNofification.close() [basic]'); + } + } +} + +/* + * Work with some UL list. + * Used for call log and text messages + */ +// Add li element to top (or to bottom). If need remove oldest element. +function guiListAdd(newLI, listId, maxSize, top = true) { + let list = document.getElementById(listId); + if (top) { + list.insertBefore(newLI, list.childNodes[0]); + } else { + list.appendChild(newLI); + } + if (list.getElementsByTagName("LI").length > maxSize) { + list.removeChild(top ? list.lastElementChild : list.childNodes[0]); + } +} + +// Search in list LI element by unique ID, and update it. +function guiListUpdate(newLI, id, listId) { + let list = document.getElementById(listId); + let oldLI = null; + let elems = list.getElementsByTagName("LI"); + for (let i = 0; i < elems.length; i++) { // without "for of" to compatibility with Edge + let li = elems[i]; + + if (li.dataset.id === id) { + oldLI = li; + break; + } + } + if (!oldLI) { + return; + } + list.replaceChild(newLI, oldLI); +} + +// Clear log list. +function guiListClear(listId) { + let list = document.getElementById(listId); + while (list.firstChild) { + list.firstChild.remove(); + } +} + +function guiListDelete(li) { + li.parentNode.removeChild(li); +} + +/* ---------------- Call log record ---------------- + * To keep call logs after page reload it saved in indexedDB. + * + * Log record: + * 'id' - fixed length string, build from time and sequence number. + * 'time' - call creation time (ms from 1970, date.getTime()) + * 'incoming' - call is incoming (true/false) + * 'user' - remote user name + * 'display_name' - remote user display name + * 'duration' time interval between call confirmation and hangup, + * has two special values: -1 or 0 + * + * at creation until confirmed, or when failed set to -1 + * after call confirmed updated to 0 + * after call ended updated to real value (sec) + * + * So you can separate failed call (-1) from established call with + * unknown duration (0). + * The unknown duration can be set, if phone page was reloaded during call. + */ +/* ---------------- Call log GUI---------------------*/ +// Create LI for log record +function guiCreateLogLI(logRecord) { + let str = new Date(logRecord.time).toLocaleDateString('en-GB', { + day: 'numeric', + month: 'short', + year: 'numeric', + hour12: false, + hour: '2-digit', + minute: '2-digit', + }); + str += ' ' + logRecord.user; + if (logRecord.display_name) + str += ' "' + logRecord.display_name + '"'; + str += ' '; + if (logRecord.duration >= 0) + str += logRecord.duration + ' sec'; + let li = document.createElement('li'); + li.innerHTML = str; + li.dataset.id = logRecord.id; + // icon selected by class name. + let className = `${logRecord.incoming ? 'in_' : 'out_'}${logRecord.duration >= 0 ? 'green' : 'red'}`; + li.classList.add(className); + return li; +} + +function guiAddLog(logRecord) { + guiListAdd(guiCreateLogLI(logRecord), 'call_log_ul', callLogDb.maxSize); +} + +function guiUpdateLog(logRecord) { + guiListUpdate(guiCreateLogLI(logRecord), logRecord.id, 'call_log_ul') +} + +function guiClearLog() { + guiListClear('call_log_ul'); +} + +// Get user from call log, and set it in dialer panel. +function guiClickOnCallLog(ev) { + let target = ev.target; + ac_log('clicked on call log:', target); + if (target.nodeName !== 'LI') + return; + let id = target.dataset.id; + let index = callLogDb.list.findIndex((r) => r.id === id); + if (index === -1) // should not be. + return; + let logRecord = callLogDb.list[index]; + let callTo = document.querySelector('#call_form [name=call_to]'); + callTo.value = logRecord.user; + guiShowPanel('dialer_panel'); + callTo.focus(); +} + +/* ---------------- Messages GUI---------------------*/ +function guiMessage() { + guiEnableSound(); + guiShowPanel('message_panel'); + + // Clear new messages visual notification + userPref.newMessages = 0; + guiStoreUserPref(userPref); + let button = document.getElementById('message_btn'); + button.innerText = 'Messages'; + button.classList.remove('new_message'); +} + +/* Create LI for message */ +function guiCreateMessageLI(msg) { + let li = document.createElement('li'); + li.innerHTML = `${createDateTimestamp(msg.time)} ${msg.incoming ? 'from ' : 'to '}${msg.user} "${msg.body}"`; + return li; +} + +function guiClearMessages() { + guiListClear('message_ul'); +} + +function guiAddMessage(msg) { + guiListAdd(guiCreateMessageLI(msg), 'message_ul', MessageDb.maxSize, false); +} + +function guiSendMessage() { + let sendTo = document.querySelector('#send_message_form [name=send_to]').value.trim(); + let textArea = document.querySelector('#send_message_form [name=message]'); + let text = textArea.value.trim(); + if (sendTo === '' || text === '') + return; + + let time = new Date(); + let contentType = 'text/plain'; + + phone.sendMessage(sendTo, text, contentType) + .then((e) => { + ac_log('message sent', e); + + guiInfo('Message sent'); + textArea.value = ''; + + // split sendTo to user and optional host + let ix = sendTo.indexOf('@'); + let user = ix === -1 ? sendTo : sendTo.substring(0, ix); + let host = ix === -1 ? null : sendTo.substring(ix + 1); + + let message = { + id: callLogDb.createId(time), + incoming: false, + time: time, + user: user, + display_name: null, + host: host, + contentType: contentType, + body: text + }; + + guiAddMessage(message); + + messageDb.add(message) + .then(() => { + ac_log('message db: added'); + }) + .catch((e) => { + ac_log('message db: add error', e); + }); + }) + .catch((e) => { + ac_log('message sending error', e); + guiError('Cannot send message: ' + e.cause); + }); +} + + +//--------------- SUBSCRIBE/NOTIFY examples ------------------------------- +function guiSubscribePanel() { + guiEnableSound(); + guiInfo(''); + guiShowPanel('subscribe_panel'); + guiSubscribeButtons(); +} + +function guiSubscribeButtons() { + document.getElementById('send_init_subscribe_btn').disabled = !!subscriber; + document.getElementById('send_initial_and_next_subscribe_btn').disabled = !!subscriber; + document.getElementById('send_next_subscribe_btn').disabled = !subscriber; + document.getElementById('send_unsubscribe_btn').disabled = !subscriber; + document.getElementById('send_notify_btn').disabled = !notifier; + document.getElementById('send_final_notify_btn').disabled = !notifier; +} + +//--------------- subscriber (client subscribe dialog) ------------------- + +function guiSendInitSubscribe() { + let user = document.querySelector('#subscribe_test_setting_form [name=user]').value.trim(); + let eventName = document.querySelector('#subscribe_test_setting_form [name=event_name]').value.trim(); + let accept = document.querySelector('#subscribe_test_setting_form [name=accept]').value.trim(); + let contentType = document.querySelector('#subscribe_test_setting_form [name=content_type]').value.trim(); + let expires = parseInt(document.querySelector('#subscribe_test_setting_form [name=expires]').value.trim()); + if (user === '') { + guiWarning('Missed user name'); + return; + } + + let target = user; // + '@' + serverConfig.domain; + let params = null; + + /* + params is optional. + Used if domain or from-user is different from used in REGISTER/INVITE + + let params = { + to_uri: new JsSIP.URI('sip', user, serverConfig.domain), + to_display_name: null, + from_uri: new JsSIP.URI('sip', userAccount.user, serverConfig.domain), + from_display_name: null, + } + */ + try { + subscriber = phone.subscribe( + target, + eventName, + accept, { + expires, + contentType, + params + }); + } catch (e) { + ac_log('Error: cannot create subscriber', e); + guiError('Cannot create subscriber'); + } + + /** + * Active event + * Received the first NOTIFY with Subscription-State: active + */ + subscriber.on('active', () => { + ac_log('subscriber>> active') + guiInfo('subscriber: active'); + }); + + /** + * Incoming NOTIFY with body event + * If NOTIFY Subscription-State: terminated - the argument isFinal = true + */ + subscriber.on('notify', (isFinal, notify, body, contentType) => { // with not empty body + ac_log(`subscriber>> receive ${isFinal ? 'final ' : ''}NOTIFY`, notify, body, contentType); + guiInfo(`receive ${isFinal ? 'final ' : ''}notify`); + }); + + /** + * Subscription terminated. + * + * Termination code converted to English text. + * + * For terminationCode==RECEIVE_FINAL_NOTIFY may be set + * SubscriptionState header parameters: + * reason (undefined or string) + * retryAfter (undefined or number) + */ + subscriber.on('terminated', (terminationCode, reason, retryAfter) => { + let terminationText = subscriberTerminationText(subscriber, terminationCode); + ac_log(`subscriber>>: terminated (${terminationText})${reason ? (' reason="' + reason + '"') : ''}${retryAfter !== undefined ? (' retry-after=' + retryAfter) : ''}`); + guiWarning(`subscriber: terminated (${terminationText})${reason ? (' reason="' + reason + '"') : ''}`); + subscriber = null; + if (retryAfter !== undefined) { + ac_log(`You asked repeat subscription after ${retryAfter} seconds`); + } + guiSubscribeButtons(); + }); + + /** + * Subscribe dialog created (subscribe OK received) + * Next after initial subscribe can be send only after the event + * + * If you send sequence: initial subscribe and immediately next subscribe, + * next subscribe should be enqueued and send after the event. + * (See subscribe enqueue example in ACD phone prototype broadsoft_acd.js) + */ + subscriber.on('dialogCreated', () => { + ac_log('subscriber>>: dialogCreated'); + }); + + if (expires > 0) { + // normal subscribe + subscriber.subscribe(); + } else { + // fetch SUBSCRIBE (with expires: 0), see RFC 6665 4.4.3 + subscriber.terminate(); + } + guiSubscribeButtons(); +} + + +// Send next SUBSCRIBE (after initial) +function guiSendNextSubscribe() { + if (subscriber === null || subscriber.state === subscriber.C.STATE_TERMINATED) { + guiWarning('No subscriber'); + return; + } + let body = JSON.stringify({ text: "Next subscribe body" }); + subscriber.subscribe(body); +} + +// After initial immediately send next subscribe. +// Next subscribe cannot be send before response to initial subscribe, +// so will be used enqueue & dequeue. +function guiSendInitAndNextSubscribe() { + guiSendInitSubscribe(); + if (subscriber) { + guiSendNextSubscribe(); + //guiSendUnsubscribe(); + } +} + +// Send unSubscribe (SUBSCRIBE with expires: 0) +function guiSendUnsubscribe() { + if (subscriber === null || subscriber.state === subscriber.C.STATE_TERMINATED) { + guiWarning('No subscriber'); + return; + } + subscriber.terminate(); +} + +function subscriberTerminationText(subscriber, terminationCode) { + if (!subscriber) + return `subscriber terminated with code ${terminationCode}`; + switch (terminationCode) { + case subscriber.C.SUBSCRIBE_RESPONSE_TIMEOUT: return 'subscribe response timeout'; + case subscriber.C.SUBSCRIBE_TRANSPORT_ERROR: return 'subscribe transport error'; + case subscriber.C.SUBSCRIBE_NON_OK_RESPONSE: return 'subscribe non-OK response'; + case subscriber.C.SUBSCRIBE_BAD_OK_RESPONSE: return 'subscribe bad OK response (missed Contact)'; + case subscriber.C.SUBSCRIBE_FAILED_AUTHENTICATION: return 'subscribe failed authentication'; + case subscriber.C.UNSUBSCRIBE_TIMEOUT: return 'un-subscribe timeout'; + case subscriber.C.RECEIVE_FINAL_NOTIFY: return 'receive final notify'; + case subscriber.C.RECEIVE_BAD_NOTIFY: return 'receive bad notify'; + default: return 'unknown termination code: ' + terminationCode; + } +} + +//------------ notifier (server subscribe dialog) ---------------------- +// +// In clients, it is used less often than subscriber +// In this test, it is used to debug the subscriber +function createNotifier(subscribe) { + guiSubscribeButtons(); + let contentType = document.querySelector('#subscribe_test_setting_form [name=content_type]').value.trim(); + let pending = true; // notifier can be created in 'active' or 'pending' state + notifier = phone.notify(subscribe, contentType, { pending }); + let isFetchSubscribe = subscribe.getHeader('expires') === '0'; + + // The event called for intitial and next subscribes. + notifier.on('subscribe', (isUnsubscribe, subscribe, body, contentType) => { + ac_log(`notifier>> receive ${isUnsubscribe ? 'un-' : ''}SUBSCRIBE`, subscribe, body, contentType, isUnsubscribe); + guiInfo('receive subscribe'); + + if (isUnsubscribe) { + notifier.terminate(`Provide current system state (final notify)${isFetchSubscribe ? ' (fetch subscribe)' : ''}`); + } else { + if (notifier.state === notifier.C.STATE_PENDING) { + notifier.notify(JSON.stringify({ text: 'Dialog state is pending. Do not provide system state' })); + } else { + notifier.notify(JSON.stringify({ text: 'Provide current system state' })); + } + } + }); + + /** + * Notification terminated + */ + notifier.on('terminated', (terminationCode, sendFinalNotify) => { + let terminationText = notifierTerminationText(notifier, terminationCode); + guiWarning(`notifier: terminated (${terminationText})`); + + // sendFinalNotify=true will be set for subscription timeout. + // You have to send final NOTIFY in the case (with or without body) + if (sendFinalNotify) { + notifier.terminate(JSON.stringify({ text: 'Terminated state. Current data' })); + } + notifier = null; + guiSubscribeButtons(); + }); + + notifier.start(); + guiSubscribeButtons(); +} + +function guiSendNotify() { + if (notifier === null || notifier.state === notifier.C.STATE_TERMINATED) { + guiWarning('No notifier'); + return; + } + // Switch state from pending to active. + if (notifier.state === notifier.C.STATE_PENDING) { + ac_log('Switch state from "pending" to "active"'); + notifier.setActiveState(); + } + + // send NOTIFY with body + let body = JSON.stringify({ text: 'current system state' }); + notifier.notify(body); +} + +function guiSendFinalNotify() { + if (notifier === null || notifier.state === notifier.C.STATE_TERMINATED) { + guiWarning('No notifier'); + return; + } + // final notify + // notifier.terminate('final state'); + + // final notify with reason and retry-after + notifier.terminate('final state', 'probation', 20); +} + +function notifierTerminationText(notifier, terminationCode) { + if (!notifier) + return `notifier terminated with code ${terminationCode}`; + switch (terminationCode) { + case notifier.C.NOTIFY_RESPONSE_TIMEOUT: return 'notify response timeout'; + case notifier.C.NOTIFY_TRANSPORT_ERROR: return 'notify transport error'; + case notifier.C.NOTIFY_NON_OK_RESPONSE: return 'notify non-OK response'; + case notifier.C.NOTIFY_FAILED_AUTHENTICATION: return 'notify failed authentication'; + case notifier.C.SEND_FINAL_NOTIFY: return 'send final notify'; + case notifier.C.RECEIVE_UNSUBSCRIBE: return 'receive un-subscribe'; + case notifier.C.SUBSCRIPTION_EXPIRED: return 'subscription expired'; + default: return 'unknown termination code: ' + terminationCode; + } +} +//---------------- end of SUBSCRIBE/NOTIFY examples ------------------ + +// Use device list in SelectDevices class instance to fill GUI select list. +function guiFillDeviceList(name) { + let device = devices.getDevice(name); // name is one of 'microphone', 'speaker', 'camera', 'ringer' + let selector = document.querySelector(`#devices [name=${name}]`); + // Clear select push-down list + while (selector.firstChild) { + selector.removeChild(selector.firstChild); + } + if (device.incomplete) { + selector.disabled = true; + ac_log(`Warning: To device selection let enable ${name} usage`); + } else { + selector.disabled = false; + } + // Loop by device labels and add option elements. + for (let ix = 0; ix < device.list.length; ix++) { + let dev = device.list[ix] + let option = document.createElement("option"); + option.text = dev.label; // device name + option.value = ix.toString(); // index in device list + option.selected = (device.index === ix); // selected device + selector.add(option); + } + document.getElementById(`${name}_dev`).style.display = (device.list.length > 1) ? 'block' : 'none'; +} + +// Set deviceId constraint for microphone and camera. +// Set deviceId for audioPlayer +function setDeviceIds() { + let micId = devices.getSelected('microphone').deviceId; + phone.setConstraint('audio', 'deviceId', userPref.devicesExact && micId ? { exact: micId } : micId); + + let camId = devices.getSelected('camera').deviceId; + phone.setConstraint('video', 'deviceId', userPref.devicesExact && camId ? { exact: camId } : camId); + + let spkrId = devices.getSelected('speaker').deviceId; + audioPlayer.setSpeakerId(spkrId); + + let ringId = devices.getSelected('ringer').deviceId + audioPlayer.setRingerId(ringId); +} + +// Set (or remove) deviceId as audio element sinkId for speaker +function setRemoteVideoSinkId(remoteVideo) { + let deviceId = devices.getSelected('speaker').deviceId; + if (deviceId === null) + deviceId = ''; // remove sinkId + if (remoteVideoDeviceId === deviceId) { + ac_log('remote video: sinkId is already assigned'); + return Promise.resolve(); + } + if (!remoteVideo.setSinkId) { + return Promise.reject(new Error('setSinkId is not implemented')); + } + ac_log(`remove video: setSinkId "${deviceId}"`); + remoteVideo.srcObject = null; // probably setSinkId check srcObject + return remoteVideo.setSinkId(deviceId) + .then(() => { + ac_log('remote video: setSinkId completed'); + remoteVideoDeviceId = deviceId; + }); +} diff --git a/examples/4.phone_prototype/sounds/bell.mp3 b/examples/4.phone_prototype/sounds/bell.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..3431fda9fdd8d70f2497aeace9b25ba82e18ce58 GIT binary patch literal 16741 zcmeHuWl$Vl7v|vZ?(XiI1h>H%+}+(JVQ_cX0Kp}}odklrLvRQZ+$BK5EaZLj?YC9C zzqe{@Z&mm0JKfWL&U2n~`dn#wDIOTWOECt?gSek-wC7F3(#^}(+>+AF(!oJeMM>%T zC*tSrrKnq)JG)s}TKqXj>F(_5WWi4PU)Sj9==|@mfjlN!{Bw){^Ipf+$@=*$#`DGk z0EqnpprBx35fG4*lhe{NF>!Ek@bim`ii?ZO$|@^sXlUr^Sy?$aIJmp}`UVCDhK0q% zBqb$fWaQ-)6&010)zsA2*SEHIb$$K%b#QQOYY};Sq_$X{n=f*3*{+xUJ@Nl+4SDQ-Hqa#u;^cl0R^+o4 z&H(@@jLi;#YEG4XbHHEYA**gf3=qM>)@5Fo5}fX-sNx9Fm=f)iy>PE7?gJUma6--) z5upKKR0@R2s2(`d@9yV=5AnW`UvJ8}E`x3MsrZY(SS{&B6mGNrjHE22jKd_qS*{%! zb(ADA@ z`_kWEv18t*%5n6DNp)U0895eJTg8lz4N$Z~+b+DXznWcm=xjMB=jgJ>n0EHsFx!Cq z&+>>HtGjw=-yhrQCmYR-qL0kZKnD?w3W<`=og07EXGu>ez8LaG$3ipez&Adysgl4k zrn%oD7Voojg3^3m)4RPygL(ZFUB_m9)khv*W#b&`nf4AY29!jz>RN13hkRzF%}<-;E6=&I zbBoqi@zQkb$_g|=@*XaB!p`ZZ;rU(~QCwT4>!FTdq8KzOejpJ}7;VBwP$Bib0ZraL zRy?@@#tosjHEE+cIxDP0$0vo|Vm@K*L#oGG3RCuagP<^+FcwWPb;b|+2;r(ED#@^& zpKrj@oCO$vWWMS0E{PV?{3EsXt^MbgT&u-GO$8u`R>PbqsQpzpcOG2jmfKaR%646PmEcApS`qh6MfW#mQ|cJk^xGjP3vn#pfoc zEHD!QMTocbRx#rE^OxiFhd)X|%AO!>i{ASUEgo=YnU~OY{hMHkiliv|c;h20tROYn zxcE$9JiI1ANt}9GToWeR>cmq<$6eMTJuCN3o-OT8R_(01&gvSyCiP`j<`|&SSdLme zAQr`tr>i4-v~*~fd7OUTMJ|&w788#uplQQ`HKiQjJIl<=`9wmV%Y!e1qbkR3P_^Rw z9hfav$+%In*KhS3q-%Kgeqv;00WZ{^9E;g3z8cMHbWEM7IodIp6Q znK(>RMB-~w(9W0wl`!F2xKuh8?``2?f?*RlNTE?!F*&=j;e%x_X#3}2Lu?((H`6#& zyz_}On2Pxc@*kmL<_vs3lFYxUcDrN@3`2fJhgor7Jw|`JaL5iq5juA zd9(DpopRTT3-Y>hdc?7m@ef2+&TCWOLSSbr_h~HPAVajQ!Wt ziHE*CKD3NA?VpY}w0cVj2t)|x1G$B>-%;B~q1ZY)9{X?f6hvr84+wZLzkPq2m>Fpu z&@Q5{^hZ|6Qi{r-12^VH_g%CYO!l9+teBecpcy!Ahlgg9WBVynME&zNT56u!zTOn6 zdW#ryb!c2@vbd`3R#G`V?A2SMfTp8n!sGjZi-nKxvD)xfgfbjl=hVza9}@^6Z$;|` zyXF|iR9Ww#NLX)jgq|W~P{mZ!2=!&fhof9ABoIfi;EY`>M)hKk4)tZe^OXG(l%VlPvqJnPzRu(yGvW;q<1kFFm?d&F7Rhfum>8;Z4X{!h_u@)I;o`?o zMPoxzPRjPf{UD%Gqh)8E&#{`j-E(4`O!Y~z^?jk&(L=7gRhHem{%Sd7 zUZfoPR3VFsM8*^5vgy|mrsx0I;op4=iM@42VibBNH;yfj0%gg=kXLtAd{00`szDeW zUuwr@5E$B6f~q_?h9exdhg21a_le)2sXmsa!>aw7x284<XnUy@29D1xpM&SP z`?t{Bv+k#!`D(+PC;RV8avpB{!pLZ8qiiv}TX`XPT#D)y&QF2vO}Zhkz=th&*-I*W zDr*U&BcziM$iZY0x6=M$`iGiOws^_hQZ?-5Z4S8A5w_Z$2YMz!)$W215`@8sF~PC! zl1YZ!{p^cRii~n~_HZK2g+@E#czFa6nJG%)*A+iQ!iDP-`8Nve9FmcB->8PhM+}AT z&*;Pp-=<&`!iSMC=YQQ}QNx#*zm?THzEq?^fCa!6)sMsN^vG#hSopp@I_x(L%N)mJ z?ha5Jg~DRC4S{kEHZS_15ILDk3T2PmElBMSx&DV2&tP8zuFb8+?NLb{Fee$$0nne- zT{XC>Ykl?&Ma{(k$j@2gKSh$47vM2AicJEOZDJ#jTTGaevO>%ZM=L?asc2%dDPh?n z8ww~9&S}SFwh%o>u6$IE?p2DXF$;d1r97b_x>KVwkD$Kkr6nxvC^WN6bE5aVDwf7; zPleBO2xzloB=z{_RiJZ%e1c?b%TpV&_R6>KL4AkWqNUe`b~4ha(McKi<@~PnTN6(~ zEO^p9RVvyz7Pe0TI!%iff}S`&R$uV?tzJQ%-v1T%r9O=Nu<*ey+fV^*7!kH$^_Dkn zCz0EN74xis2`Ih_MGD)Lo0#AM8xf-pYkNON2czq|;ao~>SH}|{Y!kyefEne6JY?e` zO1o6suMC9c7iqAJ9;I`52juVc^PT~{!b2rzU292_OpYwIDB-7-MGkhAlT);L*O70M zF-oaRh-wL(#~bsfTJt$Z8?8utVfHondP#Q7o{4myr~vUf#{}RAeRu}j(?kPo0e)_Z zChW=lcDhas8ejSiz45HVV&L$i^HFV;eSInj$um)KHRo`-Ur;Q!x0{oX8K8pQ<1G!H zW`~)9okWEz{gKy*t4ug{sRYp??Xa+7X*50ZXKoaetG-p_ptVxo;U{0`$<_}w$crlU zWhJHY-9`1M$KKH!jIMnCfgLN4_YUBEp~7gU&+1uBDrF%brN{hPIg)Z?el6ru-%)=` z+(2QJM)yxX$?{lhvFt|_6F`yu{pMN5zhxpyYaYMcTztNmO%qB+I+qwhUn7cl`(Xh8 zTqagMIyDkI2n%%zn-Z#Er_wvDweVFz>ll1K7xb$j-bl3=`Oi@}CDWcWo3#S=A6_qo z^0=#}7}-dT`dnu_Lb-aTB36zEe(~`&3}(M)VZ8mZrHPH_(@sRfZ>g6>*MT)7y-ZE` z4l7+2eF*K`TwClV&i?@Hq}q%gA(8H5DEk6lm@S|29Oqs4{e?e-KEH_BaO~pA4Io1s z>%1+7R6FfSmaQU?o4?w;)DQ0~(0zt2TO6s?d#L!`3$S3s`)?x2T+8FBh{t}x?|;W+ zR3pX39ByFwGac#Pc>LP_cbwne%ggojPS_UnL%9JvAybsts=s2|cK@5Ek_GRM9q zXID3QL@p1{QL35qVnd{Otp~3~NvLNUI!OFTl51|!CKPz8DM)8vgh?g>30!5(6cYF^{=(ewD?36808xUo_dVrh#VnL@Tq#e_j0K|XZppP9QWG~+E3$PRQ z9OscpeF#m6FrVpc2j@0#5CF<9fn-#j|!6hfJ{3jN(>T&{*%B35aJI74n1 zUf1{_%^e4u(#~*VV_3;vWF`1qf5+=Uu{TcLrB_h@C^XF|tF=OFIz%Zi1>1*$lp9a&aR8x;WHwWf~9vq{xWKfhudkIF|E z^yWcQ=OOCSpv;asV!pL-?slf(V((ha2;tqZjbbw^#F)o`T$8i zNnFp~Q2rJ`^AdV!=tdiPqW()M$Zx^e;JZUT5fnHJ3+QS2QEd3wG^kP;Nq+2BeCiVh zLL{JASJdHpk>B_y#KgwCXdMHx8Frhw#_Xz`9iHuldnCcwC1n-X5?r#|!ISm)FiE+3 z_UB#$gy*Be6l&&|D->oO zvgIhw>D*NsD>sX>=Z>e2Ed(pr2UgoL?3%S|s!LL9&3Kvwq*wVLE53idJ9njBNXF=T zZ!D9@WHoXfM5;RS0`}nx*kjLN+u>3E!)z#Rj+fA*1Ev*w23uk*m-1<7dS6f2o!kGzsYwCY1`1I7MaXhtJKcyMW!`BGS73QL2rHJmTq{vAs*WQo< zUsGjCrO9KR@$D0<^I3Ga$euKBGAaYL5IWnNJSqICB+OhJ_^y&!t4CINL|^RLSc~Lv zIwYKJw<}@#S08y3MBT^?ev!~HUbKegB_s#7w950CQ*8ocgJwiRUR{VtpLfhN>vCt` zzPrmEOK!`NliEOx!#v;kZwXVcQcFJ4lW^GCp*yZHH_Q1ANw^$95k^(F#^Im zQLsiWShB=HY!6lpBz6DOuoHqSQ3hMu5HmUki&tDkarfWyW;_+e=ZTW%*o zLEMiWCb=bv1Rsj^J;hFD@K*>YZv%Bm6!Cki*s*wx%%7QN@#$?iqK}x&v_+lSjSKl# zdnndB!`FUTZv$mZaTK%+wi5(Y5653Ge)*Z+Qw>Zi?qlMx+kWUS4LUDz%JTvgf7dva(nW@-Q_0hN#~NpOwF zT5EQ&0Gu~|W*&#cit%N8TwY-T)mC7>4p*z(GLCCRo>l2037S<1;i{#OA-^kh5+Lr4 z>b$StFMlm;-8DzPMNy`cq&LKaIlJqoUEb}GjiVJ#!gN4Z@DMJcAe7|o>~@kI_BTQ(sBZqLA{M$Q&Pik(xWr~oCMX(M%n43x zyji?%oLCu}v(;$N$H)Ovf_uPl_9LMtKq%-ZDj^KqmJTXD;3p>qD!f=FN5nTsi$)lL zy$@I#ifPswGbxSw>g#4LN;r;KfJp!V9sp=H0l+?2VkQqbRsc%L&T1f|<)!bpcg8p= zs&b@!JpNnd^oH0Wv4{Y0_b&=mcCnw`KM52uf?TQriU2V{H-KM}KG>n>98nQbEO<3q z?|0+9bPUnfM{8%q3vb-9Zbq08fCA@jHH&rbyIln&{J2a&(0#~0J0T|QQqWI|OiZYI zFaVH=8L|}wV9&%1x(Grv$OM3)f}Ve*06bTigqT4HPgkc`r)`tHf4%p4oOvC9u@t#@ z>fFcqGS1u$01!e=n*NRk0L;O(z~@_@PYNfOmzEaDtu_mg{QJKvm`y`gxSp4L140gh z0MCyHKLO+qMdAi>p@Yf z@`4OuQYd1MfQ9d#bbqy^gFhFK-oh*N1yPUH)y|@1MOD%{OhH2~Tl(ma4Y9@P2Nd#h zMc2-HV`_4p+43Lkl=P|Xl6XBXk?6Cl^r@p}H8bQ>XuCX@a6pDtmUE{TALu&X0`>Ul z4&RO1Ei~YZ41nPg{!zN@pQ=qSPR)H>@WFPZB1;WGj!3}CkR@*&lP-wb0}ThSTVF@` zb%XWx`veF*Equ8Y77wnP5l}8B=4z(fi9qm)KcX_1vd2#i^Vgyu3pDX}L*j4J*O1G| z=l$v3bw<>1vHtzgDcme?Jzg2Q$$fO*lR77&D-1J2}g}(gqn3XwB z7W>`6>Z$DrelY8kVaa}Vj^db?Z%y4I6aW*|nxALvr?$5#9Th7b1-EY!mM@GQQ2i8U zLm%Y)NvZIS#aFbUNajK7rfY0g}e|m{Mli(XE3+*cvDU*MvQ1I0vw8v@RJ{*H`g~LYfJ2Ng6-!r{I|1WYmk&+@jsNTDX{9*76aV#WvjTbu_Lu`Tw zPM2`aO%}N~X_SW8RSsQ!$w>?rkG11%KYk8_r8MyQyBr7S7&2-tci6b=B9*)_l2RCJ zD@gK;iTkw=;-EqkLbce?-q=nL-^73{cnhApfH1g(y`~nGV#*fxS;lgwC(z%RsZ zNQhH7qqyQk1+<3bB-ZrkM(n8U@m2P~tJJIMxb@a)DX?yfKv%A1DM_w?5gGwVLbWdMA<^H0zoFeX)MeZ5TCM;EoXyh zhP0qO)^+!HwLUrl95j=|o}^m?9NoNijuj29auJk@O+p8$Bt887~If1m9ek&s`A%pT{2l%yHq5d#jDvVmuq?kAbM? zQG=^p*S<`U{@_@cnKaCeeW(l;-`&UonC`!mV(>7b%?2Qx;fqx2Hnt-2ud8#EiX>!K@Ixlu%L6ks$NFR#93}ROSg#b_&QCaV^Fzij}HP6{h%#O(5w<~$i+wX1L z26Nd-O6C8vg)ccOgQUv6=2f`lc)6#&O4KRwXz@~2hkCp)a#RJ`p_191{I|Dd)(IX} zO)I}gGT>z_JgcT%4!Th?xddZIh;3{T)5}9~m`#I~GtjVfy(Gf$J-9oKaOAeh*zl$1 z6h>#J+&OY1j726sHw5MIzDec21k)Anf~YMR(*S^$Z3a<$MYgNSE#{gpHjimLNzfNz+xTkMSA8NPEe?0TJnohruM zsPPSWK2mZ)BgeH1<6ULaZtuApYmj`l=kAXa|DE2gB8Of5Go@fa(||ikmz!4O$5Wnl z!_Tv%4NDYUxMljrhK_4vIjU7mRd3$42qo%TfN8t=jCle;TE0_NYIVFzw-d;PnCW=K zE9;tXdNiZjhsB}j5kY1B&|yJPFpZo$Cx_%{B+^&~-C!1MlyGdd9Etq~)hjSPthvm9 zd`FVLaMa^ayfT&ug$1kLv(anN88mlCIr(z^x^#IG zk32zXd@e!aC6|2w+{ha(K4KX7{c9k+FlWPK&ei>Y4U~`Bz!!hKjpiB{#+TMS1nrrc z>|V(Eoiom33_cvJ+6yW`BxV4If_GX!JY;kFcv)a>GToNJZY`nw#%gJ4F^F7p-n)87 zV-ZG;I)EKk+*F$Aanj#xhPKQ*B4ag}qL+G&QfxpOGGOB|v3IQne)rK8S1VbmZ5IBh z@keR(udZFzxl8!bTTr+I4|hs?Gydh(!L7-4C}5$A<3R6;Yx3O*z0ePq6#$KJ@0G_$eroR(Eb%XGhw4MOgIR*w#nP$f7iM&TLcfn5TAKCC6TCm#~$B4>izt7Bxy46eCwp&iAyZ!(aqz&R@)|chM+@O~xc(n}v z=9W$?;;dK*E*>$pfevO*#ih)YYWXAb6b~-2@8qh(0`4T)-&*g`vLNZ(J#vgTTA421SmM!MIcJ5BnJdGO=pC7Fse`8gCn< z;za34Z8BYpyz`z$A~D@#svNB~q%nz;)tYMh>>VcJT%_FcG{h>>Yxy*Yh{`EH$drb~ zd6&0oLSYlJv5oV@<&F(2G@Bfua?`0{jdRM2qb+0Fh?@1h&7T}5%DY{8}wh;>@{zMc~Igm0AJ1=1A3;SOu9*CN0Gkx{rR5K@ZF z&?wz2=pA9FGn-(TX#ubA^D&Gm^-OCU z6M;BnQ_=Qps72z-$=gV1S#1~mrA?C- zp1K-ohiWQwnKuiAnv)?G#S+@8XTNO?Ul+UbQQa7uE$05P5UcgG%dj@pZH!Ho@~AGV zAbz}TU-_P(D(uvsV0og=G;8x3E8R$IbONcKL}Eslag|{W?TCt$)Er)0I8$5-k5W zj6_HfhC7ns&rzsOGb1_@cb{NSBs!3Z6^(UuN{uP1+sAz}Vzla~n}CS8aQ#|UtPO}7 z0s!D~`IN?!$BmTdXAQbxUFgYei-jq5n&2#SPISN3Or|0#(#P{(Dy!cTmz)gq87lbV zP1fZm{-U;7fA#C`{UdOYqtwt{k=AzZV(|OQ-fM{Zwm54D|8`)DN@)Oni9gFXMSlBn zKGS_NjItYHyPt6<-@-*nQYrG@xYDW#nO?j#tTSiyWDF+3A~R*Oi`;K*3d^J~%J$oC ziz30{Y(Sj9$y#3Ys*IEZ(9&`{_UL7b2P@{mCbKRpV1UrcBjt3RO3a{#gH)B*QJU#- z+sWESH7$AX#cp>+nm7g-nYSpZLe(LcIjNd{i)^6dQM2|*D8w(gS4~cqs{wnnJKx>o zRDSsgg)vHezR>%=A@Y?(Vl7RpJo{?x=YWHUMt^^XCR+uN)NEDk!;dFW`a7?JIFGu_ z(XRrUOhPTEKaLWj)5~nkgX}*bzjy-#a1&`ZH8P5hHwfWaTFj=L{3xM=+ zqq_@?SY`}AP8cwiAmZWrBnmw1B_d61fV5RP}Oh9Q%%ky<^*g@)$x5{-yD~cDC-J2>*c9}XDOfZR)?kE zAcC>`eHA>(p8XgJuld7*m+QC&(Njw!2ZfgVx(Y<3b6ZF&dStXhi7+Ex;;sZmIz5~Q z3KPretbm4;lCxbiB)wD|j955YuF7eGAR|D_98b-?texp>ALTM~x*< z$-epxrb*Lq?oZ*3;U)_H5q%fg*jJB%H`#KxvEonFHJT!0I~h9d=M|vBqpMGEoMgf? zB$^i%BNV25nP--2-`lCkP}+h9bPkPx8d~m(CBkV0llTqaZx!@8 zUJWNsTZ8MgZZ4=PIGBUM^pB$Q5`w6Lt{#1_Y^jG82la8?t^!qA(rsN8Utikt)4EEL zslFCGtvNI-_XE?ff0w>o5IDN~R2IK&&_8inX%*os55-8V9~d-^T5Kx#4b4mj4hwq+ z2YphE1`UlaK6=6`62^hqAeGR>!j-o3RKRaKraXC?q%L}zhjWx{=`m|@p8M-?+?H{5 zG|eghrZFTz_A|Fs=?0`_2G(j`v;CB}rD{Xq)z=oc%-W~GiDuqpea*-u?i_)=6H`#- zWLnnyfa982W_VWHLVR@^g4rO9&x+g&85Z7|FffeN`X_R!h|fzRz9Hg{!i9nX){;my zFJRvTZs0*vk1C3G|1uk=j_;Y-gnya6sZKaAS$@tj8^}x58hbK3A4uuz5Q5%pb0P}E zMU?r#%%7|#wHK(=W!IF^wc8cZ$C(;~c=r?lIZM@-B__o2Rq?B#@CacysRSN+yByH) zVJ=Hb9Am>BT`*21y z*IOQnzXpTjLfs*idvG2LUM_5@Mu_F2g&^9>_j)UxAb`8^l4Caj^5|mm^t_ZoY3h-K z*XJ+T!#Qt`ivylJqklSFl7?<<*cm2QeYT}jOT(oN*q#OK8tYDdz$RcA!(o4=-=e^J z`x0>U73-uplrd>@4(&<9y!;iR6 zcEat7D5{ThWD9CTsh_Lk^--f^0P?5fK)Nk4+|hEm9f-Wcpr1r-{O-xqpk{N^c*z&P zvc}U6Zmu;EE)6Yjv6BFvT<^Bi#!SO`3JzOrPy_(l;f19qfa^!lq(37C^S{7h_cOgY zrVaSZQj+(}qumyjl=9Zlv0mZ9hW4$!xbkpZnd7jwg96extX}G+iYLn-O1=QZ&LkL? zJ&S85sy`uoZ7j}|A8YyaN?-_AxTDZKI2Y<2i#c?2d}M9N_u2_%g$YF153B+Pr=(Z_PnzzDvd83k zIzHYvQPl{Ek|DdEtp@ZCx;{M`!BAVZk=TO3>57vxH%n~gjC9y7hMQPvOiF-6F6J~t z9v2i&WLphDr{PFfT>YZkwl*X#t7`3qrMKYgbIplIdV=h~EXC6hI_~t@{FkL(hVmCo z0Y-YfNGS2M)OB9kUNpwkmdgzv0|zfUxU42!BDWN(+)5#5kGp*1!vbrmH1D96#|n8| za?;mgnKu+{NRKR;5uV}7W^4c!P>122R{Z3rT!Kc*WwoE zZRYeX*>fZu>fE_$%BA>tE$2=xJxSr*3tj6ngF#OVb~f0b7nY&reaREWZ}I19MC&TL z%-bnG7$!O0Nzw?kYvr9O9eY}8zdllE+CP@UCJf!H{>Facf)W-y7NiO5qs;@OT>Rw- z-kg!OoEt_rD>4X-gc$XGWT3{xegs|a?!-cLTnsA{#WnepL0;{+J2rKNIl663v1umY z?ZWqg;9FApoNcSxr1Mo-ML#>fqpflDns{RQe)9-oGPuFuv`^E*B5A0!w=xqWJM|^_ z&D5;1l_z@b1r0_P+)KN_5h?A~Oh?d$EUck;)Vf3CpBybH-rKDN6CcOp!xM;;OGHS^x5lK zg0ksyr5Bbyg0JaWmF)$6{>D;lR}H>uQJudmh30nm^-Qt4v|L$J5MWvhEn5$%?Bn|~ zVfooR`QpdbT!m2559dHxGokZhABDb>1_seOa@M>BnMa>aYCb{vu7aC6rf4irUsY(u z>Og&%SW}!sSbPBGev=iSPI=Jb7!6BRU*4!xTiDL=1R@F* z$R7Czy$$NwuKTRz`{j%fWWrPLPTh3cA#HI6mk+FCJ?HzV=2Qxobn%k)Q~pi1nf(Wl zKk1*fScbM7ndH^jv7c1K8o)aODyB!lqkg%wEr)uq^JSlXTf+Mm-a7mIuF zbtGuwk%Q&u-&o2gEpYt2#Oq&{X6h4=2|I9l?5@mKdF6&aJIoDL_*3n#8_y^5#gAv~ z>Et;u$4oza*8H~dq{(0sXh}=miGZZN|YN@3r8T& zvh*xFw}FAs1l=LnjoWw zn1>-Phlk`EOGFCL&w(uAilb++D;T#EagK*@1}yb2eoa(&jFY|qcL~0>Gnw$mVAcEU z-l>B;)vpr&0+$zDRiJ%(QVY&xt|yfs*o$j~9ZE{YwX>mW_G^!7QrGw{OBh`r`dYkY z^Lli5>eI#>-9X5Z;;-(I?S!n2nuuJ5ZkMp7T#?&zZCMvNA^5Gl?|A6)m`Dym!h?6# z!z}X}+2oQR6`2CsD1h!#M^2B~)d?kRu~<3zEv5Dj6u)`?P``=PmKmd;tZzcNn>Z?VTW%&1LWs? zjML>GSl(`}cC8x}<;kRfmO>u2!976phggz3KZ)5LFaSE+*m2}B;iT4X`AufGm$FC4)a{0m%?Jx?|5e_Yjil)5DDh;?cnrz5I( zXS~8(v8xzyqRM`Iow=Z$ zgO06B7p7mSgg)8et>$qa{)DU~Q^Vo!yix$Rz`@1iaL=y783B6s0xQ~EP^cOgWK!5B zt-fK3MsrAtD9b1FzilP}(g+q?VE`vIUu6uq3-wo9I!Rb?E>MMh+0D%mavbpqj5G@4 zGLu)eEU?s!U-YP1AA2y`aAtoO00q*ag4SmJ+&odikBi4wX-_#jB%yn`TKrSh#GZ$C zS3Fhco9N9GpA6R{Z*znd3>M*W@D$=nt68P-``MEd&yn1rbcL0bHl5&MCUkRP z?{W9=cBWe9ldgRUj%IN~73)s67PFuY-l!9yCOj~QScC3X&W!J^jU_ZCtRc=%@St}Jf|0hC_W#HV#U%U6-%s-nEuoAb8w?SyWE zFz-4J27C{GCC-xphvrmN1mW`z?; zwek`J)_z%uB+!0n+`V)fS!SlI+;G!O-3_R@T(&t_cSXs$l z{(ri6TLjNBt0eVF&k-v$!(9qW!l+PEBx#tv1@*yxq}-JkOFt@C&;fADN2 zv0pqaH4kPHuisx^4n;Y3naS_f?5T>A7#~3-(C>*^_$+USoTG%HGgZW!u?!+3ol^EO z6+(sUBa`Ksng;rz>*x$Emv(XEYE|WTIp^_(N1E{{?56Qf*fXr4YllczmbjSX#=uFT zMNz1GOn9nk^?1&-d5?0a{1TuE8z%$x5#KCh^Mln-5IvHc-@KVob+@`s-bO@l}Vm%$klY#k|BD)LD!Ode%$Qo=Gc&8WhztNPC)g6 zwRx36$mE*gM_c9|(vF=&jpyM31{hl;cWt(Z0i^OiQM99SE#_ubJTdbFSY{ZEC>b?R zJx2}RPUC1B5c)#l!h^kA*)0>}=$={H_O*){^;epOZ>o{mv%p!eGgL?1hZdwFIyw_C zxAC~&jc-!$81&8*w^&C+B|Yy1m1f65?ZgQ{RlR*mnx%(vwi_;cXJILHzZk*(tNQ!X zfdcP0i9t>|q)EeFNkQ-6_B{!yu+1x(F~tezNo1`;3KSOfs?oPiBa%*HM-*rqLlCP= zYk6=;q+H^Wdc}Ev+w=rifR0~)dtSZh{l5T*CGP#_~{xmv@dG-`bO_ zqCXAjg=Kj=0K^I~V5QvVq#0)A-V*ljZ&axdHMAN1t_GQl)<@8;k%VX#>A6rt?g!#f+h;4ZsVMP5AHWoPz!=h0P)IinxY#Gu;BY| zEV?A$mm;y@rf+yC<204qHu~*Lzvo4RlZ%U%va<({<1EiuGN4ut^`T)g&Iv1K?wY?I zNy|$gUFn)c_(H>YNNGN!)h{RzMM##d}d+R zg5uzW**#dT>9&t1Q6jb<6ii80E&3f3_ZQWDL|&A!*}S7?v@$4Ry)479!Okon$eUkj z3)p@E?gDUara5lU^dH7y>B>GYf>ta47r2~BU3*{uj^?>7$-%o_VCL+8+$ciL$M`nA zhmAMBX(K$F_*x3Dp#pD9BY3p5$*__phNCM_6AKR$6uCMl z3hSyGhd7Qqg&Ep%{Lw@LFZxkH3;HXO;%lnHbh)%2iY+MzYs4ThoZ>6WpcmktQy2ri zXW&?u|0c~`K%STHBK`%A2B}f0F~q8f$_)XtTrn<32-`bYu97RJrV^b^DSOul0ku-w zVYE2#YHQBwGRvDLtWfHzG}L8;fwW%h-m5n(=;UOGk|8Q>jbJ@&ueu%Gut=S!&q8LAmrsKv_U*=Jk0A{(dz5o}P<84@mQ6#ou|%ZP z1$9}L_xLfiI?Lw~?YJWZ28%olalK*mxSb3e7gmT2-f+m^xX-}PLJ`@uH6zC2R9uDBg{i1w^^dh%_VyW7xz zrCbU*+6%N=l-6d8Qn}xae^^uITdMpHf$+P+&vQ&5)SpMk@pvM2JkJq3d^UOy0|hVv z_(JR1fqe5vWYh!+Q=yG|xnmV~kU6_mN1y;(R1r}l1E$mGE<3Q;iUpJ=?wA!kw6Lsj z222G7$p^6EoZ-oHneF!Y^B`^U1a;HUSOj8z^koCn#2{Bm=|oc#HDRdWZ{IEHcy3F= zMTy4|pk)(lL9L}FAsa_OySe9cC-QABb84;hCQ`D(en6g={`t70KcWU1SbL^+p&Rr4 zTHJc*eS1oDck_CAM)06Q0 zG1ugI+nQ5zAmpDix^yRU`{PDdb>k)(hA|Q@NifGTrV#+tzy^NJWUGcPP(Z^lc@$E! zugjTcup!QA(4{Qan%B0P&-!Qw7gmvdvz2BaFOLTu-q1<>pO42i|8JF-$+QCi;s@W+ jQ+Fxw3vk^40D?y#US25RxxDFp2JZisZ2$kc&j|bv1NwQo literal 0 HcmV?d00001 diff --git a/examples/4.phone_prototype/sounds/ring1.mp3 b/examples/4.phone_prototype/sounds/ring1.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..0abee54a6ca2ef130d1874591441f3a72d590bca GIT binary patch literal 737304 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%0Ak=?PBJVmL?xY_DL$hid@yb3{>L@&9=w+_8 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 z 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

Uq1I&9rMh&L!;Bvwamox9ir@IER%0~M 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�wv;y$5GX8Nkw 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 z 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

Y-)z!=ysIUrz11 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

?tTN{FCnU^$=*arZ^Dr?ur~ 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%0AT65SQUD+9;EWKw0-S-zF>;47QIs5Dco^3h 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

q@N^D_O`$~Fci1X(#}CjkvKETJ8eAB) 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 literal 0 HcmV?d00001 diff --git a/examples/4.phone_prototype/sounds/ring2.mp3 b/examples/4.phone_prototype/sounds/ring2.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..5b6c50eb814c6b6d3df01fbe5bdc8d89c4351811 GIT binary patch literal 77323 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 literal 0 HcmV?d00001 diff --git a/examples/service-worker.js b/examples/service-worker.js new file mode 100644 index 0000000..b475ecf --- /dev/null +++ b/examples/service-worker.js @@ -0,0 +1,31 @@ +self.oninstall = e => { + console.log('service-worker: install', e); + e.waitUntil(self.skipWaiting()); +} + +self.onactivate = e => { + console.log('service-worker: activate', e); + e.waitUntil(clients.claim()); +} + +self.onnotificationclose = e => { + console.log('service-worker: notification close', e); +} + +self.onnotificationclick = e => { + console.log('service-worker: notification click', e); + let client; + e.notification.close(); + e.waitUntil( + clients.matchAll({ type: 'window' /*,includeUncontrolled: true */}) + .then(clients => { + console.log('service-worker: matchAll:', clients); + client = clients[0]; + if (e.action !== 'reject') // accept or undefined + return client.focus(); + }) + .then(() => { + client.postMessage({ type: 'answer', action: e.action }); + }) + ); +} \ No newline at end of file diff --git a/examples/tutorial.html b/examples/tutorial.html new file mode 100644 index 0000000..2b35e9b --- /dev/null +++ b/examples/tutorial.html @@ -0,0 +1,3550 @@ + + + Examples description + + + + + + + + + + + + + +

AudioCodes WebRTC examples

+

Preface

+

+AudioCodes Ltd. provides a WebRTC Gateway functionality on its Session Border Controllers +that supports interworking of calls from clients using WebRTC to standard Voice over IP networks. +

+ +

+For browser-based WebRTC clients, AudioCodes provides a JavaScript API library (the “WebRTC Client SDK”) +to easily integrate WebRTC calling with AudioCodes SBCs. +

+ +

+AudioCodes provides a similar SDK also for native iOS and Android applications. +

+ +

+The WebRTC Client SDK for web, is based on an open-source JavaScript SIP library named “JsSIP”.
+In this document we demonstrate how to use the API to write WebRTC client phones. +

+ +

+WebRTC is one of the components of HTML 5 which is implemented on modern browsers. +

+ +

+Currently the WebRTC Client SDK supports:
+Google Chrome, new Microsoft Edge, Mozilla Firefox, Apple Safari for Mac. +
+Partial supports: iOS Safari and Chrome for Android. +

+ +

+The WebRTC Client SDK uses modern JavaScript version.
+Used JavaScript ES2015 features: class, let, for of, promises and ES2017 features: async/await. +

+ +

+This document is built as a series of fully functional examples. +

+ +

+For educational purposes, the examples use pure JavaScript, working directly with the browser’s HTML DOM elements (without using libraries such as jquery).
+The WebRTC API can only be used when a web page is loaded securely from an HTTPS site. +

+ +

+If you would like to see these examples while operating, you should be able to upload them +to your HTTPS site as well as have access to an AudioCodes SIP SBC server, +configured with WebRTC and session licenses.
+Another option at your disposal is the use of examples already demonstrated in this website.
+You may reconfigure the SBC field with your own server. +

+ +

+View the source code with a browser’s developer tools: Ctrl+Shift+I (Chrome, Firefox) or Alt+Cmd+I (Safari) and select sources +

+ +

+Each example is single HTML page with JavaScript.
+Exiting the page is the same as stopping the program in Windows.
+Reloading the page will restart the program.
+

+ +

+In an HTML file, the following is used: + +


+<body onload = "documentIsReady()">
+
+ +When the page is loaded, the documentIsReady function is called.
+documentIsReady() function plays the same role as main() in C or java languages. +

+ +

Ensure that your browser support WebRTC API

+

Check that your browser supports WebRTC

+

+function documentIsReady() {
+    if( !navigator.mediaDevices || !navigator.mediaDevices.getUserMedia )
+      guiError("WebRTC is not supported");
+    } else {
+      guiInfo("WebRTC is supported");
+    }
+}
+
+ +

Here the result will be shown in an HTML page, instead of a JavaScript console.

+

Sometime opening the JavaScript console is difficult (e.g. Chrome for Android), or impossible (e.g. Chrome for iPad)

+ +

+This simple example is suitable for learning how to see the source code in the browser.
+Please run the example in a Chrome browser (this is similar in Firefox) +

+ +

+Press Ctrl/Shift/I to open the developer tools
+Select 'Sources' tab
+Select 'Page' sub-tab
+
+You can see that sdk/webrtc-api-base/examples/0.webrtc_check_support URL contains: +

    +
  • index.html
  • +
  • phone.js
  • +
+ +Click the 1st and the 2nd files, and you'll see the source code.
+
+If the JavaScript code is compressed you can click the {} icon to expand.
+Later we'll describe how to debug JavaScript code, +or locally change it using 'overrides' +

+ +

+In phone.js you can see how to get a reference to an HTML element defined in index.html,
+and how to change style and innerHTML values. +

+

+function guiError(text) { guiStatus(text, 'Pink'); }
+function guiInfo(text) { guiStatus(text, 'Aquamarine'); }
+
+function guiStatus(text, color) {
+    let line = document.getElementById('status_line');
+    line.setAttribute('style', `background-color: ${color}`);
+    line.innerHTML = text;
+}
+
+ +

Checking available devices (camera, microphone)

+

Check for available devices

+

To make a phone call you need to at least have a microphone and headphones.
+A video call also requires a web camera.
+In this example, we check for the presence of these peripherals.

+

You can see here that WebRTC API uses the more modern callbacks in the form of 'Promise' +(.then .catch)

+ +

+function documentIsReady() {
+    // Check devices: microphone must exist, camera is optional
+    checkAvailableDevices()
+        .then((camera) => {
+            let str = 'microphone is found'
+            if (camera)
+                str = 'microphone and camera are found'
+            guiInfo(str);
+            console.log(str)
+        })
+        .catch((e) => {
+            guiError(e);
+            console.log(e);
+        })
+}
+
+// Check WebRTC support. Check presence of microphone and camera.
+function checkAvailableDevices() {
+    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia)
+        return Promise.reject('WebRTC is not supported');
+    let cam = false,
+        mic = false,
+        spkr = false;
+    return navigator.mediaDevices.enumerateDevices()
+        .then((deviceInfos) => {
+            deviceInfos.forEach(function (d) {
+                console.log(d);  // print device info for debugging
+                switch (d.kind) {
+                    case 'videoinput':
+                        cam = true;
+                        break;
+                    case 'audioinput':
+                        mic = true;
+                        break;
+                    case 'audiooutput':
+                        spkr = true;
+                        break;
+                }
+            });
+            // Chrome supports 'audiooutput', Firefox and Safari do not support.
+            if (navigator.webkitGetUserMedia === undefined) { // Not Chrome
+                spkr = true;
+            }
+            if (!spkr)
+                return Promise.reject('Missing a speaker! Please connect one and reload');
+            if (!mic)
+                return Promise.reject('Missing a microphone! Please connect one and reload');
+
+            return Promise.resolve(cam);
+        });
+}
+
+ +

Very simple click to call phone

+ +

In this example, we start using the AudioCodes WebRTC API
+

The click to call phone (for outgoing calls only), uses AudioCodes SBC anonymous user mode

+

The phone call is initiated from an anonymous user to a registered user.
+Note: an anonymous user cannot call another anonymous user.

+ +

+The phone doesn't ask the user for any information and does not save it in the browser.
+In doing so, it can be safely used in public computers such as the ones available at airports, internet Cafes, or public libraries. +

+ +

+To use this phone, a Web Master should insert a link to it in an HTML page.
+The HTML page with the link may be in an HTTP or HTTPS site.
+The phone page should be used in an HTTPS site. +

+ +

Run click-to-call example (with HTML link)

+

Run click-to-call example (with HTML form)

+

Run click-to-call example (with speech recognition/synthesis)

+ +

+The 1st example uses an HTML link to jump to the phone.html page.
+Callee user name or phone number set as URL parameter 'call'
+


+ <a href="https:// ...some site.../phone.html?call=SantaClaus">Click to call SantaClaus</a>
+
+

+ +

+The 2nd example does about the same, but the HTML link string is built dynamically using an HTML form. +

+ +

+The 3rd example is similar to the 2nd, but uses speech recognition.
+While interesting, it is presently at an experimental stage of technology.
+

+ +

+All three examples refer for the same web page: phone.html
+Let's look at its source text
+
+Included JavaScript files:
+

    +
  • ac_webrtc.min.js is a minimized JsSIP library concatenated with AudioCodes API wrapper.
    + You can open the file in notepad++ (or your editor of choice) and see copyright information + belonging to JsSIP and AudioCodes.
  • +
  • phone.js is click-to-call phone code (250 lines)
  • +
  • config.js is a small file with SBC server configurations (5 lines)
  • +
+

+ +

+The phone GUI is simple and consists of the following: +

    +
  • At the top of the page is the status line DIV
  • +
  • In the middle of the page are three panels DIV
    +Only one selected panel is shown, the others are hidden
  • +
  • At the bottom of the page are the video controls
  • +
+

+ +

+Let's look at the source text of the phone.js +

+ +

+The following global variables are used: +

    +
  • phone - instance of AudioCodesUA. Contains API methods. Singletone class
  • +
  • activeCall - represents the current call
  • +
  • callTo - phone number or user name getting from URL parameter 'call'
  • +
+

+ +

+Let's look at the documentIsReady() implementation: +

    +
  • Set loggers. Reading the JavaScript console log we can understand what +occurs during operations.
  • +
  • Check WebRTC support
  • +
  • Get "call" parameter from URL to set callTo variable
  • +
  • GUI initialization. Set callback to a button's click event
  • +
  • Check available devices. Checking that we have a microphone, headphones and a web camera
  • +
  • Init SIP stack. +
      +
    • phone.setServerConfig() - set SBC address and parameters from config.js
    • +
    • phone.setAccount() - for click-to-call used 'Anonimous' user name, and empty string password
    • +
    • phone.setListeners() - set callbacks (listeners) for phone events
    • +
    • phone.init() - starts connecting to SBC
    • +
    +
  • +
+

+ +

API usage, and events sequence

+ +
    +
  • Preparation: set server and account, event listeners
  • +
  • phone.init(). SIP stack initialization, and web socket connecting to SBC server.
  • +
  • callback loginStateChanged 'connected'
    + Called by SIP stack when SBC connection is established.
    + If the SBC server is off-line, or you use an incorrect SBC address, you'll see the following callback:
    + callback loginStateChanged 'disconnected'
  • +
  • phone.call() Send SIP INVITE to SBC
    + Used anonymous mode for Click-to-call phone.
    + Normal SIP phone have to send SIP REGISTER before SIP INVITE.
  • + +
  • callback outgoingCallProgress When we receive the SBC SIP provisional response.
    + For example 180 'Ringing' + Here we could provide some GUI visial effects, or play 'ringing-tone' sound
  • + +
  • callback callShowStreams Means that the callee answered the call (or SBC used early media)
    + Here we need to connect stream was provided by the WebRTC to our video element defined in an HTML page:
    +
    
    +            document.getElementById('remote_video').srcObject = remoteStream;
    +      
    +
  • +
  • callback callConfirmed Now we know - the call is established
    + We can perform a GUI manipulation: display 'call_established_panel' +
  • + +
  • At the end of a conversation activeCall.terminate()SIP stack sends BYE message
  • + +
  • callback callTerminated + Here we display 'call_terminated_panel'
    + and disconnect from the SBC by phone.deinit() +
  • + +
  • callback loginStateChanged 'disconnected' + It's not an error when phone.isInitialized() == false. +
  • +
+ +

+As you can see, the phone is a state machine. +Using phone API we can initiate some process (SBC connection, SBC registration, calling, hangup call, etc.) +Results are asyncronious, we receive them with a delay, using a callback
+Sometimes the result is not what we wanted.
+For example, the user may not be available. +

+ +

This phone features:

+
    +
  • Supports single outgoing call
  • +
  • Does not support incoming calls
  • +
  • Does not require caller information (used anonimous user)
  • +
+

+ +

+Note: this is a tutorial version of click-to-call phone. +We provide with our SDK a more advanced version. +

+ +

Tiny web phone

+

A tiny web phone example

+

After loading, the phone uses local storage to retrieve user account data (user name, password...)
+ If an account isn't set, it asks the user to enter the required data. +

+ +

After initialization, the phone connects to the SBC server, and sends SIP REGISTER.
+Now the SBC knows where the phone is located, so the phone can receive an incoming call. +

+ +

This phone supports a single concurrent call.
+ If during a call, there is another incoming call, the phone will automatically answer with 'Busy here'
+ Incoming and outgoing audio & video calls are supported.

+ +

This phone's GUI is made up of a status line, a panel and video controls.
+ There are 5 panels: settings, dialer, outgoing call, incoming call and call established.
+ Only one panel is shown at a time while others are hidden.

+ +

The code for outgoing call is the same as in the previous example
+Incoming calls can be answered or rejected

+ +

+activeCall.answer(phone.AUDIO);
+
+ +

+activeCall.reject();
+
+ +

The phone's actual code is fairly small (400 lines)

+ +

Simple web phone

+

A simple web phone example

+ +

+It is still a simple (1100 lines), but more advanced phone. + +

+

Added features:

+
    +
  • Option to change server configuration, phone configuration and user preferences (using local storage)
  • +
  • Hold/un-hold call
  • +
  • Answer to incoming video call with audio, audio and receive only video, audio and two-way video
  • +
  • Start sending/receiving video in audio call. Stop sending video.
  • +
  • Sending DTMF
  • +
  • Incoming call desktop notification.
  • +
  • Redirect incoming call
  • +
  • Reconnection to previously connected server if page is reloaded
  • +
  • Call restoration if page is reloaded during open call
  • +
  • Support SBC switch over between active and redundant devices
  • +
  • Audio playing: ring, ringing-tone, busy-tone, dtmf tones.
  • +
  • Support of Chrome WebAudio autoplay policy
  • +
  • Incoming call with Replaces header
  • +
+ +

Desktop notification

+ +

Desktop notificaiton is now a standard browser API.
Desktop notification document

+

+/-------- Desktop notification (for incoming call) ---------
+function guiNotificationShow(caller) {
+    if (Notification.permission !== "granted")
+        return;
+    guiNotificationClose();
+
+    const options = {
+        image: 'images/old-phone.jpg',
+        requireInteraction: true
+    }
+    desktopNotification = new Notification("Calling " + caller, options);
+    phone.log('desktopNotification created');
+    desktopNotification.onclick = function(event) {
+        event.target.close();
+        desktopNotification = null;
+    }
+}
+
+function guiNotificationClose() {
+    if (desktopNotification) {
+        desktopNotification.close();
+        desktopNotification = null;
+        phone.log('desktopNofification.close()');
+    }
+}
+
+ +

The user will be asked for permission to enable desktop notifications:

+

+// Request permission to use desktop notification (for incoming call)
+if (Notification.permission === 'default')
+    Notification.requestPermission();
+
+ + +

Redirect incoming call

+

User can answer, reject or redirect incoming call

+

Redirect uses SIP response 302 with Contact header to provide redirect address

+

+// redirect incoming call
+call.redirect(recallToAddress);
+
+ +

When calling phone receive callTerminated callback with redirect response,
+it can recall automatically to the provided address.

+

+    callTerminated: function(call, message, cause, redirectTo) {
+        ac_log('phone>>> call terminated callback, cause=%o', cause);
+        . . . . . .
+        if (cause === 'Redirected') {
+            ac_log('Redirect call to ' + redirectTo);
+            let videoOption = call.hasSendVideo() ? phone.VIDEO : phone.AUDIO;
+            activeCall = phone.call(videoOption, redirectTo);
+        }
+    }
+
+ +

Phone will reconnect to a previously connected server if the webpage is reloaded

+

+Before the webpage is closed, the “beforeunload” event is called.
+Make use of that event to save the connected server’s address to the local storage. +

+
Save connected server address
+

+    let serverAddress = phone.getServerAddress(); // currently connected server address
+    if (serverAddress !== null) {
+        let data = {
+            address: serverAddress,
+            time: new Date().getTime()
+        }
+        localStorage.setItem('phoneRestoreServer', JSON.stringify(data));
+    }
+
+ +
Raise priority of previously connected server address
+

+    // load configuration.
+    serverConfig = guiLoadServerConfig();
+
+    // if was page reloading, try reconnect previously connected server
+    let restoreData = localStorage.getItem('phoneRestoreServer');
+
+    // check if there was a saved server data in local storage
+    if (restoreData !== null) {
+        localStorage.removeItem('phoneRestoreServer');
+        let restoreServer = JSON.parse(restoreData);
+        let delay = Math.ceil(Math.abs(restoreServer.time - new Date().getTime()) / 1000);
+        // Check if the stored data has a reasonable timestamp which indicates the there was a refresh not long ago.
+
+        if (delay <=  phoneConfig.restoreCallMaxDelay) {
+            // locate the array location of the server address we found in the stored data in the servers array.
+            let ix = searchServerAddress(serverConfig.addresses, restoreServer.address);
+            if( ix !== -1){
+                ac_log('Page reloading, raise priority of previously connected server: "' + restoreServer.address + '"');
+                // set high priority to the found server in the servers array we so we can be assure this address will be used
+                const HIGH_PRIORITY = 1000;
+                serverConfig.addresses[ix] = [restoreServer.address, HIGH_PRIORITY];
+            } else {
+                ac_log('Cannot find previously used server: ' + restoreServer.address + ' in configuration');
+            }
+        }
+    }
+
+    // proceed with the connection as we have allways done and after we have the highest priority to the desired server.
+    phone.setServerConfig(serverConfig.addresses, serverConfig.domain, serverConfig.iceServers);
+
+ +

Call restoration if page is reloaded during an open call

+

+Before closing the page, the "beforeunload" event is called.
+Here you can check whether the active call exists.
+To restore it, prepare a SIP replaces header and other information, +and save it in the local storage.
+

+
Prepare restore call data
+

+    if (activeCall !== null && activeCall.isEstablished() && phoneConfig.restoreCall) {
+        let data = {
+            callTo: activeCall.data['_user'],
+            video: activeCall.getVideoState(), // sendrecv, sendonly, recvonly, inactive
+            replaces: activeCall.getReplacesHeader(),
+            time: new Date().getTime(),
+            hold: `${activeCall.isLocalHold() ? 'local' : ''}${activeCall.isRemoteHold() ? 'remote' : ''}`,
+            mute: `${activeCall.isAudioMuted() ? 'audio' : ''}${activeCall.isVideoMuted() ? 'video' : ''}`
+        }
+        localStorage.setItem('phoneRestoreCall', JSON.stringify(data));
+    }
+
+ +
Restore call
+

After reloading the page, and registering on the SBC server, + we will check if the saved call exists, if it does, we will try to restore it.

+ +

+    let restoreData = localStorage.getItem('phoneRestoreCall');
+    if( restoreData !== null ){
+        let restore = JSON.parse(restoreData);
+        let delay = Math.ceil(Math.abs(restore.time - new Date().getTime()) / 1000);
+        if (delay > phoneConfig.restoreCallMaxDelay) {
+	        ac_log('No restore call, delay is too long (' + delay + ' seconds)');
+	        return false;
+        }
+        ac_log('Trying to restore call...');
+        let videoOption = (restore.video === 'sendrecv' || restore.video === 'sendonly') ? phone.VIDEO : phone.AUDIO;
+        guiMakeCallTo(restore.callTo, videoOption, ['Replaces: ' + restore.replaces], { 'restoreCall': restore });
+    }
+
+ +

+When a call is restored we will also restore its Hold & Mute states +

+ +

+let restore = activeCall.data['restoreCall'];
+if (restore) {
+    if (restore.hold !== '') {
+        if (restore.hold.includes('remote')) {
+            ac_log('Restore remote hold');
+            guiWarning('Remote HOLD');
+            activeCall.setRemoteHoldState(); // Set JsSIP session internal state for remote hold.
+        }
+        if (restore.hold.includes('local')) {
+            ac_log('Restore local hold');
+            guiHold();                       // Send hold re-INVITE
+        }
+    } else if (restore.mute !== '') {
+        if (restore.mute.includes('audio')) {
+            ac_log('Restore mute audio');
+            guiMuteAudio();
+        }
+        if (restore.mute.includes('video')) {
+            ac_log('Restore mute video');
+            guiMuteVideo();
+        }
+    }
+}
+
+ + +

Support AudioCodes SBC switch over

+

+Two SBC's in active and standby mode are used to support High Availability.
+If the active SBC fails, the standby SBC will take-over.
+From the client's point of view, the SBC connection will be closed/failed and then reconnect and re-login to the SBC.
+This can occur during a call (there will be a short pause in the transmission of sound.)
+In this case the UI state shouldn't be changed (stay in an open call). + +


+    loginStateChanged: function(isLogin, cause) {
+         switch (cause) {
+             . . . .
+             case "login":
+                 ac_log('phone>>> loginStateChanged: login');
+                 . . . . .
+                 if (activeCall !== null && activeCall.isEstablished()) {
+                     ac_log('Re-login done, active call exists (SBC might have switched over to secondary)');
+                     guiShowPanel('call_established_panel');
+                 }
+
+
+

+

Audio player

+

To make the phone resemble a stationary one, a sound was added for the ringing and phone +tones (ringing, busy, DTMF)

+

+Because WebRTC can only be used in a modern browser, audio playing uses AudioContext API.
+Simple AudioPlayer implementation provided in utils.js +

+ +

Sounds can be loaded from site, using the following encoding: mp3, aac and ogg (vorbis).
+For modern browsers it’s not necessary to provide the same sound in alternative encodings, just use mp3 and check that it works on all supported browsers. +

+ +

+Tones can be generated by generateTone() or generateTonesSuite() methods. +

+ +
Audio player: create, initialize, download sounds from the site, generate tones
+

+    let SoundConfig = {
+        generateTones: {
+            // Ringing and busy tones vary in different countries, so those should be defined accordingly.
+            // Here f - frequency Hz, t - duration seconds
+            ringingTone: [{ f: 425, t: 1.0 }, { t: 4.0 }],
+            busyTone: [{ f: 425, t: 0.48 }, { t: 0.48 }],
+            disconnectTone: [{ f: 425, t: 0.48 }, { t: 0.48 }],
+            autoAnswerTone: [{ f: 425, t: 0.3 }]
+        },
+        downloadSounds: [
+            { ring: 'ring1' }, // ring1 by default (user can select other ring)
+            'bell'
+        ],
+		. . .
+    }
+	
+
+    let audioPlayer = new AudioPlayer();
+    audioPlayer.init(ac_log);
+
+    audioPlayer.downloadSounds('sounds/', SoundConfig.downloadSounds)
+        .then(() => {
+            // Concatenate user defined tones and DTMF tones defined in audioPlayer.
+            let tones = Object.assign({}, SoundConfig.generateTones, audioPlayer.dtmfTones);
+            return audioPlayer.generateTonesSuite(tones);
+        })
+        .then(() => {
+            ac_log('AudioPlayer: sounds are ready:', audioPlayer.sounds);
+        })
+
+ + +
Play a sound
+

+   audioPlayer.play({ name: 'ringingTone', loop: true, volume: 0.3 });
+
+ +

+   audioPlayer.play({ name: 'busyTone', volume: 0.3, repeat: 4 });
+
+ +
Stop playing
+

+   audioPlayer.stop();
+
+ + +
Support of Google Chrome’s WebAudio autoplay policy
+

+The following methods have been added: +

    +
  • isDisabled() – This checks whether autoplay is disabled or not.
  • +
  • enable() – This enables autoplay. It will only succeed when called after the user has interacted with an event prompting them to enable autoplay (for example, a button click).
  • +
+

+ +

+function guiEnableSound() {
+    if (!audioPlayer.isDisabled())
+        return;
+    audioPlayer.enable()
+        .then(() => {
+          ac_log('Sound is enabled')
+        })
+        .catch((e) => {
+            ac_log('Cannot enable sound', e);
+        });
+}
+
+ +

Configure sounds/tones using config.js

+

+The phone can use various ringback, busy and incoming calls ringtones (sounds)
+Therefore, it is convenient to adjust the sound without rebuilding the phone, by modifying the SoundConfig in the file config.js +

+ +

+let SoundConfig = {
+    generateTones: {
+        // Phone ringing, busy and other tones vary in different countries.
+        // Please see: https://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf
+
+        /* Germany
+        ringingTone: [{ f: 425, t: 1.0 }, { t: 4.0 }],
+        busyTone: [{ f: 425, t: 0.48 }, { t: 0.48 }],
+        disconnectTone: [{ f: 425, t: 0.48 }, { t: 0.48 }],
+        autoAnswerTone: [{ f: 425, t: 0.3 }]
+        */
+
+        /* France
+        ringingTone: [{f:400, t:1.5}, {t:3.5}],
+        busyTone: [{ f: 400, t: 0.5 }, { t: 0.5 }],
+        disconnectTone: [{ f: 400, t: 0.5 }, { t: 0.5 }],
+        autoAnswerTone: [{ f: 400, t: 0.3 }]
+        */
+
+        /* Great Britain */
+        ringingTone: [{ f: [400, 450], t: 0.4 }, { t: 0.2 }, { f: [400, 450], t: 0.4 }, { t: 2.0 }],
+        busyTone: [{ f: 400, t: 0.375 }, { t: 0.375 }],
+        disconnectTone: [{ f: 400, t: 0.375 }, { t: 0.375 }],
+        autoAnswerTone: [{ f: 400, t: 0.3 }]
+    },
+    downloadSounds: [
+        { ring: 'ring1' }, // ring1 by default (user can select other ring)
+        'bell'
+    ],
+    play: {
+        outgoingCallProgress: { name: 'ringingTone', loop: true, volume: 0.2 },
+        busy: { name: 'busyTone', volume: 0.2, repeat: 4 },
+        disconnect: { name: 'disconnectTone', volume: 0.2, repeat: 3 },
+        autoAnswer: { name: 'autoAnswerTone', volume: 0.2 },
+        incomingCall: { name: 'ring', loop: true, volume: 1.0, dropDisabled: true },
+        incomingMessage: { name: 'bell', volume: 1.0 },
+        dtmf: { volume: 0.15 }
+    }
+}
+
+ +

+See code example above how SoundConfig used in methods: downloadSounds and generateTonesSuite +

+ +

+SoundConfig used for all sound plays: +

+ +

+audioPlayer.play(SoundConfig.play.outgoingCallProgress);
+audioPlayer.play(SoundConfig.play.busy);
+audioPlayer.play(SoundConfig.play.disconnect);
+audioPlayer.play(SoundConfig.play.autoAnswer);
+audioPlayer.play(SoundConfig.play.incomingCall);
+audioPlayer.play(SoundConfig.play.incomingMessage);
+
+ +

+To playing DTMF added key name: +

+

+audioPlayer.play(Object.assign({ 'name': key }, SoundConfig.play.dtmf));
+
+ + + + +

Incoming call with Replaces header

+

+Incoming INVITE can contain Replaces header (used for attended transfer).
+In the case "incomingCall" callback argument replacedCall points to the call that should be replaced.
+(for other cases replacedCall is null) +

+

+Developer should close replacedCall call, and auto answer to incoming call.
+The new call should visually replace previous call in GUI. +

+ +

+incomingCall: function (call, invite, replacedCall) {
+    ac_log('phone>>> incomingCall', call, invite, replacedCall);
+    . . . .
+    // If received INVITE with Replaces header
+    if (replacedCall !== null) {
+        ac_log('phone: incomingCall, INVITE with Replaces');
+
+        // close the replaced call.
+        replacedCall.data['terminated_replaced'] = true;
+        replacedCall.terminate();
+
+        // auto answer to replaces call.
+        activeCall = call;
+        activeCall.data['open_replaced'] = true;
+
+        // Try to use the same video option as was used in replaced call.
+        let videoOption = replacedCall.hasVideo() ? phone.VIDEO : (replacedCall.hasReceiveVideo() ? phone.RECVONLY_VIDEO : phone.AUDIO);
+        activeCall.answer(videoOption);
+        return;
+    }
+}
+
+ + +

Phone prototype

+

Run phone prototype example

+

Added features:

+
    +
  • Call history, and redial
  • +
  • Blind call transfer
  • +
  • Receiving SIP NOTIFY in/out of SIP INVITE dialog (NOTIFY talk example)
  • +
  • Incoming call custom header usage (Alert-Info example)
  • +
  • Sending/Receiving out of dialog SIP MESSAGE
  • +
  • Sending/Receiving in dialog SIP INFO
  • +
  • Screen sharing
  • +
  • SIP SUBSCRIBE/NOTIFY dialog support
  • +
+ + +

Call history

+

To keep a user's call history, it's better to use IndexedDB.
If 'user name' is changed, the phone will clear its call history.
Call history is saved in a database, and also set in 'call_log_panel' as an unordered list

+

+
+/**
+ * Database with single store and with copy of the store in memory - objects list
+ * Purpose: make the list persistent.
+ * Key is part of record, based on current time, unique and has name 'id'
+ * Number of objects in store is limited, oldest objects will be deleted.
+ * If needed, additional stores can be added: override open(),
+ * and use get(), put(), clear(), delete() methods with store name.
+ */
+class AbstractDb {
+    constructor(dbName, storeName, maxSize) {
+        this.dbName = dbName;
+        this.storeName = storeName;
+        this.maxSize = maxSize; // max number of objects
+        this.db = null;
+        this.list = []; // default store copy in memory.
+        this.idSeqNumber = -1; // to generate unique key.
+    }
+
+    // Create store unique key. (no more than 1 million in the same millisecond)
+    // key must be part or record and have name 'id'
+    createId(time) {
+        this.idSeqNumber = (this.idSeqNumber + 1) % 1000000; // range 0..999999
+        return time.toString() + '-' + ('00000' + this.idSeqNumber.toString()).slice(-6);
+    }
+
+    // Open the database, if needed create it.
+    open() {
+        return new Promise((resolve, reject) => {
+            let r = indexedDB.open(this.dbName);
+            r.onupgradeneeded = (e) => {
+                e.target.result.createObjectStore(this.storeName, { keyPath: 'id' });
+            }
+            r.onsuccess = () => {
+                this.db = r.result;
+                resolve();
+            }
+            r.onerror = r.onblocked = () => { reject(r.error); };
+        });
+    }
+
+    // load records to memory, ordered by time, if needed delete oldest records
+    load() {
+        return new Promise((resolve, reject) => {
+            if (this.db === null) { reject('db is null'); return; }
+            let trn = this.db.transaction(this.storeName, 'readwrite');
+            trn.onerror = () => { reject(trn.error); }
+            let store = trn.objectStore(this.storeName)
+            let onsuccess = (list) => {
+                this.list = list;
+                let nDel = this.list.length - this.maxSize;
+                if (nDel <= 0) {
+                    resolve();
+                } else {
+                    let r = store.delete(IDBKeyRange.upperBound(this.list[nDel - 1].id));
+                    r.onerror = () => { reject(r.error); }
+                    r.onsuccess = () => {
+                        this.list = this.list.splice(-maxSize);
+                        resolve();
+                    }
+                }
+            }
+            let onerror = (e) => { reject(e); }
+            let getAll = store.getAll ? this._getAllBuiltIn : this._getAllCursor;
+            getAll(store, onsuccess, onerror);
+        });
+    }
+
+    _getAllBuiltIn(store, onsuccess, onerror) { // Chrome, Firefox
+        let r = store.getAll();
+        r.onerror = () => onerror(r.error);
+        r.onsuccess = () => onsuccess(r.result);
+    }
+
+    _getAllCursor(store, onsuccess, onerror) { // Legacy Microsoft Edge
+        let list = [];
+        let r = store.openCursor();
+        r.onerror = () => onerror(r.error);
+        r.onsuccess = (e) => {
+            let cursor = e.target.result;
+            if (cursor) {
+                list.push(cursor.value);
+                cursor.continue();
+            } else {
+                onsuccess(list);
+            }
+        };
+    }
+
+    // Add new record. If needed delete oldest records
+    add(record) {
+        return new Promise((resolve, reject) => {
+            if (this.db === null) { reject('db is null'); return; }
+            let trn = this.db.transaction(this.storeName, 'readwrite');
+            trn.onerror = () => { reject(trn.error); }
+            let store = trn.objectStore(this.storeName)
+            let r = store.add(record);
+            r.onerror = () => { reject(r.error); }
+            r.onsuccess = () => {
+                this.list.push(record);
+                let nDel = this.list.length - this.maxSize;
+                if (nDel <= 0) {
+                    resolve();
+                } else {
+                    r = store.delete(IDBKeyRange.upperBound(this.list[nDel - 1].id));
+                    r.onerror = () => { reject(r.error); }
+                    r.onsuccess = () => {
+                        this.list = this.list.splice(-this.maxSize);
+                        resolve();
+                    }
+                }
+            }
+        });
+    }
+
+    // Update record with some unique id.
+    update(record) {
+        let index = this.list.findIndex((r) => r.id === record.id);
+        if (index == -1)
+            return Promise.reject('Record is not found');
+        this.list[index] = record;
+        return this._exec('put', this.storeName, record);
+    }
+
+    // Delete record with the key (if store is default delete also from list)
+    delete(id, storeName = this.storeName) {
+        if (storeName === this.storeName) {
+            let index = this.list.findIndex((r) => r.id === id);
+            if (index == -1)
+                return Promise.reject('Record is not found');
+            this.list.splice(index, 1);
+        }
+        return this._exec('delete', storeName, id);
+    }
+
+    // Clear all store records
+    clear(storeName = this.storeName) {
+        this.list = [];
+        return this._exec('clear', storeName);
+    }
+
+    get(key, storeName) {
+        return this._exec('get', storeName, key);
+    }
+
+    put(record, storeName) {
+        return this._exec('put', storeName, record);
+    }
+
+    // Single transaction operation.
+    _exec(op, storeName, data) {
+        return new Promise((resolve, reject) => {
+            if (this.db === null) { reject('db is null'); return; }
+            let trn = this.db.transaction(storeName, 'readwrite');
+            trn.onerror = () => { reject(trn.error); }
+            let store = trn.objectStore(storeName)
+            let r;
+            switch (op) {
+                case 'clear':
+                    r = store.clear();
+                    break;
+                case 'delete':
+                    r = store.delete(data);
+                    break;
+                case 'put':
+                    r = store.put(data);
+                    break;
+                case 'get':
+                    r = store.get(data);
+                    break;
+                default:
+                    reject('db: wrong request');
+                    return;
+            }
+            r.onerror = () => { reject(r.error); }
+            r.onsuccess = () => { resolve(r.result); }
+        });
+    }
+}
+
+/**
+ * To keep phone call logs.
+ */
+class CallLogDb extends AbstractDb {
+    constructor(maxSize) {
+        super('phone', 'call_log', maxSize);
+    }
+}
+
+ + +

Custom loggers

+

By default, all logs from JsSIP and AudioCodes API write to console.log
+You can reassign them to a custom logger.
+ +


+    function setConsoleLoggers() {
+        let useTimestamp = phoneConfig.addLoggerTimestamp;
+        let useColor = ['chrome', 'firefox', 'safari'].includes(phone.getBrowser());
+
+        ac_log = function () { // Assign ac_log global variable. It's phone logger.
+            let args = [].slice.call(arguments);
+            let firstArg = [(useTimestamp ? createTimestamp() : '') + (useColor ? '%c' : '') + args[0]];
+            if (useColor) firstArg = firstArg.concat(['color: BlueViolet;']);
+            console.log.apply(console, firstArg.concat(args.slice(1)));
+        };
+        let js_log = function () {
+            let args = [].slice.call(arguments);
+            let firstArg = [(useTimestamp ? createTimestamp() : '') + args[0]];
+            console.log.apply(console, firstArg.concat(args.slice(1)));
+        };
+
+        phone.setAcLogger(ac_log);     // It's AudioCodes SDK logger.
+        phone.setJsSipLogger(js_log);  // It's JsSIP stack logger.
+    }
+
+

+ +

+Note: no need to add a timestamp to the log.
+You should enable show console log timestamps in browser. +

+

+Our customers send us logs with discovered problems.
+To our surprise, none of them sent logs with a timestamps.
+Therefore, we decided that we would add the timestamp string before each log entry in our example logger function. +

+ +

+By default, the log is printed in the browser console window.
+It can be sent via websocket to a server.
+We added the websocket logger to our examples: + +


+    function setWebsocketLoggers(url) {
+       return new Promise((resolve, reject) => {
+           let ws = new WebSocket('wss://' + url, 'wslog');
+           ws.onopen = () => { resolve(ws); }
+           ws.onerror = (e) => { reject(e); }
+       })
+           .then(ws => {
+               const log = function () {
+                   let args = [].slice.call(arguments);
+                   ws.send([createTimestamp() + args[0]].concat(args.slice(1)).join() + '\n');
+               };
+               ac_log(`Sending log to "${url}"`);
+               ac_log = log;               // It's phone logger.
+               phone.setAcLogger(log);     // It's AudioCodes SDK logger.
+               phone.setJsSipLogger(log);  // It's JsSIP stack logger.
+           })
+    }
+
+

+ +

+If the websocket logger cannot connect to the cloud service, the browser console is used. +
+ +


+    function documentIsReady() {
+        // Load configurations
+        serverConfig = guiLoadServerConfig();
+        phoneConfig = guiLoadPhoneConfig();
+        userPref = guiLoadUserPref();
+    
+        // Set logger
+        if (!serverConfig.logger) {
+            setConsoleLoggers();                      // Use console logger.
+            startPhone();
+        } else {
+            setWebsocketLoggers(serverConfig.logger)  // Use websocket logger.
+                .catch((e) => {
+                    setConsoleLoggers();              // Cannot connect. Use console logger.
+                    ac_log('Cannot connect to logger server', e);
+                })
+                .finally(() => {
+                    startPhone();
+                })
+        }
+    }
+
+

+ + +

Access to internal WebRTC objects

+

After the call is established, you have RTCPeerConnection using method call.getRTCPeerConnection(),
+and local and remote WebRTC media streams using methods call.getRTCLocalStream() and call.getRTCRemoteStream(). +

+Note: Developers may call the WebRTC API directly or use the provided SDK functions.
+The functions called via phone.getWR() (webrtc wrapper) and return Promise.
+View the examples below.
+

+ +
Print active call track information (SDK API)
+

+async function printStreamsParameters() {
+    if (activeCall === null) {
+        ac_log('activeCall is null');
+        return;
+    }
+    // Current video state set according answer SDP (hold answer will be ignored)
+    ac_log('Video State current: ' + activeCall.getVideoState() + ' enabled: ' + activeCall.getEnabledVideoState());
+
+    // WebRTC tracks
+    let li = await phone.getWR().stream.getInfo(activeCall.getRTCLocalStream());
+    let ri = await phone.getWR().stream.getInfo(activeCall.getRTCRemoteStream());
+    ac_log(`Enabled Tracks: local ${li} remote ${ri}`)
+
+    // WebRTC transceivers
+    let ti = await phone.getWR().connection.getTransceiversInfo(activeCall.getRTCPeerConnection());
+    ac_log(`Transceivers: ${ti}`);
+}
+
+ +
Print active call track information (WebRTC API)
+

+function printStreamsParameters() {
+    if (activeCall === null) {
+        ac_log('activeCall is null');
+        return;
+    }
+    // Current video state set according answer SDP (hold answer will be ignored)
+    ac_log('Video State current: ' + activeCall.getVideoState() + ' enabled: ' + activeCall.getEnabledVideoState());
+
+    // WebRTC tracks
+    ac_log(`Enabled Tracks: local ${getStreamInfo(activeCall.getRTCLocalStream())} remote ${getStreamInfo(activeCall.getRTCRemoteStream())}`)
+
+    // WebRTC transceivers
+    let conn = activeCall.getRTCPeerConnection();
+    let ts = conn.getTransceivers();
+    let at = getTransceiver(ts, 'audio');
+    let vt = getTransceiver(ts, 'video');
+    ac_log(`Transceivers: (${ts.length}) audio ${getTransInfo(at)} video ${getTransInfo(vt)}`, ts);
+}
+
+function getStreamInfo(st) {
+    if( st === null )
+      return 'stream is null'
+    return `audio: ${getTrackInfo(st.getAudioTracks())} video: ${getTrackInfo(st.getVideoTracks())}`;
+}
+
+function getTrackInfo(tr) {
+    return tr.length > 0 ? tr[0].enabled.toString() : '-'
+}
+
+function getTransceiver(transceivers, kind){
+    for (let t of transceivers) {
+        if (t.sender !== null && t.sender.track !== null && t.sender.track.kind === kind)
+            return t;
+        if (t.receiver !== null && t.receiver.track !== null && t.receiver.track.kind === kind)
+            return t;
+    }
+    return null;
+}
+
+function getTransInfo(t){
+    return t === null ? 'none' : `d=${t.direction} c=${t.currentDirection}`;
+}
+
+ +
Print active call statistics (SDK API)
+

+function printCallStats() {
+    if (activeCall === null) {
+        ac_log('activeCall is null');
+        return;
+    }
+    let conn = activeCall.getRTCPeerConnection();
+    phone.getWR().connection.getStats(conn, ['outbound-rtp', 'inbound-rtp'])
+        .then(str => {
+            ac_log('call stats: ' + str);
+        })
+        .catch(err => {
+            ac_log('stat error', err);
+        });
+}
+
+ +
Print active call statistics (WebRTC API)
+

+function printCallStats() {
+    if (activeCall === null) {
+        ac_log('activeCall is null');
+        return;
+    }
+    let conn = activeCall.getRTCPeerConnection();
+    let str = '';
+    let types = ['outboud-rtp', 'inbound-rtp'];
+    conn.getStats(null)
+        .then(report => {
+            report.forEach(now => {
+                if (types.includes(now.type)) {
+                    str += ' {';
+                    let first = true;
+                    for (let key of Object.keys(now)) {
+                        if (first) first = false;
+                        else str += ',';
+                        str += (key + '=' + now[key]);
+                    }
+                    str += '} \r\n';
+                }
+            });
+        })
+        .then(() => {
+            ac_log(str);
+        });
+}
+
+ + + +

Blind call transfer

+
Transferor
+ +

+To transfer a call, the phone places the current call on hold and sends a SIP REFER message +to the active call (thereby requesting it to initiate a new call to a different destination). +

+ +

+async function blindTransfer(transferTo) {
+    ac_log('blind transfer ' + transferTo);
+
+    //  wait until active call be on hold
+    while (activeCall !== null && !activeCall.isLocalHold()) {
+        try {
+            await activeCall.hold(true);
+        } catch (e) {
+            await new Promise(resolve => setTimeout(resolve, 1000));
+        }
+    }
+    if (activeCall === null)
+        return;
+
+    // send REFER
+    activeCall.sendRefer(transferTo);
+}
+
+ + +

+After a call transfer has initialized, the phone will check the process by using the “transferorNotification” callback.
+If the call transfer fails, it will un-hold the current call.
+If the call transfer succeeds, it will end the current call.
+

+ + +

+transferorNotification: function (call, state) {
+    switch (state) {
+        case 0:    // "in progress": REFER accepted or received NOTIFY 1xx
+            break;
+
+        case -1:   // "failed": REFER rejected or received NOTIFY >=300
+            call.hold(false); // un-hold active call
+            break;
+
+        case 1:   // "success" received NOTIFY 2xx
+            guiHangup(); // terminate active call
+            break;
+    }
+}
+
+ +
Transferee
+

+When the phone receives a REFER message it will call the address extracted from the Refer-To header. +

+ +

+To receive a REFER message, use the “transfereeREFER” callback. +This callback will allow the phone to accept or reject incoming REFER messages. +

+ +

+


+transfereeRefer: function (call, refer) {
+    if (transferCall === null) {
+        ac_log('phone>>> transferee incoming REFER: accepted');
+        return true;
+    } else {
+        ac_log('phone>>> transferee incoming REFER: rejected, because other transfer in progress');
+        return false;
+    }
+}
+
+

+ +

+If a REFER message is accepted, the SIP stack will automatically create a new call and start the calling process.
+Developers should use the "transfereeCreatedCall" callback to receive a reference to the newly created call object.
+Note: the transferee’s phone will have two calls working simultaneously, i.e. the call in which the REFER was received and a new outgoing call to the REFER’s specified destination. +

+ +

+


+transfereeCreatedCall: function (call) {
+    ac_log('phone>>> transferee created call', call);
+    transferCall = call; // Used until call will be established
+    guiInfo('call transferring to ' + call.data['_user']);
+    . . . . .
+}
+
+

+ + +

Receiving NOTIFY in/out of dialog

+

+Developers should use the "incomingNotify" callback to receive incoming NOTIFY.
+

+ +

+Note: to receive incoming in dialog NOTIFY used modified JsSIP.
+(because it's not standard SIP extension) +

+ +

+Partial implementation of Broadsoft call control: +

+ +

+


+incomingNotify: function (call, eventName, from, contentType, body, request) {
+    ac_log(`phone>>> incoming NOTIFY "${eventName}"`, call, from, contentType, body);
+    if (call === null)
+        return false; // skip out of dialog NOTIFY.
+    if (eventName !== 'talk' && eventName !== 'hold')
+        return false; // skip unsupported events
+    if (activeCall === null)
+        return false; // skip illegal state.
+
+    if (eventName === 'talk') {
+        if (!activeCall.isEstablished() && !activeCall.isOutgoing()) {
+            ac_log('incoming NOTIFY "talk": answer call');
+            // Choose the best available video option.
+            let videoOption = activeCall.hasVideo() ? (hasCamera ? phone.VIDEO : phone.RECVONLY_VIDEO) : phone.AUDIO;
+            guiAnswerCall(videoOption);
+        } else if (activeCall.isEstablished() && activeCall.isLocalHold()) {
+            ac_log('incoming NOTIFY "talk": un-hold call');
+            call.hold(false);
+        } else {
+            ac_log('incoming NOTIFY "talk": ignored');
+        }
+    } else if (eventName === 'hold') {
+        if (activeCall.isEstablished() && !activeCall.isLocalHold()) {
+            ac_log('incoming NOTIFY "hold": set call on hold');
+            activeCall.hold(true);
+        } else {
+            ac_log('incoming NOTIFY "hold": ignored');
+        }
+    }
+    return true; // mark that we 'consume' the NOTIFY.
+}
+
+

+

+ + +

Incoming call custom header usage

+

+Incoming INVITE may contain custom SIP headers.
+In the example we check Alert-Info header. +

+ +

+incomingCall: function (call, invite, replacedCall){
+    . . . .
+    // Check if incoming INVITE contains Alert-Info header.
+    let alertInfo = new AlertInfo(invite);
+    ac_log(`alert-info header ${alertInfo.exists() ? ' exists' : 'does not exist'}`);
+    if (alertInfo.hasAutoAnswer()) {
+        ac_log('*** Used Alert-Info Auto answer ***');
+        // Choose the best available video option.
+        let videoOption = activeCall.hasVideo() ? (hasCamera ? phone.VIDEO : phone.RECVONLY_VIDEO): phone.AUDIO;
+        guiAnswerCall(videoOption);
+        return;
+    }
+    . . . .
+
+ +

+"incomingCall" callback "invite" argument is JsSIP.IncomingRequest
+Developer can get the header(s) by invite.getHeaders('alert-info')
+JsSIP does not provide parser for 'Alert-Info', it is presented as raw header (string)
+We use here custom Alert-Info parser (defined in utils.js).
+In a similar way developer can use any custom SIP header.
+

+ +

Sending/Receiving out of dialog SIP MESSAGE

+ +

+To receive (out of SIP dialog) SIP message used callback "incomingMessage" +

+

+incomingMessage: function (call, from, contentType, body, request) {
+    ac_log('phone>>> incoming MESSAGE', from, contentType, body);
+	. . . . .
+}
+
+ + +

+To send SIP message, used phone.sendMessage() +

+

+function guiSendMessage() {
+    let to = document.querySelector('#send_message_form [name=send_to]').value.trim();
+    let text = document.querySelector('#send_message_form [name=message]').value.trim();
+    if (to === '' || text === '')
+        return;
+    phone.sendMessage(to, text)
+        .then((e) => {
+            ac_log('message sent', e);
+            guiInfo('Message sent');
+        })
+        .catch((e) => {
+            ac_log('message sending error', e);
+            guiError('Cannot send message: ' + e.cause);
+        });
+}
+
+ +

+Note: please check sending result.
+When receiver phone is not registered (off-line), will be catched error,
+because SBC response: 404 "User not found"
+

+ + +

Sending/Receiving in dialog SIP INFO

+ +

+To receive (in SIP dialog) SIP INFO used callback "incomingInfo" +

+

+incomingInfo: function (call, from, contentType, body, request) {
+    ac_log('phone>>> incoming INFO', call, from, contentType, body);
+	. . . . .
+}
+
+ + +

+To send SIP INFO message, used call.sendInfo() +

+ +

+function guiSendInfo() {
+    let info = {test: 'test'};
+    activeCall.sendInfo(JSON.stringify(info), 'application/json');
+}
+
+ +

Local and remote video elements overlapping

+

+Local and remote video elements can overlap each other on the screen.
+Select the video size 'Custom', and use the mouse to +drag the video element, and mouse wheel to increase or decrease its size. +

+

+You can see how it is implemented in the functions: guiSetVideoStyles(), guiUseMouse(), +and functions starts with eventMouse...
+
+

+ +

Set audio and video constraints for browsers

+

+Can be used browser names: "chrome", "firefox", "safari", "other".
+or with os name, e.g. "chrome|windows", "chrome|android", ...
+Possible OS names: "windows", "android", "macos", "ios", "linux", "other". +

+

+If for current browser much 2 entries, the latest replace the previous.
+E.g. if current browser is Safari in iOS for the below example, at first +will be set constraints for "safari", and then they will be replaced by +2nd matched entry "safari|ios". +

+ +

+let constraints = {
+    chrome: { 
+        audio: { echoCancellation: true },
+        video: { aspectRatio: 1.0 }		   
+    },
+	
+    firefox: { 
+        audio: { echoCancellation: true }
+    },
+    
+    safari: {
+        audio: { echoCancellation: false } 
+    },
+	
+    "safari|ios": {
+        audio: { echoCancellation: false } 
+    },
+	
+    other: {
+        audio: { echoCancellation: true }
+    }
+};
+
+phone.setBrowsersConstraints(constraints);
+
+ +

+We don't check in the example if Chrome browser supports for example video constraint "aspectRatio".
+It depends of used operating system, driver and web camera model.
+Therefore, to avoid over constrained error we use optional format of constraints: default or with key word "ideal", and avoid using key word "exact" +

+ + +

Set audio and video constraints for the browser

+For the purpose can be used setConstraints() method to set (or replace previously +used) audio or video constraints for getUserMedia() method
+Constraints can be set for audio (microphone) or video (camera) device. + +

+It is important to use supported constraints and values ranges, or use optional constraints format
+otherwise during call opening (in WebRTC method getUserMedia) will be over constrained error. +
+See also +Capabilities, constraints, and settings +

+ +
setConstraints() method parameters
+
    +
  • + browser [string]:
    +
      +
    • + null – current browser. +
    • +
    • + browser name, one of 'chrome', 'firefox', 'safari', 'other' +
    • +
    • + browser name, vertical line, OS name
      + OS name one of 'windows', 'android', 'macos', 'ios', 'linux', 'other'
      + + 'chrome|windows', 'chrome|macos', …
      +
    • +
    +
    +During SDK initialization it get current browser name, and OS name.
    +They can be obtained using phone.getBrowser() and phone.getOS()
    +When called setConstraints method checked if used browser name or browser-os-name is name of the current browser and OS.
    +Otherwise the method is ignored. +
  • +
  • +type [string] 'audio' or 'video' +
  • +
  • +constraints [object] e.g.:
    +{ echoCancellation: true }
    +{ echoCancellation: { ideal: true } }
    +{ echoCancellation: { exact : true } }
    +
    +
  • +
+ +

+Audio contraints example +

+ +

+let supported = navigator.mediaDevices.getSupportedConstraints();
+let ac = {};
+
+ac_log('Volume is supported: ', supported.volume ? true : false);
+if (supported.volume){
+    ac.volume = 0.7;
+}
+
+ac_log('Echo cancellation is supported: ', supported.echoCancellation ? true : false);
+if (supported.echoCancellation){
+    ac.echoCancellation = true;
+}
+
+if (Object.keys(ac).length > 0){ // Is not empty ?
+    phone.setConstraints(null, 'audio', ac); // null means current browser.
+}
+
+ + +

+Video contraints example +

+ +

+let supported = navigator.mediaDevices.getSupportedConstraints();
+let vc = {};
+
+ac_log('webcam facing mode is supported: ', supported.facingMode ? true : false);
+if (supported.facingMode){
+    vc.facingMode = { ideal: 'user' };
+}
+
+ac_log('webcam aspect ratio is supported: ', supported.aspectRatio ? true : false);
+if(supported.aspectRatio){
+    vc.aspectRatio = 1.0;
+}
+
+if (Object.keys(vc).length > 0){ // Is not empty ?
+    phone.setConstraints(null), 'video', vc);
+}
+
+ +

Add or remove single audio or video constraint for currently used browser

+

+To add or remove single audio or video constraint without modification others +constraints use setConstraint() method. +

+ +

+  // Set audio deviceId for getUserMedia()
+  phone.setConstraint('audio', 'deviceId', 'some-device-id-string'); 
+
+ +

+  // Set audio deviceId for getUserMedia() as "exact" constraint
+  // If such device does not exist getUserMedia() promise will be rejected with OverconstrainedError
+  phone.setConstraint('audio', 'deviceId', {exact: 'some-device-id-string'});
+
+ +

+  // Remove audio deviceId for getUserMedia()
+  phone.setConstraint('audio', 'deviceId', null);
+
+ +

Screen sharing

+ +

+WebRTC supports screen-sharing video stream (See navigator.mediaDevices.getDisplayMedia()).
+We know how to start sending video in audio call, or replace one video track to another in video call.
+We can add custom header to outgoing re-INVITE.
+Combining these techniques, we add screen-sharing support: +

+ +

+ +

+


+let stream = phone.openScreenSharing()
+
+Create screen-sharing stream using navigator.mediaDevices.getDisplayMedia().
+User should select of sharing type: full screen, some window or browser tab. +

+ +

+


+phone.closeScreenSharing(stream)
+
+Close screen-sharing stream previously open by openScreenSharing(). +

+ + +

+call.startScreenSharing(stream)
+
+For audio call it works the same as call.startSendingVideo()
+For video call it replaces sending video track from web camera to screen-sharing video track. +

+ +

+


+call.stopSreenSharing()
+
+Stop screen-sharing video, it can be also stopped by built-in browser button "Stop sharing".
+For audio call it's the same as call.stopSendingVideo().
+For video call will be restored previously sent video track from web camera. +

+ +

+Because screen-sharing can be terminated not only by stopScreenSharing(), but also using built-in in browser button, to phone added new callback: +


+callScreenSharingEnded(call, stream)
+
+The callback used to update GUI
+In multi call phone the same screen-sharing stream can be used in multiple startScreenSharing()
+The callback allows you to keep the usage counter and close the stream if no call is using it. +
+

+ +

+For other side screen-sharing video is usual video.
+To notify the other side that a screen-sharing video is being sent,
+the client sends re-INVITE with the special header:
+X-Screen-Sharing: on
+or
+X-Screen-Sharing: off
+
+If call was replaced, it means the same as X-Screen-Sharing: off. +

+ +

+After page reloading screen-sharing will be restored if the user approves it. +

+

+Please see the API usage in single call and multi call phone prototypes. +

+ + +

SUBSCRIBE dialog

+ +

+In SDK 1.15 added generic SIP SUBSCRIBE dialog
+Used our subscriber/notifier JsSIP extension https://github.com/versatica/JsSIP/issues/708.
+
+Please see usage example in single call phone prototype and phone prototype with ACD. +

+ + +

Phone prototype with an answering machine

+

Run phone prototype with an answering machine

+

Added feature:

+
    +
  • Automatic Answering Machine
  • +
+ + +

+When a user doesn't answer an incoming call for a set number seconds,
+the answering machine will take its place and answer the call. +

+ +

+First, a greeting message is played.
+The phone has a default greeting,
+or the user can record a custom greeting using their microphone. +

+ + +

+Then a beep sound is played.
+The calling party can now record a voice message and hang up.
+The maximum voice message time is limited. +

+ +

+The recorded message is stored in indexeddb, and will not be lost after the page reload.
+There is a visual notification that the phone +received a new voice message.
+(In our example we changed the color and border color of the button 'Answering Machine') +

+ + +In the panel of the answering machine, the user can: +
    +
  • Turn the machine on or off.
  • +
  • Set a time delay before the start of the operation.
  • +
  • Set the maximum time of the recorded message.
  • +
  • Record the custom greeting, or erase it and use the default.
  • +
  • Listen and delete the recorded messages.
  • +
+ +

+To implement answering machine the following was used: +

    +
  • MediaRecorder API (see class AudioRecorder in utils.js)
  • +
  • IndexedDB support of values with data blob (see class VoiceDb)
  • +
  • + WebRTC 1.0 API replaceTrack to switch audio sender from microphone to the audio player, + without SIP renegotiation.
    + (see class AnsweringMachine, method prepare) +
  • +
  • + Reassignment playing from speaker to audio stream.
    + (See class AnsweringMachine, method playGreeting, play parameter: streamDestination) +
  • +
  • + Added small delay before playing the greeing.
    + Without the delay WebRTC API "swallows" the beginning of the greeting message.
    + (See class AnsweringMachine, method playGreeting, play parameter: startDelay) +
  • +
+

+ +

+Because an answering machine complicates the code, and isn't needed +for all custometers, this is done as a separate example. +

+ +

Phone prototype with OAuth2 authorization

+ +

Run phone prototype with OAuth2

+

Added feature:

+
    +
  • Authorization using OAuth2
  • +
+

+For this example we're using Keycloak server; +an open source software specializing in Identity and Access Management. +

+ +

+The JavaScript phone uses the provided keycloak.js adapter
+

+ + +

Changes in comparison with the phone prototype example

+ +
    +
  • HTML setting_panel +
      +
    • Removed "Account settings" as it is unnecessary in this version.
      + The user name and display name are provided by the Keycloak server.
      +
    • + +
    • Added logout button.
    • +
    +
  • + +
  • Added global variables: +
      +
    • keycloak: Reference to Keycloak server adapter.
    • + +
    • authServerConfig: Authorization server address and parameters.
    • + +
    • authLoginPostponed: boolean flag.
      + Set when the updateToken action has failed,
      + and Keycloak requires a re-login to authorize the user.
      + The re-login directs the user to a keycloak server HTML page for
      + security purposes, so it can't be done while in an active call.
      + In this case we'll wait until the call ends. +
    • + +
    • authTests: string with SBC test names.
      + Allows you to send an invalid access token, using the REGISTER or INVITE message.
      + To disable all tests set an empty string value.
      +
    • +
    +
  • + +
  • Changed phone starting sequence +
      +
    • + Starting out, we call the keycloak adapter initialization to connect
      + to the keycloak server, login, and download the user profile. +
    • +
    • + After which it is called SIP stack initialization.
      +
    • +
    +
  • + +
  • Added checking of SIP response codes for INVITE and REGISTER to detect authorization + problems. +
  • +
+ +

Keycloak adapter initialization

+ +

+let authServerConfig = { url: 'https://webrtcoauth.example.com/auth',
+                         realm: 'demo',
+                         clientId: 'demoClient'};
+
+
+function initializeAuthServer() {
+    ac_log('keycloak: create adapter');
+    keycloak = new Keycloak(authServerConfig);
+
+    keycloak.onTokenExpired = () => {
+        ac_log('keycloak: onTokenExpired callback');
+        updateAuthToken();
+    }
+
+    ac_log('keycloak: init()');
+    keycloak.init({ onLoad: 'login-required' })
+        .then(() => {
+            ac_log('keycloak: initialized');
+            return keycloak.loadUserProfile();
+        })
+        .then(() => {
+            // To disable auto call login() if updateToken() fails.
+            keycloak.loginRequired = false;
+
+            userAccount = {
+                user: keycloak.profile.username,
+                password: '',
+                displayName: keycloak.profile.firstName + ' ' + keycloak.profile.lastName
+            }
+
+            phone.setOAuthToken(keycloak.token);
+
+            initializePhone();
+        })
+        .catch((err) => {
+            ac_log('keycloak: initialization error', err);
+        });
+}
+
+ + +

When using a keycloak adapter, the phone is no longer a Single Page Application (SPA).

+

+The first call to keycloak.init() sends the user to a Keycloak server HTML page +where the user will enter a name and a password.
+Afterwards they’ll be redirected to the page with the phone.
+Loading the phone page calls keycloak.init again but following entering the credentials, it will not redirect the user to a login page. +

+

+Depending on the configuration of the server, the user name and password are rarely required (approximately once every 2 weeks) +

+

+In subsequent calls of the phone page HTML, keycloak.init() will load the phone page directly instead of redirecting to the Keycloak server.
+It will be performed without entering the password, but still adds a few seconds to the startup. +

+ +

REGISTER with access token example

+ +

+The keycloak.js adapter provides a short-lived access token for SBC authorization. +That includes authorization for SIP REGISTER and INVITE messages using an Authorization SIP header. +

+ + +

+


+REGISTER sip:audiocodes.com SIP/2.0
+Via: SIP/2.0/WSS kiagrmh8pngt.invalid;branch=z9hG4bK3892878
+Max-Forwards: 69
+To: <sip:johndoe@audiocodes.com>
+From: "JohnDoe" <sip:johndoe@audiocodes.com>;tag=t831p2e9jk
+Call-ID: prladr5faj5nqtpo5f7sun
+CSeq: 14 REGISTER
+Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJUdDl1TF9Ya0hSampFR2NUZFRlYXZ0dmxTc0pXYWplRHhIR1MzL
+ XlVazhZIn0.eyJqdGkiOiJmOTVmYWEzZC02N2YxLTRmYjEtODlmOC1hMzQ5ZTc0Y2FlNzMiLCJleHAiOjE1MzEwNTQ4NjYsIm5iZiI6MCwiaWF0IjoxNTMxMDU
+ 0MjY2LCJpc3MiOiJodHRwczovL3dlYnJ0Y29hdXRoLmF1ZGlvY29kZXMuY29tL2F1dGgvcmVhbG1zL2RlbW8iLCJhdWQiOiJXZWJSVENEZW1vIiwic3ViIjoiM
+ jQxZjlkNWEtMzhhNC00Y2Q1LTlhOWItYzBhYjIxNzJkZDZiIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiV2ViUlRDRGVtbyIsIm5vbmNlIjoiMzBhYTdhYWEtMjd
+ jMC00NDAwLTllYjQtY2Y2NmQwZjQxYmM4IiwiYXV0aF90aW1lIjoxNTMxMDU0MjU3LCJzZXNzaW9uX3N0YXRlIjoiM2NlZDVhNmQtZjkwYy00NjU0LWIwYWItM
+ DNjNmU5MTcxNWU0IiwiYWNyIjoiMCIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ1bWFfYXV0aG9yaXphdGlvbiJ
+ dfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZ
+ mlsZSJdfX0sIm5hbWUiOiJIYWlmYTEgVXNlcjEiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJoYWlmYXVzZXIxIiwiZ2l2ZW5fbmFtZSI6IkhhaWZhMSIsImZhbWl
+ seV9uYW1lIjoiVXNlcjEiLCJlbWFpbCI6ImhhaWZhdXNlcjFAZXhhbXBsZS5jb20ifQ.hTnVH-wKGlPDwBreK6c2hxgxZq5jBd9FWplrfRzXHt6wm5cMbbGuJg
+ myJtlcVXueCh9KgFgVe6T9i7VPrtmmgCCVLMOqKSRHZkQn6xcb52Ua0NO8v66qqZKzGToKAXNoJJBOzv8s0iFpxojbu0ZgRYzTkdNtNq2YAbsNfrQRYAPKtBZA
+ Qdcm6alkU1YYqh4BVhEk5MehXYerQj8B8KmwzkmNTwJc34EhZ1CkFbyOO3bqumwSTPo4eOVDhcA82q8J4dw3kDkKZh9RpaV4RLsv-5FngPjX1CGMwFqsHd4EZ_
+ v62nvrKLm3JxHMu1GLQGuhFwjw37iqaxL8XdWaHssLkA
+Contact: <sip:5g8glmd1@kiagrmh8pngt.invalid;transport=ws>;+sip.ice;reg-id=1;+sip.instance="";expires=600
+Expires: 600
+Allow: INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO
+Supported: path,gruu,outbound
+User-Agent: AudioCodes WebRTC phone
+Content-Length: 0
+
+

+
+

Access token updating

+

+Depending on the configuration of the server, +the short-lived access token will expire after a set amount of time had elapsed +(e.g. every 10 minutes), and will need to be updated by the keycloak server. + +The function is called when: +

    +
  • access token will expire soon
  • +
  • REGISTER authorization has failed
  • +
  • INVITE authorization has failed
  • +
+

+ +

+function updateAuthToken() {
+    ac_log('keycloak: updateToken()');
+    return keycloak.updateToken(-1)
+        .then((refreshed) => {
+            if (!refreshed) {
+                ac_log('keycloak: token is still valid');
+                return;
+            }
+            ac_log('keycloak: token is refreshed');
+            phone.setOAuthToken(keycloak.token); // set access token for AudioCodes API.
+        })
+        .catch((e) => {
+            ac_log('keycloak: Failed to refresh the access token', e);
+            if (activeCall !== null && activeCall.isEstablished()) {
+                ac_log('keycloak: re-login needed. Postponed because there is an active call.');
+                authLoginPostponed = true;
+            } else {
+                ac_log('keycloak: login()');
+                keycloak.login();
+            }
+        });
+}
+
+ + +

Test mode

+

+To test the SBC, a test mode has been added. +The test mode allows you to send REGISTER and INVITE SIP messages +without an Authorization header, or with Authorization header that + contains an incorrect access token value. +

+ +

+To enable the test mode, start the phone, open JavaScript console, and type:
+ +


+    localStorage.setItem('authTests', 'r1 i1');  // set r1 and i1 test
+
+Then reload the phone page.
+When the test mode is used, the console will display:
+ +

+    Warning: USED PHONE TEST MODE: authTests='r1 i1'
+
+ +

+ +

+This can be set for one or more test names. Use space as the delimiter between test names. +

+ +Implemented tests: +
    +
  • user in SIP messages, use the wrong user name of phone owner.
    + When using an incorrect user name, SIP authorization will always fail. +
  • +
  • r1 use in 1st REGISTER with an incorrect token value.
  • +
  • i1 use in initial INVITE with incorrect token value.
  • +
  • r0 don't set to the 1st REGISTER Authentication header
  • +
  • i0 don't set to the initial INVITE Authentication header.
  • +
+

+ +

+To disable the test mode, start the phone, open JavaScript console, and type:
+

+

+    localStorage.removeItem('authTests');
+
+

+And then reload the phone page. +

+

+In a production version, instead of loading the authTests value from local storage, + set an empty string value or completely remove the pieces of code marked with 'test code' comments. +

+ +

Phone prototype with Automatic call distributor (ACD)

+

Run phone prototype with ACD

+

Added feature:

+
    +
  • Work with ACD system
  • +
+ +In this example SIP SUBSCRIBE dialogs used to work with the automatic call distributor (ACD) server. +

+ +

+To parse XML used Scott Means's Pure JavaScript XML parser https://github.com/smeans/pjxml
+MIT license
+The code converted to classes syntax. +

+ +

Multi call phone prototype

+

Run multi call phone prototype

+

Added features:

+
    +
  • Multi call support
  • +
  • Blind call transfer (more natural implementation)
  • +
  • Attended call transfer
  • +
  • Audio conference
  • +
  • Video conference
  • +
+ +

+Provided API supports multi calls.
+Before we did not use this opportunity in phone prototypes,
+because it is significantly complicates GUI and rarely necessary. +

+ +

+Nevertheless it is necessary for 3 way conference and atteneded call transfer. +

+ +

+

GUI scheme

+
    +
  • Status line.
  • +
  • Lines buttons. To select line and show each line status (free, active, or in hold)
  • +
  • Call panel for selected line.
  • +
  • Remote video of all lines receiving video. Optional local video for selected line.
  • +
  • Optional video conference settings and canvas with mixed video from all lines.
  • +
+

+ +

Conference

+

+The conference model is very simple:
+if the phone is in conference mode,
+all callers are in the same conference room and hear (and see) each other. +

+

+All newer calls will be added to this conference room. +

+

+Conference mode can be changed during its operation: audio, audio and video or switched off. +

+ + +

Audio conference

+

+To implement audio conferencing we’ll need to mix audio streams.
+There is an Audio Context API that can help us achieve that. +

+ +

+It used to work exclusively in Mozilla’s Firefox browser, and not in Google’s Chrome browser.
+Finally, in 2019 Chrome’s bug on the subject was fixed. (See Chromium issue 121673, reported in 2012)
+Now we can implement audio conferencing via Google Chrome as well. +

+ +

+In the WebRTC phone, the microphone generates audio stream that is sent to a remote phone.
+To create a conference we will replace it to an audio mixer stream. +

+ +

+Let's consider for example 3-way conferences. +

+ +

+We have 2 open calls:
+1st call A - B
+2nd call A - C
+

+ +

+In normal phone mode, A send its microphone stream to B and C.
+To create an audio conference:
+The 1st call will send to B an audio stream containing audio mixed from the microphone and audio received from C.
+The 2nd call will send to C an audio stream containing audio mixed from the microphone and audio received from B.
+

+ +

+So here we’ll use 2 audio mixers (one mixer per each call).
+We cannot use a single audio mixer to mix all streams and send it to all remote calls because then the remote user will receive and hear their own echo. +

+ +

+Similarly, we can create conferences this way that will include more participants.
+For each call we will send an audio stream mixed from the microphone and other calls. +

+ +

+Note: about tracks and streams.
+ A known problem is that some Web APIs use only streams and others will use only tracks.
+ The stream contains an audio track, or an audio track and a video track. +

+ +

+ WebRTC API supports streams with 2 or more audio tracks.
+ We don't use that (the possibility of sending multiple tracks) for conferencing, instead we send a single stream containing a single audio track (with its audio mixed) +

+ +

+ For audio calls, the phone sends a local stream to a remote phone.
+ When we create a local stream we call WebRTC getUserMedia API (use only stream)
+ The stream contains the microphone audio track.
+ To mix the microphone’s audio with the remote side’s audio we use an Audio Context API (use only streams)
+ Then we get from the mixed stream an audio track and call the WebRTC sender method to replace the track (use only track)
+

+ + + +

Video conference

+ +

+Work with video streams creates a heavy load on the processor so we’ll use a single video mixer for all calls to mix all incoming video streams and the local camera stream. +

+ +

+The same mixed video stream will be sent to all remote calls.
+Each participant will see other participants including themselves (serving as an analogue to the audio conference’s echo). +

+ +

+The browser API is bizarre; we can’t simply mix the video streams the way we do for audio.
+We’ll need to split the video streams to sequences of pictures, +draw them in canvas, using some layout,
+and then recreate the mixed stream from the picture sequence. +

+ +

+User can change the parameters of the video conference during its operation:
+the size of the call's picture, the pictures layout (linear or compact)
+and the number of frames per second (FPS).
+CPU usage varies significantly depending on size and FPS. +

+ +

Audio and video mixer

+ +

+To implement audio and video conference were added class CallAudioMixer and CallVideoMixer (see: utils.js)
+Them use the same class "call" as other API, with one addition:
+in the call instance must be defined integer variable call.data['_line_index'] +

+ +

+


+class CallAudioMixer {
+    // For each call created audio mixer instance.
+    // Аudio context can be taken from audio player.
+    constructor(audioCtx, call)
+
+    // Close mixer, release all resources.
+    close()
+
+    // Get mixed audio stream
+    getMix()
+
+    // Add call to mixer.
+    // Returns true if added, false if the call is already added.
+    add(call)
+
+    // Remove call from mixer
+    // Returns true if removed.
+    // Returns false, if the call was not added, or cannot be removed, because set in constructor.
+    remove(call)
+
+    // Returns string with calls list
+    toString()
+}
+
+

+ +

+


+class CallVideoMixer {
+    // Used single instance for all calls.
+    constructor()
+
+    // Set canvas id.
+    // Set local video element id.
+    // Set remote video element id prefix. (will be added video element index 0, 1, ...)
+    setElements(canvasId, localVideoId, remoteVideoId)
+
+    // Set number of frames per seconds of mixed stream.
+    // For example: 1, 2, 5, 10, 20, 50.
+    // Default: 10
+    setFPS(v)
+
+    // Set calls video layout: 'linear' or 'compact'
+    // Default: 'compact'
+    setLayout(v)
+
+    // Set call video size (pixels)
+    // Default w=160, h=120
+    setSize(w, h)
+
+    // Set call video size (pixels)
+    // size likes: {width: '160px', height: '120px'}
+    setSizes(size)
+
+    // Returns true when mixer is started
+    isOn()
+
+    // Start mixer
+    start()
+
+    // Stop mixer, remove all calls, release resources.
+    // After using stop the mixer can be restarted.
+    stop()
+
+    // Get mixed video stream for added call.
+    getMix(call)
+
+    // Add call to mixer or update send/receive mode.
+    // Returns true if send video was added (should be replaced connection sender track)
+    add(call, send = true, receive = true)
+
+    // Remove call from mixer.
+    // Returns true if removed, false if was not added.
+    remove(call)
+
+    // Resize video layout then changed number of video channels
+    // Used when added/removed local video channel.
+    // Called automatically in methods: add, remove, setLayout, setSize
+    //
+    // Warning: it's designed for 5 lines phone !
+    // Max number of video controls is 6 (including local video)
+    // If you use more lines, please modify this method.
+    resize()
+
+    // Returns string with calls list
+    toString()
+}
+
+

+ +

Phone conference functions

+ +

+The functions work with audio and video mixers and replace connection sender track to mixed stream track,
+or restore original sender track. +

+ +

+


+// GUI switch conference mode: off, audio, audio and video
+function guiConferenceSwitch()
+
+// Start audio conference
+function conferenceStartAudio()
+
+// Stop audio conference
+function conferenceStopAudio()
+
+// Start video conference
+function conferenceStartVideo()
+
+// Stop video conference
+function conferenceStopVideo()
+
+// Add call to conference (audio or audio/video)
+function conferenceAdd(call)
+
+// Remove call from conference (audio or audio/video)
+function conferenceRemove(call)
+
+// Assign line video stream from camera to local video element.
+// Used line set as argument or the first line that send video.
+conferenceSetLocalVideo(lineIndex = -1)
+
+// Print in console conference information.
+function conferencePrint()
+
+

+ +

Citrix desktop phone prototype

+

+Run Citrix desktop phone prototype +

+ +

+Citrix provides WebRTC Redirection SDK. The SDK can be used to build Electron applications or browser single page applications (SPA). If you use Citrix desktop, see: citrix.com +

+

+Note: Browser SPA only supports audio calls. +

+ +

Citrix SDK conversion

+

+The Citrix SDK file CitrixWebRTC.js (or CitrixWebRTC.min.js) is a Node module. To use it in the browser, it must be converted. +

+

+Notes: +

    +
  • Use the latest Citrix SDK release.
  • +
  • The file CitrixWebRTC.js used in this example was taken from the SDK beta release and could become obsolete.
  • +
+ +

+  npm install --global browserify
+  browserify CitrixWebRTC.js --outfile browserifyCitrixWebRTC.js
+
+ +

JsSIP modification

+

+Citrix API is very close to standard WebRTC API, but not 100% compatible. Therefore, Citrix API JsSIP must be modified. +

+

+Note: +We replaced a few WebRTC API functions to Citrix analogs. Review python script source to see replaced functions. +

+ +
To convert AudioCodes SDK
+

+

    +
  1. Install Python3.
  2. +
  3. Run the following script: +
    
    +py citrix_convert.py <ac_webrtc.min.js >citrix_ac_webrtc.min.js
    +
    +
  4. +
  5. For debugging, you can replace the obfuscated ac_webrtc.min.js file with the non-obfuscated files acapi.1.?.0.js and citrix_jssip.js
  6. +
+

+ +
To build citrix_jssip.js
+

+   py citrix_convert.py <jssip.js >citrix_jssip.js
+
+
+ +

Citrix cloud Windows configuration

+ +

+

To enable the Citrix SDK
+

+You must set registry in remote Citrix Windows system. Edit Windows registry (use regedit.exe command). +

+ +
    + +
  1. Enable Citrix redirection +
    
    +Key Path: HKCU\Software\Citrix\HDXMediaStream
    +Key Name: MSTeamsRedirSupport
    +Key Type: DWORD
    +Key Value: 1
    +
    +
  2. + +
  3. Add the Chrome program to the allow list. +
    
    +Key Path: HKLM\Software\WOW6432Node\Citrix\WebSocketService
    +Key Name: ProcessWhitelist
    +Key Type: MULTISZ
    +Key Value: chrome.exe
    +
    +
  4. + +
  5. [Optionally] Configure Citrix logging. +
    
    +Key Path: Computer\HKEY_CURRENT_USER\Software\Citrix\HDXMediaStream
    +Key Name: WebrpcLogLevel
    +Key Type: DWORD
    +Key Value: 0
    +
    + +Log created in local (not remote !) computer in the directory %temp%\HdxRTCEngine
    +For each RTP session created subdirectory with timestamp.
    +
    +To see log: +
    
    +   cd %temp%\HdxRTCEngine
    +
    +and select log according timestamp. +
  6. + +
+ +

+ +
Configure microphone privacy settings
+

+In Citrix Desktop Windows, open "microphone privacy setting" and enable microphone usage. +

+ + +

Modification simple phone prototype

+ +

+The provided Citrix phone prototype is a modified simple phone prototype.
+Please compare the simple phone prototype code with this version. +

+
    +
  • Support for video calls removed.
  • +
  • Citrix API in phone.js was used.
  • +
+ +

+Note: The phone.js and citrix_jssip.js does not call the Citrix API directly, but via the citrix_adapter.js wrapper. +

+ + + +

How Citrix phone starts

+
    +
  1. Phone waits for the initialization of the Citrix SDK.
    +Note: There will be error if the browser did not start in Citrix desktop or the desktop is not configured. +
  2. +
    +
  3. +Phone uses the Citrix API to collect available microphones and speakers.
    +
  4. +
    +
  5. +Phone selects microphone and speaker.
    +Citrix API does not work without selected devices +
      +
    • getUserMedia requires microphone deviceId constraints.
    • +
    • AudioElement requires speaker deviceId to be assigned to sinkId.
    • +
    +
  6. +
    +
  7. +Phone attempts to use the same microphone and speaker that were selected before.
    +Note: This does not always work, for example: +
      +
    • When the user detached the USB headset that was previously used.
    • +
    • When the phone starts up for the first time.
    • +
    +In such cases the settings screen opens, allowing the user to select the microphone and speaker. +
  8. +
    +
  9. phone starts JsSIP stack and works in the same way as other phone examples.
  10. +
+ + + +

Dual registration phone prototype

+ +

+Run dual registration phone prototype +

+ +

+JsSIP stack with our CRLF keep alive extension quite quickly (10..20 seconds) +detects websocket disconnection of SBC, +after which it reconnects with the same or with a other SBC. +

+ +

+However, some of our customers want the phone to simultaneously open 2 websocket connections with the main and backup SBC. +

+ +

+The problem is that JsSIP stack can only work with one web socket.
+JsSIP is well maintained and has reliable code.
+Making such drastic changes to it would be difficult to test and can significantly reduce its reliability.
+

+ + +

+However, the customers do not want a phone that can simultaneously call through +the main and backup SBC.
+Only one SBC will be active. (Тhe one to which the JsSIP is connected)
+

+ +

+Without changing JsSIP we will add optional backup SBC module (backup_sbc.js) +to connects to the backup SBC and sending SIP REGISTER sequence.
+If necessary, we can swap these two web sockets (JsSIP websocket and backup SBC websocket) +

+ +

Backup SBC module description and limitations

+
    +
  1. +Main and backup SBC use same account credentials (user, password, realm, domain name) +
  2. + +
  3. +BackupSBC module is not implemented complete SIP protocol. + It supports: +
      +
    • + Sending REGISTER sequence and REGISTER authentication. +
    • +
    • + Receiving INVITE and either reject it (send 486 response) + or swap main/backup transport (to answer incoming call in JsSIP stack) +
    • +
    • + Sending keep-alive CRLF ping/pong +
    • +
    +
  4. + +
  5. +In case of failure of registration on the backup SBC transport – no action item will be done beside reconnections attempts. +
  6. + +
  7. +In case of a failure on the main transport the backup websocket transport can be swapped to the main websocket transport +The phone code detecting the case (as sequence of login disconnect events) and +swap main/backup transport (if backup SBC is registered) +
  8. + +
  9. +In case of receiving an INVITE on the backup websocket transport will be called incomingInvite() callback. +The phone code check if there are open calls in main JsSIP transport. +If there exists open calls in main JsSIP transport phone will reject the call. +Otherwise it will switch main/backup transport and receive the call in main (JsSIP) transport. +
  10. + +
  11. +ACD will be supported on the main channel only. +In case of a swap we will re-subscribe to ACD service. +
  12. + +
+ + +

How phone code should be modified to use dual registration

+ +

+To understand it, see usage of "backupSBC" object in phone.js +

+ +

+

    + +
  • Creation +
    
    +    let backupSBC = new BackupSBC();
    +
    +
  • + +
  • Set parameters +
    
    +    backupSBC.setAddresses(backupAddresses);
    +    backupSBC.setLogger(backup_sbc_log);    backupSBC.setReconnectIntervals(phoneConfig.reconnectIntervalMin,phoneConfig.reconnectIntervalMax);
    +    backupSBC.setKeepAlive(phoneConfig.pingInterval);
    +
    +
  • + +
  • Listeners. +
    
    +    backupSBC.setListeners(...);
    +
    + +There are 2 listeners: +
      +
    • loginStateChanged +

      + To notify if backup SBC is connected/registered or not. +

      +
    • + +
    • incomingInvite +

      + When there is incoming in backup SBC INVITE
      + phone must decide if answer the call ( backupSBC.swap(invite) )
      + or reject it ( backupSBC.reject(invite) ) +

      +
    • +
    +
  • +
    +
  • If phone detect sequence of main SBC failures, and backup SBC is + registered it will swap main/backup SBC. +
  • +
    +
  • During page reloaded to keep currently used main and backup SBC
    + See usage of "isSwapped" variable + It set in onBeforeUnload and saved to session storage. + It used when phone starts after the page reloading. +
+

+ + +

Device selection (microphone, camera, speaker)

+ +

+It would seem that it could be easier?
+Get a list of devices (microphones, cameras, speakers).
+Choose the preferred one of each type.
+Then we use the device ID of the selected devices. +

+ +

+For input devices (microphone and camera) we use the device ID in getUserMedia constraints. + +


+     getUserMedia({audio: { deviceId: "speaker-device-id" }});
+     getUserMedia({video: { deviceId: { ideal: "camera-device-id"} }}
+     getUserMedia({audio: { deviceId: { exact: "speaker-device-id"} }}
+
+ +For output audio devices (speaker) we use audio element setSinkId() method. +

+ +However, it's really not that easy: + +
    +
  • Browser and OS implementations are different.
    + iOS does not provide output audio devices and uses system default.
    + Firefox don't enumerate output audio devices.
    + audio element setSinkId can be not implemented in some browsers - before usage + we should check if it's implemented. + +
    
    +    if (audioElement.setSinkId)
    +        audioElement.setSinkId(deviceId);
    +
    +
  • +
    + +
  • The selected device can be disconnected. + Especially if using USB or bluetooth headset. + +If disconnected while the phone page is open, this can be detected using "devicechange" listener. +
  • +
    + +
  • Device list can be used as browser fingerprint.
    + For this reason, WebRTC API provide a complete list of devices, + only if you open getUserMedia stream (for Chrome if set the device usage permission) +
  • +
    + +
  • You can detect if the device list incomplete if device labels are empty string ("")
    + If device list is incomplete some devices can be removed (e.g. there is single camera instead rear and front cameras) +
  • +
+ +

+When we start the phone we usually don't use getUserMedia.
+(It will look strange, we are not calling anywhere, but we are already asking permission to use the microphone and camera) +

+ +

+In this case, we will get an incomplete list of devices, in which there will be no devices selected in the previous browser session.
+In our examples, in this case, we add the devices selected the previous time to the list of devices. +

+ +

+Тhis approach will work if the previously selected device is connected. +

+ +

+However, if it removed, then it all depends on what constraints we use. +If we use the ideal constraint: +

+ +

+


+    getUserMedia({audio: deviceId: { ideal: "device-label" }})
+
+In the absence of this device, the default device will be used. +

+ +

+However, if we use exact constraint and device is missed, there will be an exception: +OverconstrainedError {name: 'OverconstrainedError', message: '', constraint: 'deviceId'} +


+    getUserMedia({video: deviceId: { exact: "camera-id" } });
+
+

+ +

+We provide utils.js SelectDevices class which collects and stores a list for all available devices.
+The class used in single call, multi call phone prototype and Citrix phone. +

+

Device selection in different browsers and operating systems

+

+Browser|OS       Microphone  Camera  Speaker     Note
+
+chrome|windows   +microphone +camera +speaker 
+chrome|macos     +microphone +camera +speaker 
+chrome|linux     +microphone +camera +speaker
+chrome|android   +microphone +camera +speaker   In modern Android enumerated all speakers, in obsolete (e.g. Android 9) only latest added.
+chrome|ios       +microphone +camera -speaker   Speaker cannot be reassigned.                            
+
+firefox|windows  +microphone +camera -speaker   Speaker cannot be reassigned. 
+firefox|macos    +microphone +camera -speaker   Speaker cannot be reassigned. 
+firefox|linux    +microphone +camera -speaker   Speaker cannot be reassigned. 
+firefox|android  +microphone +camera -speaker   Speaker cannot be reassigned
+firefox|ios      +microphone +camera -speaker   Speaker cannot be reassigned.
+
+safari|macos     +microphone +camera -speaker   Speaker cannot be reassigned. 
+safari|ios       +microphone +camera -speaker   Speaker cannot be reassigned. 
+
+other|other           ?        ?       ?        We did not check some OS, e.g. Chrome OS.
+
+ +

Change codecs priorities. Remove codecs

+ +

+RTCRtpTransceiver.setCodecPreferences() method using to removing or changing codecs priorities.
+The method is not implemented in Firefox. +

+ +In our SDK we provide method: phone.setCodecFilter(). +
+

+Codec set as name, e.g. 'pcma' (case insensitive)
+name with frequency e.g. 'pcma/8000'
+name, optional frequency and fmtp: e.g: 'VP9/90000#profile-id=0'or 'VP9#profile-id=0' +

+ +

+ + +

Change codecs priorities

+ +

+Make PCMU, PCMA codecs more priority than OPUS. +


+    phone.setCodecFilter({ 
+        audio: { priority: ['pcmu', 'pcma'] }
+    });
+
+

+ +

+Modify video codecs priorities. +


+    phone.setCodecFilter({ 
+        video: { priority: ['av1', 'vp9', 'vp8'] }
+    });
+
+

+ +

Removing codecs

+ +

+Note: It’s not recommended! +
+It is better to keep all browser-provided codecs to ensure compatibility with different browsers and operating systems. +

+ +

+Remove ISAC and G722 audio codecs. +


+    phone.setCodecFilter({
+        audio: {
+             remove: ['isac', 'g722'],
+        }
+    });
+
+

+ + +

+All codec filters must be set once.
+Here is a more complicated example
+


+    phone.setCodecFilter({
+        audio: {
+            remove: ['isac', 'g722'],
+            priority: ['pcma', 'pcmu']
+        },
+        video: {
+            remove: ['h264', 'vp9#profile-id=2', 'av1', 'ulpfec'],
+            priority: ['vp9', 'vp8']
+        } 
+    });
+
+

+ + +

Call quality score

+A functionality has been added to Mediant SBC that evaluates the sound quality after a call is completed.
+If this option is enabled, then after the call the web client will receive out of dialog SIP NOTIFY with +customer header X-VoiceQuality which includes a voice quality.
+Take a look to phone prototype code: +

+incomingNotify: function (call, eventName, from, contentType, body, request) {
+    ac_log(`phone>>> incoming NOTIFY "${eventName}"`, call, from, contentType, body);
+    if (call === null) { // out of dialog NOTIFY
+        if (eventName === 'vq') { // voice quality event
+            let vq = getXVoiceQuality(request); // X-VoiceQuality header parser, defined in file utlis.js
+            if (vq) {
+                ac_log(`NOTIFY: "X-VoiceQuality" header: score="${vq.score}", color="${vq.color}"`);
+            }
+        }
+    }
+	. . . .
+
+Score is small integer value and corresponding color: +
    +
  • green - good quality
  • +
  • yellow - fair quality
  • +
  • red - low quality
  • +
  • gray - N/A (cannot calculate score)
  • +
+ +

Click-to-call test call

+At the request of customers, a test call was added to the click-to-call phone.
+If set testCallEnabled:true in the file config.js will be shown additional button "Test line".
+"Test call" is call to a special SBC user configured to automatically answer and send an audible prompt.
+
+To trigger Mediant SBC to evaluate the call quality to INVITE added custom Header:X-AC-Action: test-voice-quality
+To request URL added call duration (milliseconds) parameter ;duration=10000
+After the specified interval has expired, the SBS terminates the call and sends BYE +with header:X-VoiceQuality which includes a quality score. + +

Hidden page timer throttling

+

+All modern browsers use timer throttling for hidden page.
+If timers for hidden pages work with a resolution of 1 second, this is not a problem for the phone.
+We are concerned about cases when the timer works with a deviation of more than 10 seconds. +

+ +

Since Chrome 88 used intensive timer throttling
+See Chrome timer throttling
+In the mode timer resolution is 60 seconds !
+
+Safari 14 also uses intensive timer throttling for hidden page. +

+ +

+Now we have to adapt the SDK to work with such "accurate" timers. +

+ +

+It turned out that JsSIP itself does not enter to Chrome intensive timer throttling mode, unless you use REGISTER timeout for less than 65 seconds. +

+ +

+However, if you use our SDK with a websocket keep alive pings with an interval of 10..20 seconds, +the phone enters to Chrome intensive timer throttling mode. +

+

+Another way to force the phone to enter this mode is to build its GUI +based on a framework that uses timers intensively (e.g. for smooth scrolling). +

+

+JsSIP continues to periodically send REGISTER even when timer works with big delay.
+However, there is a small chance that the phone will not be registered on the SBC +for a short period of time (about 30 seconds) before sending the next REGISTER.
+

+ +

+In modified JsSIP used for the SDK, expiration interval has been changed: the REGISTER is sent a little in advance,
+taking into account a possible timer delay of 1 minute. +

+ +

+For phone developers it is recommended to catch page visibility event,
+and when it is hidden, do not use the timers during this period.
+This will prevent entering to intensive timer throttling mode. +

+

+document.addEventListener('visibilitychange', () => {
+    if (document.hidden) {
+        stopUseTimersInGUI();
+    } else {
+        startUseTimersInGUI();
+    }
+});
+
+ +

+To phone testing/debugging can be used the code that print timer deviation: +

+ +

+   {
+        let origSetTimeout = setTimeout;
+        setTimeout = (func, delay) => {
+            let key = origSetTimeout((orderTime) => {
+                let calcTime = orderTime + delay;
+                let delta = Date.now() - calcTime;
+                console.log(new Date().toISOString().slice(11, -1) + ' TIMER execute timeout key=' + key + ' delta=' + delta);
+                func()
+            },
+                delay, Date.now());
+            console.log(new Date().toISOString().slice(11, -1) + ' TIMER: setTimeout ', delay, key);
+            return key;
+        }
+        let origClearTimeout = clearTimeout;
+        clearTimeout = (key) => {
+            console.log(new Date().toISOString().slice(11, -1) + ' TIMER: clearTimeout ', key);
+            origClearTimeout(key);
+        }
+        let origSetInterval = setInterval;
+        setInterval = (func, delay) => {
+            let counter = 0;
+            let key = origSetInterval((orderTime) => {
+                counter++;
+                let calcTime = orderTime + delay * counter;
+                let delta = Date.now() - calcTime;
+                console.log(new Date().toISOString().slice(11, -1) + ' TIMER execute interval#' + counter + ' key=' + key + ' delta=' + delta);
+                func()
+            },
+                delay, Date.now());
+            console.log(new Date().toISOString().slice(11, -1) + ' TIMER: setTimeout ', delay, key);
+            return key;
+        }
+        let origClearInterval = clearInterval;
+        clearInterval = (key) => {
+            console.log(new Date().toISOString().slice(11, -1) + ' TIMER: clearInterval ', key);
+            origClearInterval(key);
+        }
+    }
+
+ +

+Can be seen that Chrome when page is hidden uses timer throttling with timer resolution 1 seconds.
+А web phone running on a laptop with a hidden page enters intensive timer throttling after 5 minutes, +with timer resolution 60 seconds. +

+ + +

SDK setWebSocketKeepAlive method

+ +

+The method code has been rewritten.
+


+setWebSocketKeepAlive(pingInterval, pongTimeout=true, timerThrottlingBestEffort=true, pongReport=0, pongDist=false)
+
+

+ +
    +
  • + pingInterval: +
      +
    • >= 0 Ping interval in seconds. E.g. 10 or 20 seconds.
    • +
    • 0 Don't send pings.
    • +
    +
  • +
  • + pongTimeout=true (default) +
      +
    • true Close and reopen websocket after pong timeout
    • +
    • false Print warning and continue
    • +
    +
  • + + +
  • + timerThrottlingBestEffort=true (default) +
      +
    • + false: Print warning if timer throttling is detected. Do not change ping interval. +
    • +
    • + true: (default) For Chrome set internally object:
      + {log: 0, chrome: {interval: 1, visibility: true, call: true, log: 1}}
      + Print warning if timer throttling is detected. Do not change ping interval. +
      + In previous SDK 1.15 used interval: 62 to increase ping interval and exit from + intensive timer throttling mode. + Now ping/pong algorithm changed (each received pong reset timer). + Phone don't enter to intensive timer throttling mode because ping/pong keep alive, + so no need increase the ping interval when the throttling is detected. + (phone can enter to the mode because used GUI framework) +
    • +
    • + Object likes: {log: 0, chrome: {interval: 1, visibility: true, call: true, log: 1}}
      + For debugging and fine tune.

      + The object {log: 0, chrome: {interval: 1, visibility: true, call: true, log: 1}} + used internally for timerThrottlingBestEffort=true

      + The object {log: 0} used internally for timerThrottlingBestEffort=false

      + Can be used other values, e.g. to print each detected timer throttling in Safari (not only 1st) set:
      + {log: 1, chrome: {interval: 1, visibility: true, call: true}}

      + + Parameters description:
      +
        +
      • + log: [integer] log level for all browsers
        +
          +
        • 0 print when changed ping interval. Detected timer throttling printed only one time.
        • +
        • 1 print when changed ping interval and each time when detected timer throttling.
        • +
        • 2 print all relative events (when changed page visibility or call started/terminated)
        • +
        • 3 print for each ping timer deviation (milliseconds)
        • +
        + Levels 2 and 3 for debugging. +
      • + +
      • + browser names and actions.
        + Can be seen that we do something only for Chrome. +
          +
        • + interval: [integer] + if this value is not 0 and is greater than the current ping interval, + increased ping interval after timer throttling is detected. + To allow Chrome exit from intensive timer throttling mode, the interval must + be more than 60 seconds + (it was actually in SDK 1.15, since SDK 1.16 improved ping/pong algorithm don’t switch Chrome + to intensive timer throttling mode. No need increases the interval to exit the mode)
          + If programmer want be compatible with SDK 1.15 setting, he can set the interval 62 seconds. +
        • +
        • + visibility: [boolean] check page visibility
          + when page is visible: use original ping interval value,
          + when page is hidden: use increased ping interval value provided that timer throttling was previously detected. +
        • +
        • + call: [boolean] check if there is active call.
          + if there is active call use original ping interval value.
          +
        • +
        • + log: [integer] (optional) log level for the browser.
          + If set overload log value set for all browsers. +
        • +
        +
      • +
      +
    • +
    +
  • + + +
  • + pongReport=0 (default)
    +
      +
    • >= 0 Each n pongs print pong report with min and max delays. E.g. 50
    • +
    • 0 Don't print pong report.
    • +
    +
  • +
  • + pongDist=false (default) +
      +
    • true Add to report also pong delays distribution
    • +
    • false. Don't print pong delays distribution
    • +
    +
  • +
+ +

+Note:
+To prevents Chrome enter to intensive timer throttling mode mode, can be played a beep each 25 seconds.
+See phone_prototype: audioPlayer.playShortSound +

+ +

+Safari 14 uses different timer throttling algorithm.
+I don't found its description, but as I see added random timer delays, likes 0..50 seconds for hidden page.
+Increased timer interval does not help, because a page does not exit the timer throttling mode.
+For Firefox and Safari SDK detects big timer deviation (>10 seconds), prints warnings and does nothing.
+If timer delays less than 60 seconds, modified JsSIP registrar works without problem.
+

+ + +

+

Let's summarize the recommendations

+
    + +
  • Use REGISTER expries not less than 140 seconds (preferably 600 seconds)
  • +
  • Use websocket keep alive pings with an interval of 10..60 seconds.
  • +
  • Use timerThrottlingBestEffort=true
  • +
  • Listen visibilitychange event and for hidden page do not use timers.
  • +
  • Optionally for Chrome when page is hidden, play an almost inaudible beep sound every 25 seconds.
  • +
+

+ +

Supported browsers

+

Desktop browsers

+

+In the current release, the WebRTC Client SDK supports:
+

    +
  • Google Chrome for Windows and Linux
  • +
  • Browsers built in Chromium base: new Microsoft Edge, Opera and others
  • +
  • Mozilla Firefox
  • +
  • Apple Safari for Mac
  • +
+

+ + +

Mobile browsers (partial support)

+

+For mobile phones, it is preferable to use the AudioCodes native WebRTC SDK.
+However, Web WebRTC SDK also can be used (with some limitations). +

+ +

+In the current release, the WebRTC Client SDK partially supports:
+

    +
  • Chrome for Android
  • +
  • iOS Safari for IPhone
  • +
+

+ +

+For Chrome for Android and iOS Safari for IPhone the sound is played on bottom loudspeaker, +instead of top loudspeaker (acts as earpiece). +
+ +It cannot be reassigned, because WebRTC API does not expose the top loudspeaker as an available output device.
+(See navigator.mediaDevices.enumerateDevices())
+This problem can be solved if you connect external headset to the mobile phone. +

+ +

+

Chrome for Android limitations
+
    +
  • +The sound is played on bottom loudspeaker. +
  • +
  • +Notification API is not implemented (at least in simple form), so there is not incoming call notification.
    +
  • +
  • +Screen Sharing is not implemented.
    +
  • +
  • +Video call problem: the call works, but browser crashed after the call termination. +
  • +
+

+ +

+

iOS Safari limitations
+
    +
  • +The sound is played on bottom loudspeaker. +
  • +
  • +Notification API is not implemented, so there is not incoming call notification
    +
  • +
  • +Screen Sharing is not implemented.
    +
  • +
  • +Еvent "beforeunload" is not implemented, so after page reloading phone cannot restore call,
    +cannot rise priority of previously connected SBC and send SIP un-REGISTER +
  • +
  • +Video call problems:
    + +Video stream from the camera (local video stream) sometimes works, and sometimes it does not (shown as a black square).
    + +If you open the 2nd video call (in multi-call phone) then the video from the first one stops working (a black square is shown) +
  • + +
+

+ +

+

Notes about Apple Safari for Mac

+
    +
  • Since release 1.9 SDK works with Safari 13 without webrtc adapter
    +Previous SDK releases works only with webrtc adapter
  • +
  • WebRTC can be used starting version 12 of the browser, recommended latest version 14
  • +
+

+ + +

Developer's note. JavaScript console log

+

To open the JavaScript console follow the steps below:
+ In Chrome and Firefox press: Ctrl-Shift-I to open dev tools, and click to console tab.
+ In Safari press: Option(Alt)-Command-I, and click to console tab.
+ Note: should be enabled "Show develop menu in menu bar" in "Safari/Preferences/Advanced"
+

+ +

+Chrome console log settings
+To open the console: press Ctrl-Shift-I, click on the console tab.
+Click on gear icon on top:
+Disable 'Preserve log'.
+Click on 'All levels' and enable: Info, Warnings, Errors.
+To close console settings click again on gear icon. +
+
+Click on 'Customize and control DevTools' icon (above gear icon)
+Click on settings
+In 'Console' section:
+Enable 'Show timestamps' and 'Group similar'
+To close settings click on X icon at top
+

+

+About "Verbose" log level
+Using this level, problems with your certificates might be found, +violations of the JavasSript standard, misuse of Browser API, etc.
+If possible, it is worth correcting the problems found, but not all of them can be fixed.
+Therefore, this mode is recommended for debugging, but not for general use. +

+

+Firefox console log settings
+To open the console: press Ctrl-Shift-I, click on the console tab
+Disable 'Persist Logs'.
+Click on the 'Filter output' icon by the text field, Enable: Errors, Warnings, Logs and Info
+Click on the 'Filter output' icon again to close the panel.
+Click the gear icon located at the top of the console's right-hand side; +the 'Toolbox options' is seen in the in the tooltip. +Under in 'Web Console', enable 'Enable timestamp'.
+To close console: press: Ctrl-Shift-I. +

+ +

+Safari console log settings
+To open the console: press Option(Alt)-Command-I, click on the console tab
+Enable 'All'.
+
+To save console log to a file:
+

    +
  • Select a row from the console log (be sure not to highlight any text since that will change your context menu)
  • +
  • use Command + A to select all rows
  • +
  • Right click and select 'save selected'. Save the file to your computer.
  • +
+To close the console use: Option(Alt)-Command-I +

+ + +

+About 'Preserve log' or 'Persist Logs' flag
+If the flag is disabled, the console log will be cleared after page reloads.
+Generally this will be the preferred setting since it helps keep the log size to a minimum.
+
+Enable the flag when you want to see the log before and after reloading a page.
+Remember to manually clear the console logs before testing. +

+ + +

Developer's note. WebRTC adapter

+ +

+The adapter in the following link is an open source JavaScript solution.
+See webrtc adapter description
+ +The WebRTC adapter is not included in the SDK, and may be added by the developer.
+It can be downloaded from: adapter-latest.js
+

+ +

+Since SDK 1.9 we stopped using obsolete WebRTC API:
+- event "addStream"
+- RTCConnection getLocalStreams()
+- RTCConnection getRemoteStreams()
+
+The methods are not implemented in Safari 13, and added by webrtc adapter.
+Тherefore, our previous SDK releases do not work with Safari without webrtc adapter. +

+ +

+Now webrtc adapter usage is optional for all supported browsers.
+As you can see we do not use it in our phone examples.
+

+ +

Developer's note. Debugging JavaScript code

+

Let's use our 'check for available devices' example.
+In chrome open dev tools, and select sources.
+Select file phone.js
+Set breakpoint in line 48. (by clicking in the line's number)
+Reload page. Now JavaScript execution will break in line 48

+Press the 'step over next function call' serveral times in the debugger

+Check the value of some variables, then resume script execution.

+The same can be done in Mozilla's Firefox browser.
+These types of tips and knowledge can assist you in phone debugging.

+When you updating the phone's code on a website,
+you should clear browser cache and reload (in Chrome/Firefox press: Ctrl+F5)

+ +

Developer's note. Chrome local overrides

+

This option can aid you with general convenience in some tasks.
+e.g. You're interested in taking one of the examples from our website and change some of +its lines of code.
+ +

Without local overrides, you would have to create your own site, copy this example to it, +and change something in it.

+ +

Using local overrides you can accomplish this using an example from our site, and the changes +you've made are locally made to your Chrome browser with the help of Chrome's local overrides.
+To know more about how they're used, please see: local overrides +

+ +

Developer's note. About STUN protocol

+

For WebRTC - STUN protocol is critical and WebRTC cannot work without it.

+

The STUN protocol is usable when your client is connected to a network using NAT.
+In a case when the client communicates with an external internet, +NAT convert its IP and port to another IP and port so the client can't know how it is seen +from external internet (which IP and port)
+To check it, the client sends a request to a STUN server.
+The STUN server will send a response where it will write which IP and port was used in request.

+

Before establishing a connection, the WebRTC client must create an SDP offer that include all posssible phone connections IPs and ports +prepared by ICE Gathering.
+It takes all the IP available on the computer,then sends STUN requests to STUN and TURN servers +(STUN and TURN are optional and can be specified in the configuration).

+

For a WebRTC phone, you may use Google's STUN server: stun.l.google.com:19302 (Pay attention to the DNS as it returns more than one IP)
+Note: Mediant SBC works without STUN servers.
+Note: It is not recommended to use free Google STUN server for production.
+No one guarantees that it will work, so use it only for testing. +

+

If a corporative firewall disables the STUN protocol, the browser cannot receive responses +from the STUN server.

+

You can see ICE gathring using the Wireshark sniffer with the filter 'stun', as the browser sends STUN requests, + and does not receive responses.

+

+Let's use this test, to see how long it takes in your browser

+

+In the simple case, when the computer has one IP and STUN protocol is allowed in firewall, it takes less than a second. +

+

+However, consider another case: the computer has two IPs: one from a home Internet provider, +and the other is VPN of our company. +Suppose our organization's farevall is blocking the STUN protocol.
+During ICE gathering phone will send STUN requests from all available IPs.
+In this case, ICE gathering will take 40 seconds for the Chrome browser, +because during VPN IP checking, the browser will try to connect to the STUN server again and again.
+Therefore, we should set ICE gathering timeout to meet some reasonable time (a few seconds). +

+ +

WebRTC also uses the STUN protocol for other purposes such as:
+ checking if the media session is alive. +

+

A WebRTC client sends an RTP stream to the SBC server IP and port.
+It will periodically send STUN requests to SBC with the same IP and port used for the open RTP session.
+If during the call the request is not responded to, +the client will decide that the media connection has been lost.
+

+On the firewall, you’ll have to allow inbound STUN requests for your SBC server +as well with a UDP port range (the same port range that the SBC uses for RTP sessions) +

+

+If your firewall allows STUN for the STUN server, +but not for the SBC, your phone will open a connection, +work for some time (tens of seconds) and then the call will close. +

+ + +

Developer's note. Bypassing the corporate firewall

+

+The following is most important when a WebRTC phone is hosted in an organization’s intranet (private IP network), +and the SBC is hosted in the internet (e.g. Amazon’s Cloud services). +

+

The organization's firewall and NAT between the local network and the internet can cause problems in this type of set-up

+

 

+
    +
  1. SIP communication between browser and SBC: +

    SBC receives a SIP connection in a secure websocket, using port 443.
    It's the default secure websocket port that is also used for HTTPS so the port is enabled in most firewalls.

    +
  2. +
  3. STUN communication between a browser and the STUN server:
    +Note: this STUN communication is optional. To disable it, set empty values for ICE server lists in the phone’s configuration. +

    +

    Before starting an outgoing call or answering an incoming one, WebRTC runs ICE gathering (to check computer IPs)
    The browser will send a STUN binding request to the STUN server.
    We use google open STUN server: stun.l.google.com

    +

    The firewall must allow STUN communication between the browser and the external STUN server.

    +
  4. +
  5. STUN and DTLS-SRTP communication between the browser and the SBC:
    +

    Before starting an RTP transmission, the browser checks the future RTP channel:
    + It sends a STUN binding request to the SBC using the same ports it will use for RTP.
    + If the SBC responds with a STUN response, the browser starts sending RTP packets. + After the communication is established, the browser periodically sends STUN requests to check if the RTP channel is alive, + so the firewall must allow STUN and RTP communication between your browser and SBC

    +
  6. +
+

 

+

For RTP communication the browser uses WebRTC API's UDP ports.

+

As this can be an issue, we'll expand on it below.
+

+

WebRTC API designers don't provide an API to set RTP port range !

+

+To use WebRTC phone you must ask your IT security enable inbound RTP/STUN protocols for all UDP ports. +

+

If using Chrome for business, you can set the port range by Chrome corporative policy.
+(see WebRtcUdpPortRange) +

+ +

Developer's note. Setting speaker and microphone in Windows

+

+In order for the phone to work, you must properly configure the microphone and speaker for the browser. +

+

Check speaker

+

+Open the site: youtube.com and try to listen to any song.
+If you hear it, your speaker is OK.
+Otherwise open the Windows "Control Panel", select "Manage Audio Devices", +click the "Playback" tab and there you will be able to select the default device for playback. +Now repeat the "youtube" test. +

+

Check microphone

+

+Open the Windows "Control Panel", select "Manage Audio Devices", +click on the "Recording" tab and select default device.
+Say something into the microphone and and watch the green bar for activity. +

+

+You can also select a microphone internally when using Chrome as your browser. +
+Call someone and after the call is established, +click the 'camera' icon in browser address line, then +select proper microphone and camera devices for future usage. +

+ + +

About the JsSIP library used in this project

+

+HTML 5 WebRTC API supports audio and video encoding/decoding, SRTP, and SDP, +but misses the SIP protocol.
+"JsSIP" is an open source JavaScript library that provides SIP via a websocket protocol.
+It internally uses the WebRTC API, and is intended to build JavaScript WebRTC phones. +

+

The official jssip site

+

The JavaScript source code

+ +

JsSIP license information

+

+ +

+
+Name: JsSIP
+Author: José Luis Millán 
+Core Developer: Iñaki Baz Castillo 
+Copyright (c) 2012-2015 José Luis Millán - Versatica 
+
+
+License: The MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ + +

Phone examples

+

Run simple phone

+

Run phone prototype

+

Run phone prototype with answering machine

+

Run phone prototype with OAuth2

+

Run phone prototype with ACD

+

Run multi call phone prototype

+

Run Citrix desktop phone prototype

+

Run dual registration phone prototype

+ + + \ No newline at end of file diff --git a/js/LICENSE b/js/LICENSE new file mode 100644 index 0000000..8ef6702 --- /dev/null +++ b/js/LICENSE @@ -0,0 +1,51 @@ +AudioCodes Web SDK +Copyright AudioCodes Ltd + +Programmer: Igor Kolosov +Copyright (c) 2021 AudioCodes Ltd. All rights reserved. + +based on: + +JsSIP +https://github.com/versatica/JsSIP + +Author: José Luis Millán +Core Developer: Iñaki Baz Castillo +Copyright (c) 2012-2015 José Luis Millán - Versatica + +The MIT License +----------------------------------------------------------- +Provided with the SDK example: "6.phone_prototype_oauth" depends: + +file: keycloak.js – Keycloak server adapter: + +https://github.com/keycloak/keycloak + +Apache License 2.0 + +----------------------------------------------------------- +Provided with the SDK example: "7.phone_prototype_acd" depends: + +file: pjxml.js is modified XML parser: + +Pure JavaScript XML parser +Scott Means +https://github.com/smeans/pjxml + +The MIT license +----------------------------------------------------------- +Provided with the SDK example: "9.phone_prototype_citrix" depends +of Citrix WebRTC Redirection SDK. + +https://www.citrix.com/ + +Copyright Citrix Systems Inc. +----------------------------------------------------------- +utils.js AudioPlayer2 + +convertor AudioBuffer to WAV format taken from project +Matt Diamond +https://github.com/mattdiamond/Recorderjs + +MIT lisence +----------------------------------------------------------- \ No newline at end of file diff --git a/js/ac_webrtc.min.js b/js/ac_webrtc.min.js new file mode 100644 index 0000000..83c2201 --- /dev/null +++ b/js/ac_webrtc.min.js @@ -0,0 +1,16 @@ +/* + * JsSIP v3.10.0 + * the Javascript SIP library + * Copyright: 2012-2023 + * Homepage: https://jssip.net + * License: MIT + */ + +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JsSIP=e()}}(function(){return function(){return function e(t,n,r){function i(o,l){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!l&&a)return a(o,!0);if(s)return s(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[o]={exports:{}};t[o][0].call(c.exports,function(e){return i(t[o][1][e]||e)},c,c.exports,e,t,n,r)}return n[o].exports}for(var s="function"==typeof require&&require,o=0;o=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0)return t}},connection_recovery_min_interval:function(e){if(s.isDecimal(e)){var t=Number(e);if(t>0)return t}},contact_uri:function(e){if("string"==typeof e){var t=l.parse(e,"SIP_URI");if(-1!==t)return t}},display_name:function(e){return e},instance_id:function(e){return/^uuid:/i.test(e)&&(e=e.substr(5)),-1===l.parse(e,"uuid")?void 0:e},no_answer_timeout:function(e){if(s.isDecimal(e)){var t=Number(e);if(t>0)return t}},session_timers:function(e){if("boolean"==typeof e)return e},session_timers_refresh_method:function(e){if("string"==typeof e&&((e=e.toUpperCase())===o.INVITE||e===o.UPDATE))return e},session_timers_force_refresher:function(e){if("boolean"==typeof e)return e},password:function(e){return String(e)},realm:function(e){return String(e)},ha1:function(e){return String(e)},register:function(e){if("boolean"==typeof e)return e},register_expires:function(e){if(s.isDecimal(e)){var t=Number(e);if(t>0)return t}},registrar_server:function(e){/^sip:/i.test(e)||(e="".concat(o.SIP,":").concat(e));var t=a.parse(e);return t?t.user?void 0:t:void 0},use_preloaded_route:function(e){if("boolean"==typeof e)return e},extra_headers:function(e){var t=[];if(Array.isArray(e)&&e.length){var n,i=r(e);try{for(i.s();!(n=i.n()).done;){var s=n.value;"string"==typeof s&&t.push(s)}}catch(e){i.e(e)}finally{i.f()}return t}}}};n.load=function(e,t){for(var n in h.mandatory){if(!t.hasOwnProperty(n))throw new c.ConfigurationError(n);var r=t[n],i=h.mandatory[n](r);if(void 0===i)throw new c.ConfigurationError(n,r);e[n]=i}for(var o in h.optional)if(t.hasOwnProperty(o)){var l=t[o];if(s.isEmpty(l))continue;var a=h.optional[o](l);if(void 0===a)throw new c.ConfigurationError(o,l);e[o]=a}}},{"./Constants":2,"./Exceptions":6,"./Grammar":7,"./Socket":23,"./URI":29,"./Utils":30}],2:[function(e,t,n){"use strict";var r=e("../package.json");t.exports={USER_AGENT:"".concat(r.title," ").concat(r.version),SIP:"sip",SIPS:"sips",causes:{CONNECTION_ERROR:"Connection Error",REQUEST_TIMEOUT:"Request Timeout",SIP_FAILURE_CODE:"SIP Failure Code",INTERNAL_ERROR:"Internal Error",BUSY:"Busy",REJECTED:"Rejected",REDIRECTED:"Redirected",UNAVAILABLE:"Unavailable",NOT_FOUND:"Not Found",ADDRESS_INCOMPLETE:"Address Incomplete",INCOMPATIBLE_SDP:"Incompatible SDP",MISSING_SDP:"Missing SDP",AUTHENTICATION_ERROR:"Authentication Error",BYE:"Terminated",WEBRTC_ERROR:"WebRTC Error",CANCELED:"Canceled",NO_ANSWER:"No Answer",EXPIRES:"Expires",NO_ACK:"No ACK",DIALOG_ERROR:"Dialog Error",USER_DENIED_MEDIA_ACCESS:"User Denied Media Access",BAD_MEDIA_DESCRIPTION:"Bad Media Description",RTP_TIMEOUT:"RTP Timeout"},SIP_ERROR_CAUSES:{REDIRECTED:[300,301,302,305,380],BUSY:[486,600],REJECTED:[403,603],NOT_FOUND:[404,604],UNAVAILABLE:[480,410,408,430],ADDRESS_INCOMPLETE:[484,424],INCOMPATIBLE_SDP:[488,606],AUTHENTICATION_ERROR:[401,407]},ACK:"ACK",BYE:"BYE",CANCEL:"CANCEL",INFO:"INFO",INVITE:"INVITE",MESSAGE:"MESSAGE",NOTIFY:"NOTIFY",OPTIONS:"OPTIONS",REGISTER:"REGISTER",REFER:"REFER",UPDATE:"UPDATE",SUBSCRIBE:"SUBSCRIBE",DTMF_TRANSPORT:{INFO:"INFO",RFC2833:"RFC2833"},REASON_PHRASE:{100:"Trying",180:"Ringing",181:"Call Is Being Forwarded",182:"Queued",183:"Session Progress",199:"Early Dialog Terminated",200:"OK",202:"Accepted",204:"No Notification",300:"Multiple Choices",301:"Moved Permanently",302:"Moved Temporarily",305:"Use Proxy",380:"Alternative Service",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",410:"Gone",412:"Conditional Request Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Unsupported URI Scheme",417:"Unknown Resource-Priority",420:"Bad Extension",421:"Extension Required",422:"Session Interval Too Small",423:"Interval Too Brief",424:"Bad Location Information",428:"Use Identity Header",429:"Provide Referrer Identity",430:"Flow Failed",433:"Anonymity Disallowed",436:"Bad Identity-Info",437:"Unsupported Certificate",438:"Invalid Identity Header",439:"First Hop Lacks Outbound Support",440:"Max-Breadth Exceeded",469:"Bad Info Package",470:"Consent Needed",478:"Unresolvable Destination",480:"Temporarily Unavailable",481:"Call/Transaction Does Not Exist",482:"Loop Detected",483:"Too Many Hops",484:"Address Incomplete",485:"Ambiguous",486:"Busy Here",487:"Request Terminated",488:"Not Acceptable Here",489:"Bad Event",491:"Request Pending",493:"Undecipherable",494:"Security Agreement Required",500:"JsSIP Internal Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Server Time-out",505:"Version Not Supported",513:"Message Too Large",580:"Precondition Failure",600:"Busy Everywhere",603:"Decline",604:"Does Not Exist Anywhere",606:"Not Acceptable"},ALLOWED_METHODS:"INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO,NOTIFY,SUBSCRIBE",ACCEPTED_BODY_TYPES:"application/sdp, application/dtmf-relay",MAX_FORWARDS:69,SESSION_EXPIRES:90,MIN_SESSION_EXPIRES:60,CONNECTION_RECOVERY_MAX_INTERVAL:30,CONNECTION_RECOVERY_MIN_INTERVAL:2}},{"../package.json":42}],3:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:h.STATUS_CONFIRMED;if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this._owner=t,this._ua=t._ua,this._uac_pending_reply=!1,this._uas_pending_reply=!1,!n.hasHeader("contact"))return{error:"unable to create a Dialog without Contact header field"};n instanceof s.IncomingResponse&&(i=n.status_code<200?h.STATUS_EARLY:h.STATUS_CONFIRMED);var o=n.parseHeader("contact");"UAS"===r?(this._id={call_id:n.call_id,local_tag:n.to_tag,remote_tag:n.from_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this._state=i,this._remote_seqnum=n.cseq,this._local_uri=n.parseHeader("to").uri,this._remote_uri=n.parseHeader("from").uri,this._remote_target=o.uri,this._route_set=n.getHeaders("record-route"),this._ack_seqnum=this._remote_seqnum):"UAC"===r&&(this._id={call_id:n.call_id,local_tag:n.from_tag,remote_tag:n.to_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this._state=i,this._local_seqnum=n.cseq,this._local_uri=n.parseHeader("from").uri,this._remote_uri=n.parseHeader("to").uri,this._remote_target=o.uri,this._route_set=n.getHeaders("record-route").reverse(),this._ack_seqnum=null),this._ua.newDialog(this),c.debug("new ".concat(r," dialog created with status ").concat(this._state===h.STATUS_EARLY?"EARLY":"CONFIRMED"))}var t,n,i;return t=e,i=[{key:"C",get:function(){return h}}],(n=[{key:"id",get:function(){return this._id}},{key:"local_seqnum",get:function(){return this._local_seqnum},set:function(e){this._local_seqnum=e}},{key:"owner",get:function(){return this._owner}},{key:"uac_pending_reply",get:function(){return this._uac_pending_reply},set:function(e){this._uac_pending_reply=e}},{key:"uas_pending_reply",get:function(){return this._uas_pending_reply}},{key:"isTerminated",value:function(){return this._status===h.STATUS_TERMINATED}},{key:"update",value:function(e,t){this._state=h.STATUS_CONFIRMED,c.debug("dialog ".concat(this._id.toString()," changed to CONFIRMED state")),"UAC"===t&&(this._route_set=e.getHeaders("record-route").reverse())}},{key:"terminate",value:function(){c.debug("dialog ".concat(this._id.toString()," deleted")),this._ua.destroyDialog(this),this._state=h.STATUS_TERMINATED}},{key:"sendRequest",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=u.cloneArray(n.extraHeaders),i=u.cloneObject(n.eventHandlers),s=n.body||null,o=this._createRequest(e,r,s);return i.onAuthenticated=function(){t._local_seqnum+=1},new a(this,o,i).send(),o}},{key:"receiveRequest",value:function(e){this._checkInDialogRequest(e)&&(e.method===o.ACK&&null!==this._ack_seqnum?this._ack_seqnum=null:e.method===o.INVITE&&(this._ack_seqnum=e.cseq),this._owner.receiveRequest(e))}},{key:"_createRequest",value:function(e,t,n){t=u.cloneArray(t),this._local_seqnum||(this._local_seqnum=Math.floor(1e4*Math.random()));var r=e===o.CANCEL||e===o.ACK?this._local_seqnum:this._local_seqnum+=1;return new s.OutgoingRequest(e,this._remote_target,this._ua,{cseq:r,call_id:this._id.call_id,from_uri:this._local_uri,from_tag:this._id.local_tag,to_uri:this._remote_uri,to_tag:this._id.remote_tag,route_set:this._route_set},t,n)}},{key:"_checkInDialogRequest",value:function(e){var t=this;if(this._remote_seqnum)if(e.cseqthis._remote_seqnum&&(this._remote_seqnum=e.cseq);else this._remote_seqnum=e.cseq;if(e.method===o.INVITE||e.method===o.UPDATE&&e.body){if(!0===this._uac_pending_reply)e.reply(491);else{if(!0===this._uas_pending_reply){var n=1+(10*Math.random()|0);return e.reply(500,null,["Retry-After:".concat(n)]),!1}this._uas_pending_reply=!0;e.server_transaction.on("stateChanged",function n(){e.server_transaction.state!==l.C.STATUS_ACCEPTED&&e.server_transaction.state!==l.C.STATUS_COMPLETED&&e.server_transaction.state!==l.C.STATUS_TERMINATED||(e.server_transaction.removeListener("stateChanged",n),t._uas_pending_reply=!1)})}e.hasHeader("contact")&&e.server_transaction.on("stateChanged",function(){e.server_transaction.state===l.C.STATUS_ACCEPTED&&(t._remote_target=e.parseHeader("contact").uri)})}else e.method===o.NOTIFY&&e.hasHeader("contact")&&e.server_transaction.on("stateChanged",function(){e.server_transaction.state===l.C.STATUS_COMPLETED&&(t._remote_target=e.parseHeader("contact").uri)});return!0}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Dialog/RequestSender":4,"./Logger":9,"./SIPMessage":22,"./Transactions":26,"./Utils":30}],4:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=200&&e.status_code<300?this._eventHandlers.onSuccessResponse(e):e.status_code>=300&&this._eventHandlers.onErrorResponse(e):(this._request.cseq=this._dialog.local_seqnum+=1,this._reattemptTimer=setTimeout(function(){t._dialog.isTerminated()||(t._reattempt=!0,t.send())},1e3)):e.status_code>=200&&e.status_code<300?this._eventHandlers.onSuccessResponse(e):e.status_code>=300&&this._eventHandlers.onErrorResponse(e)}}])&&r(t.prototype,n),a&&r(t,a),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"../Constants":2,"../RequestSender":21,"../Transactions":26}],5:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:null;if(this._algorithm=t.algorithm,this._realm=t.realm,this._nonce=t.nonce,this._opaque=t.opaque,this._stale=t.stale,this._algorithm){if("MD5"!==this._algorithm)return o.warn('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted'),!1}else this._algorithm="MD5";if(!this._nonce)return o.warn("authenticate() | challenge without Digest nonce, authentication aborted"),!1;if(!this._realm)return o.warn("authenticate() | challenge without Digest realm, authentication aborted"),!1;if(!this._credentials.password){if(!this._credentials.ha1)return o.warn("authenticate() | no plain SIP password nor ha1 provided, authentication aborted"),!1;if(this._credentials.realm!==this._realm)return o.warn('authenticate() | no plain SIP password, and stored `realm` does not match the given `realm`, cannot authenticate [stored:"%s", given:"%s"]',this._credentials.realm,this._realm),!1}if(t.qop)if(t.qop.indexOf("auth-int")>-1)this._qop="auth-int";else{if(!(t.qop.indexOf("auth")>-1))return o.warn('authenticate() | challenge without Digest qop different than "auth" or "auth-int", authentication aborted'),!1;this._qop="auth"}else this._qop=null;this._method=n,this._uri=r,this._cnonce=l||s.createRandomToken(12),this._nc+=1;var a,u,c=Number(this._nc).toString(16);return this._ncHex="00000000".substr(0,8-c.length)+c,4294967296===this._nc&&(this._nc=1,this._ncHex="00000001"),this._credentials.password?this._ha1=s.calculateMD5("".concat(this._credentials.username,":").concat(this._realm,":").concat(this._credentials.password)):this._ha1=this._credentials.ha1,"auth"===this._qop?(a="".concat(this._method,":").concat(this._uri),u=s.calculateMD5(a),o.debug('authenticate() | using qop=auth [a2:"%s"]',a),this._response=s.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(this._ncHex,":").concat(this._cnonce,":auth:").concat(u))):"auth-int"===this._qop?(a="".concat(this._method,":").concat(this._uri,":").concat(s.calculateMD5(i||"")),u=s.calculateMD5(a),o.debug('authenticate() | using qop=auth-int [a2:"%s"]',a),this._response=s.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(this._ncHex,":").concat(this._cnonce,":auth-int:").concat(u))):null===this._qop&&(a="".concat(this._method,":").concat(this._uri),u=s.calculateMD5(a),o.debug('authenticate() | using qop=null [a2:"%s"]',a),this._response=s.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(u))),o.debug("authenticate() | response generated"),!0}},{key:"toString",value:function(){var e=[];if(!this._response)throw new Error("response field does not exist, cannot generate Authorization header");return e.push("algorithm=".concat(this._algorithm)),e.push('username="'.concat(this._credentials.username,'"')),e.push('realm="'.concat(this._realm,'"')),e.push('nonce="'.concat(this._nonce,'"')),e.push('uri="'.concat(this._uri,'"')),e.push('response="'.concat(this._response,'"')),this._opaque&&e.push('opaque="'.concat(this._opaque,'"')),this._qop&&(e.push("qop=".concat(this._qop)),e.push('cnonce="'.concat(this._cnonce,'"')),e.push("nc=".concat(this._ncHex))),"Digest ".concat(e.join(", "))}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Logger":9,"./Utils":30}],6:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n",s++):(e=null,0===o&&u('">"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","')),null===e&&(59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(92===n.charCodeAt(s)?(e="\\",s++):(e=null,0===o&&u('"\\\\"')),null===e&&null===(e=m())&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null===e&&(93===n.charCodeAt(s)?(e="]",s++):(e=null,0===o&&u('"]"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(123===n.charCodeAt(s)?(e="{",s++):(e=null,0===o&&u('"{"')),null===e&&(125===n.charCodeAt(s)?(e="}",s++):(e=null,0===o&&u('"}"')),null===e&&null===(e=v())&&(e=g()))))))))))))))));return e},word:x,STAR:U,SLASH:D,EQUAL:M,LPAREN:q,RPAREN:L,RAQUOT:H,LAQUOT:F,COMMA:j,SEMI:B,COLON:G,LDQUOT:V,RDQUOT:W,comment:function e(){var t,n,r;var i;i=s;t=q();if(null!==t){for(n=[],null===(r=Y())&&null===(r=X())&&(r=e());null!==r;)n.push(r),null===(r=Y())&&null===(r=X())&&(r=e());null!==n&&null!==(r=L())?t=[t,n,r]:(t=null,s=i)}else t=null,s=i;return t},ctext:Y,quoted_string:K,quoted_string_clean:z,qdtext:$,quoted_pair:X,SIP_URI_noparams:J,SIP_URI:Q,uri_scheme:Z,uri_scheme_sips:ee,uri_scheme_sip:te,userinfo:ne,user:re,user_unreserved:ie,password:se,hostport:oe,host:le,hostname:ae,domainlabel:ue,toplabel:ce,IPv6reference:he,IPv6address:de,h16:fe,ls32:_e,IPv4address:pe,dec_octet:me,port:ve,uri_parameters:ge,uri_parameter:ye,transport_param:Te,user_param:be,method_param:Se,ttl_param:Ee,maddr_param:Ce,lr_param:Ae,other_param:we,pname:Re,pvalue:Ie,paramchar:Oe,param_unreserved:Ne,headers:ke,header:Pe,hname:xe,hvalue:Ue,hnv_unreserved:De,Request_Response:function(){var e;null===(e=ht())&&(e=Me());return e},Request_Line:Me,Request_URI:qe,absoluteURI:Le,hier_part:He,net_path:Fe,abs_path:je,opaque_part:Be,uric:Ge,uric_no_slash:Ve,path_segments:We,segment:Ye,param:Ke,pchar:ze,scheme:$e,authority:Xe,srvr:Je,reg_name:Qe,query:Ze,SIP_Version:et,INVITEm:tt,ACKm:nt,OPTIONSm:rt,BYEm:it,CANCELm:st,REGISTERm:ot,SUBSCRIBEm:lt,NOTIFYm:at,REFERm:ut,Method:ct,Status_Line:ht,Status_Code:dt,extension_code:ft,Reason_Phrase:_t,Allow_Events:function(){var e,t,n,r,i,o;if(i=s,null!==(e=Lt())){for(t=[],o=s,null!==(n=j())&&null!==(r=Lt())?n=[n,r]:(n=null,s=o);null!==n;)t.push(n),o=s,null!==(n=j())&&null!==(r=Lt())?n=[n,r]:(n=null,s=o);null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e},Call_ID:function(){var e,t,r,i,l,a;i=s,l=s,null!==(e=x())?(a=s,64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null!==t&&null!==(r=x())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l);null!==e&&(c=i,e=void(jn=n.substring(s,c)));var c;null===e&&(s=i);return e},Contact:function(){var e,t,n,r,i,o,l;if(i=s,null===(e=U()))if(o=s,null!==(e=pt())){for(t=[],l=s,null!==(n=j())&&null!==(r=pt())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=j())&&null!==(r=pt())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;null!==e&&(e=function(e){var t,n;for(n=jn.multi_header.length,t=0;tl&&(l=s,a=[]),a.push(e))}function c(){var e;return"\r\n"===n.substr(s,2)?(e="\r\n",s+=2):(e=null,0===o&&u('"\\r\\n"')),e}function h(){var e;return/^[0-9]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[0-9]")),e}function d(){var e;return/^[a-zA-Z]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[a-zA-Z]")),e}function f(){var e;return/^[0-9a-fA-F]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[0-9a-fA-F]")),e}function _(){var e;return null===(e=v())&&(e=g()),e}function p(){var e;return/^[\0-\xFF]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\0-\\xFF]")),e}function m(){var e;return/^["]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u('["]')),e}function v(){var e;return 32===n.charCodeAt(s)?(e=" ",s++):(e=null,0===o&&u('" "')),e}function g(){var e;return 9===n.charCodeAt(s)?(e="\t",s++):(e=null,0===o&&u('"\\t"')),e}function y(){var e;return/^[a-zA-Z0-9]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[a-zA-Z0-9]")),e}function T(){var e;return 59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","'))))))))))),e}function b(){var e;return null===(e=y())&&(e=S()),e}function S(){var e;return 45===n.charCodeAt(s)?(e="-",s++):(e=null,0===o&&u('"-"')),null===e&&(95===n.charCodeAt(s)?(e="_",s++):(e=null,0===o&&u('"_"')),null===e&&(46===n.charCodeAt(s)?(e=".",s++):(e=null,0===o&&u('"."')),null===e&&(33===n.charCodeAt(s)?(e="!",s++):(e=null,0===o&&u('"!"')),null===e&&(126===n.charCodeAt(s)?(e="~",s++):(e=null,0===o&&u('"~"')),null===e&&(42===n.charCodeAt(s)?(e="*",s++):(e=null,0===o&&u('"*"')),null===e&&(39===n.charCodeAt(s)?(e="'",s++):(e=null,0===o&&u('"\'"')),null===e&&(40===n.charCodeAt(s)?(e="(",s++):(e=null,0===o&&u('"("')),null===e&&(41===n.charCodeAt(s)?(e=")",s++):(e=null,0===o&&u('")"')))))))))),e}function E(){var e,t,r,i,l;return i=s,l=s,37===n.charCodeAt(s)?(e="%",s++):(e=null,0===o&&u('"%"')),null!==e&&null!==(t=f())&&null!==(r=f())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=e.join("")),null===e&&(s=i),e}function C(){var e,t,n,r,i,o;for(r=s,i=s,o=s,e=[],t=_();null!==t;)e.push(t),t=_();if(null!==e&&null!==(t=c())?e=[e,t]:(e=null,s=o),null!==(e=null!==e?e:"")){if(null!==(n=_()))for(t=[];null!==n;)t.push(n),n=_();else t=null;null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return null!==e&&(e=" "),null===e&&(s=r),e}function A(){var e;return e=null!==(e=C())?e:""}function w(){var e,t,r,i,l;for(i=s,l=s,e=[],null===(t=v())&&(t=g());null!==t;)e.push(t),null===(t=v())&&(t=g());return null!==e?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=":"),null===e&&(s=i),e}function R(){var e,t,r,i,o,l,a,u;if(o=s,l=s,null!==(t=I()))for(e=[];null!==t;)e.push(t),t=I();else e=null;if(null!==e){for(t=[],a=s,r=[],i=C();null!==i;)r.push(i),i=C();for(null!==r&&null!==(i=I())?r=[r,i]:(r=null,s=a);null!==r;){for(t.push(r),a=s,r=[],i=C();null!==i;)r.push(i),i=C();null!==r&&null!==(i=I())?r=[r,i]:(r=null,s=a)}null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return null!==e&&(u=o,e=n.substring(s,u)),null===e&&(s=o),e}function I(){var e;return/^[!-~]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[!-~]")),null===e&&(e=O()),e}function O(){var e;return/^[\x80-\uFFFF]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\x80-\\uFFFF]")),e}function N(){var e;return/^[\x80-\xBF]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\x80-\\xBF]")),e}function k(){var e,t,r,i;if(r=s,null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"'))))))))))));else e=null;return null!==e&&(i=r,e=n.substring(s,i)),null===e&&(s=r),e}function P(){var e,t,r,i;if(r=s,null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"'))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')))))))))));else e=null;return null!==e&&(i=r,e=n.substring(s,i)),null===e&&(s=r),e}function x(){var e,t,r,i;if(r=s,null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')),null===t&&(40===n.charCodeAt(s)?(t="(",s++):(t=null,0===o&&u('"("')),null===t&&(41===n.charCodeAt(s)?(t=")",s++):(t=null,0===o&&u('")"')),null===t&&(60===n.charCodeAt(s)?(t="<",s++):(t=null,0===o&&u('"<"')),null===t&&(62===n.charCodeAt(s)?(t=">",s++):(t=null,0===o&&u('">"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(92===n.charCodeAt(s)?(t="\\",s++):(t=null,0===o&&u('"\\\\"')),null===t&&null===(t=m())&&(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null===t&&(91===n.charCodeAt(s)?(t="[",s++):(t=null,0===o&&u('"["')),null===t&&(93===n.charCodeAt(s)?(t="]",s++):(t=null,0===o&&u('"]"')),null===t&&(63===n.charCodeAt(s)?(t="?",s++):(t=null,0===o&&u('"?"')),null===t&&(123===n.charCodeAt(s)?(t="{",s++):(t=null,0===o&&u('"{"')),null===t&&(125===n.charCodeAt(s)?(t="}",s++):(t=null,0===o&&u('"}"')))))))))))))))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')),null===t&&(40===n.charCodeAt(s)?(t="(",s++):(t=null,0===o&&u('"("')),null===t&&(41===n.charCodeAt(s)?(t=")",s++):(t=null,0===o&&u('")"')),null===t&&(60===n.charCodeAt(s)?(t="<",s++):(t=null,0===o&&u('"<"')),null===t&&(62===n.charCodeAt(s)?(t=">",s++):(t=null,0===o&&u('">"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(92===n.charCodeAt(s)?(t="\\",s++):(t=null,0===o&&u('"\\\\"')),null===t&&null===(t=m())&&(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null===t&&(91===n.charCodeAt(s)?(t="[",s++):(t=null,0===o&&u('"["')),null===t&&(93===n.charCodeAt(s)?(t="]",s++):(t=null,0===o&&u('"]"')),null===t&&(63===n.charCodeAt(s)?(t="?",s++):(t=null,0===o&&u('"?"')),null===t&&(123===n.charCodeAt(s)?(t="{",s++):(t=null,0===o&&u('"{"')),null===t&&(125===n.charCodeAt(s)?(t="}",s++):(t=null,0===o&&u('"}"'))))))))))))))))))))))));else e=null;return null!==e&&(i=r,e=n.substring(s,i)),null===e&&(s=r),e}function U(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="*"),null===e&&(s=i),e}function D(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="/"),null===e&&(s=i),e}function M(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="="),null===e&&(s=i),e}function q(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(40===n.charCodeAt(s)?(t="(",s++):(t=null,0===o&&u('"("')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="("),null===e&&(s=i),e}function L(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(41===n.charCodeAt(s)?(t=")",s++):(t=null,0===o&&u('")"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=")"),null===e&&(s=i),e}function H(){var e,t,r,i;return r=s,i=s,62===n.charCodeAt(s)?(e=">",s++):(e=null,0===o&&u('">"')),null!==e&&null!==(t=A())?e=[e,t]:(e=null,s=i),null!==e&&(e=">"),null===e&&(s=r),e}function F(){var e,t,r,i;return r=s,i=s,null!==(e=A())?(60===n.charCodeAt(s)?(t="<",s++):(t=null,0===o&&u('"<"')),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(e="<"),null===e&&(s=r),e}function j(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=","),null===e&&(s=i),e}function B(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=";"),null===e&&(s=i),e}function G(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=":"),null===e&&(s=i),e}function V(){var e,t,n,r;return n=s,r=s,null!==(e=A())&&null!==(t=m())?e=[e,t]:(e=null,s=r),null!==e&&(e='"'),null===e&&(s=n),e}function W(){var e,t,n,r;return n=s,r=s,null!==(e=m())&&null!==(t=A())?e=[e,t]:(e=null,s=r),null!==e&&(e='"'),null===e&&(s=n),e}function Y(){var e;return/^[!-']/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[!-']")),null===e&&(/^[*-[]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[*-[]")),null===e&&(/^[\]-~]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\]-~]")),null===e&&null===(e=O())&&(e=C()))),e}function K(){var e,t,r,i,o,l,a;if(o=s,l=s,null!==(e=A()))if(null!==(t=m())){for(r=[],null===(i=$())&&(i=X());null!==i;)r.push(i),null===(i=$())&&(i=X());null!==r&&null!==(i=m())?e=[e,t,r,i]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;return null!==e&&(a=o,e=n.substring(s,a)),null===e&&(s=o),e}function z(){var e,t,r,i,o,l,a,u;if(o=s,l=s,null!==(e=A()))if(null!==(t=m())){for(r=[],null===(i=$())&&(i=X());null!==i;)r.push(i),null===(i=$())&&(i=X());null!==r&&null!==(i=m())?e=[e,t,r,i]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;return null!==e&&(a=o,e=(u=n.substring(s,a).trim()).substring(1,u.length-1).replace(/\\([\x00-\x09\x0b-\x0c\x0e-\x7f])/g,"$1")),null===e&&(s=o),e}function $(){var e;return null===(e=C())&&(33===n.charCodeAt(s)?(e="!",s++):(e=null,0===o&&u('"!"')),null===e&&(/^[#-[]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[#-[]")),null===e&&(/^[\]-~]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\]-~]")),null===e&&(e=O())))),e}function X(){var e,t,r;return r=s,92===n.charCodeAt(s)?(e="\\",s++):(e=null,0===o&&u('"\\\\"')),null!==e?(/^[\0-\t]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[\\0-\\t]")),null===t&&(/^[\x0B-\f]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[\\x0B-\\f]")),null===t&&(/^[\x0E-]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[\\x0E-]")))),null!==t?e=[e,t]:(e=null,s=r)):(e=null,s=r),e}function J(){var e,t,r,i,l,a;return l=s,a=s,null!==(e=Z())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=null!==(r=ne())?r:"")&&null!==(i=oe())?e=[e,t,r,i]:(e=null,s=a)):(e=null,s=a),null!==e&&(e=function(e){try{jn.uri=new Hn(jn.scheme,jn.user,jn.host,jn.port),delete jn.scheme,delete jn.user,delete jn.host,delete jn.host_type,delete jn.port}catch(e){jn=-1}}()),null===e&&(s=l),e}function Q(){var e,t,i,l,a,c,h,d;return h=s,d=s,null!==(e=Z())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(i=null!==(i=ne())?i:"")&&null!==(l=oe())&&null!==(a=ge())&&null!==(c=null!==(c=ke())?c:"")?e=[e,t,i,l,a,c]:(e=null,s=d)):(e=null,s=d),null!==e&&(e=function(e){try{jn.uri=new Hn(jn.scheme,jn.user,jn.host,jn.port,jn.uri_params,jn.uri_headers),delete jn.scheme,delete jn.user,delete jn.host,delete jn.host_type,delete jn.port,delete jn.uri_params,"SIP_URI"===r&&(jn=jn.uri)}catch(e){jn=-1}}()),null===e&&(s=h),e}function Z(){var e;return null===(e=ee())&&(e=te()),e}function ee(){var e,t,r;return t=s,"sips"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"sips"')),null!==e&&(r=e,e=void(jn.scheme=r.toLowerCase())),null===e&&(s=t),e}function te(){var e,t,r;return t=s,"sip"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"sip"')),null!==e&&(r=e,e=void(jn.scheme=r.toLowerCase())),null===e&&(s=t),e}function ne(){var e,t,r,i,l,a,c;return i=s,l=s,null!==(e=re())?(a=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=se())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?(64===n.charCodeAt(s)?(r="@",s++):(r=null,0===o&&u('"@"')),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l)):(e=null,s=l),null!==e&&(c=i,e=void(jn.user=decodeURIComponent(n.substring(s-1,c)))),null===e&&(s=i),e}function re(){var e,t;if(null===(t=b())&&null===(t=E())&&(t=ie()),null!==t)for(e=[];null!==t;)e.push(t),null===(t=b())&&null===(t=E())&&(t=ie());else e=null;return e}function ie(){var e;return 38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","')),null===e&&(59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"'))))))))),e}function se(){var e,t,r,i;for(r=s,e=[],null===(t=b())&&null===(t=E())&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')))))));null!==t;)e.push(t),null===(t=b())&&null===(t=E())&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')))))));return null!==e&&(i=r,e=void(jn.password=n.substring(s,i))),null===e&&(s=r),e}function oe(){var e,t,r,i,l;return i=s,null!==(e=le())?(l=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=ve())?t=[t,r]:(t=null,s=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),e}function le(){var e,t,r;return t=s,null===(e=ae())&&null===(e=pe())&&(e=he()),null!==e&&(r=t,jn.host=n.substring(s,r).toLowerCase(),e=jn.host),null===e&&(s=t),e}function ae(){var e,t,r,i,l,a,c;for(i=s,l=s,e=[],a=s,null!==(t=ue())?(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r?t=[t,r]:(t=null,s=a)):(t=null,s=a);null!==t;)e.push(t),a=s,null!==(t=ue())?(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r?t=[t,r]:(t=null,s=a)):(t=null,s=a);return null!==e&&null!==(t=ce())?(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==(r=null!==r?r:"")?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(c=i,jn.host_type="domain",e=n.substring(s,c)),null===e&&(s=i),e}function ue(){var e,t,r,i;if(i=s,null!==(e=y())){for(t=[],null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==r;)t.push(r),null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e}function ce(){var e,t,r,i;if(i=s,null!==(e=d())){for(t=[],null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==r;)t.push(r),null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e}function he(){var e,t,r,i,l,a;return i=s,l=s,91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null!==e&&null!==(t=de())?(93===n.charCodeAt(s)?(r="]",s++):(r=null,0===o&&u('"]"')),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=i,jn.host_type="IPv6",e=n.substring(s,a)),null===e&&(s=i),e}function de(){var e,t,r,i,l,a,c,h,d,f,_,p,m,v,g,y,T;return v=s,g=s,null!==(e=fe())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?(58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?(58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?(58===n.charCodeAt(s)?(h=":",s++):(h=null,0===o&&u('":"')),null!==h&&null!==(d=fe())?(58===n.charCodeAt(s)?(f=":",s++):(f=null,0===o&&u('":"')),null!==f&&null!==(_=fe())?(58===n.charCodeAt(s)?(p=":",s++):(p=null,0===o&&u('":"')),null!==p&&null!==(m=_e())?e=[e,t,r,i,l,a,c,h,d,f,_,p,m]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?(58===n.charCodeAt(s)?(d=":",s++):(d=null,0===o&&u('":"')),null!==d&&null!==(f=fe())?(58===n.charCodeAt(s)?(_=":",s++):(_=null,0===o&&u('":"')),null!==_&&null!==(p=_e())?e=[e,t,r,i,l,a,c,h,d,f,_,p]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?(58===n.charCodeAt(s)?(d=":",s++):(d=null,0===o&&u('":"')),null!==d&&null!==(f=_e())?e=[e,t,r,i,l,a,c,h,d,f]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=_e())?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=_e())?e=[e,t,r,i,l,a]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=_e())?e=[e,t,r,i]:(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=_e())?e=[e,t]:(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?e=[e,t]:(e=null,s=g),null===e&&(g=s,null!==(e=fe())?("::"===n.substr(s,2)?(t="::",s+=2):(t=null,0===o&&u('"::"')),null!==t&&null!==(r=fe())?(58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?(58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?(58===n.charCodeAt(s)?(h=":",s++):(h=null,0===o&&u('":"')),null!==h&&null!==(d=fe())?(58===n.charCodeAt(s)?(f=":",s++):(f=null,0===o&&u('":"')),null!==f&&null!==(_=_e())?e=[e,t,r,i,l,a,c,h,d,f,_]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?("::"===n.substr(s,2)?(r="::",s+=2):(r=null,0===o&&u('"::"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?(58===n.charCodeAt(s)?(d=":",s++):(d=null,0===o&&u('":"')),null!==d&&null!==(f=_e())?e=[e,t,r,i,l,a,c,h,d,f]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?("::"===n.substr(s,2)?(i="::",s+=2):(i=null,0===o&&u('"::"')),null!==i&&null!==(l=fe())?(58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?(58===n.charCodeAt(s)?(h=":",s++):(h=null,0===o&&u('":"')),null!==h&&null!==(d=_e())?e=[e,t,r,i,l,a,c,h,d]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?("::"===n.substr(s,2)?(l="::",s+=2):(l=null,0===o&&u('"::"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=_e())?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?(y=s,58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?l=[l,a]:(l=null,s=y),null!==(l=null!==l?l:"")?("::"===n.substr(s,2)?(a="::",s+=2):(a=null,0===o&&u('"::"')),null!==a&&null!==(c=_e())?e=[e,t,r,i,l,a,c]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?(y=s,58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?l=[l,a]:(l=null,s=y),null!==(l=null!==l?l:"")?(y=s,58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?a=[a,c]:(a=null,s=y),null!==(a=null!==a?a:"")?("::"===n.substr(s,2)?(c="::",s+=2):(c=null,0===o&&u('"::"')),null!==c&&null!==(h=fe())?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?(y=s,58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?l=[l,a]:(l=null,s=y),null!==(l=null!==l?l:"")?(y=s,58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?a=[a,c]:(a=null,s=y),null!==(a=null!==a?a:"")?(y=s,58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?c=[c,h]:(c=null,s=y),null!==(c=null!==c?c:"")?("::"===n.substr(s,2)?(h="::",s+=2):(h=null,0===o&&u('"::"')),null!==h?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g))))))))))))))),null!==e&&(T=v,jn.host_type="IPv6",e=n.substring(s,T)),null===e&&(s=v),e}function fe(){var e,t,n,r,i;return i=s,null!==(e=f())&&null!==(t=null!==(t=f())?t:"")&&null!==(n=null!==(n=f())?n:"")&&null!==(r=null!==(r=f())?r:"")?e=[e,t,n,r]:(e=null,s=i),e}function _e(){var e,t,r,i;return i=s,null!==(e=fe())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),null===e&&(e=pe()),e}function pe(){var e,t,r,i,l,a,c,h,d,f;return h=s,d=s,null!==(e=me())?(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null!==t&&null!==(r=me())?(46===n.charCodeAt(s)?(i=".",s++):(i=null,0===o&&u('"."')),null!==i&&null!==(l=me())?(46===n.charCodeAt(s)?(a=".",s++):(a=null,0===o&&u('"."')),null!==a&&null!==(c=me())?e=[e,t,r,i,l,a,c]:(e=null,s=d)):(e=null,s=d)):(e=null,s=d)):(e=null,s=d),null!==e&&(f=h,jn.host_type="IPv4",e=n.substring(s,f)),null===e&&(s=h),e}function me(){var e,t,r,i;return i=s,"25"===n.substr(s,2)?(e="25",s+=2):(e=null,0===o&&u('"25"')),null!==e?(/^[0-5]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[0-5]")),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null===e&&(i=s,50===n.charCodeAt(s)?(e="2",s++):(e=null,0===o&&u('"2"')),null!==e?(/^[0-4]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[0-4]")),null!==t&&null!==(r=h())?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),null===e&&(i=s,49===n.charCodeAt(s)?(e="1",s++):(e=null,0===o&&u('"1"')),null!==e&&null!==(t=h())&&null!==(r=h())?e=[e,t,r]:(e=null,s=i),null===e&&(i=s,/^[1-9]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[1-9]")),null!==e&&null!==(t=h())?e=[e,t]:(e=null,s=i),null===e&&(e=h())))),e}function ve(){var e,t,n,r,i,o,l,a;return o=s,l=s,null!==(e=null!==(e=h())?e:"")&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")?e=[e,t,n,r,i]:(e=null,s=l),null!==e&&(a=e,a=parseInt(a.join("")),jn.port=a,e=a),null===e&&(s=o),e}function ge(){var e,t,r,i;for(e=[],i=s,59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null!==t&&null!==(r=ye())?t=[t,r]:(t=null,s=i);null!==t;)e.push(t),i=s,59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null!==t&&null!==(r=ye())?t=[t,r]:(t=null,s=i);return e}function ye(){var e;return null===(e=Te())&&null===(e=be())&&null===(e=Se())&&null===(e=Ee())&&null===(e=Ce())&&null===(e=Ae())&&(e=we()),e}function Te(){var e,t,r,i,l;return r=s,i=s,"transport="===n.substr(s,10).toLowerCase()?(e=n.substr(s,10),s+=10):(e=null,0===o&&u('"transport="')),null!==e?("udp"===n.substr(s,3).toLowerCase()?(t=n.substr(s,3),s+=3):(t=null,0===o&&u('"udp"')),null===t&&("tcp"===n.substr(s,3).toLowerCase()?(t=n.substr(s,3),s+=3):(t=null,0===o&&u('"tcp"')),null===t&&("sctp"===n.substr(s,4).toLowerCase()?(t=n.substr(s,4),s+=4):(t=null,0===o&&u('"sctp"')),null===t&&("tls"===n.substr(s,3).toLowerCase()?(t=n.substr(s,3),s+=3):(t=null,0===o&&u('"tls"')),null===t&&(t=k())))),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.transport=l.toLowerCase())),null===e&&(s=r),e}function be(){var e,t,r,i,l;return r=s,i=s,"user="===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"user="')),null!==e?("phone"===n.substr(s,5).toLowerCase()?(t=n.substr(s,5),s+=5):(t=null,0===o&&u('"phone"')),null===t&&("ip"===n.substr(s,2).toLowerCase()?(t=n.substr(s,2),s+=2):(t=null,0===o&&u('"ip"')),null===t&&(t=k())),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.user=l.toLowerCase())),null===e&&(s=r),e}function Se(){var e,t,r,i,l;return r=s,i=s,"method="===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"method="')),null!==e&&null!==(t=ct())?e=[e,t]:(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.method=l)),null===e&&(s=r),e}function Ee(){var e,t,r,i,l;return r=s,i=s,"ttl="===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"ttl="')),null!==e&&null!==(t=An())?e=[e,t]:(e=null,s=i),null!==e&&(l=e[1],jn.params||(jn.params={}),e=void(jn.params.ttl=l)),null===e&&(s=r),e}function Ce(){var e,t,r,i,l;return r=s,i=s,"maddr="===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"maddr="')),null!==e&&null!==(t=le())?e=[e,t]:(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.maddr=l)),null===e&&(s=r),e}function Ae(){var e,t,r,i,l,a;return i=s,l=s,"lr"===n.substr(s,2).toLowerCase()?(e=n.substr(s,2),s+=2):(e=null,0===o&&u('"lr"')),null!==e?(a=s,61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=k())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l),null!==e&&(jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.lr=void 0)),null===e&&(s=i),e}function we(){var e,t,r,i,l,a,c,h;return i=s,l=s,null!==(e=Re())?(a=s,61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=Ie())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l),null!==e&&(c=e[0],h=e[1],jn.uri_params||(jn.uri_params={}),h=void 0===h?void 0:h[1],e=void(jn.uri_params[c.toLowerCase()]=h)),null===e&&(s=i),e}function Re(){var e,t,n;if(n=s,null!==(t=Oe()))for(e=[];null!==t;)e.push(t),t=Oe();else e=null;return null!==e&&(e=e.join("")),null===e&&(s=n),e}function Ie(){var e,t,n;if(n=s,null!==(t=Oe()))for(e=[];null!==t;)e.push(t),t=Oe();else e=null;return null!==e&&(e=e.join("")),null===e&&(s=n),e}function Oe(){var e;return null===(e=Ne())&&null===(e=b())&&(e=E()),e}function Ne(){var e;return 91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null===e&&(93===n.charCodeAt(s)?(e="]",s++):(e=null,0===o&&u('"]"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')))))))),e}function ke(){var e,t,r,i,l,a,c;if(a=s,63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null!==e)if(null!==(t=Pe())){for(r=[],c=s,38===n.charCodeAt(s)?(i="&",s++):(i=null,0===o&&u('"&"')),null!==i&&null!==(l=Pe())?i=[i,l]:(i=null,s=c);null!==i;)r.push(i),c=s,38===n.charCodeAt(s)?(i="&",s++):(i=null,0===o&&u('"&"')),null!==i&&null!==(l=Pe())?i=[i,l]:(i=null,s=c);null!==r?e=[e,t,r]:(e=null,s=a)}else e=null,s=a;else e=null,s=a;return e}function Pe(){var e,t,r,i,l,a,c;return i=s,l=s,null!==(e=xe())?(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=Ue())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[0],c=e[2],a=a.join("").toLowerCase(),c=c.join(""),jn.uri_headers||(jn.uri_headers={}),e=void(jn.uri_headers[a]?jn.uri_headers[a].push(c):jn.uri_headers[a]=[c])),null===e&&(s=i),e}function xe(){var e,t;if(null===(t=De())&&null===(t=b())&&(t=E()),null!==t)for(e=[];null!==t;)e.push(t),null===(t=De())&&null===(t=b())&&(t=E());else e=null;return e}function Ue(){var e,t;for(e=[],null===(t=De())&&null===(t=b())&&(t=E());null!==t;)e.push(t),null===(t=De())&&null===(t=b())&&(t=E());return e}function De(){var e;return 91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null===e&&(93===n.charCodeAt(s)?(e="]",s++):(e=null,0===o&&u('"]"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')))))))),e}function Me(){var e,t,n,r,i,o;return o=s,null!==(e=ct())&&null!==(t=v())&&null!==(n=qe())&&null!==(r=v())&&null!==(i=et())?e=[e,t,n,r,i]:(e=null,s=o),e}function qe(){var e;return null===(e=Q())&&(e=Le()),e}function Le(){var e,t,r,i;return i=s,null!==(e=$e())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t?(null===(r=He())&&(r=Be()),null!==r?e=[e,t,r]:(e=null,s=i)):(e=null,s=i)):(e=null,s=i),e}function He(){var e,t,r,i,l;return i=s,null===(e=Fe())&&(e=je()),null!==e?(l=s,63===n.charCodeAt(s)?(t="?",s++):(t=null,0===o&&u('"?"')),null!==t&&null!==(r=Ze())?t=[t,r]:(t=null,s=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),e}function Fe(){var e,t,r,i;return i=s,"//"===n.substr(s,2)?(e="//",s+=2):(e=null,0===o&&u('"//"')),null!==e&&null!==(t=Xe())&&null!==(r=null!==(r=je())?r:"")?e=[e,t,r]:(e=null,s=i),e}function je(){var e,t,r;return r=s,47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null!==e&&null!==(t=We())?e=[e,t]:(e=null,s=r),e}function Be(){var e,t,n,r;if(r=s,null!==(e=Ve())){for(t=[],n=Ge();null!==n;)t.push(n),n=Ge();null!==t?e=[e,t]:(e=null,s=r)}else e=null,s=r;return e}function Ge(){var e;return null===(e=T())&&null===(e=b())&&(e=E()),e}function Ve(){var e;return null===(e=b())&&null===(e=E())&&(59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","'))))))))))),e}function We(){var e,t,r,i,l,a;if(l=s,null!==(e=Ye())){for(t=[],a=s,47===n.charCodeAt(s)?(r="/",s++):(r=null,0===o&&u('"/"')),null!==r&&null!==(i=Ye())?r=[r,i]:(r=null,s=a);null!==r;)t.push(r),a=s,47===n.charCodeAt(s)?(r="/",s++):(r=null,0===o&&u('"/"')),null!==r&&null!==(i=Ye())?r=[r,i]:(r=null,s=a);null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return e}function Ye(){var e,t,r,i,l,a;for(l=s,e=[],t=ze();null!==t;)e.push(t),t=ze();if(null!==e){for(t=[],a=s,59===n.charCodeAt(s)?(r=";",s++):(r=null,0===o&&u('";"')),null!==r&&null!==(i=Ke())?r=[r,i]:(r=null,s=a);null!==r;)t.push(r),a=s,59===n.charCodeAt(s)?(r=";",s++):(r=null,0===o&&u('";"')),null!==r&&null!==(i=Ke())?r=[r,i]:(r=null,s=a);null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return e}function Ke(){var e,t;for(e=[],t=ze();null!==t;)e.push(t),t=ze();return e}function ze(){var e;return null===(e=b())&&null===(e=E())&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","'))))))))),e}function $e(){var e,t,r,i,l,a;if(i=s,l=s,null!==(e=d())){for(t=[],null===(r=d())&&null===(r=h())&&(43===n.charCodeAt(s)?(r="+",s++):(r=null,0===o&&u('"+"')),null===r&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')))));null!==r;)t.push(r),null===(r=d())&&null===(r=h())&&(43===n.charCodeAt(s)?(r="+",s++):(r=null,0===o&&u('"+"')),null===r&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')))));null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return null!==e&&(a=i,e=void(jn.scheme=n.substring(s,a))),null===e&&(s=i),e}function Xe(){var e;return null===(e=Je())&&(e=Qe()),e}function Je(){var e,t,r,i;return r=s,i=s,null!==(e=ne())?(64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==(e=null!==e?e:"")&&null!==(t=oe())?e=[e,t]:(e=null,s=r),e=null!==e?e:""}function Qe(){var e,t;if(null===(t=b())&&null===(t=E())&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')),null===t&&(59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null===t&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=b())&&null===(t=E())&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')),null===t&&(59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null===t&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"'))))))))));else e=null;return e}function Ze(){var e,t;for(e=[],t=Ge();null!==t;)e.push(t),t=Ge();return e}function et(){var e,t,r,i,l,a,c,d,f;if(c=s,d=s,"sip"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"SIP"')),null!==e)if(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null!==t){if(null!==(i=h()))for(r=[];null!==i;)r.push(i),i=h();else r=null;if(null!==r)if(46===n.charCodeAt(s)?(i=".",s++):(i=null,0===o&&u('"."')),null!==i){if(null!==(a=h()))for(l=[];null!==a;)l.push(a),a=h();else l=null;null!==l?e=[e,t,r,i,l]:(e=null,s=d)}else e=null,s=d;else e=null,s=d}else e=null,s=d;else e=null,s=d;return null!==e&&(f=c,e=void(jn.sip_version=n.substring(s,f))),null===e&&(s=c),e}function tt(){var e;return"INVITE"===n.substr(s,6)?(e="INVITE",s+=6):(e=null,0===o&&u('"INVITE"')),e}function nt(){var e;return"ACK"===n.substr(s,3)?(e="ACK",s+=3):(e=null,0===o&&u('"ACK"')),e}function rt(){var e;return"OPTIONS"===n.substr(s,7)?(e="OPTIONS",s+=7):(e=null,0===o&&u('"OPTIONS"')),e}function it(){var e;return"BYE"===n.substr(s,3)?(e="BYE",s+=3):(e=null,0===o&&u('"BYE"')),e}function st(){var e;return"CANCEL"===n.substr(s,6)?(e="CANCEL",s+=6):(e=null,0===o&&u('"CANCEL"')),e}function ot(){var e;return"REGISTER"===n.substr(s,8)?(e="REGISTER",s+=8):(e=null,0===o&&u('"REGISTER"')),e}function lt(){var e;return"SUBSCRIBE"===n.substr(s,9)?(e="SUBSCRIBE",s+=9):(e=null,0===o&&u('"SUBSCRIBE"')),e}function at(){var e;return"NOTIFY"===n.substr(s,6)?(e="NOTIFY",s+=6):(e=null,0===o&&u('"NOTIFY"')),e}function ut(){var e;return"REFER"===n.substr(s,5)?(e="REFER",s+=5):(e=null,0===o&&u('"REFER"')),e}function ct(){var e,t,r;return t=s,null===(e=tt())&&null===(e=nt())&&null===(e=rt())&&null===(e=it())&&null===(e=st())&&null===(e=ot())&&null===(e=lt())&&null===(e=at())&&null===(e=ut())&&(e=k()),null!==e&&(r=t,jn.method=n.substring(s,r),e=jn.method),null===e&&(s=t),e}function ht(){var e,t,n,r,i,o;return o=s,null!==(e=et())&&null!==(t=v())&&null!==(n=dt())&&null!==(r=v())&&null!==(i=_t())?e=[e,t,n,r,i]:(e=null,s=o),e}function dt(){var e,t,n;return t=s,null!==(e=ft())&&(n=e,e=void(jn.status_code=parseInt(n.join("")))),null===e&&(s=t),e}function ft(){var e,t,n,r;return r=s,null!==(e=h())&&null!==(t=h())&&null!==(n=h())?e=[e,t,n]:(e=null,s=r),e}function _t(){var e,t,r,i;for(r=s,e=[],null===(t=T())&&null===(t=b())&&null===(t=E())&&null===(t=O())&&null===(t=N())&&null===(t=v())&&(t=g());null!==t;)e.push(t),null===(t=T())&&null===(t=b())&&null===(t=E())&&null===(t=O())&&null===(t=N())&&null===(t=v())&&(t=g());return null!==e&&(i=r,e=void(jn.reason_phrase=n.substring(s,i))),null===e&&(s=r),e}function pt(){var e,t,n,r,i,o,l;if(i=s,o=s,null===(e=J())&&(e=mt()),null!==e){for(t=[],l=s,null!==(n=B())&&null!==(r=gt())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=B())&&null!==(r=gt())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;return null!==e&&(e=function(e){var t;jn.multi_header||(jn.multi_header=[]);try{t=new Fn(jn.uri,jn.display_name,jn.params),delete jn.uri,delete jn.display_name,delete jn.params}catch(e){t=null}jn.multi_header.push({possition:s,offset:e,parsed:t})}(i)),null===e&&(s=i),e}function mt(){var e,t,n,r,i;return i=s,null!==(e=null!==(e=vt())?e:"")&&null!==(t=F())&&null!==(n=Q())&&null!==(r=H())?e=[e,t,n,r]:(e=null,s=i),e}function vt(){var e,t,n,r,i,o,l,a;if(i=s,o=s,null!==(e=k())){for(t=[],l=s,null!==(n=C())&&null!==(r=k())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=C())&&null!==(r=k())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;return null===e&&(e=z()),null!==e&&(a=e,e=void(jn.display_name="string"==typeof a?a:a[1].reduce(function(e,t){return e+t[0]+t[1]},a[0]))),null===e&&(s=i),e}function gt(){var e;return null===(e=yt())&&null===(e=Tt())&&(e=Et()),e}function yt(){var e,t,r,i,l,a;return i=s,l=s,"q"===n.substr(s,1).toLowerCase()?(e=n.substr(s,1),s++):(e=null,0===o&&u('"q"')),null!==e&&null!==(t=M())&&null!==(r=St())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],jn.params||(jn.params={}),e=void(jn.params.q=a)),null===e&&(s=i),e}function Tt(){var e,t,r,i,l,a;return i=s,l=s,"expires"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"expires"')),null!==e&&null!==(t=M())&&null!==(r=bt())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],jn.params||(jn.params={}),e=void(jn.params.expires=a)),null===e&&(s=i),e}function bt(){var e,t,n;if(n=s,null!==(t=h()))for(e=[];null!==t;)e.push(t),t=h();else e=null;return null!==e&&(e=parseInt(e.join(""))),null===e&&(s=n),e}function St(){var e,t,r,i,l,a,c,d,f;return a=s,c=s,48===n.charCodeAt(s)?(e="0",s++):(e=null,0===o&&u('"0"')),null!==e?(d=s,46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null!==t&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")&&null!==(l=null!==(l=h())?l:"")?t=[t,r,i,l]:(t=null,s=d),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=c)):(e=null,s=c),null!==e&&(f=a,e=parseFloat(n.substring(s,f))),null===e&&(s=a),e}function Et(){var e,t,n,r,i,o,l,a;return r=s,i=s,null!==(e=k())?(o=s,null!==(t=M())&&null!==(n=Ct())?t=[t,n]:(t=null,s=o),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(l=e[0],a=e[1],jn.params||(jn.params={}),a=void 0===a?void 0:a[1],e=void(jn.params[l.toLowerCase()]=a)),null===e&&(s=r),e}function Ct(){var e;return null===(e=k())&&null===(e=le())&&(e=K()),e}function At(){var e;return"render"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"render"')),null===e&&("session"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"session"')),null===e&&("icon"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"icon"')),null===e&&("alert"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"alert"')),null===e&&(e=k())))),e}function wt(){var e;return null===(e=Rt())&&(e=Et()),e}function Rt(){var e,t,r,i;return i=s,"handling"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"handling"')),null!==e&&null!==(t=M())?("optional"===n.substr(s,8).toLowerCase()?(r=n.substr(s,8),s+=8):(r=null,0===o&&u('"optional"')),null===r&&("required"===n.substr(s,8).toLowerCase()?(r=n.substr(s,8),s+=8):(r=null,0===o&&u('"required"')),null===r&&(r=k())),null!==r?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),e}function It(){var e,t,n,r,i,o,l,a;if(l=s,null!==(e=Ot()))if(null!==(t=D()))if(null!==(n=Ut())){for(r=[],a=s,null!==(i=B())&&null!==(o=Dt())?i=[i,o]:(i=null,s=a);null!==i;)r.push(i),a=s,null!==(i=B())&&null!==(o=Dt())?i=[i,o]:(i=null,s=a);null!==r?e=[e,t,n,r]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;else e=null,s=l;return e}function Ot(){var e;return null===(e=Nt())&&(e=kt()),e}function Nt(){var e;return"text"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"text"')),null===e&&("image"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"image"')),null===e&&("audio"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"audio"')),null===e&&("video"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"video"')),null===e&&("application"===n.substr(s,11).toLowerCase()?(e=n.substr(s,11),s+=11):(e=null,0===o&&u('"application"')),null===e&&(e=Pt()))))),e}function kt(){var e;return"message"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"message"')),null===e&&("multipart"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"multipart"')),null===e&&(e=Pt())),e}function Pt(){var e;return null===(e=k())&&(e=xt()),e}function xt(){var e,t,r;return r=s,"x-"===n.substr(s,2).toLowerCase()?(e=n.substr(s,2),s+=2):(e=null,0===o&&u('"x-"')),null!==e&&null!==(t=k())?e=[e,t]:(e=null,s=r),e}function Ut(){var e;return null===(e=Pt())&&(e=k()),e}function Dt(){var e,t,n,r;return r=s,null!==(e=k())&&null!==(t=M())&&null!==(n=Mt())?e=[e,t,n]:(e=null,s=r),e}function Mt(){var e;return null===(e=k())&&(e=K()),e}function qt(){var e,t,n,r;if(n=s,null!==(t=h()))for(e=[];null!==t;)e.push(t),t=h();else e=null;return null!==e&&(r=e,e=void(jn.value=parseInt(r.join("")))),null===e&&(s=n),e}function Lt(){var e,t,r,i,l,a;if(l=s,null!==(e=P())){for(t=[],a=s,46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r&&null!==(i=P())?r=[r,i]:(r=null,s=a);null!==r;)t.push(r),a=s,46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r&&null!==(i=P())?r=[r,i]:(r=null,s=a);null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return e}function Ht(){var e;return null===(e=Ft())&&(e=Et()),e}function Ft(){var e,t,r,i,l,a;return i=s,l=s,"tag"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"tag"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.tag=a)),null===e&&(s=i),e}function jt(){var e,t,r,i,l,a,c,h;if(c=s,"digest"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"Digest"')),null!==e)if(null!==(t=C()))if(null!==(r=Vt())){for(i=[],h=s,null!==(l=j())&&null!==(a=Vt())?l=[l,a]:(l=null,s=h);null!==l;)i.push(l),h=s,null!==(l=j())&&null!==(a=Vt())?l=[l,a]:(l=null,s=h);null!==i?e=[e,t,r,i]:(e=null,s=c)}else e=null,s=c;else e=null,s=c;else e=null,s=c;return null===e&&(e=Bt()),e}function Bt(){var e,t,n,r,i,o,l,a;if(l=s,null!==(e=k()))if(null!==(t=C()))if(null!==(n=Gt())){for(r=[],a=s,null!==(i=j())&&null!==(o=Gt())?i=[i,o]:(i=null,s=a);null!==i;)r.push(i),a=s,null!==(i=j())&&null!==(o=Gt())?i=[i,o]:(i=null,s=a);null!==r?e=[e,t,n,r]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;else e=null,s=l;return e}function Gt(){var e,t,n,r;return r=s,null!==(e=k())&&null!==(t=M())?(null===(n=k())&&(n=K()),null!==n?e=[e,t,n]:(e=null,s=r)):(e=null,s=r),e}function Vt(){var e;return null===(e=Wt())&&null===(e=Kt())&&null===(e=$t())&&null===(e=Jt())&&null===(e=Qt())&&null===(e=Zt())&&null===(e=en())&&(e=Gt()),e}function Wt(){var e,t,r,i;return i=s,"realm"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"realm"')),null!==e&&null!==(t=M())&&null!==(r=Yt())?e=[e,t,r]:(e=null,s=i),e}function Yt(){var e,t,n;return t=s,null!==(e=z())&&(n=e,e=void(jn.realm=n)),null===e&&(s=t),e}function Kt(){var e,t,r,i,l,a,c,h,d;if(h=s,"domain"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"domain"')),null!==e)if(null!==(t=M()))if(null!==(r=V()))if(null!==(i=zt())){if(l=[],d=s,null!==(c=v()))for(a=[];null!==c;)a.push(c),c=v();else a=null;for(null!==a&&null!==(c=zt())?a=[a,c]:(a=null,s=d);null!==a;){if(l.push(a),d=s,null!==(c=v()))for(a=[];null!==c;)a.push(c),c=v();else a=null;null!==a&&null!==(c=zt())?a=[a,c]:(a=null,s=d)}null!==l&&null!==(a=W())?e=[e,t,r,i,l,a]:(e=null,s=h)}else e=null,s=h;else e=null,s=h;else e=null,s=h;else e=null,s=h;return e}function zt(){var e;return null===(e=Le())&&(e=je()),e}function $t(){var e,t,r,i;return i=s,"nonce"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"nonce"')),null!==e&&null!==(t=M())&&null!==(r=Xt())?e=[e,t,r]:(e=null,s=i),e}function Xt(){var e,t,n;return t=s,null!==(e=z())&&(n=e,e=void(jn.nonce=n)),null===e&&(s=t),e}function Jt(){var e,t,r,i,l,a;return i=s,l=s,"opaque"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"opaque"')),null!==e&&null!==(t=M())&&null!==(r=z())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.opaque=a)),null===e&&(s=i),e}function Qt(){var e,t,r,i,l;return i=s,"stale"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"stale"')),null!==e&&null!==(t=M())?(l=s,"true"===n.substr(s,4).toLowerCase()?(r=n.substr(s,4),s+=4):(r=null,0===o&&u('"true"')),null!==r&&(r=void(jn.stale=!0)),null===r&&(s=l),null===r&&(l=s,"false"===n.substr(s,5).toLowerCase()?(r=n.substr(s,5),s+=5):(r=null,0===o&&u('"false"')),null!==r&&(r=void(jn.stale=!1)),null===r&&(s=l)),null!==r?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),e}function Zt(){var e,t,r,i,l,a;return i=s,l=s,"algorithm"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"algorithm"')),null!==e&&null!==(t=M())?("md5"===n.substr(s,3).toLowerCase()?(r=n.substr(s,3),s+=3):(r=null,0===o&&u('"MD5"')),null===r&&("md5-sess"===n.substr(s,8).toLowerCase()?(r=n.substr(s,8),s+=8):(r=null,0===o&&u('"MD5-sess"')),null===r&&(r=k())),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[2],e=void(jn.algorithm=a.toUpperCase())),null===e&&(s=i),e}function en(){var e,t,r,i,l,a,c,h,d,f;if(h=s,"qop"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"qop"')),null!==e)if(null!==(t=M()))if(null!==(r=V())){if(d=s,null!==(i=tn())){for(l=[],f=s,44===n.charCodeAt(s)?(a=",",s++):(a=null,0===o&&u('","')),null!==a&&null!==(c=tn())?a=[a,c]:(a=null,s=f);null!==a;)l.push(a),f=s,44===n.charCodeAt(s)?(a=",",s++):(a=null,0===o&&u('","')),null!==a&&null!==(c=tn())?a=[a,c]:(a=null,s=f);null!==l?i=[i,l]:(i=null,s=d)}else i=null,s=d;null!==i&&null!==(l=W())?e=[e,t,r,i,l]:(e=null,s=h)}else e=null,s=h;else e=null,s=h;else e=null,s=h;return e}function tn(){var e,t,r;return t=s,"auth-int"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"auth-int"')),null===e&&("auth"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"auth"')),null===e&&(e=k())),null!==e&&(r=e,jn.qop||(jn.qop=[]),e=void jn.qop.push(r.toLowerCase())),null===e&&(s=t),e}function nn(){var e,t,n,r,i,o,l;if(i=s,o=s,null!==(e=mt())){for(t=[],l=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;return null!==e&&(e=function(e){var t;jn.multi_header||(jn.multi_header=[]);try{t=new Fn(jn.uri,jn.display_name,jn.params),delete jn.uri,delete jn.display_name,delete jn.params}catch(e){t=null}jn.multi_header.push({possition:s,offset:e,parsed:t})}(i)),null===e&&(s=i),e}function rn(){var e;return null===(e=sn())&&(e=Et()),e}function sn(){var e,t,r,i,l,a,c;if(l=s,a=s,"cause"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"cause"')),null!==e)if(null!==(t=M())){if(null!==(i=h()))for(r=[];null!==i;)r.push(i),i=h();else r=null;null!==r?e=[e,t,r]:(e=null,s=a)}else e=null,s=a;else e=null,s=a;return null!==e&&(c=e[2],e=void(jn.cause=parseInt(c.join("")))),null===e&&(s=l),e}function on(){var e,t,n,r,i,o;if(i=s,null!==(e=mt())){for(t=[],o=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=o);null!==n;)t.push(n),o=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=o);null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e}function ln(){var e,t,r;return t=s,"active"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"active"')),null===e&&("pending"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"pending"')),null===e&&("terminated"===n.substr(s,10).toLowerCase()?(e=n.substr(s,10),s+=10):(e=null,0===o&&u('"terminated"')),null===e&&(e=k()))),null!==e&&(r=t,e=void(jn.state=n.substring(s,r))),null===e&&(s=t),e}function an(){var e,t,r,i,l,a,c,h;return i=s,l=s,"reason"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"reason"')),null!==e&&null!==(t=M())&&null!==(r=un())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=void(void 0!==(a=e[2])&&(jn.reason=a))),null===e&&(s=i),null===e&&(i=s,l=s,"expires"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"expires"')),null!==e&&null!==(t=M())&&null!==(r=bt())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=void(void 0!==(h=e[2])&&(jn.expires=h))),null===e&&(s=i),null===e&&(i=s,l=s,"retry_after"===n.substr(s,11).toLowerCase()?(e=n.substr(s,11),s+=11):(e=null,0===o&&u('"retry_after"')),null!==e&&null!==(t=M())&&null!==(r=bt())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=void(void 0!==(c=e[2])&&(jn.retry_after=c))),null===e&&(s=i),null===e&&(e=Et()))),e}function un(){var e;return"deactivated"===n.substr(s,11).toLowerCase()?(e=n.substr(s,11),s+=11):(e=null,0===o&&u('"deactivated"')),null===e&&("probation"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"probation"')),null===e&&("rejected"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"rejected"')),null===e&&("timeout"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"timeout"')),null===e&&("giveup"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"giveup"')),null===e&&("noresource"===n.substr(s,10).toLowerCase()?(e=n.substr(s,10),s+=10):(e=null,0===o&&u('"noresource"')),null===e&&("invariant"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"invariant"')),null===e&&(e=k()))))))),e}function cn(){var e;return null===(e=Ft())&&(e=Et()),e}function hn(){var e,t,n,r,i,o,l,a;if(l=s,null!==(e=yn()))if(null!==(t=C()))if(null!==(n=Sn())){for(r=[],a=s,null!==(i=B())&&null!==(o=dn())?i=[i,o]:(i=null,s=a);null!==i;)r.push(i),a=s,null!==(i=B())&&null!==(o=dn())?i=[i,o]:(i=null,s=a);null!==r?e=[e,t,n,r]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;else e=null,s=l;return e}function dn(){var e;return null===(e=fn())&&null===(e=_n())&&null===(e=pn())&&null===(e=mn())&&null===(e=vn())&&(e=Et()),e}function fn(){var e,t,r,i,l,a;return i=s,l=s,"ttl"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"ttl"')),null!==e&&null!==(t=M())&&null!==(r=An())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.ttl=a)),null===e&&(s=i),e}function _n(){var e,t,r,i,l,a;return i=s,l=s,"maddr"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"maddr"')),null!==e&&null!==(t=M())&&null!==(r=le())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.maddr=a)),null===e&&(s=i),e}function pn(){var e,t,r,i,l,a;return i=s,l=s,"received"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"received"')),null!==e&&null!==(t=M())?(null===(r=pe())&&(r=de()),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[2],e=void(jn.received=a)),null===e&&(s=i),e}function mn(){var e,t,r,i,l,a;return i=s,l=s,"branch"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"branch"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.branch=a)),null===e&&(s=i),e}function vn(){var e,t,r,i,l;return i=s,"rport"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"rport"')),null!==e?(l=s,null!==(t=M())&&null!==(r=gn())?t=[t,r]:(t=null,s=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),e}function gn(){var e,t,n,r,i,o,l,a;return o=s,l=s,null!==(e=null!==(e=h())?e:"")&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")?e=[e,t,n,r,i]:(e=null,s=l),null!==e&&(a=e,e=void(jn.rport=parseInt(a.join("")))),null===e&&(s=o),e}function yn(){var e,t,n,r,i,o;return o=s,null!==(e=Tn())&&null!==(t=D())&&null!==(n=k())&&null!==(r=D())&&null!==(i=bn())?e=[e,t,n,r,i]:(e=null,s=o),e}function Tn(){var e,t,r;return t=s,"sip"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"SIP"')),null===e&&(e=k()),null!==e&&(r=e,e=void(jn.protocol=r)),null===e&&(s=t),e}function bn(){var e,t,r;return t=s,"udp"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"UDP"')),null===e&&("tcp"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"TCP"')),null===e&&("tls"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"TLS"')),null===e&&("sctp"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"SCTP"')),null===e&&(e=k())))),null!==e&&(r=e,e=void(jn.transport=r)),null===e&&(s=t),e}function Sn(){var e,t,n,r,i;return r=s,null!==(e=En())?(i=s,null!==(t=G())&&null!==(n=Cn())?t=[t,n]:(t=null,s=i),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=r)):(e=null,s=r),e}function En(){var e,t,r;return t=s,null===(e=pe())&&null===(e=he())&&(e=ae()),null!==e&&(r=t,e=void(jn.host=n.substring(s,r))),null===e&&(s=t),e}function Cn(){var e,t,n,r,i,o,l,a;return o=s,l=s,null!==(e=null!==(e=h())?e:"")&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")?e=[e,t,n,r,i]:(e=null,s=l),null!==e&&(a=e,e=void(jn.port=parseInt(a.join("")))),null===e&&(s=o),e}function An(){var e,t,n,r,i;return r=s,i=s,null!==(e=h())&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")?e=[e,t,n]:(e=null,s=i),null!==e&&(e=parseInt(e.join(""))),null===e&&(s=r),e}function wn(){var e,t,n;return t=s,null!==(e=bt())&&(n=e,e=void(jn.expires=n)),null===e&&(s=t),e}function Rn(){var e;return null===(e=In())&&(e=Et()),e}function In(){var e,t,r,i,l,a;return i=s,l=s,"refresher"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"refresher"')),null!==e&&null!==(t=M())?("uac"===n.substr(s,3).toLowerCase()?(r=n.substr(s,3),s+=3):(r=null,0===o&&u('"uac"')),null===r&&("uas"===n.substr(s,3).toLowerCase()?(r=n.substr(s,3),s+=3):(r=null,0===o&&u('"uas"'))),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[2],e=void(jn.refresher=a.toLowerCase())),null===e&&(s=i),e}function On(){var e,t;for(e=[],null===(t=I())&&null===(t=N())&&(t=C());null!==t;)e.push(t),null===(t=I())&&null===(t=N())&&(t=C());return e}function Nn(){var e,t,r,i,l,a,c,h,d,f,_,p;return f=s,_=s,null!==(e=Pn())?(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null!==t&&null!==(r=kn())?(45===n.charCodeAt(s)?(i="-",s++):(i=null,0===o&&u('"-"')),null!==i&&null!==(l=kn())?(45===n.charCodeAt(s)?(a="-",s++):(a=null,0===o&&u('"-"')),null!==a&&null!==(c=kn())?(45===n.charCodeAt(s)?(h="-",s++):(h=null,0===o&&u('"-"')),null!==h&&null!==(d=xn())?e=[e,t,r,i,l,a,c,h,d]:(e=null,s=_)):(e=null,s=_)):(e=null,s=_)):(e=null,s=_)):(e=null,s=_),null!==e&&(p=f,e[0],e=void(jn=n.substring(s+5,p))),null===e&&(s=f),e}function kn(){var e,t,n,r,i;return i=s,null!==(e=f())&&null!==(t=f())&&null!==(n=f())&&null!==(r=f())?e=[e,t,n,r]:(e=null,s=i),e}function Pn(){var e,t,n;return n=s,null!==(e=kn())&&null!==(t=kn())?e=[e,t]:(e=null,s=n),e}function xn(){var e,t,n,r;return r=s,null!==(e=kn())&&null!==(t=kn())&&null!==(n=kn())?e=[e,t,n]:(e=null,s=r),e}function Un(){var e,t,r,i,l,a,c;return i=s,l=s,null!==(e=x())?(a=s,64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null!==t&&null!==(r=x())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l),null!==e&&(c=i,e=void(jn.call_id=n.substring(s,c))),null===e&&(s=i),e}function Dn(){var e;return null===(e=Mn())&&null===(e=qn())&&null===(e=Ln())&&(e=Et()),e}function Mn(){var e,t,r,i,l,a;return i=s,l=s,"to-tag"===n.substr(s,6)?(e="to-tag",s+=6):(e=null,0===o&&u('"to-tag"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.to_tag=a)),null===e&&(s=i),e}function qn(){var e,t,r,i,l,a;return i=s,l=s,"from-tag"===n.substr(s,8)?(e="from-tag",s+=8):(e=null,0===o&&u('"from-tag"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.from_tag=a)),null===e&&(s=i),e}function Ln(){var e,t;return t=s,"early-only"===n.substr(s,10)?(e="early-only",s+=10):(e=null,0===o&&u('"early-only"')),null!==e&&(e=void(jn.early_only=!0)),null===e&&(s=t),e}var Hn=e("./URI"),Fn=e("./NameAddrHeader"),jn={};if(null===i[r]()||s!==n.length){var Bn=Math.max(s,l),Gn=Bn2&&void 0!==arguments[2]?arguments[2]:{},i=e;if(void 0===e||void 0===t)throw new TypeError("Not enough arguments");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(i));var s=d.cloneArray(r.extraHeaders),o=d.cloneObject(r.eventHandlers),l=r.contentType||"text/plain",a={};for(var u in r.fromUserName&&(a.from_uri=new p("sip",r.fromUserName,this._ua.configuration.uri.host),s.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()))),r.fromDisplayName&&(a.from_display_name=r.fromDisplayName),o)Object.prototype.hasOwnProperty.call(o,u)&&this.on(u,o[u]);s.push("Content-Type: ".concat(l)),this._request=new h.OutgoingRequest(c.MESSAGE,e,this._ua,a,s),t&&(this._request.body=t);var _=new f(this._ua,this._request,{onRequestTimeout:function(){n._onRequestTimeout()},onTransportError:function(){n._onTransportError()},onReceiveResponse:function(e){n._receiveResponse(e)}});this._newMessage("local",this._request),_.send()}},{key:"init_incoming",value:function(e){this._request=e,this._newMessage("remote",e),this._is_replied||(this._is_replied=!0,e.reply(200)),this._close()}},{key:"accept",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=d.cloneArray(e.extraHeaders),n=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"accept" not supported for outgoing Message');if(this._is_replied)throw new Error("incoming Message already replied");this._is_replied=!0,this._request.reply(200,null,t,n)}},{key:"reject",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.status_code||480,n=e.reason_phrase,r=d.cloneArray(e.extraHeaders),i=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"reject" not supported for outgoing Message');if(this._is_replied)throw new Error("incoming Message already replied");if(t<300||t>=700)throw new TypeError("Invalid status_code: ".concat(t));this._is_replied=!0,this._request.reply(t,n,r,i)}},{key:"_receiveResponse",value:function(e){if(!this._closed)switch(!0){case/^1[0-9]{2}$/.test(e.status_code):break;case/^2[0-9]{2}$/.test(e.status_code):this._succeeded("remote",e);break;default:var t=d.sipErrorCause(e.status_code);this._failed("remote",e,t)}}},{key:"_onRequestTimeout",value:function(){this._closed||this._failed("system",null,c.causes.REQUEST_TIMEOUT)}},{key:"_onTransportError",value:function(){this._closed||this._failed("system",null,c.causes.CONNECTION_ERROR)}},{key:"_close",value:function(){this._closed=!0,this._ua.destroyMessage(this)}},{key:"_newMessage",value:function(e,t){"remote"===e?(this._direction="incoming",this._local_identity=t.to,this._remote_identity=t.from):"local"===e&&(this._direction="outgoing",this._local_identity=t.from,this._remote_identity=t.to),this._ua.newMessage(this,{originator:e,message:this,request:t})}},{key:"_failed",value:function(e,t,n){m.debug("MESSAGE failed"),this._close(),m.debug('emit "failed"'),this.emit("failed",{originator:e,response:t||null,cause:n})}},{key:"_succeeded",value:function(e,t){m.debug("MESSAGE succeeded"),this._close(),m.debug('emit "succeeded"'),this.emit("succeeded",{originator:e,response:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./URI":29,"./Utils":30,events:33}],11:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n"),this._parameters)Object.prototype.hasOwnProperty.call(this._parameters,t)&&(e+=";".concat(t),null!==this._parameters[t]&&(e+="=".concat(this._parameters[t])));return e}}])&&r(t.prototype,n),o&&r(t,o),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Grammar":7,"./URI":29}],12:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n"),i._headers.push(i._contact)),o&&i._headers.push("Allow-Events: ".concat(o)),i._target=t.from.uri.user,t.to_tag=d.newTag();var m=new f(l(i),t,"UAS");if(m.error)throw _.warn(m.error),new Error("SUBSCRIBE missed Contact");return i._dialog=m,i._expires>0&&i._setExpiresTimer(),i}return t=c,r=[{key:"C",get:function(){return p}}],(n=[{key:"C",get:function(){return p}},{key:"receiveRequest",value:function(e){if(e.method===h.SUBSCRIBE){var t=e.getHeader("expires");null==t&&(t="900",_.debug("Missed expires header. Set by default ".concat(t))),this._expires=parseInt(t),e.reply(200,null,["Expires: ".concat(this._expires),"".concat(this._contact)]);var n=e.body,r=e.getHeader("content-type"),i=0===this._expires;i||this._setExpiresTimer(),_.debug('emit "subscribe"'),this.emit("subscribe",i,e,n,r),i&&this._dialogTerminated(p.RECEIVE_UNSUBSCRIBE)}else e.reply(405)}},{key:"start",value:function(){_.debug("start()"),this.receiveRequest(this._initial_subscribe)}},{key:"setActiveState",value:function(){_.debug("setActiveState()"),this._state===p.STATE_PENDING&&(this._state=p.STATE_ACTIVE)}},{key:"notify",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(_.debug("notify()"),this._dialog){var n=this._stateNumberToString(this._state);if(this._state!==p.STATE_TERMINATED){var r=Math.floor((this._expires_timestamp-(new Date).getTime())/1e3);r<0&&(r=0),n+=";expires=".concat(r)}else this._terminated_reason&&(n+=";reason=".concat(this._terminated_reason)),null!==this._terminated_retry_after&&(n+=";retry-after=".concat(this._terminated_retry_after));var i=this._headers.slice();i.push("Subscription-State: ".concat(n)),t&&i.push("Content-Type: ".concat(this._content_type)),this._dialog.sendRequest(h.NOTIFY,{body:t,extraHeaders:i,eventHandlers:{onRequestTimeout:function(){e._dialogTerminated(p.NOTIFY_RESPONSE_TIMEOUT)},onTransportError:function(){e._dialogTerminated(p.NOTIFY_TRANSPORT_ERROR)},onErrorResponse:function(t){401===t.status_code||407===t.status_code?e._dialogTerminated(p.NOTIFY_FAILED_AUTHENTICATION):e._dialogTerminated(p.NOTIFY_NON_OK_RESPONSE)},onDialogError:function(){e._dialogTerminated(p.NOTIFY_NON_OK_RESPONSE)}}})}else _.warn("final notify has sent")}},{key:"terminate",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;_.debug("terminate()"),this._state=p.STATE_TERMINATED,this._terminated_reason=t,this._terminated_retry_after=n,this.notify(e),this._dialogTerminated(p.SEND_FINAL_NOTIFY)}},{key:"state",get:function(){return this._state}},{key:"id",get:function(){return this._dialog?this._dialog.id:null}},{key:"_dialogTerminated",value:function(e){if(this._dialog){this._state=p.STATE_TERMINATED,clearTimeout(this._expires_timer),this._dialog&&(this._dialog.terminate(),this._dialog=null);var t=e===p.SUBSCRIPTION_EXPIRED;_.debug('emit "terminated" code='.concat(e,", send final notify=").concat(t)),this.emit("terminated",e,t)}}},{key:"_setExpiresTimer",value:function(){var e=this;this._expires_timestamp=(new Date).getTime()+1e3*this._expires,clearTimeout(this._expires_timer),this._expires_timer=setTimeout(function(){e._dialog&&(e._terminated_reason="timeout",e.notify(),e._dialogTerminated(p.SUBSCRIPTION_EXPIRED))},1e3*this._expires)}},{key:"_stateNumberToString",value:function(e){switch(e){case p.STATE_PENDING:return"pending";case p.STATE_ACTIVE:return"active";case p.STATE_TERMINATED:return"terminated";default:throw new TypeError("wrong state value")}}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),c}()},{"./Constants":2,"./Dialog":3,"./Logger":9,"./Utils":30,events:33}],13:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{},i=e;if(void 0===e)throw new TypeError("A target is required for OPTIONS");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(i));var s=d.cloneArray(r.extraHeaders),o=d.cloneObject(r.eventHandlers),l=r.contentType||"application/sdp";for(var a in o)Object.prototype.hasOwnProperty.call(o,a)&&this.on(a,o[a]);s.push("Content-Type: ".concat(l)),this._request=new h.OutgoingRequest(c.OPTIONS,e,this._ua,null,s),t&&(this._request.body=t);var u=new f(this._ua,this._request,{onRequestTimeout:function(){n._onRequestTimeout()},onTransportError:function(){n._onTransportError()},onReceiveResponse:function(e){n._receiveResponse(e)}});this._newOptions("local",this._request),u.send()}},{key:"init_incoming",value:function(e){this._request=e,this._newOptions("remote",e),this._is_replied||(this._is_replied=!0,e.reply(200)),this._close()}},{key:"accept",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=d.cloneArray(e.extraHeaders),n=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"accept" not supported for outgoing Options');if(this._is_replied)throw new Error("incoming Options already replied");this._is_replied=!0,this._request.reply(200,null,t,n)}},{key:"reject",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.status_code||480,n=e.reason_phrase,r=d.cloneArray(e.extraHeaders),i=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"reject" not supported for outgoing Options');if(this._is_replied)throw new Error("incoming Options already replied");if(t<300||t>=700)throw new TypeError("Invalid status_code: ".concat(t));this._is_replied=!0,this._request.reply(t,n,r,i)}},{key:"_receiveResponse",value:function(e){if(!this._closed)switch(!0){case/^1[0-9]{2}$/.test(e.status_code):break;case/^2[0-9]{2}$/.test(e.status_code):this._succeeded("remote",e);break;default:var t=d.sipErrorCause(e.status_code);this._failed("remote",e,t)}}},{key:"_onRequestTimeout",value:function(){this._closed||this._failed("system",null,c.causes.REQUEST_TIMEOUT)}},{key:"_onTransportError",value:function(){this._closed||this._failed("system",null,c.causes.CONNECTION_ERROR)}},{key:"_close",value:function(){this._closed=!0,this._ua.destroyMessage(this)}},{key:"_newOptions",value:function(e,t){"remote"===e?(this._direction="incoming",this._local_identity=t.to,this._remote_identity=t.from):"local"===e&&(this._direction="outgoing",this._local_identity=t.from,this._remote_identity=t.to),this._ua.newOptions(this,{originator:e,message:this,request:t})}},{key:"_failed",value:function(e,t,n){p.debug("OPTIONS failed"),this._close(),p.debug('emit "failed"'),this.emit("failed",{originator:e,response:t||null,cause:n})}},{key:"_succeeded",value:function(e,t){p.debug("OPTIONS succeeded"),this._close(),p.debug('emit "succeeded"'),this.emit("succeeded",{originator:e,response:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,events:33}],14:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,s=function(){};return{s:s,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;w.debug("connect()");var r=e,i=m.cloneObject(t.eventHandlers),s=m.cloneArray(t.extraHeaders),o=m.cloneObject(t.mediaConstraints,{audio:!0,video:!0}),l=t.mediaStream||null,a=m.cloneObject(t.pcConfig,{iceServers:[]}),u=t.rtcConstraints||null,c=t.rtcOfferConstraints||null;if(this._rtcOfferConstraints=c,this._rtcAnswerConstraints=t.rtcAnswerConstraints||null,this._data=t.data||this._data,void 0===e)throw new TypeError("Not enough arguments");if(this._status!==R.STATUS_NULL)throw new _.InvalidStateError(this._status);if(!window.RTCPeerConnection)throw new _.NotSupportedError("WebRTC not supported");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(r));for(var h in this._sessionTimers.enabled&&m.isDecimal(t.sessionTimersExpires)&&(t.sessionTimersExpires>=f.MIN_SESSION_EXPIRES?this._sessionTimers.defaultExpires=t.sessionTimersExpires:this._sessionTimers.defaultExpires=f.SESSION_EXPIRES),i)Object.prototype.hasOwnProperty.call(i,h)&&this.on(h,i[h]);this._from_tag=m.newTag();var d=t.anonymous||!1,p={from_tag:this._from_tag};this._contact=this._ua.contact.toString({anonymous:d,outbound:!0}),d?(p.from_display_name="Anonymous",p.from_uri=new A("sip","anonymous","anonymous.invalid"),s.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString())),s.push("Privacy: id")):t.fromUserName&&(p.from_uri=new A("sip",t.fromUserName,this._ua.configuration.uri.host),s.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()))),t.fromDisplayName&&(p.from_display_name=t.fromDisplayName),s.push("Contact: ".concat(this._contact)),s.push("Content-Type: application/sdp"),this._sessionTimers.enabled&&s.push("Session-Expires: ".concat(this._sessionTimers.defaultExpires).concat(this._ua.configuration.session_timers_force_refresher?";refresher=uac":"")),this._request=new g.InitialOutgoingInviteRequest(e,this._ua,p,s),this._id=this._request.call_id+this._from_tag,this._createRTCConnection(a,u),this._direction="outgoing",this._local_identity=this._request.from,this._remote_identity=this._request.to,n&&n(this),this._newRTCSession("local",this._request),this._sendInitialRequest(o,c,l)}},{key:"init_incoming",value:function(e,t){var n,r=this;w.debug("init_incoming()");var i=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0;if(e.body&&"application/sdp"!==i)e.reply(415);else if(this._status=R.STATUS_INVITE_RECEIVED,this._from_tag=e.from_tag,this._id=e.call_id+this._from_tag,this._request=e,this._contact=this._ua.contact.toString(),e.hasHeader("expires")&&(n=1e3*e.getHeader("expires")),e.to_tag=m.newTag(),this._createDialog(e,"UAS",!0)){if(e.body?this._late_sdp=!1:this._late_sdp=!0,this._status=R.STATUS_WAITING_FOR_ANSWER,this._timers.userNoAnswerTimer=setTimeout(function(){e.reply(408),r._failed("local",null,f.causes.NO_ANSWER)},this._ua.configuration.no_answer_timeout),n&&(this._timers.expiresTimer=setTimeout(function(){r._status===R.STATUS_WAITING_FOR_ANSWER&&(e.reply(487),r._failed("system",null,f.causes.EXPIRES))},n)),this._direction="incoming",this._local_identity=e.to,this._remote_identity=e.from,t&&t(this),this._newRTCSession("remote",e),this._status!==R.STATUS_TERMINATED){var s=["Contact: ".concat(this._contact)],o=this._ua.modes.ringing_header_mode;void 0!==o&&(Array.isArray(o)?s=s.concat(o):s.push(o)),e.reply(180,null,s),this._progress("local",null)}}else e.reply(500,"Missing Contact header field")}},{key:"answer",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("answer()");var n=this._request,r=m.cloneArray(t.extraHeaders),s=m.cloneObject(t.mediaConstraints),o=t.mediaStream||null,l=m.cloneObject(t.pcConfig,{iceServers:[]}),a=t.rtcConstraints||null,u=t.rtcAnswerConstraints||null,c=m.cloneObject(t.rtcOfferConstraints),h=!1,d=!1,p=!1,v=!1;if(this._rtcAnswerConstraints=u,this._rtcOfferConstraints=t.rtcOfferConstraints||null,this._data=t.data||this._data,"incoming"!==this._direction)throw new _.NotSupportedError('"answer" not supported for outgoing RTCSession');if(this._status!==R.STATUS_WAITING_FOR_ANSWER)throw new _.InvalidStateError(this._status);if(this._sessionTimers.enabled&&m.isDecimal(t.sessionTimersExpires)&&(t.sessionTimersExpires>=f.MIN_SESSION_EXPIRES?this._sessionTimers.defaultExpires=t.sessionTimersExpires:this._sessionTimers.defaultExpires=f.SESSION_EXPIRES),this._status=R.STATUS_ANSWERED,this._createDialog(n,"UAS")){clearTimeout(this._timers.userNoAnswerTimer),r.unshift("Contact: ".concat(this._contact));var g=n.parseSDP();Array.isArray(g.media)||(g.media=[g.media]);var y,T=i(g.media);try{for(T.s();!(y=T.n()).done;){var b=y.value;"audio"===b.type&&(h=!0,b.direction&&"sendrecv"!==b.direction||(p=!0)),"video"===b.type&&(d=!0,b.direction&&"sendrecv"!==b.direction||(v=!0))}}catch(e){T.e(e)}finally{T.f()}if(o&&!1===s.audio){var S,E=i(o.getAudioTracks());try{for(E.s();!(S=E.n()).done;){var C=S.value;o.removeTrack(C)}}catch(e){E.e(e)}finally{E.f()}}if(o&&!1===s.video){var A,I=i(o.getVideoTracks());try{for(I.s();!(A=I.n()).done;){var O=A.value;o.removeTrack(O)}}catch(e){I.e(e)}finally{I.f()}}o||void 0!==s.audio||(s.audio=p),o||void 0!==s.video||(s.video=v),o||h||c.offerToReceiveAudio||(s.audio=!1),o||d||c.offerToReceiveVideo||(s.video=!1),this._createRTCConnection(l,a),Promise.resolve().then(function(){return o||(s.audio||s.video?(e._localMediaStreamLocallyGenerated=!0,navigator.mediaDevices.getUserMedia(s).catch(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");throw n.reply(480),e._failed("local",null,f.causes.USER_DENIED_MEDIA_ACCESS),w.warn('emit "getusermediafailed" [error:%o]',t),e.emit("getusermediafailed",t),new Error("getUserMedia() failed")})):void 0)}).then(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");e._localMediaStream=t,t&&t.getTracks().forEach(function(n){e._connection.addTrack(n,t)})}).then(function(){if(!e._late_sdp){var t={originator:"remote",type:"offer",sdp:n.body};w.debug('emit "sdp"'),e.emit("sdp",t);var r=new RTCSessionDescription({type:"offer",sdp:t.sdp});return e._connectionPromiseQueue=e._connectionPromiseQueue.then(function(){return e._connection.setRemoteDescription(r)}).catch(function(t){throw n.reply(488),e._failed("system",null,f.causes.WEBRTC_ERROR),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',t),e.emit("peerconnection:setremotedescriptionfailed",t),new Error("peerconnection.setRemoteDescription() failed")}),e._connectionPromiseQueue}}).then(function(){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");return e._connecting(n),e._late_sdp?e._createLocalDescription("offer",e._rtcOfferConstraints).catch(function(){throw n.reply(500),new Error("_createLocalDescription() failed")}):e._createLocalDescription("answer",u).catch(function(){throw n.reply(500),new Error("_createLocalDescription() failed")})}).then(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");e._handleSessionTimersInIncomingRequest(n,r),n.reply(200,null,r,t,function(){e._status=R.STATUS_WAITING_FOR_ACK,e._setInvite2xxTimer(n,t),e._setACKTimer(),e._accepted("local")},function(){e._failed("system",null,f.causes.CONNECTION_ERROR)})}).catch(function(t){e._status!==R.STATUS_TERMINATED&&w.warn(t)})}else n.reply(500,"Error creating dialog")}},{key:"terminate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("terminate()");var n,r=t.cause||f.causes.BYE,i=m.cloneArray(t.extraHeaders),s=t.body,o=t.status_code,l=t.reason_phrase;if(this._status===R.STATUS_TERMINATED)throw new _.InvalidStateError(this._status);switch(this._status){case R.STATUS_NULL:case R.STATUS_INVITE_SENT:case R.STATUS_1XX_RECEIVED:if(w.debug("canceling session"),o&&(o<200||o>=700))throw new TypeError("Invalid status_code: ".concat(o));o&&(l=l||f.REASON_PHRASE[o]||"",n="SIP ;cause=".concat(o,' ;text="').concat(l,'"')),this._status===R.STATUS_NULL||this._status===R.STATUS_INVITE_SENT?(this._is_canceled=!0,this._cancel_reason=n):this._status===R.STATUS_1XX_RECEIVED&&this._request.cancel(n),this._status=R.STATUS_CANCELED,this._failed("local",null,f.causes.CANCELED);break;case R.STATUS_WAITING_FOR_ANSWER:case R.STATUS_ANSWERED:if(w.debug("rejecting session"),(o=o||480)<300||o>=700)throw new TypeError("Invalid status_code: ".concat(o));this._request.reply(o,l,i,s),this._failed("local",null,f.causes.REJECTED);break;case R.STATUS_WAITING_FOR_ACK:case R.STATUS_CONFIRMED:if(w.debug("terminating session"),l=t.reason_phrase||f.REASON_PHRASE[o]||"",o&&(o<200||o>=700))throw new TypeError("Invalid status_code: ".concat(o));if(o&&i.push("Reason: SIP ;cause=".concat(o,'; text="').concat(l,'"')),this._status===R.STATUS_WAITING_FOR_ACK&&"incoming"===this._direction&&this._request.server_transaction.state!==p.C.STATUS_TERMINATED){var a=this._dialog;this.receiveRequest=function(t){t.method===f.ACK&&(e.sendRequest(f.BYE,{extraHeaders:i,body:s}),a.terminate())},this._request.server_transaction.on("stateChanged",function(){e._request.server_transaction.state===p.C.STATUS_TERMINATED&&(e.sendRequest(f.BYE,{extraHeaders:i,body:s}),a.terminate())}),this._ended("local",null,r),this._dialog=a,this._ua.newDialog(a)}else this.sendRequest(f.BYE,{extraHeaders:i,body:s}),this._ended("local",null,r)}}},{key:"sendDTMF",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};w.debug("sendDTMF() | tones: %s",e);var n=0,r=t.duration||null,i=t.interToneGap||null,s=t.transportType||f.DTMF_TRANSPORT.INFO;if(void 0===e)throw new TypeError("Not enough arguments");if(this._status!==R.STATUS_CONFIRMED&&this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_1XX_RECEIVED)throw new _.InvalidStateError(this._status);if(s!==f.DTMF_TRANSPORT.INFO&&s!==f.DTMF_TRANSPORT.RFC2833)throw new TypeError("invalid transportType: ".concat(s));if("number"==typeof e&&(e=e.toString()),!e||"string"!=typeof e||!e.match(/^[0-9A-DR#*,]+$/i))throw new TypeError("Invalid tones: ".concat(e));if(r&&!m.isDecimal(r))throw new TypeError("Invalid tone duration: ".concat(r));if(r?rb.C.MAX_DURATION?(w.debug('"duration" value is greater than the maximum allowed, setting it to '.concat(b.C.MAX_DURATION," milliseconds")),r=b.C.MAX_DURATION):r=Math.abs(r):r=b.C.DEFAULT_DURATION,t.duration=r,i&&!m.isDecimal(i))throw new TypeError("Invalid interToneGap: ".concat(i));if(i?i=this._tones.length)return void(this._tones=null);var l=this._tones[n];n+=1;if(","===l)o=2e3;else{var a=new b(this);t.eventHandlers={onFailed:function(){s._tones=null}},a.send(l,t),o=r+i}setTimeout(e.bind(this),o)}.call(this));else{var o=this._getDTMFRTPSender();o&&(e=o.toneBuffer+e,o.insertDTMF(e,r,i))}}},{key:"sendInfo",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(w.debug("sendInfo()"),this._status!==R.STATUS_CONFIRMED&&this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_1XX_RECEIVED)throw new _.InvalidStateError(this._status);new S(this).send(e,t,n)}},{key:"mute",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{audio:!0,video:!1};w.debug("mute()");var t=!1,n=!1;!1===this._audioMuted&&e.audio&&(t=!0,this._audioMuted=!0,this._toggleMuteAudio(!0)),!1===this._videoMuted&&e.video&&(n=!0,this._videoMuted=!0,this._toggleMuteVideo(!0)),!0!==t&&!0!==n||this._onmute({audio:t,video:n})}},{key:"unmute",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{audio:!0,video:!0};w.debug("unmute()");var t=!1,n=!1;!0===this._audioMuted&&e.audio&&(t=!0,this._audioMuted=!1,!1===this._localHold&&this._toggleMuteAudio(!1)),!0===this._videoMuted&&e.video&&(n=!0,this._videoMuted=!1,!1===this._localHold&&this._toggleMuteVideo(!1)),!0!==t&&!0!==n||this._onunmute({audio:t,video:n})}},{key:"hold",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(w.debug("hold()"),this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!0===this._localHold)return!1;if(!this._isReadyToReOffer())return!1;this._localHold=!0,this._onhold("local");var r={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Hold Failed"})}};return t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:r,extraHeaders:t.extraHeaders}),!0}},{key:"unhold",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(w.debug("unhold()"),this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!1===this._localHold)return!1;if(!this._isReadyToReOffer())return!1;this._localHold=!1,this._onunhold("local");var r={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Unhold Failed"})}};return t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:r,extraHeaders:t.extraHeaders}),!0}},{key:"renegotiate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;w.debug("renegotiate()");var r=t.rtcOfferConstraints||null;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!this._isReadyToReOffer())return!1;var i={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Media Renegotiation Failed"})}};return this._setLocalMediaStatus(),t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:i,rtcOfferConstraints:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:i,rtcOfferConstraints:r,extraHeaders:t.extraHeaders}),!0}},{key:"refer",value:function(e,t){var n=this;w.debug("refer()");var r=e;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(r));var i=new C(this);i.sendRefer(e,t);var s=i.id;return this._referSubscribers[s]=i,i.on("requestFailed",function(){delete n._referSubscribers[s]}),i.on("accepted",function(){delete n._referSubscribers[s]}),i.on("failed",function(){delete n._referSubscribers[s]}),i}},{key:"sendRequest",value:function(e,t){return w.debug("sendRequest()"),this._dialog.sendRequest(e,t)}},{key:"receiveRequest",value:function(e){var t=this;if(w.debug("receiveRequest()"),e.method===f.CANCEL)this._status!==R.STATUS_WAITING_FOR_ANSWER&&this._status!==R.STATUS_ANSWERED||(this._status=R.STATUS_CANCELED,this._request.reply(487),this._failed("remote",e,f.causes.CANCELED));else switch(e.method){case f.ACK:if(this._status!==R.STATUS_WAITING_FOR_ACK)return;if(this._status=R.STATUS_CONFIRMED,clearTimeout(this._timers.ackTimer),clearTimeout(this._timers.invite2xxTimer),this._late_sdp){if(!e.body){this.terminate({cause:f.causes.MISSING_SDP,status_code:400});break}var n={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",n);var r=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(r)}).then(function(){t._is_confirmed||t._confirmed("remote",e)}).catch(function(e){t.terminate({cause:f.causes.BAD_MEDIA_DESCRIPTION,status_code:488}),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}else this._is_confirmed||this._confirmed("remote",e);break;case f.BYE:this._status===R.STATUS_CONFIRMED||this._status===R.STATUS_WAITING_FOR_ACK?(e.reply(200),this._ended("remote",e,f.causes.BYE)):this._status===R.STATUS_INVITE_RECEIVED||this._status===R.STATUS_WAITING_FOR_ANSWER?(e.reply(200),this._request.reply(487,"BYE Received"),this._ended("remote",e,f.causes.BYE)):e.reply(403,"Wrong Status");break;case f.INVITE:this._status===R.STATUS_CONFIRMED?e.hasHeader("replaces")?this._receiveReplaces(e):this._receiveReinvite(e):e.reply(403,"Wrong Status");break;case f.INFO:if(this._status===R.STATUS_1XX_RECEIVED||this._status===R.STATUS_WAITING_FOR_ANSWER||this._status===R.STATUS_ANSWERED||this._status===R.STATUS_WAITING_FOR_ACK||this._status===R.STATUS_CONFIRMED){var i=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0;i&&i.match(/^application\/dtmf-relay/i)?new b(this).init_incoming(e):void 0!==i?new S(this).init_incoming(e):e.reply(415)}else e.reply(403,"Wrong Status");break;case f.UPDATE:this._status===R.STATUS_CONFIRMED?this._receiveUpdate(e):e.reply(403,"Wrong Status");break;case f.REFER:this._status===R.STATUS_CONFIRMED?this._receiveRefer(e):e.reply(403,"Wrong Status");break;case f.NOTIFY:var s={event:e.event,request:e,taken:!1};if(this.emit("sipEvent",s),s.taken){e.reply(200);break}this._status===R.STATUS_CONFIRMED?this._receiveNotify(e):e.reply(403,"Wrong Status");break;default:e.reply(501)}}},{key:"onTransportError",value:function(){w.warn("onTransportError()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:500,reason_phrase:f.causes.CONNECTION_ERROR,cause:f.causes.CONNECTION_ERROR})}},{key:"onRequestTimeout",value:function(){w.warn("onRequestTimeout()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:408,reason_phrase:f.causes.REQUEST_TIMEOUT,cause:f.causes.REQUEST_TIMEOUT})}},{key:"onDialogError",value:function(){w.warn("onDialogError()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:500,reason_phrase:f.causes.DIALOG_ERROR,cause:f.causes.DIALOG_ERROR})}},{key:"newDTMF",value:function(e){w.debug("newDTMF()"),this.emit("newDTMF",e)}},{key:"newInfo",value:function(e){w.debug("newInfo()"),this.emit("newInfo",e)}},{key:"_isReadyToReOffer",value:function(){return this._rtcReady?this._dialog?!0!==this._dialog.uac_pending_reply&&!0!==this._dialog.uas_pending_reply||(w.debug("_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress"),!1):(w.debug("_isReadyToReOffer() | session not established yet"),!1):(w.debug("_isReadyToReOffer() | internal WebRTC status not ready"),!1)}},{key:"_close",value:function(){if(w.debug("close()"),this._localMediaStream&&this._localMediaStreamLocallyGenerated&&(w.debug("close() | closing local MediaStream"),m.closeMediaStream(this._localMediaStream)),this._status!==R.STATUS_TERMINATED){if(this._status=R.STATUS_TERMINATED,this._connection)try{this._connection.close()}catch(e){w.warn("close() | error closing the RTCPeerConnection: %o",e)}for(var e in this._timers)Object.prototype.hasOwnProperty.call(this._timers,e)&&clearTimeout(this._timers[e]);for(var t in clearTimeout(this._sessionTimers.timer),this._dialog&&(this._dialog.terminate(),delete this._dialog),this._earlyDialogs)Object.prototype.hasOwnProperty.call(this._earlyDialogs,t)&&(this._earlyDialogs[t].terminate(),delete this._earlyDialogs[t]);for(var n in this._referSubscribers)Object.prototype.hasOwnProperty.call(this._referSubscribers,n)&&delete this._referSubscribers[n];this._ua.destroyRTCSession(this)}}},{key:"_setInvite2xxTimer",value:function(e,t){var n=v.T1;this._timers.invite2xxTimer=setTimeout(function r(){this._status===R.STATUS_WAITING_FOR_ACK&&(e.reply(200,null,["Contact: ".concat(this._contact)],t),nv.T2&&(n=v.T2),this._timers.invite2xxTimer=setTimeout(r.bind(this),n))}.bind(this),n)}},{key:"_setACKTimer",value:function(){var e=this;this._timers.ackTimer=setTimeout(function(){e._status===R.STATUS_WAITING_FOR_ACK&&(w.debug("no ACK received, terminating the session"),clearTimeout(e._timers.invite2xxTimer),e.sendRequest(f.BYE),e._ended("remote",null,f.causes.NO_ACK))},v.TIMER_H)}},{key:"_createRTCConnection",value:function(e,t){var n=this;this._connection=new RTCPeerConnection(e,t),this._connection.addEventListener("iceconnectionstatechange",function(){var e=n._connection.iceConnectionState;if("failed"===e&&n.terminate({cause:f.causes.RTP_TIMEOUT,status_code:408,reason_phrase:f.causes.RTP_TIMEOUT}),void 0!==n._ua.modes.chrome_rtp_timeout_fix&&navigator.webkitGetUserMedia&&"disconnected"===e){var t=n._ua.modes.chrome_rtp_timeout_fix;w.debug("AC: Chrome RTP timeout fix: iceConnectionState==disconnected: check that this will continue for ".concat(t," seconds..."));!function e(){"disconnected"===n._connection.iceConnectionState?t-- >0?setTimeout(function(){return e()},1e3):(w.debug("AC: Chrome RTP timeout fix: Hangup call"),n.terminate({cause:f.causes.RTP_TIMEOUT,status_code:408,reason_phrase:f.causes.RTP_TIMEOUT})):w.debug("AC: Chrome RTP timeout fix: iceConnectionState=".concat(n._connection.iceConnectionState))}()}}),w.debug('emit "peerconnection"'),this.emit("peerconnection",{peerconnection:this._connection})}},{key:"_createLocalDescription",value:function(e,t){var n=this;if(w.debug("createLocalDescription()"),"offer"!==e&&"answer"!==e)throw new Error('createLocalDescription() | invalid type "'.concat(e,'"'));var r=this._connection;return this._rtcReady=!1,Promise.resolve().then(function(){return"offer"===e?r.createOffer(t).catch(function(e){return w.warn('emit "peerconnection:createofferfailed" [error:%o]',e),n.emit("peerconnection:createofferfailed",e),Promise.reject(e)}):r.createAnswer(t).catch(function(e){return w.warn('emit "peerconnection:createanswerfailed" [error:%o]',e),n.emit("peerconnection:createanswerfailed",e),Promise.reject(e)})}).then(function(e){return r.setLocalDescription(e).catch(function(e){return n._rtcReady=!0,w.warn('emit "peerconnection:setlocaldescriptionfailed" [error:%o]',e),n.emit("peerconnection:setlocaldescriptionfailed",e),Promise.reject(e)})}).then(function(){var i=t&&t.iceRestart;if("complete"===r.iceGatheringState&&!i||"gathering"===r.iceGatheringState&&n._iceReady){n._rtcReady=!0;var s={originator:"local",type:e,sdp:r.localDescription.sdp};return w.debug('emit "sdp"'),n.emit("sdp",s),Promise.resolve(s.sdp)}return new Promise(function(t){var i,s,o=!1;n._iceReady=!1;var l=function(){r.removeEventListener("icecandidate",i),r.removeEventListener("icegatheringstatechange",s),o=!0,n._rtcReady=!0,n._iceReady=!0;var l={originator:"local",type:e,sdp:r.localDescription.sdp};w.debug('emit "sdp"'),n.emit("sdp",l),t(l.sdp)};r.addEventListener("icecandidate",i=function(e){var t=e.candidate;t?n.emit("icecandidate",{candidate:t,ready:l}):o||l()}),r.addEventListener("icegatheringstatechange",s=function(){"complete"!==r.iceGatheringState||o||l()}),void 0!==n._ua.modes.ice_timeout_fix&&setTimeout(function(){o||(w.debug("AC: ICE gathering timeout fix"),l())},n._ua.modes.ice_timeout_fix)})})}},{key:"_createDialog",value:function(e,t,n){var r="UAS"===t?e.to_tag:e.from_tag,i="UAS"===t?e.from_tag:e.to_tag,s=e.call_id+r+i,o=this._earlyDialogs[s];if(n)return!!o||((o=new y(this,e,t,y.C.STATUS_EARLY)).error?(w.debug(o.error),this._failed("remote",e,f.causes.INTERNAL_ERROR),!1):(this._earlyDialogs[s]=o,!0));if(this._from_tag=e.from_tag,this._to_tag=e.to_tag,o)return o.update(e,t),this._dialog=o,delete this._earlyDialogs[s],!0;var l=new y(this,e,t);return l.error?(w.debug(l.error),this._failed("remote",e,f.causes.INTERNAL_ERROR),!1):(this._dialog=l,!0)}},{key:"_receiveReinvite",value:function(e){var t=this;w.debug("receiveReinvite()");var n=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,r={request:e,callback:void 0,reject:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i=!0;var n=t.status_code||403,r=t.reason_phrase||"",s=m.cloneArray(t.extraHeaders);if(this._status!==R.STATUS_CONFIRMED)return!1;if(n<300||n>=700)throw new TypeError("Invalid status_code: ".concat(n));e.reply(n,r,s)}.bind(this)},i=!1;if(this.emit("reinvite",r),!i){if(this._late_sdp=!1,!e.body)return this._late_sdp=!0,this._remoteHold&&(this._remoteHold=!1,this._onunhold("remote")),void(this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._createLocalDescription("offer",t._rtcOfferConstraints)}).then(function(e){s.call(t,e)}).catch(function(){e.reply(500)}));if("application/sdp"!==n)return w.debug("invalid Content-Type"),void e.reply(415);this._processInDialogSdpOffer(e).then(function(e){t._status!==R.STATUS_TERMINATED&&s.call(t,e)}).catch(function(e){w.warn(e)})}function s(t){var n=this,i=["Contact: ".concat(this._contact)];this._handleSessionTimersInIncomingRequest(e,i),this._late_sdp&&(t=this._mangleOffer(t)),e.reply(200,null,i,t,function(){n._status=R.STATUS_WAITING_FOR_ACK,n._setInvite2xxTimer(e,t),n._setACKTimer()}),"function"==typeof r.callback&&r.callback()}}},{key:"_receiveUpdate",value:function(e){var t=this;w.debug("receiveUpdate()");var n=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,r={request:e,callback:void 0,reject:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i=!0;var n=t.status_code||403,r=t.reason_phrase||"",s=m.cloneArray(t.extraHeaders);if(this._status!==R.STATUS_CONFIRMED)return!1;if(n<300||n>=700)throw new TypeError("Invalid status_code: ".concat(n));e.reply(n,r,s)}.bind(this)},i=!1;if(this.emit("update",r),!i)if(e.body){if("application/sdp"!==n)return w.debug("invalid Content-Type"),void e.reply(415);this._processInDialogSdpOffer(e).then(function(e){t._status!==R.STATUS_TERMINATED&&s.call(t,e)}).catch(function(e){w.warn(e)})}else s.call(this,null);function s(t){var n=["Contact: ".concat(this._contact)];this._handleSessionTimersInIncomingRequest(e,n),e.reply(200,null,n,t),"function"==typeof r.callback&&r.callback()}}},{key:"_processInDialogSdpOffer",value:function(e){var t=this;w.debug("_processInDialogSdpOffer()");var n,r=e.parseSDP(),s=!1,o=i(r.media);try{for(o.s();!(n=o.n()).done;){var l=n.value;if(-1!==I.indexOf(l.type)){var a=l.direction||r.direction||"sendrecv";if("sendonly"!==a&&"inactive"!==a){s=!1;break}s=!0}}}catch(e){o.e(e)}finally{o.f()}var u={originator:"remote",type:"offer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",u);var c=new RTCSessionDescription({type:"offer",sdp:u.sdp});return this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");return t._connection.setRemoteDescription(c).catch(function(n){throw e.reply(488),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',n),t.emit("peerconnection:setremotedescriptionfailed",n),n})}).then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");!0===t._remoteHold&&!1===s?(t._remoteHold=!1,t._onunhold("remote")):!1===t._remoteHold&&!0===s&&(t._remoteHold=!0,t._onhold("remote"))}).then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");return t._createLocalDescription("answer",t._rtcAnswerConstraints).catch(function(t){throw e.reply(500),w.warn('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]',t),t})}).catch(function(e){w.warn("_processInDialogSdpOffer() failed [error: %o]",e)}),this._connectionPromiseQueue}},{key:"_receiveRefer",value:function(e){var t=this;if(w.debug("receiveRefer()"),!e.refer_to)return w.debug("no Refer-To header field present in REFER"),void e.reply(400);if(e.refer_to.uri.scheme!==f.SIP)return w.debug("Refer-To header field points to a non-SIP URI scheme"),void e.reply(416);e.reply(202);var n=new E(this,e.cseq);w.debug('emit "refer"'),this.emit("refer",{request:e,accept:function(r,i){(function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t="function"==typeof t?t:null,this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;var i=new u(this._ua);if(i.on("progress",function(e){var t=e.response;n.notify(t.status_code,t.reason_phrase)}),i.on("accepted",function(e){var t=e.response;n.notify(t.status_code,t.reason_phrase)}),i.on("_failed",function(e){var t=e.message,r=e.cause;t?n.notify(t.status_code,t.reason_phrase):n.notify(487,r)}),e.refer_to.uri.hasHeader("replaces")){var s=decodeURIComponent(e.refer_to.uri.getHeader("replaces"));r.extraHeaders=m.cloneArray(r.extraHeaders),r.extraHeaders.push("Replaces: ".concat(s))}i.connect(e.refer_to.uri.toAor(),r,t)}).call(t,r,i)},reject:function(){(function(){n.notify(603)}).call(t)}})}},{key:"_receiveNotify",value:function(e){switch(w.debug("receiveNotify()"),e.event||e.reply(400),e.event.event){case"refer":var t,n;if(e.event.params&&e.event.params.id)t=e.event.params.id,n=this._referSubscribers[t];else{if(1!==Object.keys(this._referSubscribers).length)return void e.reply(400,"Missing event id parameter");n=this._referSubscribers[Object.keys(this._referSubscribers)[0]]}if(!n)return void e.reply(481,"Subscription does not exist");n.receiveNotify(e),e.reply(200);break;default:e.reply(489)}}},{key:"_receiveReplaces",value:function(e){var t=this;w.debug("receiveReplaces()"),this.emit("replaces",{request:e,accept:function(n){(function(t){var n=this;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;var r=new u(this._ua);r.on("confirmed",function(){n.terminate()}),r.init_incoming(e,t)}).call(t,n)},reject:function(){(function(){w.debug("Replaced INVITE rejected by the user"),e.reply(486)}).call(t)}})}},{key:"_sendInitialRequest",value:function(e,t,n){var r=this,i=new T(this._ua,this._request,{onRequestTimeout:function(){r.onRequestTimeout()},onTransportError:function(){r.onTransportError()},onAuthenticated:function(e){r._request=e},onReceiveResponse:function(e){r._receiveInviteResponse(e)}});Promise.resolve().then(function(){return n||(e.audio||e.video?(r._localMediaStreamLocallyGenerated=!0,navigator.mediaDevices.getUserMedia(e).catch(function(e){if(r._status===R.STATUS_TERMINATED)throw new Error("terminated");throw r._failed("local",null,f.causes.USER_DENIED_MEDIA_ACCESS),w.warn('emit "getusermediafailed" [error:%o]',e),r.emit("getusermediafailed",e),e})):void 0)}).then(function(e){if(r._status===R.STATUS_TERMINATED)throw new Error("terminated");return r._localMediaStream=e,e&&e.getTracks().forEach(function(t){r._connection.addTrack(t,e)}),r._connecting(r._request),r._createLocalDescription("offer",t).catch(function(e){throw r._failed("local",null,f.causes.WEBRTC_ERROR),e})}).then(function(e){if(r._is_canceled||r._status===R.STATUS_TERMINATED)throw new Error("terminated");r._request.body=e,r._status=R.STATUS_INVITE_SENT,w.debug('emit "sending" [request:%o]',r._request),r.emit("sending",{request:r._request}),i.send()}).catch(function(e){r._status!==R.STATUS_TERMINATED&&w.warn(e)})}},{key:"_getDTMFRTPSender",value:function(){var e=this._connection.getSenders().find(function(e){return e.track&&"audio"===e.track.kind});if(e&&e.dtmf)return e.dtmf;w.warn("sendDTMF() | no local audio track to send DTMF with")}},{key:"_receiveInviteResponse",value:function(e){var t=this;if(w.debug("receiveInviteResponse()"),this._dialog&&e.status_code>=200&&e.status_code<=299){if(this._dialog.id.call_id===e.call_id&&this._dialog.id.local_tag===e.from_tag&&this._dialog.id.remote_tag===e.to_tag)return void this.sendRequest(f.ACK);var n=new y(this,e,"UAC");return void 0!==n.error?void w.debug(n.error):(this.sendRequest(f.ACK),void this.sendRequest(f.BYE))}if(this._is_canceled)e.status_code>=100&&e.status_code<200?this._request.cancel(this._cancel_reason):e.status_code>=200&&e.status_code<299&&this._acceptAndTerminate(e);else if(this._status===R.STATUS_INVITE_SENT||this._status===R.STATUS_1XX_RECEIVED)switch(!0){case/^100$/.test(e.status_code):this._status=R.STATUS_1XX_RECEIVED;break;case/^1[0-9]{2}$/.test(e.status_code):if(!e.to_tag){w.debug("1xx response received without to tag");break}if(e.hasHeader("contact")&&!this._createDialog(e,"UAC",!0))break;if(this._status=R.STATUS_1XX_RECEIVED,!e.body){this._progress("remote",e);break}var r={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",r);var i=new RTCSessionDescription({type:"answer",sdp:r.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){return t._progress("remote",e)}).catch(function(e){w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)});break;case/^2[0-9]{2}$/.test(e.status_code):if(this._status=R.STATUS_CONFIRMED,!e.body){this._acceptAndTerminate(e,400,f.causes.MISSING_SDP),this._failed("remote",e,f.causes.BAD_MEDIA_DESCRIPTION);break}if(!this._createDialog(e,"UAC"))break;var s={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",s);var o=new RTCSessionDescription({type:"answer",sdp:s.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){if("stable"===t._connection.signalingState)return t._connection.createOffer(t._rtcOfferConstraints).then(function(e){return t._connection.setLocalDescription(e)}).catch(function(n){t._acceptAndTerminate(e,500,n.toString()),t._failed("local",e,f.causes.WEBRTC_ERROR)})}).then(function(){t._connection.setRemoteDescription(o).then(function(){t._handleSessionTimersInIncomingResponse(e),t._accepted("remote",e),t.sendRequest(f.ACK),t._confirmed("local",null)}).catch(function(n){t._acceptAndTerminate(e,488,"Not Acceptable Here"),t._failed("remote",e,f.causes.BAD_MEDIA_DESCRIPTION),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',n),t.emit("peerconnection:setremotedescriptionfailed",n)})});break;default:var l=m.sipErrorCause(e.status_code);this._failed("remote",e,l)}}},{key:"_sendReinvite",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("sendReinvite()");var n=m.cloneArray(t.extraHeaders),r=m.cloneObject(t.eventHandlers),i=t.rtcOfferConstraints||this._rtcOfferConstraints||null,s=!1;function o(e){r.failed&&r.failed(e)}n.push("Contact: ".concat(this._contact)),n.push("Content-Type: application/sdp"),this._sessionTimers.running&&n.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(this._sessionTimers.refresher?"uac":"uas")),this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return e._createLocalDescription("offer",i)}).then(function(t){var i={originator:"local",type:"offer",sdp:t=e._mangleOffer(t)};w.debug('emit "sdp"'),e.emit("sdp",i),e.sendRequest(f.INVITE,{extraHeaders:n,body:t,eventHandlers:{onSuccessResponse:function(t){(function(e){var t=this;if(this._status===R.STATUS_TERMINATED)return;if(this.sendRequest(f.ACK),s)return;if(this._handleSessionTimersInIncomingResponse(e),!e.body)return void o.call(this);if(!e.hasHeader("Content-Type")||"application/sdp"!==e.getHeader("Content-Type").toLowerCase())return void o.call(this);var n={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",n);var i=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){r.succeeded&&r.succeeded(e)}).catch(function(e){o.call(t),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}).call(e,t),s=!0},onErrorResponse:function(t){o.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}).catch(function(){o()})}},{key:"_sendUpdate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("sendUpdate()");var n=m.cloneArray(t.extraHeaders),r=m.cloneObject(t.eventHandlers),i=t.rtcOfferConstraints||this._rtcOfferConstraints||null,s=t.sdpOffer||!1,o=!1;function l(e){var t=this;if(this._status!==R.STATUS_TERMINATED&&!o)if(this._handleSessionTimersInIncomingResponse(e),s){if(!e.body)return void a.call(this);if(!e.hasHeader("Content-Type")||"application/sdp"!==e.getHeader("Content-Type").toLowerCase())return void a.call(this);var n={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",n);var i=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){r.succeeded&&r.succeeded(e)}).catch(function(e){a.call(t),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}else r.succeeded&&r.succeeded(e)}function a(e){r.failed&&r.failed(e)}n.push("Contact: ".concat(this._contact)),this._sessionTimers.running&&n.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(this._sessionTimers.refresher?"uac":"uas")),s?(n.push("Content-Type: application/sdp"),this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return e._createLocalDescription("offer",i)}).then(function(t){var r={originator:"local",type:"offer",sdp:t=e._mangleOffer(t)};w.debug('emit "sdp"'),e.emit("sdp",r),e.sendRequest(f.UPDATE,{extraHeaders:n,body:t,eventHandlers:{onSuccessResponse:function(t){l.call(e,t),o=!0},onErrorResponse:function(t){a.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}).catch(function(){a.call(e)})):this.sendRequest(f.UPDATE,{extraHeaders:n,eventHandlers:{onSuccessResponse:function(t){l.call(e,t)},onErrorResponse:function(t){a.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}},{key:"_acceptAndTerminate",value:function(e,t,n){w.debug("acceptAndTerminate()");var r=[];t&&(n=n||f.REASON_PHRASE[t]||"",r.push("Reason: SIP ;cause=".concat(t,'; text="').concat(n,'"'))),(this._dialog||this._createDialog(e,"UAC"))&&(this.sendRequest(f.ACK),this.sendRequest(f.BYE,{extraHeaders:r})),this._status=R.STATUS_TERMINATED}},{key:"_mangleOffer",value:function(e){if(!this._localHold&&!this._remoteHold)return e;if(e=h.parse(e),this._localHold&&!this._remoteHold){w.debug("mangleOffer() | me on hold, mangling offer");var t,n=i(e.media);try{for(n.s();!(t=n.n()).done;){var r=t.value;-1!==I.indexOf(r.type)&&(r.direction?"sendrecv"===r.direction?r.direction="sendonly":"recvonly"===r.direction&&(r.direction="inactive"):r.direction="sendonly")}}catch(e){n.e(e)}finally{n.f()}}else if(this._localHold&&this._remoteHold){w.debug("mangleOffer() | both on hold, mangling offer");var s,o=i(e.media);try{for(o.s();!(s=o.n()).done;){var l=s.value;-1!==I.indexOf(l.type)&&(l.direction="inactive")}}catch(e){o.e(e)}finally{o.f()}}else if(this._remoteHold){w.debug("mangleOffer() | remote on hold, mangling offer");var a,u=i(e.media);try{for(u.s();!(a=u.n()).done;){var c=a.value;-1!==I.indexOf(c.type)&&(c.direction?"sendrecv"===c.direction?c.direction="recvonly":"recvonly"===c.direction&&(c.direction="inactive"):c.direction="recvonly")}}catch(e){u.e(e)}finally{u.f()}}return h.write(e)}},{key:"_setLocalMediaStatus",value:function(){var e=!0,t=!0;(this._localHold||this._remoteHold)&&(e=!1,t=!1),this._audioMuted&&(e=!1),this._videoMuted&&(t=!1),this._toggleMuteAudio(!e),this._toggleMuteVideo(!t)}},{key:"_handleSessionTimersInIncomingRequest",value:function(e,t){var n;this._sessionTimers.enabled&&(e.session_expires&&e.session_expires>=f.MIN_SESSION_EXPIRES?(this._sessionTimers.currentExpires=e.session_expires,n=e.session_expires_refresher||"uas"):(this._sessionTimers.currentExpires=this._sessionTimers.defaultExpires,n="uas"),t.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(n)),this._sessionTimers.refresher="uas"===n,this._runSessionTimer())}},{key:"_handleSessionTimersInIncomingResponse",value:function(e){var t;this._sessionTimers.enabled&&(e.session_expires&&e.session_expires>=f.MIN_SESSION_EXPIRES?(this._sessionTimers.currentExpires=e.session_expires,t=e.session_expires_refresher||"uac"):(this._sessionTimers.currentExpires=this._sessionTimers.defaultExpires,t="uac"),this._sessionTimers.refresher="uac"===t,this._runSessionTimer())}},{key:"_runSessionTimer",value:function(){var e=this,t=this._sessionTimers.currentExpires;this._sessionTimers.running=!0,clearTimeout(this._sessionTimers.timer),this._sessionTimers.refresher?this._sessionTimers.timer=setTimeout(function(){e._status!==R.STATUS_TERMINATED&&e._isReadyToReOffer()&&(w.debug("runSessionTimer() | sending session refresh request"),e._sessionTimers.refreshMethod===f.UPDATE?e._sendUpdate():e._sendReinvite())},500*t):this._sessionTimers.timer=setTimeout(function(){e._status!==R.STATUS_TERMINATED&&(w.warn("runSessionTimer() | timer expired, terminating the session"),e.terminate({cause:f.causes.REQUEST_TIMEOUT,status_code:408,reason_phrase:"Session Timer Expired"}))},1100*t)}},{key:"_toggleMuteAudio",value:function(e){var t,n=i(this._connection.getSenders().filter(function(e){return e.track&&"audio"===e.track.kind}));try{for(n.s();!(t=n.n()).done;){t.value.track.enabled=!e}}catch(e){n.e(e)}finally{n.f()}}},{key:"_toggleMuteVideo",value:function(e){var t,n=i(this._connection.getSenders().filter(function(e){return e.track&&"video"===e.track.kind}));try{for(n.s();!(t=n.n()).done;){t.value.track.enabled=!e}}catch(e){n.e(e)}finally{n.f()}}},{key:"_newRTCSession",value:function(e,t){w.debug("newRTCSession()"),this._ua.newRTCSession(this,{originator:e,session:this,request:t})}},{key:"_connecting",value:function(e){w.debug("session connecting"),w.debug('emit "connecting"'),this.emit("connecting",{request:e})}},{key:"_progress",value:function(e,t){w.debug("session progress"),w.debug('emit "progress"'),this.emit("progress",{originator:e,response:t||null})}},{key:"_accepted",value:function(e,t){w.debug("session accepted"),this._start_time=new Date,w.debug('emit "accepted"'),this.emit("accepted",{originator:e,response:t||null})}},{key:"_confirmed",value:function(e,t){w.debug("session confirmed"),this._is_confirmed=!0,w.debug('emit "confirmed"'),this.emit("confirmed",{originator:e,ack:t||null})}},{key:"_ended",value:function(e,t,n){w.debug("session ended"),this._end_time=new Date,this._close(),w.debug('emit "ended"'),this.emit("ended",{originator:e,message:t||null,cause:n})}},{key:"_failed",value:function(e,t,n){w.debug("session failed"),w.debug('emit "_failed"'),this.emit("_failed",{originator:e,message:t||null,cause:n}),this._close(),w.debug('emit "failed"'),this.emit("failed",{originator:e,message:t||null,cause:n})}},{key:"_onhold",value:function(e){w.debug("session onhold"),this._setLocalMediaStatus(),w.debug('emit "hold"'),this.emit("hold",{originator:e})}},{key:"_onunhold",value:function(e){w.debug("session onunhold"),this._setLocalMediaStatus(),w.debug('emit "unhold"'),this.emit("unhold",{originator:e})}},{key:"_onmute",value:function(e){var t=e.audio,n=e.video;w.debug("session onmute"),this._setLocalMediaStatus(),w.debug('emit "muted"'),this.emit("muted",{audio:t,video:n})}},{key:"_onunmute",value:function(e){var t=e.audio,n=e.video;w.debug("session onunmute"),this._setLocalMediaStatus(),w.debug('emit "unmuted"'),this.emit("unmuted",{audio:t,video:n})}}])&&o(t.prototype,n),r&&o(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Dialog":3,"./Exceptions":6,"./Logger":9,"./RTCSession/DTMF":16,"./RTCSession/Info":17,"./RTCSession/ReferNotifier":18,"./RTCSession/ReferSubscriber":19,"./RequestSender":21,"./SIPMessage":22,"./Timers":25,"./Transactions":26,"./URI":29,"./Utils":30,events:33,"sdp-transform":39}],16:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};if(void 0===e)throw new TypeError("Not enough arguments");if(this._direction="outgoing",this._session.status!==this._session.C.STATUS_CONFIRMED&&this._session.status!==this._session.C.STATUS_WAITING_FOR_ACK)throw new h.InvalidStateError(this._session.status);var r=d.cloneArray(n.extraHeaders);if(this.eventHandlers=d.cloneObject(n.eventHandlers),"string"==typeof e)e=e.toUpperCase();else{if("number"!=typeof e)throw new TypeError("Invalid tone: ".concat(e));e=e.toString()}if(!e.match(/^[0-9A-DR#*]$/))throw new TypeError("Invalid tone: ".concat(e));this._tone=e,this._duration=n.duration,r.push("Content-Type: application/dtmf-relay");var i="Signal=".concat(this._tone,"\r\n");i+="Duration=".concat(this._duration),this._session.newDTMF({originator:"local",dtmf:this,request:this._request}),this._session.sendRequest(c.INFO,{extraHeaders:r,eventHandlers:{onSuccessResponse:function(e){t.emit("succeeded",{originator:"remote",response:e})},onErrorResponse:function(e){t.eventHandlers.onFailed&&t.eventHandlers.onFailed(),t.emit("failed",{originator:"remote",response:e})},onRequestTimeout:function(){t._session.onRequestTimeout()},onTransportError:function(){t._session.onTransportError()},onDialogError:function(){t._session.onDialogError()}},body:i})}},{key:"init_incoming",value:function(e){var t=/^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/,n=/^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;if(this._direction="incoming",this._request=e,e.reply(200),e.body){var r=e.body.split("\n");r.length>=1&&t.test(r[0])&&(this._tone=r[0].replace(t,"$2")),r.length>=2&&n.test(r[1])&&(this._duration=parseInt(r[1].replace(n,"$2"),10))}this._duration||(this._duration=_.DEFAULT_DURATION),this._tone?this._session.newDTMF({originator:"remote",dtmf:this,request:e}):f.debug("invalid INFO DTMF received, discarded")}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}(),t.exports.C=_},{"../Constants":2,"../Exceptions":6,"../Logger":9,"../Utils":30,events:33}],17:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{};if(this._direction="outgoing",t&&void 0===e)throw new TypeError("Not enough arguments");if(this._session.status!==this._session.C.STATUS_CONFIRMED&&this._session.status!==this._session.C.STATUS_WAITING_FOR_ACK)throw new c.InvalidStateError(this._session.status);this._contentType=e,this._body=t;var i=h.cloneArray(r.extraHeaders);e&&i.push("Content-Type: ".concat(e)),this._session.newInfo({originator:"local",info:this,request:this.request}),this._session.sendRequest(u.INFO,{extraHeaders:i,eventHandlers:{onSuccessResponse:function(e){n.emit("succeeded",{originator:"remote",response:e})},onErrorResponse:function(e){n.emit("failed",{originator:"remote",response:e})},onTransportError:function(){n._session.onTransportError()},onRequestTimeout:function(){n._session.onRequestTimeout()},onDialogError:function(){n._session.onDialogError()}},body:t})}},{key:"init_incoming",value:function(e){this._direction="incoming",this.request=e,e.reply(200),this._contentType=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,this._body=e.body,this._session.newInfo({originator:"remote",info:this,request:e})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),d}()},{"../Constants":2,"../Exceptions":6,"../Utils":30,events:33}],18:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=200?"terminated;reason=noresource":"active;expires=".concat(this._expires);try{this._session.sendRequest(s.NOTIFY,{extraHeaders:["Event: ".concat(l.event_type,";id=").concat(this._id),"Subscription-State: ".concat(n),"Content-Type: ".concat(l.body_type)],body:"SIP/2.0 ".concat(e," ").concat(t),eventHandlers:{onErrorResponse:function(){this._active=!1}}})}catch(e){o.debug("send NOTIFY exception [ignored]")}}}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"../Constants":2,"../Logger":9}],19:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};f.debug("sendRefer()");var r=d.cloneArray(n.extraHeaders),i=d.cloneObject(n.eventHandlers);for(var s in i)Object.prototype.hasOwnProperty.call(i,s)&&this.on(s,i[s]);var o=null;n.replaces&&(o=n.replaces._request.call_id,o+=";to-tag=".concat(n.replaces._to_tag),o+=";from-tag=".concat(n.replaces._from_tag),o=encodeURIComponent(o));var l="Refer-To: <".concat(e).concat(o?"?Replaces=".concat(o):"",">");if(r.push(l),!r.some(function(e){return e.toLowerCase().startsWith("referred-by:")})){var a="Referred-By: <".concat(this._session._ua._configuration.uri._scheme,":").concat(this._session._ua._configuration.uri._user,"@").concat(this._session._ua._configuration.uri._host,">");r.push(a)}r.push("Contact: ".concat(this._session.contact));var u=this._session.sendRequest(c.REFER,{extraHeaders:r,eventHandlers:{onSuccessResponse:function(e){t._requestSucceeded(e)},onErrorResponse:function(e){t._requestFailed(e,c.causes.REJECTED)},onTransportError:function(){t._requestFailed(null,c.causes.CONNECTION_ERROR)},onRequestTimeout:function(){t._requestFailed(null,c.causes.REQUEST_TIMEOUT)},onDialogError:function(){t._requestFailed(null,c.causes.DIALOG_ERROR)}}});this._id=u.cseq}},{key:"receiveNotify",value:function(e){if(f.debug("receiveNotify()"),e.body){var t=h.parse(e.body.trim().split("\r\n",1)[0],"Status_Line");if(-1!==t)switch(!0){case/^100$/.test(t.status_code):this.emit("trying",{request:e,status_line:t});break;case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",{request:e,status_line:t});break;case/^2[0-9]{2}$/.test(t.status_code):this.emit("accepted",{request:e,status_line:t});break;default:this.emit("failed",{request:e,status_line:t})}else f.debug('receiveNotify() | error parsing NOTIFY body: "'.concat(e.body,'"'))}}},{key:"_requestSucceeded",value:function(e){f.debug("REFER succeeded"),f.debug('emit "requestSucceeded"'),this.emit("requestSucceeded",{response:e})}},{key:"_requestFailed",value:function(e,t){f.debug("REFER failed"),f.debug('emit "requestFailed"'),this.emit("requestFailed",{response:e||null,cause:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"../Constants":2,"../Grammar":7,"../Logger":9,"../Utils":30,events:33}],20:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n"'),this._contact+=";reg-id=".concat(this._reg_id),this._contact+=";+sip.instance=".concat(this._sipInstance),this._auth=null}var t,n,i;return t=e,(n=[{key:"registered",get:function(){return this._registered}},{key:"setExtraHeaders",value:function(e){Array.isArray(e)||(e=[]),this._extraHeaders=e.slice()}},{key:"setExtraContactParams",value:function(e){for(var t in e instanceof Object||(e={}),this._extraContactParams="",e)if(Object.prototype.hasOwnProperty.call(e,t)){var n=e[t];this._extraContactParams+=";".concat(t),n&&(this._extraContactParams+="=".concat(n))}}},{key:"register",value:function(){var e=this;if(this._registering)u.debug("Register request in progress...");else{var t=this._extraHeaders.slice();t.push("Contact: ".concat(this._contact,";expires=").concat(this._expires).concat(this._extraContactParams)),t.push("Expires: ".concat(this._expires)),this._auth&&t.push(this._auth);var n=new l.OutgoingRequest(o.REGISTER,this._registrar,this._ua,{to_uri:this._to_uri,call_id:this._call_id,cseq:this._cseq+=1},t),r=new a(this._ua,n,{onRequestTimeout:function(){e._registrationFailure(null,o.causes.REQUEST_TIMEOUT)},onTransportError:function(){e._registrationFailure(null,o.causes.CONNECTION_ERROR)},onAuthenticated:function(t){var n,r;(e._cseq+=1,e._ua.modes.cache_register_auth_mode)&&((r=t.getHeader(n="Authorization"))?e._auth="".concat(n,": ").concat(r):(r=t.getHeader(n="Proxy-Authorization"))&&(e._auth="".concat(n,": ").concat(r)))},onReceiveResponse:function(t){if(t.cseq===e._cseq)switch(null!==e._registrationTimer&&(clearTimeout(e._registrationTimer),e._registrationTimer=null),!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):if(e._registering=!1,!t.hasHeader("Contact")){u.debug("no Contact header in response to REGISTER, response ignored");break}var n=t.headers.Contact.reduce(function(e,t){return e.concat(t.parsed)},[]),r=n.find(function(t){return e._sipInstance===t.getParam("+sip.instance")&&e._reg_id===parseInt(t.getParam("reg-id"))});if(r||(r=n.find(function(t){return t.uri.user===e._ua.contact.uri.user})),!r){u.debug("no Contact header pointing to us, response ignored");break}var i=r.getParam("expires");!i&&t.hasHeader("expires")&&(i=t.getHeader("expires")),i||(i=e._expires),(i=Number(i))<10&&(i=10);var l=i>=140?1e3*i/2+Math.floor(1e3*(i/2-70)*Math.random()):1e3*i-5e3;e._registrationTimer=setTimeout(function(){e._registrationTimer=null,0===e._ua.listeners("registrationExpiring").length?e.register():e._ua.emit("registrationExpiring")},l),r.hasParam("temp-gruu")&&(e._ua.contact.temp_gruu=r.getParam("temp-gruu").replace(/"/g,"")),r.hasParam("pub-gruu")&&(e._ua.contact.pub_gruu=r.getParam("pub-gruu").replace(/"/g,"")),e._registered||(e._registered=!0,e._ua.registered({response:t}));break;case/^423$/.test(t.status_code):t.hasHeader("min-expires")?(e._expires=Number(t.getHeader("min-expires")),e._expires<10&&(e._expires=10),e.register()):(u.debug("423 response received for REGISTER without Min-Expires"),e._registrationFailure(t,o.causes.SIP_FAILURE_CODE));break;default:var a=s.sipErrorCause(t.status_code);e._registrationFailure(t,a)}}});this._registering=!0,r.send()}}},{key:"unregister",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(this._registered){this._registered=!1,null!==this._registrationTimer&&(clearTimeout(this._registrationTimer),this._registrationTimer=null);var n=this._extraHeaders.slice();t.all?n.push("Contact: *".concat(this._extraContactParams)):n.push("Contact: ".concat(this._contact,";expires=0").concat(this._extraContactParams)),n.push("Expires: 0"),this._auth&&n.push(this._auth);var r=new l.OutgoingRequest(o.REGISTER,this._registrar,this._ua,{to_uri:this._to_uri,call_id:this._call_id,cseq:this._cseq+=1},n);new a(this._ua,r,{onRequestTimeout:function(){e._unregistered(null,o.causes.REQUEST_TIMEOUT)},onTransportError:function(){e._unregistered(null,o.causes.CONNECTION_ERROR)},onAuthenticated:function(){e._cseq+=1},onReceiveResponse:function(t){switch(!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):e._unregistered(t);break;default:var n=s.sipErrorCause(t.status_code);e._unregistered(t,n)}}}).send(),this._auth=null}else u.debug("already unregistered")}},{key:"close",value:function(){this._registered&&this.unregister()}},{key:"onTransportClosed",value:function(){this._registering=!1,null!==this._registrationTimer&&(clearTimeout(this._registrationTimer),this._registrationTimer=null),this._registered&&(this._registered=!1,this._ua.unregistered({}))}},{key:"_registrationFailure",value:function(e,t){this._registering=!1,this._ua.registrationFailed({response:e||null,cause:t}),this._registered&&(this._registered=!1,this._ua.unregistered({response:e||null,cause:t}))}},{key:"_unregistered",value:function(e,t){this._registering=!1,this._registered=!1,this._ua.unregistered({response:e||null,cause:t||null})}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30}],21:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,o=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return o=e.done,e},e:function(e){l=!0,s=e},f:function(){try{o||null==n.return||n.return()}finally{if(l)throw s}}}}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n")),this.setHeader("via",""),this.setHeader("max-forwards",p.MAX_FORWARDS);var l=i.to_uri||n,a=i.to_tag?{tag:i.to_tag}:null,u=void 0!==i.to_display_name?i.to_display_name:null;this.to=new v(l,u,a),this.setHeader("to",this.to.toString());var h,d=i.from_uri||r.configuration.uri,f={tag:i.from_tag||m.newTag()};h=void 0!==i.from_display_name?i.from_display_name:r.configuration.display_name?r.configuration.display_name:null,this.from=new v(d,h,f),this.setHeader("from",this.from.toString());var _=i.call_id||r.configuration.jssip_id+m.createRandomToken(15);this.call_id=_,this.setHeader("call-id",_);var g=i.cseq||Math.floor(1e4*Math.random());this.cseq=g,this.setHeader("cseq","".concat(g," ").concat(t))}return d(e,[{key:"setHeader",value:function(e,t){for(var n=new RegExp("^\\s*".concat(e,"\\s*:"),"i"),r=0;r1&&void 0!==arguments[1]?arguments[1]:0;if(e=m.headerize(e),this.headers[e]){if(!(t>=this.headers[e].length)){var n=this.headers[e][t],r=n.raw;if(n.parsed)return n.parsed;var i=g.parse(r,e.replace(/-/g,"_"));return-1===i?(this.headers[e].splice(t,1),void y.debug('error parsing "'.concat(e,'" header field with value "').concat(r,'"'))):(n.parsed=i,i)}y.debug('not so many "'.concat(e,'" headers present'))}else y.debug('header "'.concat(e,'" not present'))}},{key:"s",value:function(e,t){return this.parseHeader(e,t)}},{key:"setHeader",value:function(e,t){var n={raw:t};this.headers[m.headerize(e)]=[n]}},{key:"parseSDP",value:function(e){return!e&&this.sdp?this.sdp:(this.sdp=f.parse(this.body||""),this.sdp)}},{key:"toString",value:function(){return this.data}}]),e}(),E=function(e){i(n,S);var t=o(n);function n(e){var r;return c(this,n),(r=t.call(this)).ua=e,r.headers={},r.ruri=null,r.transport=null,r.server_transaction=null,r}return d(n,[{key:"reply",value:function(e,t,n,r,i,s){var o=[],l=this.getHeader("To");if(t=t||null,!(e=e||null)||e<100||e>699)throw new TypeError("Invalid status_code: ".concat(e));if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: ".concat(t));t=t||p.REASON_PHRASE[e]||"",n=m.cloneArray(n),this.ua.configuration.extra_headers&&(n=n.concat(this.ua.configuration.extra_headers));var u="SIP/2.0 ".concat(e," ").concat(t,"\r\n");if(this.method===p.INVITE&&e>100&&e<=200){var c,h=a(this.getHeaders("record-route"));try{for(h.s();!(c=h.n()).done;){var d=c.value;u+="Record-Route: ".concat(d,"\r\n")}}catch(e){h.e(e)}finally{h.f()}}var f,_=a(this.getHeaders("via"));try{for(_.s();!(f=_.n()).done;){var v=f.value;u+="Via: ".concat(v,"\r\n")}}catch(e){_.e(e)}finally{_.f()}!this.to_tag&&e>100?l+=";tag=".concat(m.newTag()):this.to_tag&&!this.s("to").hasParam("tag")&&(l+=";tag=".concat(this.to_tag)),u+="To: ".concat(l,"\r\n"),u+="From: ".concat(this.getHeader("From"),"\r\n"),u+="Call-ID: ".concat(this.call_id,"\r\n"),u+="CSeq: ".concat(this.cseq," ").concat(this.method,"\r\n");var g,y=a(n);try{for(y.s();!(g=y.n()).done;){var T=g.value;u+="".concat(T.trim(),"\r\n")}}catch(e){y.e(e)}finally{y.f()}switch(this.method){case p.INVITE:this.ua.configuration.session_timers&&o.push("timer"),(this.ua.contact.pub_gruu||this.ua.contact.temp_gruu)&&o.push("gruu"),o.push("ice","replaces");break;case p.UPDATE:this.ua.configuration.session_timers&&o.push("timer"),r&&o.push("ice"),o.push("replaces")}if(o.push("outbound"),this.method===p.OPTIONS?(u+="Allow: ".concat(p.ALLOWED_METHODS,"\r\n"),u+="Accept: ".concat(p.ACCEPTED_BODY_TYPES,"\r\n")):405===e?u+="Allow: ".concat(p.ALLOWED_METHODS,"\r\n"):415===e&&(u+="Accept: ".concat(p.ACCEPTED_BODY_TYPES,"\r\n")),u+="Supported: ".concat(o,"\r\n"),r){var b=m.str_utf8_length(r);u+="Content-Type: application/sdp\r\n",u+="Content-Length: ".concat(b,"\r\n\r\n"),u+=r}else u+="Content-Length: ".concat(0,"\r\n\r\n");this.server_transaction.receiveResponse(e,u,i,s)}},{key:"reply_sl",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=this.getHeaders("via");if(!e||e<100||e>699)throw new TypeError("Invalid status_code: ".concat(e));if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: ".concat(t));t=t||p.REASON_PHRASE[e]||"";var r,i="SIP/2.0 ".concat(e," ").concat(t,"\r\n"),s=a(n);try{for(s.s();!(r=s.n()).done;){var o=r.value;i+="Via: ".concat(o,"\r\n")}}catch(e){s.e(e)}finally{s.f()}var l=this.getHeader("To");if(!this.to_tag&&e>100?l+=";tag=".concat(m.newTag()):this.to_tag&&!this.s("to").hasParam("tag")&&(l+=";tag=".concat(this.to_tag)),i+="To: ".concat(l,"\r\n"),i+="From: ".concat(this.getHeader("From"),"\r\n"),i+="Call-ID: ".concat(this.call_id,"\r\n"),i+="CSeq: ".concat(this.cseq," ").concat(this.method,"\r\n"),this.ua.configuration.extra_headers){var u,c=a(this.ua.configuration.extra_headers);try{for(c.s();!(u=c.n()).done;){var h=u.value;i+="".concat(h.trim(),"\r\n")}}catch(e){c.e(e)}finally{c.f()}}i+="Content-Length: ".concat(0,"\r\n\r\n"),this.transport.send(i)}}]),n}(),C=function(e){i(n,S);var t=o(n);function n(){var e;return c(this,n),(e=t.call(this)).headers={},e.status_code=null,e.reason_phrase=null,e}return d(n)}();t.exports={OutgoingRequest:T,InitialOutgoingInviteRequest:b,IncomingRequest:E,IncomingResponse:C}},{"./Constants":2,"./Grammar":7,"./Logger":9,"./NameAddrHeader":11,"./Utils":30,"sdp-transform":39}],23:[function(e,t,n){"use strict";var r=e("./Logger"),i=e("./Utils"),s=e("./Grammar"),o=new r("Socket");n.isSocket=function(e){if(Array.isArray(e))return!1;if(void 0===e)return o.warn("undefined JsSIP.Socket instance"),!1;try{if(!i.isString(e.url))throw o.warn("missing or invalid JsSIP.Socket url property"),new Error("Missing or invalid JsSIP.Socket url property");if(!i.isString(e.via_transport))throw o.warn("missing or invalid JsSIP.Socket via_transport property"),new Error("Missing or invalid JsSIP.Socket via_transport property");if(-1===s.parse(e.sip_uri,"SIP_URI"))throw o.warn("missing or invalid JsSIP.Socket sip_uri property"),new Error("missing or invalid JsSIP.Socket sip_uri property")}catch(e){return!1}try{["connect","disconnect","send"].forEach(function(t){if(!i.isFunction(e[t]))throw o.warn("missing or invalid JsSIP.Socket method: ".concat(t)),new Error("Missing or invalid JsSIP.Socket method: ".concat(t))})}catch(e){return!1}return!0}},{"./Grammar":7,"./Logger":9,"./Utils":30}],24:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return s(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n2e3&&(g.debug("update sending re-SUBSCRIBE time"),this._scheduleSubscribe(l))}o!==y.STATE_PENDING&&s===y.STATE_PENDING?(g.debug('emit "pending"'),this.emit("pending")):o!==y.STATE_ACTIVE&&s===y.STATE_ACTIVE&&(g.debug('emit "active"'),this.emit("active"));var u=e.body,c=s===y.STATE_TERMINATED;if(u){var h=e.getHeader("content-type");g.debug('emit "notify"'),this.emit("notify",c,e,u,h)}if(c){var f=i.reason,_=void 0;i.params&&void 0!==i.params["retry-after"]&&(_=parseInt(i.params["retry-after"])),this._dialogTerminated(y.RECEIVE_FINAL_NOTIFY,f,_)}}},{key:"subscribe",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;g.debug("subscribe()"),this._state===y.STATE_INIT?this._sendInitialSubscribe(e,this._headers):this._sendSubsequentSubscribe(e,this._headers)}},{key:"terminate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(g.debug("terminate()"),!this._terminated){this._terminated=!0;var n=this._headers.map(function(e){return e.startsWith("Expires")?"Expires: 0":e});this._state===y.STATE_INIT?this._sendInitialSubscribe(t,n):this._sendSubsequentSubscribe(t,n);this._unsubscribe_timeout_timer=setTimeout(function(){e._dialogTerminated(y.UNSUBSCRIBE_TIMEOUT)},3e4)}}},{key:"state",get:function(){return this._state}},{key:"id",get:function(){return this._dialog?this._dialog.id:null}},{key:"_sendInitialSubscribe",value:function(e,t){var n=this;if(e){if(!this._content_type)throw new TypeError("content_type is undefined");(t=t.slice()).push("Content-Type: ".concat(this._content_type))}this._state=y.STATE_NOTIFY_WAIT;var r=new p.OutgoingRequest(d.SUBSCRIBE,this._ua.normalizeTarget(this._target),this._ua,this._params,t,e);new m(this._ua,r,{onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},onReceiveResponse:function(e){n._receiveSubscribeResponse(e)}}).send()}},{key:"_receiveSubscribeResponse",value:function(e){if(e.status_code>=200&&e.status_code<300){if(null===this._dialog){var t=new v(this,e,"UAC");if(t.error)return g.warn(t.error),void this._dialogTerminated(y.SUBSCRIBE_BAD_OK_RESPONSE);this._dialog=t,g.debug('emit "accepted"'),this.emit("accepted");var n,r=i(this._queue);try{for(r.s();!(n=r.n()).done;){var s=n.value;g.debug("dequeue subscribe"),this._sendSubsequentSubscribe(s.body,s.headers)}}catch(e){r.e(e)}finally{r.f()}}var o=e.getHeader("expires");0===o||o||(g.warn("response without Expires header"),o="900");var l=parseInt(o);l>0&&this._scheduleSubscribe(l)}else 401===e.status_code||407===e.status_code?this._dialogTerminated(y.SUBSCRIBE_FAILED_AUTHENTICATION):e.status_code>=300&&this._dialogTerminated(y.SUBSCRIBE_NON_OK_RESPONSE)}},{key:"_sendSubsequentSubscribe",value:function(e,t){var n=this;if(this._state!==y.STATE_TERMINATED){if(!this._dialog)return g.debug("enqueue subscribe"),void this._queue.push({body:e,headers:t.slice()});if(e){if(!this._content_type)throw new TypeError("content_type is undefined");(t=t.slice()).push("Content-Type: ".concat(this._content_type))}this._dialog.sendRequest(d.SUBSCRIBE,{body:e,extraHeaders:t,eventHandlers:{onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},onSuccessResponse:function(e){n._receiveSubscribeResponse(e)},onErrorResponse:function(e){n._receiveSubscribeResponse(e)},onDialogError:function(e){n._receiveSubscribeResponse(e)}}})}}},{key:"_dialogTerminated",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:void 0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0;this._state!==y.STATE_TERMINATED&&(this._state=y.STATE_TERMINATED,clearTimeout(this._expires_timer),clearTimeout(this._unsubscribe_timeout_timer),this._dialog&&(this._dialog.terminate(),this._dialog=null),g.debug('emit "terminated" code='.concat(e)),this.emit("terminated",e,t,n))}},{key:"_scheduleSubscribe",value:function(e){var t=this,n=e>=140?1e3*e/2+Math.floor(1e3*(e/2-70)*Math.random()):1e3*e-5e3;this._expires_timestamp=(new Date).getTime()+1e3*e,g.debug("next SUBSCRIBE will be sent in ".concat(Math.floor(n/1e3)," sec")),clearTimeout(this._expires_timer),this._expires_timer=setTimeout(function(){t._expires_timer=null,t._sendSubsequentSubscribe(null,t._headers)},n)}},{key:"_stateStringToNumber",value:function(e){switch(e){case"pending":return y.STATE_PENDING;case"active":return y.STATE_ACTIVE;case"terminated":return y.STATE_TERMINATED;case"init":return y.STATE_INIT;case"notify_wait":return y.STATE_NOTIFY_WAIT;default:throw new TypeError("wrong state value")}}}])&&o(t.prototype,n),r&&o(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Dialog":3,"./Grammar":7,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,events:33}],25:[function(e,t,n){"use strict";var r=500;t.exports={T1:r,T2:4e3,T4:5e3,TIMER_B:32e3,TIMER_D:0,TIMER_F:32e3,TIMER_H:32e3,TIMER_I:0,TIMER_J:0,TIMER_K:0,TIMER_L:32e3,TIMER_M:32e3,PROVISIONAL_RESPONSE_INTERVAL:6e4}},{}],26:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){for(var n=0;n=100&&n<=199)switch(this.state){case S.STATUS_CALLING:this.stateChanged(S.STATUS_PROCEEDING),this.eventHandlers.onReceiveResponse(e);break;case S.STATUS_PROCEEDING:this.eventHandlers.onReceiveResponse(e)}else if(n>=200&&n<=299)switch(this.state){case S.STATUS_CALLING:case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_ACCEPTED),this.M=setTimeout(function(){t.timer_M()},m.TIMER_M),this.eventHandlers.onReceiveResponse(e);break;case S.STATUS_ACCEPTED:this.eventHandlers.onReceiveResponse(e)}else if(n>=300&&n<=699)switch(this.state){case S.STATUS_CALLING:case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_COMPLETED),this.sendACK(e),this.eventHandlers.onReceiveResponse(e);break;case S.STATUS_COMPLETED:this.sendACK(e)}}}]),n}(),A=function(e){l(n,d);var t=u(n);function n(e,r,s,o){var l;i(this,n),(l=t.call(this)).id="z9hG4bK".concat(Math.floor(1e7*Math.random())),l.transport=r,l.request=s,l.eventHandlers=o;var a="SIP/2.0/".concat(r.via_transport);return a+=" ".concat(e.configuration.via_host,";branch=").concat(l.id),l.request.setHeader("via",a),l}return o(n,[{key:"C",get:function(){return S}},{key:"send",value:function(){this.transport.send(this.request)||this.onTransportError()}},{key:"onTransportError",value:function(){y.debug("transport error occurred for transaction ".concat(this.id)),this.eventHandlers.onTransportError()}}]),n}(),w=function(e){l(n,d);var t=u(n);function n(e,r,s){var o;return i(this,n),(o=t.call(this)).type=S.NON_INVITE_SERVER,o.id=s.via_branch,o.ua=e,o.transport=r,o.request=s,o.last_response="",s.server_transaction=c(o),o.state=S.STATUS_TRYING,e.newTransaction(c(o)),o}return o(n,[{key:"C",get:function(){return S}},{key:"stateChanged",value:function(e){this.state=e,this.emit("stateChanged")}},{key:"timer_J",value:function(){T.debug("Timer J expired for transaction ".concat(this.id)),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"onTransportError",value:function(){this.transportError||(this.transportError=!0,T.debug("transport error occurred, deleting transaction ".concat(this.id)),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"receiveResponse",value:function(e,t,n,r){if(100===e)switch(this.state){case S.STATUS_TRYING:this.stateChanged(S.STATUS_PROCEEDING),this.transport.send(t)||this.onTransportError();break;case S.STATUS_PROCEEDING:this.last_response=t,this.transport.send(t)?n&&n():(this.onTransportError(),r&&r())}else if(e>=200&&e<=699)switch(this.state){case S.STATUS_TRYING:case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_COMPLETED),this.last_response=t,this.timer_J(),this.transport.send(t)?n&&n():(this.onTransportError(),r&&r());break;case S.STATUS_COMPLETED:}}}]),n}(),R=function(e){l(n,d);var t=u(n);function n(e,r,s){var o;return i(this,n),(o=t.call(this)).type=S.INVITE_SERVER,o.id=s.via_branch,o.ua=e,o.transport=r,o.request=s,o.last_response="",s.server_transaction=c(o),o.state=S.STATUS_PROCEEDING,e.newTransaction(c(o)),o.resendProvisionalTimer=null,s.reply(100),o}return o(n,[{key:"C",get:function(){return S}},{key:"stateChanged",value:function(e){this.state=e,this.emit("stateChanged")}},{key:"timer_H",value:function(){b.debug("Timer H expired for transaction ".concat(this.id)),this.state===S.STATUS_COMPLETED&&b.debug("ACK not received, dialog will be terminated"),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"timer_I",value:function(){this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"timer_L",value:function(){b.debug("Timer L expired for transaction ".concat(this.id)),this.state===S.STATUS_ACCEPTED&&(this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"onTransportError",value:function(){this.transportError||(this.transportError=!0,b.debug("transport error occurred, deleting transaction ".concat(this.id)),null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),clearTimeout(this.L),clearTimeout(this.H),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"resend_provisional",value:function(){this.transport.send(this.last_response)||this.onTransportError()}},{key:"receiveResponse",value:function(e,t,n,r){var i=this;if(e>=100&&e<=199)switch(this.state){case S.STATUS_PROCEEDING:this.transport.send(t)||this.onTransportError(),this.last_response=t}if(e>100&&e<=199&&this.state===S.STATUS_PROCEEDING)null===this.resendProvisionalTimer&&(this.resendProvisionalTimer=setInterval(function(){i.resend_provisional()},m.PROVISIONAL_RESPONSE_INTERVAL));else if(e>=200&&e<=299)switch(this.state){case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_ACCEPTED),this.last_response=t,this.L=setTimeout(function(){i.timer_L()},m.TIMER_L),null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null);case S.STATUS_ACCEPTED:this.transport.send(t)?n&&n():(this.onTransportError(),r&&r())}else if(e>=300&&e<=699)switch(this.state){case S.STATUS_PROCEEDING:null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),this.transport.send(t)?(this.stateChanged(S.STATUS_COMPLETED),this.H=setTimeout(function(){i.timer_H()},m.TIMER_H),n&&n()):(this.onTransportError(),r&&r())}}}]),n}();t.exports={C:S,NonInviteClientTransaction:E,InviteClientTransaction:C,AckClientTransaction:A,NonInviteServerTransaction:w,InviteServerTransaction:R,checkTransaction:function(e,t){var n,r=e._transactions;switch(t.method){case _.INVITE:if(n=r.ist[t.via_branch]){switch(n.state){case S.STATUS_PROCEEDING:n.transport.send(n.last_response);break;case S.STATUS_ACCEPTED:}return!0}break;case _.ACK:if(!(n=r.ist[t.via_branch]))return!1;if(n.state===S.STATUS_ACCEPTED)return!1;if(n.state===S.STATUS_COMPLETED)return n.state=S.STATUS_CONFIRMED,n.timer_I(),!0;break;case _.CANCEL:return(n=r.ist[t.via_branch])?(t.reply_sl(200),n.state!==S.STATUS_PROCEEDING):(t.reply_sl(481),!0);default:if(n=r.nist[t.via_branch]){switch(n.state){case S.STATUS_TRYING:break;case S.STATUS_PROCEEDING:case S.STATUS_COMPLETED:n.transport.send(n.last_response)}return!0}}}}},{"./Constants":2,"./Logger":9,"./SIPMessage":22,"./Timers":25,events:33}],27:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,s=function(){};return{s:s,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n2&&void 0!==arguments[2]?arguments[2]:c.recovery_options;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),u.debug("new()"),this._ua=t,this.status=c.STATUS_DISCONNECTED,this.socket=null,this.sockets=[],this.recovery_options=r,this.recover_attempts=0,this.recovery_timer=null,this.close_requested=!1;try{this.textDecoder=new TextDecoder("utf8")}catch(e){u.warn("cannot use TextDecoder: ".concat(e))}if(void 0===n)throw new TypeError("Invalid argument. undefined 'sockets' argument");n instanceof Array||(n=[n]),n.forEach(function(e){if(!l.isSocket(e.socket))throw new TypeError("Invalid argument. invalid 'JsSIP.Socket' instance");if(e.weight&&!Number(e.weight))throw new TypeError("Invalid argument. 'weight' attribute is not a number");this.sockets.push({socket:e.socket,weight:e.weight||0,status:c.SOCKET_STATUS_READY})},this),this._getSocket()}var t,n,i;return t=e,(n=[{key:"via_transport",get:function(){return this.socket.via_transport}},{key:"url",get:function(){return this.socket.url}},{key:"sip_uri",get:function(){return this.socket.sip_uri}},{key:"connect",value:function(){u.debug("connect()"),this.isConnected()?u.debug("Transport is already connected"):this.isConnecting()?u.debug("Transport is connecting"):(this.close_requested=!1,this.status=c.STATUS_CONNECTING,this.onconnecting({socket:this.socket,attempts:this.recover_attempts}),this.close_requested||(this.socket.onconnect=this._onConnect.bind(this),this.socket.ondisconnect=this._onDisconnect.bind(this),this.socket.ondata=this._onData.bind(this),this.socket.connect()))}},{key:"disconnect",value:function(){u.debug("close()"),this.close_requested=!0,this.recover_attempts=0,this.status=c.STATUS_DISCONNECTED,null!==this.recovery_timer&&(clearTimeout(this.recovery_timer),this.recovery_timer=null),this.socket.onconnect=function(){},this.socket.ondisconnect=function(){},this.socket.ondata=function(){},this.socket.disconnect(),this.ondisconnect({socket:this.socket,error:!1})}},{key:"send",value:function(e){if(u.debug("send()"),!this.isConnected())return u.warn("unable to send message, transport is not connected"),!1;var t=e.toString();return u.debug("sending message:\n\n".concat(t,"\n")),this.socket.send(t)}},{key:"isConnected",value:function(){return this.status===c.STATUS_CONNECTED}},{key:"isConnecting",value:function(){return this.status===c.STATUS_CONNECTING}},{key:"_get_number_of_sbc",value:function(){return this.sockets.length}},{key:"_switch_sbc",value:function(){var e=this.ondisconnect;this.ondisconnect=function(){},this.disconnect(),this.ondisconnect=e,this.close_requested=!1,this.sockets.forEach(function(e){this.socket===e.socket&&(e.status=c.SOCKET_STATUS_ERROR)},this),this._getSocket(),this.connect()}},{key:"_register_redirect",value:function(e){var t,n=null,i=r(this.sockets);try{for(i.s();!(t=i.n()).done;){var s=t.value;if(s.socket.url===e){n=s.socket;break}}}catch(e){i.e(e)}finally{i.f()}if(null===n&&!e.includes(":",6)){e+=":443";var o,l=r(this.sockets);try{for(l.s();!(o=l.n()).done;){var a=o.value;if(a.socket.url===e){n=a.socket;break}}}catch(e){l.e(e)}finally{l.f()}}if(null===n)return!1;var u=this.ondisconnect;return this.ondisconnect=function(){},this.disconnect(),this.ondisconnect=u,this.socket=n,this.connect(),!0}},{key:"_reconnect",value:function(){var e=this;this.recover_attempts+=1;var t=Math.floor(Math.random()*Math.pow(2,this.recover_attempts)+1);tthis.recovery_options.max_interval&&(t=this.recovery_options.max_interval),u.debug("reconnection attempt: ".concat(this.recover_attempts,". next connection attempt in ").concat(t," seconds")),this.recovery_timer=setTimeout(function(){e.close_requested||e.isConnected()||e.isConnecting()||(e._getSocket(),e.connect())},1e3*t)}},{key:"_getSocket",value:function(){var e=[];if(this.sockets.forEach(function(t){t.status!==c.SOCKET_STATUS_ERROR&&(0===e.length?e.push(t):t.weight>e[0].weight?e=[t]:t.weight===e[0].weight&&e.push(t))}),0===e.length)return this.sockets.forEach(function(e){e.status=c.SOCKET_STATUS_READY}),void this._getSocket();var t=Math.floor(Math.random()*e.length);this.socket=e[t].socket}},{key:"_onConnect",value:function(){this.recover_attempts=0,this._ha_connect_time=void 0,this.status=c.STATUS_CONNECTED,null!==this.recovery_timer&&(clearTimeout(this.recovery_timer),this.recovery_timer=null),this.onconnect({socket:this})}},{key:"_onDisconnect",value:function(e,t,n){var r=this.status;if(this.status=c.STATUS_DISCONNECTED,this.ondisconnect({socket:this.socket,error:e,code:t,reason:n}),!this.close_requested){if(void 0!==this._ua.modes.sbc_ha_pairs_mode){if(r===c.STATUS_CONNECTED)return u.debug("AC: SBC HA pairs mode: Reconnect to the same SBC ".concat(this._ua.modes.sbc_ha_pairs_mode," seconds left")),this._ha_connect_time=(new Date).getTime()+1e3*this._ua.modes.sbc_ha_pairs_mode,void this._connect2();if(void 0!==this._ha_connect_time){var i=this._ha_connect_time-(new Date).getTime();if(i>0)return u.debug("AC: SBC HA pairs mode: Repeat ".concat(i/1e3," seconds left")),void this._connect2();u.debug("AC: SBC HA pairs mode: Failed"),this._ha_connect_time=void 0}}this.sockets.forEach(function(e){this.socket===e.socket&&(e.status=c.SOCKET_STATUS_ERROR)},this),this._reconnect()}}},{key:"_connect2",value:function(){var e=this,t=0;if(this._ha_last_connect){var n=(new Date).getTime()-this._ha_last_connect;t=n>500?0:500-n}this.recovery_timer=setTimeout(function(){e.close_requested||e.isConnected()||e.isConnecting()||(e._ha_last_connect=(new Date).getTime(),e.connect())},t)}},{key:"_onData",value:function(e){if("\r\n"!==e){if("string"!=typeof e){try{e=this.textDecoder?this.textDecoder.decode(e):String.fromCharCode.apply(null,new Uint8Array(e))}catch(e){return void u.debug("received binary message failed to be converted into string, message discarded")}u.debug("received binary message:\n\n".concat(e,"\n"))}else u.debug("received text message:\n\n".concat(e,"\n"));this.ondata({transport:this,message:e})}else u.debug("received message with CRLF Keep Alive response")}}])&&s(t.prototype,n),i&&s(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Logger":9,"./Socket":23}],28:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{},t=e.anonymous||null,n=e.outbound||null,r="<";return r+=t?this.temp_gruu||"sip:anonymous@anonymous.invalid;transport=ws":this.pub_gruu||this.uri.toString(),!n||(t?this.temp_gruu:this.pub_gruu)||(r+=";ob"),r+=">"}};var r=["authorization_user","password","realm","ha1","authorization_jwt","display_name","register"];for(var i in this._configuration)Object.prototype.hasOwnProperty.call(this._configuration,i)&&(-1!==r.indexOf(i)?Object.defineProperty(this._configuration,i,{writable:!0,configurable:!1}):Object.defineProperty(this._configuration,i,{writable:!1,configurable:!1}));for(var s in R.debug("configuration parameters after validation:"),this._configuration)if(Object.prototype.hasOwnProperty.call(w.settings,s))switch(s){case"uri":case"registrar_server":R.debug("- ".concat(s,": ").concat(this._configuration[s]));break;case"password":case"ha1":case"authorization_jwt":R.debug("- ".concat(s,": NOT SHOWN"));break;default:R.debug("- ".concat(s,": ").concat(JSON.stringify(this._configuration[s])))}}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),c}()},{"./Config":1,"./Constants":2,"./Exceptions":6,"./Logger":9,"./Message":10,"./Notifier":12,"./Options":13,"./Parser":14,"./RTCSession":15,"./Registrator":20,"./SIPMessage":22,"./Subscriber":24,"./Transactions":26,"./Transport":27,"./URI":29,"./Utils":30,"./sanityCheck":32,events:33}],29:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,s=function(){};return{s:s,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n4&&void 0!==arguments[4]?arguments[4]:{},l=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{};if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),!r)throw new TypeError('missing or invalid "host" parameter');for(var a in this._parameters={},this._headers={},this._scheme=t||o.SIP,this._user=n,this._host=r,this._port=i,s)Object.prototype.hasOwnProperty.call(s,a)&&this.setParam(a,s[a]);for(var u in l)Object.prototype.hasOwnProperty.call(l,u)&&this.setHeader(u,l[u])}var t,n,i;return t=e,i=[{key:"parse",value:function(e){return-1!==(e=a.parse(e,"SIP_URI"))?e:void 0}}],(n=[{key:"scheme",get:function(){return this._scheme},set:function(e){this._scheme=e.toLowerCase()}},{key:"user",get:function(){return this._user},set:function(e){this._user=e}},{key:"host",get:function(){return this._host},set:function(e){this._host=e.toLowerCase()}},{key:"port",get:function(){return this._port},set:function(e){this._port=0===e?e:parseInt(e,10)||null}},{key:"setParam",value:function(e,t){e&&(this._parameters[e.toLowerCase()]=null==t?null:t.toString())}},{key:"getParam",value:function(e){if(e)return this._parameters[e.toLowerCase()]}},{key:"hasParam",value:function(e){if(e)return!!this._parameters.hasOwnProperty(e.toLowerCase())}},{key:"deleteParam",value:function(e){if(e=e.toLowerCase(),this._parameters.hasOwnProperty(e)){var t=this._parameters[e];return delete this._parameters[e],t}}},{key:"clearParams",value:function(){this._parameters={}}},{key:"setHeader",value:function(e,t){this._headers[l.headerize(e)]=Array.isArray(t)?t:[t]}},{key:"getHeader",value:function(e){if(e)return this._headers[l.headerize(e)]}},{key:"hasHeader",value:function(e){if(e)return!!this._headers.hasOwnProperty(l.headerize(e))}},{key:"deleteHeader",value:function(e){if(e=l.headerize(e),this._headers.hasOwnProperty(e)){var t=this._headers[e];return delete this._headers[e],t}}},{key:"clearHeaders",value:function(){this._headers={}}},{key:"clone",value:function(){return new e(this._scheme,this._user,this._host,this._port,JSON.parse(JSON.stringify(this._parameters)),JSON.parse(JSON.stringify(this._headers)))}},{key:"toString",value:function(){var e=[],t="".concat(this._scheme,":");for(var n in this._user&&(t+="".concat(l.escapeUser(this._user),"@")),t+=this._host,(this._port||0===this._port)&&(t+=":".concat(this._port)),this._parameters)Object.prototype.hasOwnProperty.call(this._parameters,n)&&(t+=";".concat(n),null!==this._parameters[n]&&(t+="=".concat(this._parameters[n])));for(var i in this._headers)if(Object.prototype.hasOwnProperty.call(this._headers,i)){var s,o=r(this._headers[i]);try{for(o.s();!(s=o.n()).done;){var a=s.value;e.push("".concat(i,"=").concat(a))}}catch(e){o.e(e)}finally{o.f()}}return e.length>0&&(t+="?".concat(e.join("&"))),t}},{key:"toAor",value:function(e){var t="".concat(this._scheme,":");return this._user&&(t+="".concat(l.escapeUser(this._user),"@")),t+=this._host,e&&(this._port||0===this._port)&&(t+=":".concat(this._port)),t}}])&&s(t.prototype,n),i&&s(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Grammar":7,"./Utils":30}],30:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return s(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:32,r="";for(t=0;t>>32-t}function n(e,t){var n=2147483648&e,r=2147483648&t,i=1073741824&e,s=1073741824&t,o=(1073741823&e)+(1073741823&t);return i&s?2147483648^o^n^r:i|s?1073741824&o?3221225472^o^n^r:1073741824^o^n^r:o^n^r}function r(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return e&t|~e&n}(r,i,s),o),a)),n(t(e,l),r)}function i(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return e&n|t&~n}(r,i,s),o),a)),n(t(e,l),r)}function s(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return e^t^n}(r,i,s),o),a)),n(t(e,l),r)}function o(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return t^(e|~n)}(r,i,s),o),a)),n(t(e,l),r)}function l(e){var t,n="",r="";for(t=0;t<=3;t++)n+=(r="0".concat((e>>>8*t&255).toString(16))).substr(r.length-2,2);return n}var a,u,c,h,d,f,_,p,m,v;for(a=function(e){for(var t,n=e.length,r=n+8,i=16*((r-r%64)/64+1),s=new Array(i-1),o=0,l=0;l>>29,s}(e=function(e){for(var t="",n=0;n127&&r<2048?(t+=String.fromCharCode(r>>6|192),t+=String.fromCharCode(63&r|128)):(t+=String.fromCharCode(r>>12|224),t+=String.fromCharCode(r>>6&63|128),t+=String.fromCharCode(63&r|128))}return t}(e)),_=1732584193,p=4023233417,m=2562383102,v=271733878,u=0;u1&&void 0!==arguments[1]?arguments[1]:{};return e&&Object.assign({},e)||t}},{"./Constants":2,"./Grammar":7,"./URI":29}],31:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1)return d.debug("more than one Via header field present in the response, dropping the response"),!1},function(){var e=h.str_utf8_length(s.body),t=s.getHeader("content-length");if(e0&&l.length>s){l.warned=!0;var a=new Error("Possible EventEmitter memory leak detected. "+l.length+' "'+String(t)+'" listeners added. Use emitter.setMaxListeners() to increase limit.');a.name="MaxListenersExceededWarning",a.emitter=e,a.type=t,a.count=l.length,"object"==typeof console&&console.warn&&console.warn("%s: %s",a.name,a.message)}}else l=o[t]=n,++e._eventsCount;return e}function d(){if(!this.fired)switch(this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length){case 0:return this.listener.call(this.target);case 1:return this.listener.call(this.target,arguments[0]);case 2:return this.listener.call(this.target,arguments[0],arguments[1]);case 3:return this.listener.call(this.target,arguments[0],arguments[1],arguments[2]);default:for(var e=new Array(arguments.length),t=0;t1&&(t=arguments[1]),t instanceof Error)throw t;var a=new Error('Unhandled "error" event. ('+t+")");throw a.context=t,a}if(!(n=o[e]))return!1;var u="function"==typeof n;switch(r=arguments.length){case 1:!function(e,t,n){if(t)e.call(n);else for(var r=e.length,i=m(e,r),s=0;s=0;o--)if(n[o]===t||n[o].listener===t){l=n[o].listener,s=o;break}if(s<0)return this;0===s?n.shift():function(e,t){for(var n=t,r=n+1,i=e.length;r=0;s--)this.removeListener(e,t[s]);return this},o.prototype.listeners=function(e){return _(this,e,!0)},o.prototype.rawListeners=function(e){return _(this,e,!1)},o.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):p.call(e,t)},o.prototype.listenerCount=p,o.prototype.eventNames=function(){return this._eventsCount>0?Reflect.ownKeys(this._events):[]}},{}],34:[function(e,t,n){(function(r){(function(){n.formatArgs=function(e){if(e[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+e[0]+(this.useColors?"%c ":" ")+"+"+t.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;e.splice(1,0,n,"color: inherit");let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,e=>{"%%"!==e&&(r++,"%c"===e&&(i=r))}),e.splice(i,0,n)},n.save=function(e){try{e?n.storage.setItem("debug",e):n.storage.removeItem("debug")}catch(e){}},n.load=function(){let e;try{e=n.storage.getItem("debug")}catch(e){}!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG);return e},n.useColors=function(){if("undefined"!=typeof window&&window.process&&("renderer"===window.process.type||window.process.__nwjs))return!0;if("undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;return"undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},n.storage=function(){try{return localStorage}catch(e){}}(),n.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),n.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],n.log=console.debug||console.log||(()=>{}),t.exports=e("./common")(n);const{formatters:i}=t.exports;i.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}}).call(this)}).call(this,e("_process"))},{"./common":35,_process:37}],35:[function(e,t,n){t.exports=function(t){function n(e){let t,i,s,o=null;function l(...e){if(!l.enabled)return;const r=l,i=Number(new Date),s=i-(t||i);r.diff=s,r.prev=t,r.curr=i,t=i,e[0]=n.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let o=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(t,i)=>{if("%%"===t)return"%";o++;const s=n.formatters[i];if("function"==typeof s){const n=e[o];t=s.call(r,n),e.splice(o,1),o--}return t}),n.formatArgs.call(r,e),(r.log||n.log).apply(r,e)}return l.namespace=e,l.useColors=n.useColors(),l.color=n.selectColor(e),l.extend=r,l.destroy=n.destroy,Object.defineProperty(l,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==o?o:(i!==n.namespaces&&(i=n.namespaces,s=n.enabled(e)),s),set:e=>{o=e}}),"function"==typeof n.init&&n.init(l),l}function r(e,t){const r=n(this.namespace+(void 0===t?":":t)+e);return r.log=this.log,r}function i(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return n.debug=n,n.default=n,n.coerce=function(e){return e instanceof Error?e.stack||e.message:e},n.disable=function(){const e=[...n.names.map(i),...n.skips.map(i).map(e=>"-"+e)].join(",");return n.enable(""),e},n.enable=function(e){let t;n.save(e),n.namespaces=e,n.names=[],n.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),i=r.length;for(t=0;t{n[e]=t[e]}),n.names=[],n.skips=[],n.formatters={},n.selectColor=function(e){let t=0;for(let n=0;n=1.5*n;return Math.round(e/n)+" "+r+(i?"s":"")}t.exports=function(e,t){t=t||{};var n=typeof e;if("string"===n&&e.length>0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var n=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return n*a;case"weeks":case"week":case"w":return n*l;case"days":case"day":case"d":return n*o;case"hours":case"hour":case"hrs":case"hr":case"h":return n*s;case"minutes":case"minute":case"mins":case"min":case"m":return n*i;case"seconds":case"second":case"secs":case"sec":case"s":return n*r;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}(e);if("number"===n&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=o)return u(e,t,o,"day");if(t>=s)return u(e,t,s,"hour");if(t>=i)return u(e,t,i,"minute");if(t>=r)return u(e,t,r,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=o)return Math.round(e/o)+"d";if(t>=s)return Math.round(e/s)+"h";if(t>=i)return Math.round(e/i)+"m";if(t>=r)return Math.round(e/r)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],37:[function(e,t,n){var r,i,s=t.exports={};function o(){throw new Error("setTimeout has not been defined")}function l(){throw new Error("clearTimeout has not been defined")}function a(e){if(r===setTimeout)return setTimeout(e,0);if((r===o||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch(t){try{return r.call(null,e,0)}catch(t){return r.call(this,e,0)}}}!function(){try{r="function"==typeof setTimeout?setTimeout:o}catch(e){r=o}try{i="function"==typeof clearTimeout?clearTimeout:l}catch(e){i=l}}();var u,c=[],h=!1,d=-1;function f(){h&&u&&(h=!1,u.length?c=u.concat(c):d=-1,c.length&&_())}function _(){if(!h){var e=a(f);h=!0;for(var t=c.length;t;){for(u=c,c=[];++d1)for(var n=1;n1&&(e[n[0]]=void 0),e};n.parseParams=function(e){return e.split(/;\s?/).reduce(l,{})},n.parseFmtpConfig=n.parseParams,n.parsePayloads=function(e){return e.toString().split(" ").map(Number)},n.parseRemoteCandidates=function(e){for(var t=[],n=e.split(" ").map(r),i=0;i=r)return e;var i=n[t];switch(t+=1,e){case"%%":return"%";case"%s":return String(i);case"%d":return Number(i);case"%v":return""}})}.apply(null,r)},o=["v","o","s","i","u","e","p","c","b","t","r","z","a"],l=["i","c","b","a"];t.exports=function(e,t){t=t||{},null==e.version&&(e.version=0),null==e.name&&(e.name=" "),e.media.forEach(function(e){null==e.payloads&&(e.payloads="")});var n=t.outerOrder||o,i=t.innerOrder||l,a=[];return n.forEach(function(t){r[t].forEach(function(n){n.name in e&&null!=e[n.name]?a.push(s(t,n,e)):n.push in e&&null!=e[n.push]&&e[n.push].forEach(function(e){a.push(s(t,n,e))})})}),e.media.forEach(function(e){a.push(s("m",r.m[0],e)),i.forEach(function(t){r[t].forEach(function(n){n.name in e&&null!=e[n.name]?a.push(s(t,n,e)):n.push in e&&null!=e[n.push]&&e[n.push].forEach(function(e){a.push(s(t,n,e))})})})}),a.join("\r\n")+"\r\n"}},{"./grammar":38}],42:[function(e,t,n){t.exports={name:"jssip",title:"JsSIP",description:"the Javascript SIP library",version:"3.10.0",homepage:"https://jssip.net",contributors:["José Luis Millán (https://github.com/jmillan)","Iñaki Baz Castillo (https://inakibaz.me)"],types:"lib/JsSIP.d.ts",main:"lib-es5/JsSIP.js",keywords:["sip","websocket","webrtc","node","browser","library"],license:"MIT",repository:{type:"git",url:"https://github.com/versatica/JsSIP.git"},bugs:{url:"https://github.com/versatica/JsSIP/issues"},dependencies:{"@types/events":"^3.0.0","@types/debug":"^4.1.7",debug:"^4.3.1",events:"^3.3.0","sdp-transform":"^2.14.1"},devDependencies:{"@babel/core":"^7.19.6","@babel/preset-env":"^7.19.4","ansi-colors":"^3.2.4",browserify:"^16.5.1",eslint:"^5.16.0","fancy-log":"^1.3.3",gulp:"^4.0.2","gulp-babel":"^8.0.0","gulp-eslint":"^5.0.0","gulp-expect-file":"^1.0.2","gulp-header":"^2.0.9","gulp-nodeunit-runner":"^0.2.2","gulp-plumber":"^1.2.1","gulp-rename":"^1.4.0","gulp-uglify-es":"^1.0.4",pegjs:"^0.7.0","vinyl-buffer":"^1.0.1","vinyl-source-stream":"^2.0.0"},scripts:{lint:"node npm-scripts.js lint",test:"node npm-scripts.js test",prepublish:"node npm-scripts.js prepublish",release:"node npm-scripts.js release"}}},{}]},{},[8])(8)}); + +"use strict"; +/* + * AudioCodes WebRTC API v1.19.0 + * © 2023 AudioCodes Ltd. All rights reserved. + * + */class AudioCodesUA{constructor(){return this._isInitialized=!1,this.serverConfig={},this.account={user:null,userAuth:null,displayName:null,password:null,registerExpires:600,useSessionTimer:!1},this.constraints={audio:!0,video:!0},this.chromiumBased=[{n:"Edge",s:"edg/"},{n:"Opera",s:"opr/"},{n:"Samsung",s:"samsungbrowser/"},{n:"Yandex",s:"yabrowser/"}],this.modes={video_call_audio_answer_firefox_fix:!0,video_call_audio_answer_safari_fix:!0,ice_timeout_fix:2e3,chrome_rtp_timeout_fix:13,sbc_ha_pairs_mode:void 0,ringing_header_mode:void 0,sbc_switch_register5xx_mode:!0,cache_register_auth_mode:!0,check_remote_sdp_mode:!0},this.credentials=[],this.listeners={},this.registerExtraHeaders=null,this.jssipUA=null,this.browser="",this.browserVersion=0,this.browserName="",this.os="other",this.reconnectMin=2,this.reconnectMax=30,this.u17=void 0,this.activeCalls=0,this.wsPingStarted=!1,this.wsSocket=null,this.wsOnMessage=null,this.wsPingMs=0,this.wsOrigPingMs=0,this.wsThrottlingPingMs=0,this.wsVisibility=!1,this.wsCall=!1,this.wsLog=0,this.wsPongTimeout=!0,this.wsIsThrottling=!1,this.wsPingJob=null,this.wsPingTime=null,this.wsNextPingTime=null,this.wsPongReceived=!1,this.wsPongSupported=null,this.wsPongTimeoutTime=null,this.wsPongDelays=null,this.wsPongDelaysIx=0,this.wsPongReport=0,this.wsPongReportCounter=0,this.wsPongDist=!1,this.wsIsPingDebugLog=!1,this.dtmfUseWebRTC=!0,this.dtmfDuration=250,this.dtmfInterToneGap=250,this.enableAddVideo=!1,this.oauthToken=null,this.oauthTokenUseInInvite=!0,this.networkPriority=void 0,AudioCodesUA.ac_log=console.log,AudioCodesUA.js_log=null,void 0===AudioCodesUA.instance&&(AudioCodesUA.instance=this),this._detectBrowser(),this._detectOS(),this.webrtcapi=AudioCodesWebRTCWrapper,this.replacedCall=null,this.codecFilter=null,this.AUDIO=Symbol("audio"),this.VIDEO=Symbol("video"),this.RECVONLY_VIDEO=Symbol("recvonly_video"),AudioCodesUA.instance}version(){return"1.19.0"}getBrowserName(){return this.browserName}getBrowser(){return this.browser}getBrowserVersion(){return this.browserVersion}getOS(){return this.os}getWR(){return this.webrtcapi}checkAvailableDevices(){return this.getWR().checkAvailableDevices()}getServerAddress(){if(null===this.wsSocket)return null;let e=this.wsSocket.url;return e.endsWith("/")&&(e=e.slice(0,-1)),e}setOAuthToken(e,i=!0){this.oauthToken=e,this.oauthTokenUseInInvite=i,this.setRegisterExtraHeaders(this.registerExtraHeaders)}setUserAgent(e){this.u17=e}setConstraints(e,i,s){let t=this.browser,o=this.browser+"|"+this.os;if(null===e||e===t||e===o){if(AudioCodesUA.ac_log(`AC: setConstraints ${e} ${i} ${JSON.stringify(s)}`),"audio"!==i&&"video"!==i)throw new TypeError(`Wrong type: ${i}`);this.constraints[i]=s}else AudioCodesUA.ac_log(`AC: setConstraints ${e} - ignored, no current browser`)}setConstraint(e,i,s){if(null!==s&&void 0!==s?AudioCodesUA.ac_log(`AC: setConstraint ${e} ${i}=${JSON.stringify(s)}`):AudioCodesUA.ac_log(`AC: setConstraint remove ${e} ${i}`),"audio"!==e&&"video"!==e)throw new TypeError(`Wrong type: ${e}`);null!==s&&void 0!==s?(!0===this.constraints[e]&&(this.constraints[e]={}),this.constraints[e][i]=s):!0!==this.constraints[e]&&!1!==this.constraints[e]&&(delete this.constraints[e][i],0===Object.keys(this.constraints[e]).length&&(this.constraints[e]=!0))}setBrowsersConstraints(e){let i=this.browser,s=this.browser+"|"+this.os;for(let t in e){if(t!==i&&t!==s)continue;let o=e[t];void 0!==o.audio&&this.setConstraints(t,"audio",o.audio),void 0!==o.video&&this.setConstraints(t,"video",o.video)}}setCodecFilter(e){e&&(AudioCodesUA.ac_log(`AC: setCodecFilter ${JSON.stringify(e)}`),this.codecFilter=this._cf_unpack(e))}setServerConfig(e,i,s=[]){this.serverConfig={addresses:e,domain:i,iceServers:this._convertIceList(s)},AudioCodesUA.ac_log(`AC: setServerConfig() ${JSON.stringify(this.serverConfig)}`)}setReconnectIntervals(e,i){AudioCodesUA.ac_log(`AC: setReconnectIntervals min=${e} max=${i}`),this.reconnectMin=e,this.reconnectMax=i}setAccount(e,i,s,t){void 0!==i&&null!==i&&0!==i.length||(i=void 0),void 0!==t&&null!==t&&0!==t.length||(t=e);let o=this.account;o.user=e,o.displayName=i,o.password=s,o.authUser=t}setRegisterExpires(e){AudioCodesUA.ac_log(`AC: setRegisterExpires=${e}`),this.account.registerExpires=e}setUseSessionTimer(e){AudioCodesUA.ac_log(`AC: setUseSessionTimer=${e}`),this.account.useSessionTimer=e}setDtmfOptions(e,i=null,s=null){AudioCodesUA.ac_log(`AC: setDtmfOptions useWebRTC=${e} duration=${i} interToneGap=${s}`),this.dtmfUseWebRTC=e,null!==i&&(this.dtmfDuration=i),null!==s&&(this.dtmfInterToneGap=s)}setEnableAddVideo(e){AudioCodesUA.ac_log(`AC: setEnableAddVideo=${e}`),this.enableAddVideo=e}getEnableAddVideo(){return this.enableAddVideo}getAccount(){return this.account}setListeners(e){AudioCodesUA.ac_log("AC: setListeners()");for(let i of["loginStateChanged","outgoingCallProgress","callTerminated","callConfirmed","callShowStreams","incomingCall","callHoldStateChanged"])if(!(i in e))throw new Error(`${i} listener is missed`);this.listeners=e}static getSessionStatusName(e){switch(e){case 0:return"NULL (0)";case 1:return"INVITE_SENT (1)";case 2:return"1XX_RECEIVED (2)";case 3:return"INVITE_RECEIVED (3)";case 4:return"WAITING_FOR_ANSWER (4)";case 5:return"ANSWERED (5)";case 6:return"WAITING_FOR_ACK (6)";case 7:return"CANCELED (7)";case 8:return"TERMINATED (8)";case 9:return"CONFIRMED (9)";default:return"Unknown ("+e+")"}}setAcLogger(e){AudioCodesUA.ac_log=e}setJsSipLogger(e){AudioCodesUA.js_log=e}isInitialized(){return this._isInitialized}setModes(e={}){AudioCodesUA.ac_log(`AC: setModes() ${JSON.stringify(e)}`),Object.assign(this.modes,e),this._normalizeModes()}_normalizeModes(){function e(e,i){return"number"==typeof e&&e<=i?void 0:e}let i=this.modes;i.sbc_ha_pairs_mode=e(i.sbc_ha_pairs_mode,0),i.chrome_rtp_timeout_fix=e(i.chrome_rtp_timeout_fix,0)}init(e=!0){if(AudioCodesUA.ac_log(`AC: init() autoLogin=${e}`),this._isInitialized)return;this._isInitialized=!0,JsSIP.debug.enable("JsSIP:*"),JsSIP.debug.formatArgs=function(){AudioCodesUA.js_log&&(this.log=AudioCodesUA.js_log)};let i=[];for(let e of this.serverConfig.addresses)e instanceof Array?i.push({socket:new JsSIP.WebSocketInterface(e[0]),weight:e[1]}):i.push(new JsSIP.WebSocketInterface(e));let s={sockets:i,uri:"sip:"+this.account.user+"@"+this.serverConfig.domain,contact_uri:"sip:"+this.account.user+"@"+this._randomToken(12)+".invalid;transport=ws",authorization_user:this.account.authUser,password:this.account.password,register:e,session_timers:this.account.useSessionTimer,register_expires:this.account.registerExpires,user_agent:this.u17,connection_recovery_min_interval:this.reconnectMin,connection_recovery_max_interval:this.reconnectMax};this.account.displayName&&this.account.displayName.length>0&&(s.display_name=this.account.displayName),this.jssipUA=new JsSIP.UA(s),this.setRegisterExtraHeaders(this.registerExtraHeaders),this._setUACallbacks(),AudioCodesUA.ac_log(`AC: applied SDK modes: ${JSON.stringify(this.modes,(e,i)=>void 0===i?"":i)}`),this.jssipUA.modes=this.modes;for(let e of this.credentials)this.jssipUA.addCredential(e);this.credentials=[],this.jssipUA.start()}deinit(){this._isInitialized=!1,this.jssipUA&&this.jssipUA.stop()}setRegisterExtraHeaders(e){if(this.registerExtraHeaders=e,this.jssipUA){let i=null!==e?e:[];null!==this.oauthToken&&(i=i.slice()).push(`Authorization: Bearer ${this.oauthToken}`),this.jssipUA.registrator().setExtraHeaders(i)}}getRegisterExtraHeaders(){return this.registerExtraHeaders}login(){AudioCodesUA.ac_log("AC: login()"),this.jssipUA.register()}logout(){AudioCodesUA.ac_log("AC: logout()"),this.jssipUA.isRegistered()&&this.jssipUA.unregister()}switchSBC(e=!0){return AudioCodesUA.ac_log("AC: switchSBC()"),this.jssipUA.switchSBC(e)}getNumberOfSBC(){return this.jssipUA.getNumberOfSBC()}setWebSocketKeepAlive(e,i=!0,s=!0,t=0,o=!1){if(AudioCodesUA.ac_log(`AC: setWebSocketKeepAlive pingInterval=${e} pongTimeout=${i}`+` timerThrottlingBestEffort=${JSON.stringify(s)} pongReport=${t} pongDist=${o}`),"number"!=typeof e||"boolean"!=typeof i)throw new TypeError("setWebSocketKeepAlive: wrong type of first or second argument");let n;this.wsPingMs=this.wsOrigPingMs=1e3*e,this.wsPongTimeout=i,this.wsPongReport=t,this.wsPongDist=o,this.wsPongReportCounter=0,this.wsIsThrottling=!1;let r=(n=!0===s?{log:0,chrome:{interval:1,visibility:!0,call:!0,log:1}}:!1===s?{log:0}:s)[this.browser];this.wsThrottlingPingMs=r&&void 0!==r.interval?1e3*r.interval:0,this.wsVisibility=!(!r||void 0===r.visibility)&&r.visibility,this.wsCall=!(!r||void 0===r.call)&&r.call,this.wsLog=r&&void 0!==r.log?r.log:n.log,this.wsPongDelays=new Array(this.wsPongReport>0?this.wsPongReport:50),this.wsPongDelaysIx=0,0!==this.wsOrigPingMs&&0!==this.wsThrottlingPingMs&&this.wsVisibility&&document.addEventListener("visibilitychange",this._onVisibilityChange.bind(this))}_pingLog(){return` (ping=${this.wsPingMs/1e3} sec)`}_visibilityLog(e){let i="AC: keep-alive: Page is "+(document.hidden?"hidden":"visible");document.hidden&&(this.wsCall&&(i+=", "+(0===this.activeCalls?"no active call":"active call")),i+=" and "+(this.wsIsThrottling?"was":"was not")+" trottling"),e&&(i+=this._pingLog()),AudioCodesUA.ac_log(i)}_activeCallsLog(e){let i=`AC: keep-alive: ${0===this.activeCalls?"Call ended":"Call started"}`;0===this.activeCalls&&(this.wsVisibility&&(i+=", page is "+(document.hidden?"hidden":"visible")),i+=" and "+(this.wsIsThrottling?"was":"was not")+" trottling"),e&&(i+=this._pingLog()),AudioCodesUA.ac_log(i)}_onActiveCallsChange(e){if(this.activeCalls+=e,this.wsCall&&0!==this.wsPingMs&&0!==this.wsThrottlingPingMs)if(this.activeCalls<0&&AudioCodesUA.ac_log("Warning: keep-alive: activeCalls < 0"),0===this.activeCalls){if((!this.wsVisibility||document.hidden)&&this.wsIsThrottling&&this.wsPingMs=2&&this._activeCallsLog(!1)}else if(1===this.activeCalls&&e>0){if(this.wsPingMs>this.wsOrigPingMs)return this.wsPingMs=this.wsOrigPingMs,void this._activeCallsLog(!0);this.wsLog>=2&&this._activeCallsLog(!1)}}_onVisibilityChange(){if(this.wsVisibility&&0!==this.wsPingMs&&0!==this.wsThrottlingPingMs)if(document.hidden){if(this.wsCall&&0===this.activeCalls&&this.wsIsThrottling&&this.wsPingMs=2&&this._visibilityLog(!1)}else{if(this.wsPingMs>this.wsOrigPingMs)return this.wsPingMs=this.wsOrigPingMs,void this._visibilityLog(!0);this.wsLog>=2&&this._visibilityLog(!1)}}_onMessageHook(e){"\r\n"===e.data?this._onPong():this.wsOnMessage(e)}_onPong(){if(!this.wsPingStarted)return;let e;this.wsPongReceived=!0,null===this.wsPongSupported&&(AudioCodesUA.ac_log("AC: keep-alive: Server supports CRLF pong"),this.wsPongSupported=!0),null!==this.wsPongTimeoutTime?(e=Date.now()-this.wsPongTimeoutTime,this.wsPongTimeoutTime=null,AudioCodesUA.ac_log(`AC: keep-alive: Received pong that exceeded the timeout, delay=${e}`)):e=Date.now()-this.wsPingTime;let i=this.wsPingMs-e;i<0&&(AudioCodesUA.ac_log(`AC: nextPing calculated to ${i}ms, so resetting to 0ms.`),i=0),null!==this.wsPingJob&&clearTimeout(this.wsPingJob),this.wsPingJob=setTimeout(this._sendPing.bind(this),i),this.wsPongDelays[this.wsPongDelaysIx]=e,this.wsPongDelaysIx=this.wsPongDelaysIx+1,this.wsPongDelaysIx===this.wsPongDelays.length&&(this.wsPongDelaysIx=0),this.wsPongReport>0&&this.wsPongReportCounter++}_onPongTimeout(e){if(AudioCodesUA.ac_log(`AC: keep-alive: Pong timeout (not received within ${e/1e3} seconds)`),AudioCodesUA.ac_log(`AC: keep-alive: Previous pongs statistics: ${this._createPongReport(!0)}`),this.wsPongTimeout){AudioCodesUA.ac_log("AC: keep-alive: Close websocket connection"),this._stopWsKeepAlive();let e=this.wsSocket;e.onopen=void 0,e.onerror=void 0,e.onclose=void 0,e.onmessage=void 0,setTimeout(()=>{try{e.close()}catch(e){AudioCodesUA.ac_log("AC: Close websocket error",e)}},0),this.wsWebSocketInterface._ws=null,this.wsWebSocketInterface._onClose.call(this.wsWebSocketInterface,{wasClean:!1,code:1001,reason:"Going Away"})}else AudioCodesUA.ac_log("AC: keep-alive: Warning: websocket is not closed, because pongTimeout=false")}_sendPing(){try{let e=Date.now();if(null!==this.wsPingTime){let i=e-this.wsNextPingTime;this.wsLog>=3&&AudioCodesUA.ac_log(`AC: keep-alive: timer deviation (ms): ${i}`);let s=this.wsPingMs;if(Math.abs(i)>=1e4&&((this.wsLog>0||!this.wsIsThrottling)&&(AudioCodesUA.ac_log(`AC: keep-alive detected timer throttling: ${Math.round(i/1e3)} seconds ${i>0?"later":"earlier"}`),0===this.wsLog&&AudioCodesUA.ac_log("AC: keep-alive: The next timer throttling will not be shown in the logs, because log==0")),this.wsIsThrottling=!0,this.wsPingMs0&&this.wsPongReportCounter>=this.wsPongReport&&(this.wsPongReportCounter=0,AudioCodesUA.ac_log(`AC: keep-alive: Pong statistics: ${this._createPongReport(this.wsPongDist)}`))}catch(e){AudioCodesUA.ac_log("AC: keep-alive: send ping error",e)}}_startWsKeepAlive(){let e=this.jssipUA._transport;this.wsWebSocketInterface=e.socket,this.wsSocket=this.wsWebSocketInterface._ws,0!==this.wsPingMs&&(this.wsOnMessage=this.wsSocket.onmessage,this.wsSocket.onmessage=this._onMessageHook.bind(this),this._stopWsKeepAlive(),this.wsPingTime=null,this.wsPingStarted=!0,this.wsPongSupported=null,this.wsPingJob=setTimeout(this._sendPing.bind(this),this.wsPingMs))}_stopWsKeepAlive(){this.wsPingStarted=!1,null!==this.wsPingJob&&(clearTimeout(this.wsPingJob),this.wsPingJob=null)}_createPongReport(e){let i,s="",t=!1,o=1e6,n=0;e&&(i=new Array(this.wsPingMs/1e3*4).fill(0));let r=0;for(let s=0;sn&&(n=a),e)){let e=Math.floor(a/250);e>=i.length&&(e=i.length-1,t=!0),i[e]++}}if(e){s="\r\npongs distribution (1/4 second step): ";for(let e=0;e{AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "connected"'),this._startWsKeepAlive(),this.listeners.loginStateChanged(!1,"connected",null)}),this.jssipUA.on("disconnected",()=>{this._stopWsKeepAlive(),AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "disconnected"'),this.listeners.loginStateChanged(!1,"disconnected",null)}),this.jssipUA.on("registered",e=>{AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=true "login"'),this.listeners.loginStateChanged(!0,"login",e.response)}),this.jssipUA.on("unregistered",e=>{AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "logout"'),this.listeners.loginStateChanged(!1,"logout",e.response)}),this.jssipUA.on("registrationFailed",e=>{let i=e.response?e.response.status_code:0;if(i>=300&&i<400){let i=e.response.parseHeader("contact");if(i){let e=i.uri,s="wss://"+e.host;if(e.port&&443!==e.port&&(s+=":"+e.port.toString()),AudioCodesUA.ac_log(`AC: registerRedirect("${s}")`),this.jssipUA.registerRedirect(s))return}else AudioCodesUA.ac_log('AC: 3xx response without "Contact" is ignored')}else if(i>=500&&i<600&&AudioCodesUA.instance.modes.sbc_switch_register5xx_mode&&AudioCodesUA.instance.switchSBC(!1))return;AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "login failed"'),this.listeners.loginStateChanged(!1,"login failed",e.response?e.response:null)}),this.listeners.incomingMessage&&this.jssipUA.on("newMessage",e=>{"remote"===e.originator&&(AudioCodesUA.ac_log("AC>>: incomingMessage",e),this.listeners.incomingMessage(null,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request))}),this.listeners.incomingNotify&&this.jssipUA.on("sipEvent",e=>{AudioCodesUA.ac_log("AC>>: incoming out of dialog NOTIFY",e),this.listeners.incomingNotify(null,e.event?e.event.event:null,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request)||e.request.reply(481)}),this.listeners.incomingSubscribe&&this.jssipUA.on("newSubscribe",e=>{let i=e.request,s=i.parseHeader("event"),t=i.getHeaders("accept");AudioCodesUA.ac_log("AC>>: incomingSubscribe",i,s.event,t);let o=this.listeners.incomingSubscribe(i,s.event,t);o>0&&i.reply(o)}),this.jssipUA.on("newRTCSession",function(e){AudioCodesUA.ac_log(`AC: event ${"remote"===e.originator?"incoming":"outgoing"} "newRTCSession"`,e);let i,s=new AudioCodesSession(e.session);if(s.js_session.on("sipEvent",function(e){if(!AudioCodesUA.instance.listeners.incomingNotify)return;let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: incoming NOTIFY",i,e),e.taken=AudioCodesUA.instance.listeners.incomingNotify(i,e.event?e.event.event:null,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request)}),s.js_session.on("newInfo",function(e){if(!AudioCodesUA.instance.listeners.incomingInfo)return;if("local"===e.originator)return;let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: incoming INFO",i,e),AudioCodesUA.instance.listeners.incomingInfo(i,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request)}),s.js_session.on("replaces",function(e){AudioCodesUA.instance.replacedCall=this.data.ac_session,AudioCodesUA.ac_log("AC>>: incoming INVITE with Replaces. This call will be replaced:",this.data.ac_session),e.accept()}),s.js_session.on("sdp",function(e){AudioCodesUA.instance._sdp_checking(this,e)}),s.js_session.on("connecting",function(e){AudioCodesUA.ac_log("AC>>: connecting");let i=AudioCodesUA.instance.codecFilter;i&&(AudioCodesUA.instance._cf_filter("audio",this.data.ac_session,i.audio),AudioCodesUA.instance._cf_filter("video",this.data.ac_session,i.video))}),s.js_session.on("reinvite",function(e){if(!AudioCodesUA.instance.listeners.callIncomingReinvite)return;let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: callIncomingReinvite start"),AudioCodesUA.instance.listeners.callIncomingReinvite(i,!0,e.request),e.callback=function(){AudioCodesUA.ac_log("AC>>: callIncomingIncomingReinvite end"),AudioCodesUA.instance.listeners.callIncomingReinvite(i,!1,null)}}),s.js_session.on("hold",function(e){let i=this.data.ac_session,s="remote"===e.originator;AudioCodesUA.ac_log(`AC>>: callHoldStateChanged isHold=true isRemote=${s} session:`,i),AudioCodesUA.instance.listeners.callHoldStateChanged(i,!0,s)}),s.js_session.on("unhold",function(e){let i=this.data.ac_session,s="remote"===e.originator;AudioCodesUA.ac_log(`AC>>: callHoldStateChanged isHold=false isRemote=${s} session:`,i),AudioCodesUA.instance.listeners.callHoldStateChanged(i,!1,s)}),s.js_session.on("progress",function(e){if("remote"===e.originator){let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: outgoingCallProgress",i),AudioCodesUA.instance.listeners.outgoingCallProgress(i,e.response)}}),s.js_session.on("failed",function(e){let i=this.data.ac_session,s=null;if("Redirected"===e.cause&&e.message&&e.message.headers){let i=e.message.parseHeader("Contact");i&&(s=i.uri.toString())}AudioCodesUA.ac_log("AC>>: callTerminated (failed)",i,e.cause,s),AudioCodesUA.instance.listeners.callTerminated(i,e.message,e.cause,s)}),s.js_session.on("accepted",function(e){let i=this.data.ac_session;i.data._accepted=!0,"remote"===e.originator&&(i.data._ok_response=e.response)}),"remote"===e.originator&&null!==AudioCodesUA.instance.replacedCall&&s.js_session.removeAllListeners("confirmed"),s.js_session.on("confirmed",function(){let e,i=this.data.ac_session,t=null;"_ok_response"in i.data?(t=i.data._ok_response,delete i.data._ok_response,e="ACK sent"):e="ACK received",s.data._video_call_audio_answer_firefox&&(s.data._video_call_audio_answer_firefox=!1,AudioCodesUA.ac_log("AC: [video call/audio answer] Firefox workaround. Send re-INVITE"),s.sendReInvite({showStreams:!0})),AudioCodesUA.ac_log("AC>>: callConfirmed",i,e),AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance,1),AudioCodesUA.instance.listeners.callConfirmed(i,t,e)}),s.js_session.on("ended",function(e){let i=this.data.ac_session;i.data._screenSharing&&i._onEndedScreenSharing.call(i,"call terminated"),AudioCodesUA.ac_log("AC>>: callTerminated (ended)",i,e.cause),AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance,-1),AudioCodesUA.instance.listeners.callTerminated(i,e.message,e.cause)}),s.js_session.on("refer",function(e){if(AudioCodesUA.instance.listeners.transfereeCreatedCall){let i,s=this.data.ac_session;if(i=!AudioCodesUA.instance.listeners.transfereeRefer||AudioCodesUA.instance.listeners.transfereeRefer(s,e.request)){let i;AudioCodesUA.ac_log("AC>>: incoming REFER accepted"),i=s.isScreenSharing()?s.doesScreenSharingReplaceCamera():s.hasSendVideo();let t=AudioCodesUA.instance._callOptions(i,!0);e.accept(e=>{e.data._created_by_refer=s},t)}else AudioCodesUA.ac_log("AC>>: incoming REFER rejected"),e.reject()}else AudioCodesUA.ac_log("AC>>: incoming REFER rejected, because transfereeCreatedCall is not set"),e.reject()}),s._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo),s.js_session.connection?(AudioCodesUA.instance._set_connection_listener(s),AudioCodesUA.ac_log('AC: connection exists, set "track" listener')):(AudioCodesUA.ac_log("AC: peer connection does not exist, wait creation"),s.js_session.on("peerconnection",()=>{AudioCodesUA.instance._set_connection_listener(s),AudioCodesUA.ac_log('AC: [event connection] connection created, set "track" listener')})),i="remote"===e.originator?e.request.from:e.request.to,s.data._user=i.uri.user,s.data._host=i.uri.host,s.data._display_name=i.display_name,s.data._create_time=new Date,"remote"===e.originator){let i,t,o,n=null;if(null!==AudioCodesUA.instance.replacedCall&&(n=AudioCodesUA.instance.replacedCall,AudioCodesUA.instance.replacedCall=null),e.request.body){o=!0;let s=new AudioCodesSDP(e.request.body);[i,t]=s.getMediaDirection("video",!0)}else o=!1,s.data._incoming_invite_without_sdp=!0,i=t=!0,AudioCodesUA.ac_log("AC: warning incoming INVITE without SDP");s._setVideoState(i,t),AudioCodesUA.ac_log(`AC>>: incomingCall ${s.hasVideo()?"video":"audio"} from "${s.data._display_name}" ${s.data._user}`,s,n),AudioCodesUA.instance.listeners.incomingCall(s,e.request,n,o)}else s.js_session.data._created_by_refer?(AudioCodesUA.ac_log("AC>>: outgoing call created by REFER"),s.data._created_by_refer=s.js_session.data._created_by_refer,AudioCodesUA.instance.listeners.transfereeCreatedCall(s)):AudioCodesUA.ac_log("AC>>: outgoing call created by phone.call()")})}_get_from(e){return{user:e.from.uri.user,host:e.from.uri.host,displayName:e.from.display_name?e.from.display_name:null}}_get_content_type(e){let i=e.headers["Content-Type"];return i&&i.length>0?i[0].parsed:null}_set_connection_listener(e){AudioCodesUA.instance.getWR().connection.addEventListener(e.js_session.connection,"track",i=>{if(AudioCodesUA.ac_log(`AC>>: "track" event kind= ${i.track.kind}`,i),i.streams.length>0){let s=i.streams[0];AudioCodesUA.ac_log(`AC: set call remote stream id=${s.id}`,e),e.data._remoteMediaStream=s}else AudioCodesUA.ac_log('AC: Warning "track" event without stream');if("video"===i.track.kind){if(!e.hasEnabledReceiveVideo()){e.data._video_call_audio_answer_safari&&(i.track.onmute=(()=>{AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Fired video track "mute" event. Call callShowStream'),i.track.onmute=null;let s=e.getRTCLocalStream(),t=e.getRTCRemoteStream();AudioCodesUA.ac_log("AC>>: callShowStreams",e,s,t),AudioCodesUA.instance.listeners.callShowStreams(e,s,t)}),AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Set video track "mute" event listener'),e.data._video_call_audio_answer_safari=!1),AudioCodesUA.ac_log('AC>>: event "track" video and !hasEnabledReceiveVideo therefore change transceiver direction.',e);let s=AudioCodesUA.instance.getWR().connection.getTransceiver(e.js_session.connection,"video");if(null!==s){let i=e.hasEnabledSendVideo()?"sendonly":"inactive";AudioCodesUA.instance.getWR().transceiver.setDirection(s,i)}}return void(AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",e,AudioCodesUA.instance.codecFilter.video))}let s=e.getRTCLocalStream(),t=e.getRTCRemoteStream();AudioCodesUA.ac_log("AC>>: callShowStreams",e,s,t),AudioCodesUA.instance.listeners.callShowStreams(e,s,t)})}_check_remote_sdp(e,i){try{i.codec_map||(i.codec_map={});let s=e.getMedia("audio");AudioCodesUA.instance._check_remote_m(s,i.codec_map);let t=e.getMedia("video");t&&AudioCodesUA.instance._check_remote_m(t,i.codec_map)}catch(e){AudioCodesUA.ac_log("AC:SDP exception",e)}}_check_remote_m(e,i){let s={};function t(e,i){let s=i.indexOf(" ",e);return-1===s?["?","?"]:[i.substring(e,s),i.substring(s+1).toLowerCase()]}for(let i of e)if(i.startsWith("a=rtpmap:")){let[e,o]=t(9,i);s[e]||(s[e]={}),s[e].rtpmap=o}else if(i.startsWith("a=fmtp:")){let[e,o]=t(7,i);s[e]||(s[e]={}),s[e].fmtp=o}for(let e of Object.keys(s))if(i[e])s[e].rtpmap===i[e].rtpmap?s[e].fmtp!==i[e].fmtp&&AudioCodesUA.ac_log(`AC:SDP [The same payload type and codec name, different fmtp] pt=${e} rtpmap=${s[e].rtpmap} fmtp=${s[e].fmtp}, previously was fmtp=${i[e].fmtp}`):(parseInt(e)>=64||s[e].rtpmap&&i[e].rtpmap)&&AudioCodesUA.ac_log(`AC:SDP [The same payload type, different codec names] pt=${e} rtpmap=${s[e].rtpmap}, previously was rtpmap=${i[e].rtpmap}`);else{let t,o=s[e];for(let[e,s]of Object.entries(i))if(o.rtpmap===s.rtpmap&&o.fmtp===s.fmtp){t=e;break}if(t){let s=i[t];o.fmtp||s.fmtp?AudioCodesUA.ac_log(`AC:SDP [The same codec name used with different payload types] pt=${e} rtpmap=${o.rtpmap} fmtp=${o.fmtp}, previously was pt=${t} rtpmap=${s.rtpmap} fmtp=${s.fmtp}`):AudioCodesUA.ac_log(`AC:SDP [The same codec name used with different payload types] pt=${e} rtpmap=${o.rtpmap}, previously was pt=${t} rtpmap=${s.rtpmap}`)}else i[e]=o}}_sdp_checking(e,i){let s,t,o,n=i.originator+" "+i.type,r=e.data.ac_session;try{s=new AudioCodesSDP(i.sdp),[t,o]=s.getMediaDirection("video","remote"===i.originator)}catch(i){return void AudioCodesUA.ac_log("AC: cannot parse SDP",i)}let a=r.data._initial;switch("answer"===i.type&&(r.data._initial=!1),AudioCodesUA.ac_log(`AC: Event "sdp" ${a?"initial":""} ${n} Session state:${AudioCodesUA.getSessionStatusName(e._status)}`),n){case"remote offer":AudioCodesUA.instance.modes.check_remote_sdp_mode&&AudioCodesUA.instance._check_remote_sdp(s,e.data);break;case"remote answer":if(AudioCodesUA.instance.modes.check_remote_sdp_mode&&AudioCodesUA.instance._check_remote_sdp(s,e.data),r.isLocalHold()||r.isRemoteHold())break;r._setVideoState(t,o);break;case"local offer":AudioCodesUA.instance.networkPriority&&AudioCodesUA.instance._set_senders_dscp(e);break;case"local answer":if(r.isLocalHold()||r.isRemoteHold())break;AudioCodesUA.instance.networkPriority&&AudioCodesUA.instance._set_senders_dscp(e),r._setVideoState(t,o)}}_set_senders_dscp(e){if("chrome"!==AudioCodesUA.instance.browser)return;AudioCodesUA.ac_log("AC: _set_senders_dscp()");let i=AudioCodesUA.instance.networkPriority;AudioCodesUA.instance._set_dscp(e,"audio",i),AudioCodesUA.instance._set_dscp(e,"video",i)}_set_dscp(e,i,s){let t=e.connection,o=AudioCodesUA.instance.getWR().connection.getTransceiver(t,i);return o||"video"!==i?Promise.resolve().then(()=>{let e=o.sender.getParameters();if(!e)throw new Error("sender getParameters() returns undefined");let t=e.encodings;if(!t)throw new Error("parameters encodings is undefined");if(0===t.length)throw new Error("parameters encodings is empty array");let n=t[0].networkPriority;if(!n)throw new Error("parameters encodings networkPriority is undefined");return n===s||(t[0].networkPriority=s,o.sender.setParameters(e).then(()=>(AudioCodesUA.ac_log(`AC: DSCP: ${i} "${s}"`),!0)))}).catch(e=>(AudioCodesUA.ac_log(`AC: DSCP: ${i} error: ${e}`),!1)):Promise.resolve(!1)}_cf_unpack(e){function i(e,i){let s,t=i.indexOf("/"),o=i.indexOf("#");s=-1!==t?t:-1!==o?o:void 0;let n={mimeType:(e+"/"+i.substring(0,s)).toLowerCase()};return-1!==t&&(s=-1!==o?o:void 0,n.clockRate=parseInt(i.substring(t+1,s))),-1!==o&&(n.sdpFmtpLine=i.substring(o+1)),n}if(!e)return null;let s={};for(let t in e){s[t]={};for(let o in e[t])s[t][o]=e[t][o].map(e=>i(t,e))}return s}_cf_pack(e){return e.map(e=>(function(e){let i=e.mimeType.substring(6).toLowerCase();return e.clockRate&&(i+="/"+e.clockRate),e.sdpFmtpLine&&(i+="#"+e.sdpFmtpLine),i})(e))}_cf_str(e){return JSON.stringify(AudioCodesUA.instance._cf_pack(e))}_cf_match(e,i){let s=e.mimeType.toLowerCase();for(let t of i)if(t.mimeType===s){if(t.clockRate&&t.clockRate!==e.clockRate)continue;if(t.sdpFmtpLine&&t.sdpFmtpLine!==e.sdpFmtpLine)continue;return!0}return!1}_cf_find(e,i){let s=[];for(let t of i){let i=t.mimeType.toLowerCase();if(e.mimeType===i){if(e.clockRate&&e.clockRate!==t.clockRate)continue;if(e.sdpFmtpLine&&e.sdpFmtpLine!==t.sdpFmtpLine)continue;s.push(t)}}return s}_cf_filter(e,i,s){if(s&&!i.data[`_used_${e}_codec_filter`])try{let t=i.getRTCPeerConnection(),o=AudioCodesUA.instance.getWR().connection.getTransceiver(t,e);if(!o)return void("audio"===e&&AudioCodesUA.ac_log("AC: codec-filter: cannot get audio transceiver"));if(i.data[`_used_${e}_codec_filter`]=!0,!RTCRtpSender.getCapabilities||!RTCRtpReceiver.getCapabilities||!o.setCodecPreferences)return void AudioCodesUA.ac_log("AC: codec-filter is not supported.");let n=RTCRtpSender.getCapabilities(e).codecs,r=RTCRtpReceiver.getCapabilities(e).codecs,a=[];for(let e of r){-1===n.findIndex(i=>e.mimeType===i.mimeType&&e.clockRate===i.clockRate&&e.sdpFmtpLine===i.sdpFmtpLine)&&a.push(e)}let d=n.concat(a);if(AudioCodesUA.ac_log(`AC: ${e} codec-filter original: ${AudioCodesUA.instance._cf_str(d)}\n(receiver: ${a.length})`),s.remove&&s.remove.length>0){let i=d.length;(d=d.filter(e=>!AudioCodesUA.instance._cf_match(e,s.remove))).length0){let i=[];for(let e of s.priority){let s=AudioCodesUA.instance._cf_find(e,d);0!==s.length&&(i=i.concat(s),d=d.filter(e=>!s.includes(e)))}d=i.concat(d),AudioCodesUA.ac_log(`AC: ${e} codec-filter changed priority: ${AudioCodesUA.instance._cf_str(d)}`)}return void o.setCodecPreferences(d)}catch(e){return void AudioCodesUA.ac_log("AC: codec filter exception",e)}}_convertIceList(e){let i=[];for(let s of e)"string"==typeof s&&(s={urls:"stun:"+s}),i.push(s);return i}_randomToken(e){let i="";for(let s=0;s{let n={contentType:s,eventHandlers:{succeeded:e=>t(e),failed:e=>o(e)}};this.jssipUA.sendMessage(e,i,n)})}isScreenSharingSupported(){return AudioCodesUA.instance.getWR().hasDisplayMedia()}openScreenSharing(){return this.isScreenSharingSupported()?(AudioCodesUA.ac_log("AC: openScreenSharing()"),AudioCodesUA.instance.getWR().getDisplayMedia().then(e=>e).catch(e=>{throw AudioCodesUA.ac_log("AC: openScreenSharing() error",e),e})):(AudioCodesUA.ac_log("AC: openScreenSharing: screen sharing is not supported in the browser"),Promise.reject("Screen sharing is not supported"))}closeScreenSharing(e){if(AudioCodesUA.ac_log("AC: closeScreenSharing()"),e){let i=e.getVideoTracks();if(0==i.length)return;let s=i[0];"live"===s.readyState&&(s.stop(),s.dispatchEvent(new Event("ended")))}}setNetworkPriority(e){if(AudioCodesUA.ac_log(`AC: setNetworkPriority ${e}`),void 0!==e&&"high"!==e&&"medium"!==e&&"low"!==e&&"very-low"!==e)throw new TypeError(`setNetworkPriority: illegal value: ${e}`);this.networkPriority=e}subscribe(...e){return this.jssipUA.subscribe(...e)}notify(...e){return this.jssipUA.notify(...e)}addCredential(e){if(!e.realm||!e.password||!e.username)throw new TypeError("wrong credential structure");this.credentials.push(e)}}class AudioCodesSession{constructor(e){this.js_session=e,this.data={_user:null,_display_name:null,_create_time:null,_initial:!0,_remoteMediaStream:null,_wasUsedSendVideo:!1,_screenSharing:null,_video:{send:!1,receive:!1,enabledSend:!1,enabledReceive:!1}},e.data.ac_session=this}getRTCPeerConnection(){return this.js_session.connection}getRTCLocalStream(){return this.js_session._localMediaStream}getRTCRemoteStream(){return this.data._remoteMediaStream}isEstablished(){return this.js_session.isEstablished()}isTerminated(){return this.js_session.isEnded()}isOutgoing(){return"outgoing"===this.js_session.direction}isAudioMuted(){return this.js_session.isMuted().audio}isVideoMuted(){return this.js_session.isMuted().video}wasAccepted(){return!0===this.data._accepted}getReplacesHeader(){if(!this.js_session.isEstablished()||!this.js_session._dialog)return AudioCodesUA.ac_log("getReplacesHeader(): call is not established"),null;let e=this.js_session._dialog.id;return`${e.call_id};to-tag=${e.remote_tag};from-tag=${e.local_tag}`}muteAudio(e){AudioCodesUA.ac_log(`AC: muteAudio() arg=${e} `),e?this.js_session.mute({audio:!0,video:!1}):this.js_session.unmute({audio:!0,video:!1})}muteVideo(e){AudioCodesUA.ac_log(`AC: muteVideo() arg=${e} `),e?this.js_session.mute({audio:!1,video:!0}):this.js_session.unmute({audio:!1,video:!0})}sendDTMF(e){let i=AudioCodesUA.instance.dtmfUseWebRTC;if(i&&"safari"===AudioCodesUA.instance.browser){void 0===AudioCodesUA.instance.getWR().connection.getDTMFSender(this.js_session.connection)&&(i=!1)}AudioCodesUA.ac_log(`AC: sendDTMF() tone=${e} ${i?"[RFC2833]":"[INFO]"}`);let s={duration:AudioCodesUA.instance.dtmfDuration,interToneGap:AudioCodesUA.instance.dtmfInterToneGap,transportType:i?"RFC2833":"INFO"};this.js_session.sendDTMF(e,s)}sendInfo(e,i,s=null){AudioCodesUA.ac_log("AC: sendInfo()",e,i,s);let t=null!==s?{extraHeaders:s}:void 0;this.js_session.sendInfo(i,e,t)}duration(){let e=this.js_session.start_time;if(!e)return 0;let i=this.js_session.end_time;return i||(i=new Date),Math.floor((i.getTime()-e.getTime())/1e3)}hasSendVideo(){return this.data._video.send}hasReceiveVideo(){return this.data._video.receive}hasVideo(){return this.hasSendVideo()&&this.hasReceiveVideo()}getVideoState(){return this.hasSendVideo()&&this.hasReceiveVideo()?"sendrecv":this.hasSendVideo()?"sendonly":this.hasReceiveVideo()?"recvonly":"inactive"}_setVideoState(e,i){AudioCodesUA.ac_log(`AC: _setVideoState(send=${e}, receive=${i})`),this.data._video.send=e,this.data._video.receive=i}hasEnabledSendVideo(){return this.data._video.enabledSend}hasEnabledReceiveVideo(){return this.data._video.enabledReceive}getEnabledVideoState(){return this.hasEnabledSendVideo()&&this.hasEnabledReceiveVideo()?"sendrecv":this.hasEnabledSendVideo()?"sendonly":this.hasEnabledReceiveVideo()?"recvonly":"inactive"}_setEnabledSendVideo(e){AudioCodesUA.ac_log(`AC: _setEnabledSendVideo(${e})`),this.data._video.enabledSend=e}_setEnabledReceiveVideo(e){AudioCodesUA.ac_log(`AC: _setEnabledReceiveVideo(${e})`),this.data._video.enabledReceive=e}answer(e,i=null,s=null){if(this.data._answer_called)return void AudioCodesUA.ac_log("AC: answer() is already called. [Ignored]");if(this.data._answer_called=!0,!1===e?e=AudioCodesUA.instance.AUDIO:!0===e&&(e=AudioCodesUA.instance.VIDEO),"symbol"!=typeof e||![AudioCodesUA.instance.AUDIO,AudioCodesUA.instance.RECVONLY_VIDEO,AudioCodesUA.instance.VIDEO].includes(e))throw new TypeError(`Illegal videoOption=${e.toString()}`);if(AudioCodesUA.ac_log(`AC: ${e.description} answer`),this.hasVideo()||e!==AudioCodesUA.instance.RECVONLY_VIDEO&&e!==AudioCodesUA.instance.VIDEO||(AudioCodesUA.ac_log('AC: incoming INVITE without video, so answer can be only "audio"'),e=AudioCodesUA.instance.AUDIO),this.hasVideo()&&e===AudioCodesUA.instance.AUDIO){let e=AudioCodesUA.instance,i=e.browser,s=e.modes,t=e.browserVersion;"firefox"===i&&s.video_call_audio_answer_firefox_fix?this.data._video_call_audio_answer_firefox=!0:"safari"===i&&(!0===s.video_call_audio_answer_safari_fix&&t<14||"force"===s.video_call_audio_answer_safari_fix)&&(this.data._video_call_audio_answer_safari=!0)}switch(e){case AudioCodesUA.instance.AUDIO:this._setEnabledSendVideo(!1),this.data._incoming_invite_without_sdp?this._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo):this._setEnabledReceiveVideo(!this.hasVideo()&&AudioCodesUA.instance.enableAddVideo),this._setVideoState(!1,!1);break;case AudioCodesUA.instance.VIDEO:this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(!0),this._setVideoState(!0,!0);break;case AudioCodesUA.instance.RECVONLY_VIDEO:this._setEnabledSendVideo(!1),this._setEnabledReceiveVideo(!0),this._setVideoState(!1,!0)}let t=AudioCodesUA.instance._callOptions(e===AudioCodesUA.instance.VIDEO,!1,i,s);Promise.resolve().then(()=>t.mediaStream?t.mediaStream:AudioCodesUA.instance.getWR().getUserMedia(t.mediaConstraints)).then(e=>{t.mediaStream=e,this.js_session._localMediaStreamLocallyGenerated=!0,AudioCodesUA.ac_log("AC: answer options:",t),this.js_session.answer(t)}).catch(e=>{AudioCodesUA.ac_log("AC: getUserMedia failure",e),this.reject(488)})}reject(e=486,i=null){AudioCodesUA.ac_log("AC: reject()");try{let s={status_code:e};i&&(s.extraHeaders=i),this.js_session.terminate(s)}catch(e){AudioCodesUA.ac_log("AC: call reject error:",e)}}terminate(){AudioCodesUA.ac_log("AC: terminate()");try{this.js_session.terminate()}catch(e){AudioCodesUA.ac_log("AC: call terminate error:",e)}}redirect(e,i=302,s=null){AudioCodesUA.ac_log(`AC: redirect() callTo=${e}`);try{let t={status_code:i,extraHeaders:["Contact: "+AudioCodesUA.instance.jssipUA.normalizeTarget(e)]};s&&t.extraHeaders.push(...s),this.js_session.terminate(t)}catch(e){AudioCodesUA.ac_log("AC: call redirect error:",e)}}isLocalHold(){return this.js_session.isOnHold().local}isRemoteHold(){return this.js_session.isOnHold().remote}isReadyToReOffer(){return this.js_session._isReadyToReOffer()}hold(e){return AudioCodesUA.ac_log(`AC: hold(${e})`),new Promise((i,s)=>{(e?this.js_session.hold:this.js_session.unhold).call(this.js_session,{},()=>{AudioCodesUA.ac_log("AC: hold()/unhold() is completed"),i()})||(AudioCodesUA.ac_log("AC: hold()/unhold() failed"),s())})}enableReceiveVideo(e){this._setEnabledReceiveVideo(e);let i=this.getRTCPeerConnection(),s=AudioCodesUA.instance.getWR().connection.getTransceiver(i,"video");if(null!==s){let e=this.getEnabledVideoState();AudioCodesUA.instance.getWR().transceiver.setDirection(s,e)}return AudioCodesUA.ac_log(`AC: enableReceiveVideo(${e}) ${null!==s?"":"No video transceiver"}`),null!==s}startSendingVideo(e={}){let i=e&&!1!==e.enabledReceiveVideo;return this.hasEnabledSendVideo()?(AudioCodesUA.ac_log("AC: startSendingVideo(). Already started"),Promise.reject("video already started")):(AudioCodesUA.ac_log("AC: startSendingVideo()"),AudioCodesUA.instance.getWR().getUserMedia({video:AudioCodesUA.instance.constraints.video}).catch(e=>{throw AudioCodesUA.ac_log("AC: startSendingVideo() getUserMedia failure",e),e}).then(e=>{let s=e.getVideoTracks()[0];this.getRTCLocalStream().addTrack(s),this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(i);let t=this.data._wasUsedSendVideo;return AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(),this.getRTCLocalStream(),s,this.hasEnabledReceiveVideo(),t).then(()=>{!t&&AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",this,AudioCodesUA.instance.codecFilter.video)}).catch(e=>{throw AudioCodesUA.ac_log("AC: startSendingVideo(). Adding video error",e),e})}).then(()=>this._renegotiate(e)))}stopSendingVideo(e={}){return this.hasEnabledSendVideo()?(AudioCodesUA.ac_log("AC: stopSendingVideo()"),AudioCodesUA.instance.getWR().connection.removeVideo(this.getRTCPeerConnection(),this.getRTCLocalStream()).catch(e=>{throw AudioCodesUA.ac_log("AC: stopSendingVideo(). Remove video error",e),e}).then(()=>(this._setEnabledSendVideo(!1),this.data._wasUsedSendVideo=!0,this._renegotiate(e)))):(AudioCodesUA.ac_log("AC: stopSendingVideo(). Already stopped"),Promise.reject("video already stopped"))}_doRenegotiate(e){return this.js_session.isEnded()?Promise.reject("call is ended"):new Promise(i=>{if(!this.js_session.renegotiate(e,()=>i(!0)))return i(!1)})}_renegotiate(e,i=30,s=500){return AudioCodesUA.ac_log(`AC: _renegotiate() attemptsLeft=${i}`),this._doRenegotiate(e).then(t=>{if(t)return AudioCodesUA.ac_log("AC: Renegotiation success"),!0;if(i<=1)throw new Error("Too many attempts");return new Promise(e=>setTimeout(e,s)).then(()=>this._renegotiate(e,i-1,s))}).catch(e=>{throw AudioCodesUA.ac_log("AC: Renegotiation failed",e),e})}sendReInvite(e={}){return AudioCodesUA.ac_log("AC: sendReInvite()"),this._renegotiate(e).then(()=>{if(e.showStreams){let e=this.getRTCLocalStream(),i=this.getRTCRemoteStream();AudioCodesUA.ac_log("AC>>: [after send re-INVITE] callShowStreams",this,e,i),AudioCodesUA.instance.listeners.callShowStreams(this,e,i)}})}startScreenSharing(e,i={localScreenSharing:!0,enabledReceiveVideo:!0,separateVideo:!1}){if(AudioCodesUA.ac_log("AC: startScreenSharing"),!e)return Promise.reject("missed stream argument");if(this.data._screenSharing)return Promise.reject("the call is already using screen-sharing");let s=i&&!1!==i.enabledReceiveVideo,t=e.getVideoTracks()[0],o=void 0;i.localScreenSharing&&(o=this._onEndedScreenSharingTrack.bind(this),t.addEventListener("ended",o)),this.data._screenSharing={stream:e,onended:o,hadSendVideo:this.hasSendVideo()};let n=this.data._wasUsedSendVideo;return this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(s),AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(),this.getRTCLocalStream(),t,this.hasEnabledReceiveVideo(),n).then(()=>{!n&&AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",this,AudioCodesUA.instance.codecFilter.video)}).catch(e=>{throw AudioCodesUA.ac_log("AC: startScreenSharing() error",e),this.data._screenSharing=null,e}).then(()=>{return this._renegotiate({extraHeaders:["X-Screen-Sharing: on"]})})}stopScreenSharing(){return AudioCodesUA.ac_log("AC: stopScreenSharing"),this.data._screenSharing?this._onEndedScreenSharing("called stopScreenSharing()"):Promise.reject("the call does not use screen-sharing")}isScreenSharing(){return!!this.data._screenSharing}doesScreenSharingReplaceCamera(){let e=this.data._screenSharing;return e&&e.hadSendVideo}_onEndedScreenSharingTrack(){return this._onEndedScreenSharing("track ended")}_onEndedScreenSharing(e){let i=this.data._screenSharing;this.data._screenSharing=null;let s=i.stream,t=i.onended;if(s&&t){s.getVideoTracks()[0].removeEventListener("ended",t)}return Promise.resolve().then(()=>{if(!this.isTerminated()){let e=this.getRTCPeerConnection(),s=this.getRTCLocalStream(),t={extraHeaders:["X-Screen-Sharing: off"]};return i.hadSendVideo?(AudioCodesUA.ac_log("AC: screen sharing stopped - restore previously sending video track"),AudioCodesUA.instance.getWR().connection.replaceSenderTrack(e,"video",s),this._renegotiate(t)):(AudioCodesUA.ac_log("AC: screen sharing stopped - stop send video"),this.stopSendingVideo(t))}}).then(()=>{AudioCodesUA.instance.listeners.callScreenSharingEnded&&(AudioCodesUA.ac_log(`AC>>: callScreenSharingEnded "${e}"`,this,s),AudioCodesUA.instance.listeners.callScreenSharingEnded(this,s))})}setRemoteHoldState(){this.js_session._remoteHold=!0}sendRefer(e,i=null){if(!AudioCodesUA.instance.listeners.transferorNotification)throw new Error("transferorNotification listener is missed");let s=this,t={eventHandlers:{requestSucceeded(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [REFER accepted]"),AudioCodesUA.instance.listeners.transferorNotification(s,0)},requestFailed(){AudioCodesUA.ac_log("AC>>: transferorNotification failed [REFER failed]"),AudioCodesUA.instance.listeners.transferorNotification(s,-1)},trying(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [NOTIFY 1xx]"),AudioCodesUA.instance.listeners.transferorNotification(s,0)},progress(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [NOTIFY 1xx]"),AudioCodesUA.instance.listeners.transferorNotification(s,0)},accepted(){AudioCodesUA.ac_log("AC>>: transferorNotification success [NOTIFY 2xx]"),AudioCodesUA.instance.listeners.transferorNotification(s,1)},failed(){AudioCodesUA.ac_log("AC>>: transferorNotification failed [NOTIFY >= 300]"),AudioCodesUA.instance.listeners.transferorNotification(s,-1)}}};null!==i&&(t.replaces=i.js_session),this.js_session.refer(e,t)}}class AudioCodesSDP{constructor(e){this.start=[],this.media=[];let i=e.split("\n").map(e=>e.trim()).filter(e=>e.length>0),s=this.start;for(let e of i)e.startsWith("m=")&&(s=[],this.media.push(s)),s.push(e)}getMedia(e){for(let i of this.media)if(i.length>0&&i[0].startsWith("m="+e))return i;return null}checkSendRecv(e){switch(e){case"a=sendrecv":return"sendrecv";case"a=sendonly":return"sendonly";case"a=recvonly":return"recvonly";case"a=inactive":return"inactive";default:return null}}getMediaDirectionValue(e){let i,s=this.getMedia(e);if(null===s)return null;let t="sendrecv";for(let e of this.start)if(null!==(i=this.checkSendRecv(e))){t=i;break}for(let e of s)if(null!==(i=this.checkSendRecv(e))){t=i;break}return t}getMediaDirection(e,i){let s=this.getMediaDirectionValue(e);switch(s){case"sendrecv":return[!0,!0,s];case"sendonly":return i?[!1,!0,s]:[!0,!1,s];case"recvonly":return i?[!0,!1,s]:[!1,!0,s];case null:case"inactive":return[!1,!1,s]}}toString(){let e=this.start;for(let i of this.media)e=e.concat(i);return e.join("\r\n")+"\r\n"}}let AudioCodesWebRTCWrapper={getUserMedia:e=>(AudioCodesUA.ac_log(`[webrtc] getUserMedia constraints=${JSON.stringify(e)}`),navigator.mediaDevices.getUserMedia(e)),hasDisplayMedia:()=>navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia,getDisplayMedia:()=>(AudioCodesUA.ac_log("[webrtc] getDisplayMedia"),navigator.mediaDevices.getDisplayMedia({video:!0})),mediaDevices:{enumerateDevices:()=>navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices?navigator.mediaDevices.enumerateDevices():Promise.reject("WebRTC is not supported"),addDeviceChangeListener(e){navigator.mediaDevices&&navigator.mediaDevices.addEventListener("devicechange",e)},removeDeviceChangeListener(e){navigator.mediaDevices&&navigator.mediaDevices.removeEventListener("devicechange",e)}},checkAvailableDevices(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia)return Promise.reject("WebRTC is not supported");let e=!1,i=!1,s=!1;return navigator.mediaDevices.enumerateDevices().then(t=>(t.forEach(function(t){switch(t.kind){case"videoinput":e=!0;break;case"audioinput":i=!0;break;case"audiooutput":s=!0}}),void 0===navigator.webkitGetUserMedia&&(s=!0),s?i?Promise.resolve(e):Promise.reject("Missing a microphone! Please connect one and reload"):Promise.reject("Missing a speaker! Please connect one and reload")))},transceiver:{setDirection(e,i){let s="";null!==e.sender.track?s=e.sender.track.kind:null!==e.receiver.track&&(s=e.receiver.track.kind),AudioCodesUA.ac_log(`[webrtc] set ${s} transceiver direction=${i}`),e.direction=i}},stream:{getInfo(e){function i(e){return e.length>0?e[0].enabled.toString():"-"}return null===e?Promise.resolve("stream is null"):Promise.resolve(`audio: ${i(e.getAudioTracks())} video: ${i(e.getVideoTracks())}`)}},connection:{getTransceiversInfo(e){function i(e){return null===e?"none":`d=${e.direction} c=${e.currentDirection}`}let s=e.getTransceivers(),t=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"audio"),o=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");return Promise.resolve(`(${s.length}) audio ${i(t)} video ${i(o)}`)},getTransceiver(e,i){for(let s of e.getTransceivers()){if(null!==s.sender&&null!==s.sender.track&&s.sender.track.kind===i)return s;if(null!==s.receiver&&null!==s.receiver.track&&s.receiver.track.kind===i)return s}return null},addEventListener:(e,i,s)=>(AudioCodesUA.ac_log(`[webrtc] Connection addEventListener ${i}`),"track"!==i?Promise.reject(`Wrong event name: ${i}`):(e.addEventListener(i,s),Promise.resolve())),getDTMFSender(e){let i=e.getSenders().find(e=>e.track&&"audio"===e.track.kind);if(i&&i.dtmf)return i.dtmf},addVideo(e,i,s,t,o){AudioCodesUA.ac_log("[webrtc] Connection addVideo");let n=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");if(null!==n){let e=t?"sendrecv":"sendonly";AudioCodesUA.instance.getWR().transceiver.setDirection(n,e)}return null===n||null===n.sender.track&&!o?(AudioCodesUA.ac_log("[webrtc] addVideo (connection addTrack)"),e.addTrack(s,i),Promise.resolve(!0)):(AudioCodesUA.ac_log("[webrtc] addVideo (video transceiver sender replaceTrack)"),n.sender.replaceTrack(s).then(()=>!1))},removeVideo(e,i){AudioCodesUA.ac_log("[webrtc] Connection removeVideo");let s=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");if(null===s)return Promise.reject("no video transceiver found");if(e.removeTrack(s.sender),i)for(let e of i.getVideoTracks())i.removeTrack(e),e.stop();return Promise.resolve()},replaceSenderTrack(e,i,s){AudioCodesUA.ac_log(`[webrtc] ReplaceSenderTrack ${i}`);let t=null;for(let s of e.getSenders())if(null!==s.track&&s.track.kind===i){t=s;break}if(null===t)return Promise.reject(`No ${i} sender`);let o="audio"===i?s.getAudioTracks():s.getVideoTracks();return 0===o.length?Promise.reject(`No ${i} track`):t.replaceTrack(o[0])},getStats(e,i){let s="";return e.getStats(null).then(e=>(e.forEach(e=>{if(i.includes(e.type)){s+=" {";let i=!0;for(let t of Object.keys(e))i?i=!1:s+=",",s+=t+"="+e[t];s+="} \r\n"}}),s))}}}; diff --git a/js/ac_webrtc_and_utils_es5.min.js b/js/ac_webrtc_and_utils_es5.min.js new file mode 100644 index 0000000..11cf65d --- /dev/null +++ b/js/ac_webrtc_and_utils_es5.min.js @@ -0,0 +1,16 @@ +/* + * JsSIP v3.10.0 + * the Javascript SIP library + * Copyright: 2012-2023 + * Homepage: https://jssip.net + * License: MIT + */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JsSIP=e()}}(function(){return function(){return function e(t,n,r){function i(s,a){if(!n[s]){if(!t[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(o)return o(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[s]={exports:{}};t[s][0].call(c.exports,function(e){return i(t[s][1][e]||e)},c,c.exports,e,t,n,r)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;s=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0)return t}},connection_recovery_min_interval:function(e){if(o.isDecimal(e)){var t=Number(e);if(t>0)return t}},contact_uri:function(e){if("string"==typeof e){var t=a.parse(e,"SIP_URI");if(-1!==t)return t}},display_name:function(e){return e},instance_id:function(e){return/^uuid:/i.test(e)&&(e=e.substr(5)),-1===a.parse(e,"uuid")?void 0:e},no_answer_timeout:function(e){if(o.isDecimal(e)){var t=Number(e);if(t>0)return t}},session_timers:function(e){if("boolean"==typeof e)return e},session_timers_refresh_method:function(e){if("string"==typeof e&&((e=e.toUpperCase())===s.INVITE||e===s.UPDATE))return e},session_timers_force_refresher:function(e){if("boolean"==typeof e)return e},password:function(e){return String(e)},realm:function(e){return String(e)},ha1:function(e){return String(e)},register:function(e){if("boolean"==typeof e)return e},register_expires:function(e){if(o.isDecimal(e)){var t=Number(e);if(t>0)return t}},registrar_server:function(e){/^sip:/i.test(e)||(e="".concat(s.SIP,":").concat(e));var t=l.parse(e);return t?t.user?void 0:t:void 0},use_preloaded_route:function(e){if("boolean"==typeof e)return e},extra_headers:function(e){var t=[];if(Array.isArray(e)&&e.length){var n,i=r(e);try{for(i.s();!(n=i.n()).done;){var o=n.value;"string"==typeof o&&t.push(o)}}catch(e){i.e(e)}finally{i.f()}return t}}}};n.load=function(e,t){for(var n in d.mandatory){if(!t.hasOwnProperty(n))throw new c.ConfigurationError(n);var r=t[n],i=d.mandatory[n](r);if(void 0===i)throw new c.ConfigurationError(n,r);e[n]=i}for(var s in d.optional)if(t.hasOwnProperty(s)){var a=t[s];if(o.isEmpty(a))continue;var l=d.optional[s](a);if(void 0===l)throw new c.ConfigurationError(s,a);e[s]=l}}},{"./Constants":2,"./Exceptions":6,"./Grammar":7,"./Socket":23,"./URI":29,"./Utils":30}],2:[function(e,t,n){"use strict";var r=e("../package.json");t.exports={USER_AGENT:"".concat(r.title," ").concat(r.version),SIP:"sip",SIPS:"sips",causes:{CONNECTION_ERROR:"Connection Error",REQUEST_TIMEOUT:"Request Timeout",SIP_FAILURE_CODE:"SIP Failure Code",INTERNAL_ERROR:"Internal Error",BUSY:"Busy",REJECTED:"Rejected",REDIRECTED:"Redirected",UNAVAILABLE:"Unavailable",NOT_FOUND:"Not Found",ADDRESS_INCOMPLETE:"Address Incomplete",INCOMPATIBLE_SDP:"Incompatible SDP",MISSING_SDP:"Missing SDP",AUTHENTICATION_ERROR:"Authentication Error",BYE:"Terminated",WEBRTC_ERROR:"WebRTC Error",CANCELED:"Canceled",NO_ANSWER:"No Answer",EXPIRES:"Expires",NO_ACK:"No ACK",DIALOG_ERROR:"Dialog Error",USER_DENIED_MEDIA_ACCESS:"User Denied Media Access",BAD_MEDIA_DESCRIPTION:"Bad Media Description",RTP_TIMEOUT:"RTP Timeout"},SIP_ERROR_CAUSES:{REDIRECTED:[300,301,302,305,380],BUSY:[486,600],REJECTED:[403,603],NOT_FOUND:[404,604],UNAVAILABLE:[480,410,408,430],ADDRESS_INCOMPLETE:[484,424],INCOMPATIBLE_SDP:[488,606],AUTHENTICATION_ERROR:[401,407]},ACK:"ACK",BYE:"BYE",CANCEL:"CANCEL",INFO:"INFO",INVITE:"INVITE",MESSAGE:"MESSAGE",NOTIFY:"NOTIFY",OPTIONS:"OPTIONS",REGISTER:"REGISTER",REFER:"REFER",UPDATE:"UPDATE",SUBSCRIBE:"SUBSCRIBE",DTMF_TRANSPORT:{INFO:"INFO",RFC2833:"RFC2833"},REASON_PHRASE:{100:"Trying",180:"Ringing",181:"Call Is Being Forwarded",182:"Queued",183:"Session Progress",199:"Early Dialog Terminated",200:"OK",202:"Accepted",204:"No Notification",300:"Multiple Choices",301:"Moved Permanently",302:"Moved Temporarily",305:"Use Proxy",380:"Alternative Service",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",410:"Gone",412:"Conditional Request Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Unsupported URI Scheme",417:"Unknown Resource-Priority",420:"Bad Extension",421:"Extension Required",422:"Session Interval Too Small",423:"Interval Too Brief",424:"Bad Location Information",428:"Use Identity Header",429:"Provide Referrer Identity",430:"Flow Failed",433:"Anonymity Disallowed",436:"Bad Identity-Info",437:"Unsupported Certificate",438:"Invalid Identity Header",439:"First Hop Lacks Outbound Support",440:"Max-Breadth Exceeded",469:"Bad Info Package",470:"Consent Needed",478:"Unresolvable Destination",480:"Temporarily Unavailable",481:"Call/Transaction Does Not Exist",482:"Loop Detected",483:"Too Many Hops",484:"Address Incomplete",485:"Ambiguous",486:"Busy Here",487:"Request Terminated",488:"Not Acceptable Here",489:"Bad Event",491:"Request Pending",493:"Undecipherable",494:"Security Agreement Required",500:"JsSIP Internal Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Server Time-out",505:"Version Not Supported",513:"Message Too Large",580:"Precondition Failure",600:"Busy Everywhere",603:"Decline",604:"Does Not Exist Anywhere",606:"Not Acceptable"},ALLOWED_METHODS:"INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO,NOTIFY,SUBSCRIBE",ACCEPTED_BODY_TYPES:"application/sdp, application/dtmf-relay",MAX_FORWARDS:69,SESSION_EXPIRES:90,MIN_SESSION_EXPIRES:60,CONNECTION_RECOVERY_MAX_INTERVAL:30,CONNECTION_RECOVERY_MIN_INTERVAL:2}},{"../package.json":42}],3:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:d.STATUS_CONFIRMED;if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this._owner=t,this._ua=t._ua,this._uac_pending_reply=!1,this._uas_pending_reply=!1,!n.hasHeader("contact"))return{error:"unable to create a Dialog without Contact header field"};n instanceof o.IncomingResponse&&(i=n.status_code<200?d.STATUS_EARLY:d.STATUS_CONFIRMED);var s=n.parseHeader("contact");"UAS"===r?(this._id={call_id:n.call_id,local_tag:n.to_tag,remote_tag:n.from_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this._state=i,this._remote_seqnum=n.cseq,this._local_uri=n.parseHeader("to").uri,this._remote_uri=n.parseHeader("from").uri,this._remote_target=s.uri,this._route_set=n.getHeaders("record-route"),this._ack_seqnum=this._remote_seqnum):"UAC"===r&&(this._id={call_id:n.call_id,local_tag:n.from_tag,remote_tag:n.to_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this._state=i,this._local_seqnum=n.cseq,this._local_uri=n.parseHeader("from").uri,this._remote_uri=n.parseHeader("to").uri,this._remote_target=s.uri,this._route_set=n.getHeaders("record-route").reverse(),this._ack_seqnum=null),this._ua.newDialog(this),c.debug("new ".concat(r," dialog created with status ").concat(this._state===d.STATUS_EARLY?"EARLY":"CONFIRMED"))}var t,n,i;return t=e,i=[{key:"C",get:function(){return d}}],(n=[{key:"id",get:function(){return this._id}},{key:"local_seqnum",get:function(){return this._local_seqnum},set:function(e){this._local_seqnum=e}},{key:"owner",get:function(){return this._owner}},{key:"uac_pending_reply",get:function(){return this._uac_pending_reply},set:function(e){this._uac_pending_reply=e}},{key:"uas_pending_reply",get:function(){return this._uas_pending_reply}},{key:"isTerminated",value:function(){return this._status===d.STATUS_TERMINATED}},{key:"update",value:function(e,t){this._state=d.STATUS_CONFIRMED,c.debug("dialog ".concat(this._id.toString()," changed to CONFIRMED state")),"UAC"===t&&(this._route_set=e.getHeaders("record-route").reverse())}},{key:"terminate",value:function(){c.debug("dialog ".concat(this._id.toString()," deleted")),this._ua.destroyDialog(this),this._state=d.STATUS_TERMINATED}},{key:"sendRequest",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=u.cloneArray(n.extraHeaders),i=u.cloneObject(n.eventHandlers),o=n.body||null,s=this._createRequest(e,r,o);return i.onAuthenticated=function(){t._local_seqnum+=1},new l(this,s,i).send(),s}},{key:"receiveRequest",value:function(e){this._checkInDialogRequest(e)&&(e.method===s.ACK&&null!==this._ack_seqnum?this._ack_seqnum=null:e.method===s.INVITE&&(this._ack_seqnum=e.cseq),this._owner.receiveRequest(e))}},{key:"_createRequest",value:function(e,t,n){t=u.cloneArray(t),this._local_seqnum||(this._local_seqnum=Math.floor(1e4*Math.random()));var r=e===s.CANCEL||e===s.ACK?this._local_seqnum:this._local_seqnum+=1;return new o.OutgoingRequest(e,this._remote_target,this._ua,{cseq:r,call_id:this._id.call_id,from_uri:this._local_uri,from_tag:this._id.local_tag,to_uri:this._remote_uri,to_tag:this._id.remote_tag,route_set:this._route_set},t,n)}},{key:"_checkInDialogRequest",value:function(e){var t=this;if(this._remote_seqnum)if(e.cseqthis._remote_seqnum&&(this._remote_seqnum=e.cseq);else this._remote_seqnum=e.cseq;if(e.method===s.INVITE||e.method===s.UPDATE&&e.body){if(!0===this._uac_pending_reply)e.reply(491);else{if(!0===this._uas_pending_reply){var n=1+(10*Math.random()|0);return e.reply(500,null,["Retry-After:".concat(n)]),!1}this._uas_pending_reply=!0;e.server_transaction.on("stateChanged",function n(){e.server_transaction.state!==a.C.STATUS_ACCEPTED&&e.server_transaction.state!==a.C.STATUS_COMPLETED&&e.server_transaction.state!==a.C.STATUS_TERMINATED||(e.server_transaction.removeListener("stateChanged",n),t._uas_pending_reply=!1)})}e.hasHeader("contact")&&e.server_transaction.on("stateChanged",function(){e.server_transaction.state===a.C.STATUS_ACCEPTED&&(t._remote_target=e.parseHeader("contact").uri)})}else e.method===s.NOTIFY&&e.hasHeader("contact")&&e.server_transaction.on("stateChanged",function(){e.server_transaction.state===a.C.STATUS_COMPLETED&&(t._remote_target=e.parseHeader("contact").uri)});return!0}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Dialog/RequestSender":4,"./Logger":9,"./SIPMessage":22,"./Transactions":26,"./Utils":30}],4:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=200&&e.status_code<300?this._eventHandlers.onSuccessResponse(e):e.status_code>=300&&this._eventHandlers.onErrorResponse(e):(this._request.cseq=this._dialog.local_seqnum+=1,this._reattemptTimer=setTimeout(function(){t._dialog.isTerminated()||(t._reattempt=!0,t.send())},1e3)):e.status_code>=200&&e.status_code<300?this._eventHandlers.onSuccessResponse(e):e.status_code>=300&&this._eventHandlers.onErrorResponse(e)}}])&&r(t.prototype,n),l&&r(t,l),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"../Constants":2,"../RequestSender":21,"../Transactions":26}],5:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:null;if(this._algorithm=t.algorithm,this._realm=t.realm,this._nonce=t.nonce,this._opaque=t.opaque,this._stale=t.stale,this._algorithm){if("MD5"!==this._algorithm)return s.warn('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted'),!1}else this._algorithm="MD5";if(!this._nonce)return s.warn("authenticate() | challenge without Digest nonce, authentication aborted"),!1;if(!this._realm)return s.warn("authenticate() | challenge without Digest realm, authentication aborted"),!1;if(!this._credentials.password){if(!this._credentials.ha1)return s.warn("authenticate() | no plain SIP password nor ha1 provided, authentication aborted"),!1;if(this._credentials.realm!==this._realm)return s.warn('authenticate() | no plain SIP password, and stored `realm` does not match the given `realm`, cannot authenticate [stored:"%s", given:"%s"]',this._credentials.realm,this._realm),!1}if(t.qop)if(t.qop.indexOf("auth-int")>-1)this._qop="auth-int";else{if(!(t.qop.indexOf("auth")>-1))return s.warn('authenticate() | challenge without Digest qop different than "auth" or "auth-int", authentication aborted'),!1;this._qop="auth"}else this._qop=null;this._method=n,this._uri=r,this._cnonce=a||o.createRandomToken(12),this._nc+=1;var l,u,c=Number(this._nc).toString(16);return this._ncHex="00000000".substr(0,8-c.length)+c,4294967296===this._nc&&(this._nc=1,this._ncHex="00000001"),this._credentials.password?this._ha1=o.calculateMD5("".concat(this._credentials.username,":").concat(this._realm,":").concat(this._credentials.password)):this._ha1=this._credentials.ha1,"auth"===this._qop?(l="".concat(this._method,":").concat(this._uri),u=o.calculateMD5(l),s.debug('authenticate() | using qop=auth [a2:"%s"]',l),this._response=o.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(this._ncHex,":").concat(this._cnonce,":auth:").concat(u))):"auth-int"===this._qop?(l="".concat(this._method,":").concat(this._uri,":").concat(o.calculateMD5(i||"")),u=o.calculateMD5(l),s.debug('authenticate() | using qop=auth-int [a2:"%s"]',l),this._response=o.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(this._ncHex,":").concat(this._cnonce,":auth-int:").concat(u))):null===this._qop&&(l="".concat(this._method,":").concat(this._uri),u=o.calculateMD5(l),s.debug('authenticate() | using qop=null [a2:"%s"]',l),this._response=o.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(u))),s.debug("authenticate() | response generated"),!0}},{key:"toString",value:function(){var e=[];if(!this._response)throw new Error("response field does not exist, cannot generate Authorization header");return e.push("algorithm=".concat(this._algorithm)),e.push('username="'.concat(this._credentials.username,'"')),e.push('realm="'.concat(this._realm,'"')),e.push('nonce="'.concat(this._nonce,'"')),e.push('uri="'.concat(this._uri,'"')),e.push('response="'.concat(this._response,'"')),this._opaque&&e.push('opaque="'.concat(this._opaque,'"')),this._qop&&(e.push("qop=".concat(this._qop)),e.push('cnonce="'.concat(this._cnonce,'"')),e.push("nc=".concat(this._ncHex))),"Digest ".concat(e.join(", "))}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Logger":9,"./Utils":30}],6:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n",o++):(e=null,0===s&&u('">"')),null===e&&(64===n.charCodeAt(o)?(e="@",o++):(e=null,0===s&&u('"@"')),null===e&&(44===n.charCodeAt(o)?(e=",",o++):(e=null,0===s&&u('","')),null===e&&(59===n.charCodeAt(o)?(e=";",o++):(e=null,0===s&&u('";"')),null===e&&(58===n.charCodeAt(o)?(e=":",o++):(e=null,0===s&&u('":"')),null===e&&(92===n.charCodeAt(o)?(e="\\",o++):(e=null,0===s&&u('"\\\\"')),null===e&&null===(e=v())&&(47===n.charCodeAt(o)?(e="/",o++):(e=null,0===s&&u('"/"')),null===e&&(91===n.charCodeAt(o)?(e="[",o++):(e=null,0===s&&u('"["')),null===e&&(93===n.charCodeAt(o)?(e="]",o++):(e=null,0===s&&u('"]"')),null===e&&(63===n.charCodeAt(o)?(e="?",o++):(e=null,0===s&&u('"?"')),null===e&&(61===n.charCodeAt(o)?(e="=",o++):(e=null,0===s&&u('"="')),null===e&&(123===n.charCodeAt(o)?(e="{",o++):(e=null,0===s&&u('"{"')),null===e&&(125===n.charCodeAt(o)?(e="}",o++):(e=null,0===s&&u('"}"')),null===e&&null===(e=g())&&(e=m()))))))))))))))));return e},word:x,STAR:U,SLASH:D,EQUAL:M,LPAREN:L,RPAREN:j,RAQUOT:H,LAQUOT:q,COMMA:F,SEMI:V,COLON:B,LDQUOT:W,RDQUOT:G,comment:function e(){var t,n,r;var i;i=o;t=L();if(null!==t){for(n=[],null===(r=z())&&null===(r=$())&&(r=e());null!==r;)n.push(r),null===(r=z())&&null===(r=$())&&(r=e());null!==n&&null!==(r=j())?t=[t,n,r]:(t=null,o=i)}else t=null,o=i;return t},ctext:z,quoted_string:Y,quoted_string_clean:K,qdtext:J,quoted_pair:$,SIP_URI_noparams:X,SIP_URI:Q,uri_scheme:Z,uri_scheme_sips:ee,uri_scheme_sip:te,userinfo:ne,user:re,user_unreserved:ie,password:oe,hostport:se,host:ae,hostname:le,domainlabel:ue,toplabel:ce,IPv6reference:de,IPv6address:he,h16:fe,ls32:_e,IPv4address:pe,dec_octet:ve,port:ge,uri_parameters:me,uri_parameter:ye,transport_param:be,user_param:Te,method_param:Ce,ttl_param:Se,maddr_param:Ae,lr_param:we,other_param:Ee,pname:Re,pvalue:Ie,paramchar:ke,param_unreserved:Oe,headers:Pe,header:Ne,hname:xe,hvalue:Ue,hnv_unreserved:De,Request_Response:function(){var e;null===(e=dt())&&(e=Me());return e},Request_Line:Me,Request_URI:Le,absoluteURI:je,hier_part:He,net_path:qe,abs_path:Fe,opaque_part:Ve,uric:Be,uric_no_slash:We,path_segments:Ge,segment:ze,param:Ye,pchar:Ke,scheme:Je,authority:$e,srvr:Xe,reg_name:Qe,query:Ze,SIP_Version:et,INVITEm:tt,ACKm:nt,OPTIONSm:rt,BYEm:it,CANCELm:ot,REGISTERm:st,SUBSCRIBEm:at,NOTIFYm:lt,REFERm:ut,Method:ct,Status_Line:dt,Status_Code:ht,extension_code:ft,Reason_Phrase:_t,Allow_Events:function(){var e,t,n,r,i,s;if(i=o,null!==(e=jt())){for(t=[],s=o,null!==(n=F())&&null!==(r=jt())?n=[n,r]:(n=null,o=s);null!==n;)t.push(n),s=o,null!==(n=F())&&null!==(r=jt())?n=[n,r]:(n=null,o=s);null!==t?e=[e,t]:(e=null,o=i)}else e=null,o=i;return e},Call_ID:function(){var e,t,r,i,a,l;i=o,a=o,null!==(e=x())?(l=o,64===n.charCodeAt(o)?(t="@",o++):(t=null,0===s&&u('"@"')),null!==t&&null!==(r=x())?t=[t,r]:(t=null,o=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=a)):(e=null,o=a);null!==e&&(c=i,e=void(Fn=n.substring(o,c)));var c;null===e&&(o=i);return e},Contact:function(){var e,t,n,r,i,s,a;if(i=o,null===(e=U()))if(s=o,null!==(e=pt())){for(t=[],a=o,null!==(n=F())&&null!==(r=pt())?n=[n,r]:(n=null,o=a);null!==n;)t.push(n),a=o,null!==(n=F())&&null!==(r=pt())?n=[n,r]:(n=null,o=a);null!==t?e=[e,t]:(e=null,o=s)}else e=null,o=s;null!==e&&(e=function(e){var t,n;for(n=Fn.multi_header.length,t=0;ta&&(a=o,l=[]),l.push(e))}function c(){var e;return"\r\n"===n.substr(o,2)?(e="\r\n",o+=2):(e=null,0===s&&u('"\\r\\n"')),e}function d(){var e;return/^[0-9]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[0-9]")),e}function h(){var e;return/^[a-zA-Z]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[a-zA-Z]")),e}function f(){var e;return/^[0-9a-fA-F]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[0-9a-fA-F]")),e}function _(){var e;return null===(e=g())&&(e=m()),e}function p(){var e;return/^[\0-\xFF]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[\\0-\\xFF]")),e}function v(){var e;return/^["]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u('["]')),e}function g(){var e;return 32===n.charCodeAt(o)?(e=" ",o++):(e=null,0===s&&u('" "')),e}function m(){var e;return 9===n.charCodeAt(o)?(e="\t",o++):(e=null,0===s&&u('"\\t"')),e}function y(){var e;return/^[a-zA-Z0-9]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[a-zA-Z0-9]")),e}function b(){var e;return 59===n.charCodeAt(o)?(e=";",o++):(e=null,0===s&&u('";"')),null===e&&(47===n.charCodeAt(o)?(e="/",o++):(e=null,0===s&&u('"/"')),null===e&&(63===n.charCodeAt(o)?(e="?",o++):(e=null,0===s&&u('"?"')),null===e&&(58===n.charCodeAt(o)?(e=":",o++):(e=null,0===s&&u('":"')),null===e&&(64===n.charCodeAt(o)?(e="@",o++):(e=null,0===s&&u('"@"')),null===e&&(38===n.charCodeAt(o)?(e="&",o++):(e=null,0===s&&u('"&"')),null===e&&(61===n.charCodeAt(o)?(e="=",o++):(e=null,0===s&&u('"="')),null===e&&(43===n.charCodeAt(o)?(e="+",o++):(e=null,0===s&&u('"+"')),null===e&&(36===n.charCodeAt(o)?(e="$",o++):(e=null,0===s&&u('"$"')),null===e&&(44===n.charCodeAt(o)?(e=",",o++):(e=null,0===s&&u('","'))))))))))),e}function T(){var e;return null===(e=y())&&(e=C()),e}function C(){var e;return 45===n.charCodeAt(o)?(e="-",o++):(e=null,0===s&&u('"-"')),null===e&&(95===n.charCodeAt(o)?(e="_",o++):(e=null,0===s&&u('"_"')),null===e&&(46===n.charCodeAt(o)?(e=".",o++):(e=null,0===s&&u('"."')),null===e&&(33===n.charCodeAt(o)?(e="!",o++):(e=null,0===s&&u('"!"')),null===e&&(126===n.charCodeAt(o)?(e="~",o++):(e=null,0===s&&u('"~"')),null===e&&(42===n.charCodeAt(o)?(e="*",o++):(e=null,0===s&&u('"*"')),null===e&&(39===n.charCodeAt(o)?(e="'",o++):(e=null,0===s&&u('"\'"')),null===e&&(40===n.charCodeAt(o)?(e="(",o++):(e=null,0===s&&u('"("')),null===e&&(41===n.charCodeAt(o)?(e=")",o++):(e=null,0===s&&u('")"')))))))))),e}function S(){var e,t,r,i,a;return i=o,a=o,37===n.charCodeAt(o)?(e="%",o++):(e=null,0===s&&u('"%"')),null!==e&&null!==(t=f())&&null!==(r=f())?e=[e,t,r]:(e=null,o=a),null!==e&&(e=e.join("")),null===e&&(o=i),e}function A(){var e,t,n,r,i,s;for(r=o,i=o,s=o,e=[],t=_();null!==t;)e.push(t),t=_();if(null!==e&&null!==(t=c())?e=[e,t]:(e=null,o=s),null!==(e=null!==e?e:"")){if(null!==(n=_()))for(t=[];null!==n;)t.push(n),n=_();else t=null;null!==t?e=[e,t]:(e=null,o=i)}else e=null,o=i;return null!==e&&(e=" "),null===e&&(o=r),e}function w(){var e;return e=null!==(e=A())?e:""}function E(){var e,t,r,i,a;for(i=o,a=o,e=[],null===(t=g())&&(t=m());null!==t;)e.push(t),null===(t=g())&&(t=m());return null!==e?(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e=":"),null===e&&(o=i),e}function R(){var e,t,r,i,s,a,l,u;if(s=o,a=o,null!==(t=I()))for(e=[];null!==t;)e.push(t),t=I();else e=null;if(null!==e){for(t=[],l=o,r=[],i=A();null!==i;)r.push(i),i=A();for(null!==r&&null!==(i=I())?r=[r,i]:(r=null,o=l);null!==r;){for(t.push(r),l=o,r=[],i=A();null!==i;)r.push(i),i=A();null!==r&&null!==(i=I())?r=[r,i]:(r=null,o=l)}null!==t?e=[e,t]:(e=null,o=a)}else e=null,o=a;return null!==e&&(u=s,e=n.substring(o,u)),null===e&&(o=s),e}function I(){var e;return/^[!-~]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[!-~]")),null===e&&(e=k()),e}function k(){var e;return/^[\x80-\uFFFF]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[\\x80-\\uFFFF]")),e}function O(){var e;return/^[\x80-\xBF]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[\\x80-\\xBF]")),e}function P(){var e,t,r,i;if(r=o,null===(t=y())&&(45===n.charCodeAt(o)?(t="-",o++):(t=null,0===s&&u('"-"')),null===t&&(46===n.charCodeAt(o)?(t=".",o++):(t=null,0===s&&u('"."')),null===t&&(33===n.charCodeAt(o)?(t="!",o++):(t=null,0===s&&u('"!"')),null===t&&(37===n.charCodeAt(o)?(t="%",o++):(t=null,0===s&&u('"%"')),null===t&&(42===n.charCodeAt(o)?(t="*",o++):(t=null,0===s&&u('"*"')),null===t&&(95===n.charCodeAt(o)?(t="_",o++):(t=null,0===s&&u('"_"')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(96===n.charCodeAt(o)?(t="`",o++):(t=null,0===s&&u('"`"')),null===t&&(39===n.charCodeAt(o)?(t="'",o++):(t=null,0===s&&u('"\'"')),null===t&&(126===n.charCodeAt(o)?(t="~",o++):(t=null,0===s&&u('"~"')))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(o)?(t="-",o++):(t=null,0===s&&u('"-"')),null===t&&(46===n.charCodeAt(o)?(t=".",o++):(t=null,0===s&&u('"."')),null===t&&(33===n.charCodeAt(o)?(t="!",o++):(t=null,0===s&&u('"!"')),null===t&&(37===n.charCodeAt(o)?(t="%",o++):(t=null,0===s&&u('"%"')),null===t&&(42===n.charCodeAt(o)?(t="*",o++):(t=null,0===s&&u('"*"')),null===t&&(95===n.charCodeAt(o)?(t="_",o++):(t=null,0===s&&u('"_"')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(96===n.charCodeAt(o)?(t="`",o++):(t=null,0===s&&u('"`"')),null===t&&(39===n.charCodeAt(o)?(t="'",o++):(t=null,0===s&&u('"\'"')),null===t&&(126===n.charCodeAt(o)?(t="~",o++):(t=null,0===s&&u('"~"'))))))))))));else e=null;return null!==e&&(i=r,e=n.substring(o,i)),null===e&&(o=r),e}function N(){var e,t,r,i;if(r=o,null===(t=y())&&(45===n.charCodeAt(o)?(t="-",o++):(t=null,0===s&&u('"-"')),null===t&&(33===n.charCodeAt(o)?(t="!",o++):(t=null,0===s&&u('"!"')),null===t&&(37===n.charCodeAt(o)?(t="%",o++):(t=null,0===s&&u('"%"')),null===t&&(42===n.charCodeAt(o)?(t="*",o++):(t=null,0===s&&u('"*"')),null===t&&(95===n.charCodeAt(o)?(t="_",o++):(t=null,0===s&&u('"_"')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(96===n.charCodeAt(o)?(t="`",o++):(t=null,0===s&&u('"`"')),null===t&&(39===n.charCodeAt(o)?(t="'",o++):(t=null,0===s&&u('"\'"')),null===t&&(126===n.charCodeAt(o)?(t="~",o++):(t=null,0===s&&u('"~"'))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(o)?(t="-",o++):(t=null,0===s&&u('"-"')),null===t&&(33===n.charCodeAt(o)?(t="!",o++):(t=null,0===s&&u('"!"')),null===t&&(37===n.charCodeAt(o)?(t="%",o++):(t=null,0===s&&u('"%"')),null===t&&(42===n.charCodeAt(o)?(t="*",o++):(t=null,0===s&&u('"*"')),null===t&&(95===n.charCodeAt(o)?(t="_",o++):(t=null,0===s&&u('"_"')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(96===n.charCodeAt(o)?(t="`",o++):(t=null,0===s&&u('"`"')),null===t&&(39===n.charCodeAt(o)?(t="'",o++):(t=null,0===s&&u('"\'"')),null===t&&(126===n.charCodeAt(o)?(t="~",o++):(t=null,0===s&&u('"~"')))))))))));else e=null;return null!==e&&(i=r,e=n.substring(o,i)),null===e&&(o=r),e}function x(){var e,t,r,i;if(r=o,null===(t=y())&&(45===n.charCodeAt(o)?(t="-",o++):(t=null,0===s&&u('"-"')),null===t&&(46===n.charCodeAt(o)?(t=".",o++):(t=null,0===s&&u('"."')),null===t&&(33===n.charCodeAt(o)?(t="!",o++):(t=null,0===s&&u('"!"')),null===t&&(37===n.charCodeAt(o)?(t="%",o++):(t=null,0===s&&u('"%"')),null===t&&(42===n.charCodeAt(o)?(t="*",o++):(t=null,0===s&&u('"*"')),null===t&&(95===n.charCodeAt(o)?(t="_",o++):(t=null,0===s&&u('"_"')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(96===n.charCodeAt(o)?(t="`",o++):(t=null,0===s&&u('"`"')),null===t&&(39===n.charCodeAt(o)?(t="'",o++):(t=null,0===s&&u('"\'"')),null===t&&(126===n.charCodeAt(o)?(t="~",o++):(t=null,0===s&&u('"~"')),null===t&&(40===n.charCodeAt(o)?(t="(",o++):(t=null,0===s&&u('"("')),null===t&&(41===n.charCodeAt(o)?(t=")",o++):(t=null,0===s&&u('")"')),null===t&&(60===n.charCodeAt(o)?(t="<",o++):(t=null,0===s&&u('"<"')),null===t&&(62===n.charCodeAt(o)?(t=">",o++):(t=null,0===s&&u('">"')),null===t&&(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null===t&&(92===n.charCodeAt(o)?(t="\\",o++):(t=null,0===s&&u('"\\\\"')),null===t&&null===(t=v())&&(47===n.charCodeAt(o)?(t="/",o++):(t=null,0===s&&u('"/"')),null===t&&(91===n.charCodeAt(o)?(t="[",o++):(t=null,0===s&&u('"["')),null===t&&(93===n.charCodeAt(o)?(t="]",o++):(t=null,0===s&&u('"]"')),null===t&&(63===n.charCodeAt(o)?(t="?",o++):(t=null,0===s&&u('"?"')),null===t&&(123===n.charCodeAt(o)?(t="{",o++):(t=null,0===s&&u('"{"')),null===t&&(125===n.charCodeAt(o)?(t="}",o++):(t=null,0===s&&u('"}"')))))))))))))))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(o)?(t="-",o++):(t=null,0===s&&u('"-"')),null===t&&(46===n.charCodeAt(o)?(t=".",o++):(t=null,0===s&&u('"."')),null===t&&(33===n.charCodeAt(o)?(t="!",o++):(t=null,0===s&&u('"!"')),null===t&&(37===n.charCodeAt(o)?(t="%",o++):(t=null,0===s&&u('"%"')),null===t&&(42===n.charCodeAt(o)?(t="*",o++):(t=null,0===s&&u('"*"')),null===t&&(95===n.charCodeAt(o)?(t="_",o++):(t=null,0===s&&u('"_"')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(96===n.charCodeAt(o)?(t="`",o++):(t=null,0===s&&u('"`"')),null===t&&(39===n.charCodeAt(o)?(t="'",o++):(t=null,0===s&&u('"\'"')),null===t&&(126===n.charCodeAt(o)?(t="~",o++):(t=null,0===s&&u('"~"')),null===t&&(40===n.charCodeAt(o)?(t="(",o++):(t=null,0===s&&u('"("')),null===t&&(41===n.charCodeAt(o)?(t=")",o++):(t=null,0===s&&u('")"')),null===t&&(60===n.charCodeAt(o)?(t="<",o++):(t=null,0===s&&u('"<"')),null===t&&(62===n.charCodeAt(o)?(t=">",o++):(t=null,0===s&&u('">"')),null===t&&(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null===t&&(92===n.charCodeAt(o)?(t="\\",o++):(t=null,0===s&&u('"\\\\"')),null===t&&null===(t=v())&&(47===n.charCodeAt(o)?(t="/",o++):(t=null,0===s&&u('"/"')),null===t&&(91===n.charCodeAt(o)?(t="[",o++):(t=null,0===s&&u('"["')),null===t&&(93===n.charCodeAt(o)?(t="]",o++):(t=null,0===s&&u('"]"')),null===t&&(63===n.charCodeAt(o)?(t="?",o++):(t=null,0===s&&u('"?"')),null===t&&(123===n.charCodeAt(o)?(t="{",o++):(t=null,0===s&&u('"{"')),null===t&&(125===n.charCodeAt(o)?(t="}",o++):(t=null,0===s&&u('"}"'))))))))))))))))))))))));else e=null;return null!==e&&(i=r,e=n.substring(o,i)),null===e&&(o=r),e}function U(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(42===n.charCodeAt(o)?(t="*",o++):(t=null,0===s&&u('"*"')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e="*"),null===e&&(o=i),e}function D(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(47===n.charCodeAt(o)?(t="/",o++):(t=null,0===s&&u('"/"')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e="/"),null===e&&(o=i),e}function M(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e="="),null===e&&(o=i),e}function L(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(40===n.charCodeAt(o)?(t="(",o++):(t=null,0===s&&u('"("')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e="("),null===e&&(o=i),e}function j(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(41===n.charCodeAt(o)?(t=")",o++):(t=null,0===s&&u('")"')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e=")"),null===e&&(o=i),e}function H(){var e,t,r,i;return r=o,i=o,62===n.charCodeAt(o)?(e=">",o++):(e=null,0===s&&u('">"')),null!==e&&null!==(t=w())?e=[e,t]:(e=null,o=i),null!==e&&(e=">"),null===e&&(o=r),e}function q(){var e,t,r,i;return r=o,i=o,null!==(e=w())?(60===n.charCodeAt(o)?(t="<",o++):(t=null,0===s&&u('"<"')),null!==t?e=[e,t]:(e=null,o=i)):(e=null,o=i),null!==e&&(e="<"),null===e&&(o=r),e}function F(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(44===n.charCodeAt(o)?(t=",",o++):(t=null,0===s&&u('","')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e=","),null===e&&(o=i),e}function V(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(59===n.charCodeAt(o)?(t=";",o++):(t=null,0===s&&u('";"')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e=";"),null===e&&(o=i),e}function B(){var e,t,r,i,a;return i=o,a=o,null!==(e=w())?(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=w())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(e=":"),null===e&&(o=i),e}function W(){var e,t,n,r;return n=o,r=o,null!==(e=w())&&null!==(t=v())?e=[e,t]:(e=null,o=r),null!==e&&(e='"'),null===e&&(o=n),e}function G(){var e,t,n,r;return n=o,r=o,null!==(e=v())&&null!==(t=w())?e=[e,t]:(e=null,o=r),null!==e&&(e='"'),null===e&&(o=n),e}function z(){var e;return/^[!-']/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[!-']")),null===e&&(/^[*-[]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[*-[]")),null===e&&(/^[\]-~]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[\\]-~]")),null===e&&null===(e=k())&&(e=A()))),e}function Y(){var e,t,r,i,s,a,l;if(s=o,a=o,null!==(e=w()))if(null!==(t=v())){for(r=[],null===(i=J())&&(i=$());null!==i;)r.push(i),null===(i=J())&&(i=$());null!==r&&null!==(i=v())?e=[e,t,r,i]:(e=null,o=a)}else e=null,o=a;else e=null,o=a;return null!==e&&(l=s,e=n.substring(o,l)),null===e&&(o=s),e}function K(){var e,t,r,i,s,a,l,u;if(s=o,a=o,null!==(e=w()))if(null!==(t=v())){for(r=[],null===(i=J())&&(i=$());null!==i;)r.push(i),null===(i=J())&&(i=$());null!==r&&null!==(i=v())?e=[e,t,r,i]:(e=null,o=a)}else e=null,o=a;else e=null,o=a;return null!==e&&(l=s,e=(u=n.substring(o,l).trim()).substring(1,u.length-1).replace(/\\([\x00-\x09\x0b-\x0c\x0e-\x7f])/g,"$1")),null===e&&(o=s),e}function J(){var e;return null===(e=A())&&(33===n.charCodeAt(o)?(e="!",o++):(e=null,0===s&&u('"!"')),null===e&&(/^[#-[]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[#-[]")),null===e&&(/^[\]-~]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[\\]-~]")),null===e&&(e=k())))),e}function $(){var e,t,r;return r=o,92===n.charCodeAt(o)?(e="\\",o++):(e=null,0===s&&u('"\\\\"')),null!==e?(/^[\0-\t]/.test(n.charAt(o))?(t=n.charAt(o),o++):(t=null,0===s&&u("[\\0-\\t]")),null===t&&(/^[\x0B-\f]/.test(n.charAt(o))?(t=n.charAt(o),o++):(t=null,0===s&&u("[\\x0B-\\f]")),null===t&&(/^[\x0E-]/.test(n.charAt(o))?(t=n.charAt(o),o++):(t=null,0===s&&u("[\\x0E-]")))),null!==t?e=[e,t]:(e=null,o=r)):(e=null,o=r),e}function X(){var e,t,r,i,a,l;return a=o,l=o,null!==(e=Z())?(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=null!==(r=ne())?r:"")&&null!==(i=se())?e=[e,t,r,i]:(e=null,o=l)):(e=null,o=l),null!==e&&(e=function(e){try{Fn.uri=new Hn(Fn.scheme,Fn.user,Fn.host,Fn.port),delete Fn.scheme,delete Fn.user,delete Fn.host,delete Fn.host_type,delete Fn.port}catch(e){Fn=-1}}()),null===e&&(o=a),e}function Q(){var e,t,i,a,l,c,d,h;return d=o,h=o,null!==(e=Z())?(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(i=null!==(i=ne())?i:"")&&null!==(a=se())&&null!==(l=me())&&null!==(c=null!==(c=Pe())?c:"")?e=[e,t,i,a,l,c]:(e=null,o=h)):(e=null,o=h),null!==e&&(e=function(e){try{Fn.uri=new Hn(Fn.scheme,Fn.user,Fn.host,Fn.port,Fn.uri_params,Fn.uri_headers),delete Fn.scheme,delete Fn.user,delete Fn.host,delete Fn.host_type,delete Fn.port,delete Fn.uri_params,"SIP_URI"===r&&(Fn=Fn.uri)}catch(e){Fn=-1}}()),null===e&&(o=d),e}function Z(){var e;return null===(e=ee())&&(e=te()),e}function ee(){var e,t,r;return t=o,"sips"===n.substr(o,4).toLowerCase()?(e=n.substr(o,4),o+=4):(e=null,0===s&&u('"sips"')),null!==e&&(r=e,e=void(Fn.scheme=r.toLowerCase())),null===e&&(o=t),e}function te(){var e,t,r;return t=o,"sip"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"sip"')),null!==e&&(r=e,e=void(Fn.scheme=r.toLowerCase())),null===e&&(o=t),e}function ne(){var e,t,r,i,a,l,c;return i=o,a=o,null!==(e=re())?(l=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=oe())?t=[t,r]:(t=null,o=l),null!==(t=null!==t?t:"")?(64===n.charCodeAt(o)?(r="@",o++):(r=null,0===s&&u('"@"')),null!==r?e=[e,t,r]:(e=null,o=a)):(e=null,o=a)):(e=null,o=a),null!==e&&(c=i,e=void(Fn.user=decodeURIComponent(n.substring(o-1,c)))),null===e&&(o=i),e}function re(){var e,t;if(null===(t=T())&&null===(t=S())&&(t=ie()),null!==t)for(e=[];null!==t;)e.push(t),null===(t=T())&&null===(t=S())&&(t=ie());else e=null;return e}function ie(){var e;return 38===n.charCodeAt(o)?(e="&",o++):(e=null,0===s&&u('"&"')),null===e&&(61===n.charCodeAt(o)?(e="=",o++):(e=null,0===s&&u('"="')),null===e&&(43===n.charCodeAt(o)?(e="+",o++):(e=null,0===s&&u('"+"')),null===e&&(36===n.charCodeAt(o)?(e="$",o++):(e=null,0===s&&u('"$"')),null===e&&(44===n.charCodeAt(o)?(e=",",o++):(e=null,0===s&&u('","')),null===e&&(59===n.charCodeAt(o)?(e=";",o++):(e=null,0===s&&u('";"')),null===e&&(63===n.charCodeAt(o)?(e="?",o++):(e=null,0===s&&u('"?"')),null===e&&(47===n.charCodeAt(o)?(e="/",o++):(e=null,0===s&&u('"/"'))))))))),e}function oe(){var e,t,r,i;for(r=o,e=[],null===(t=T())&&null===(t=S())&&(38===n.charCodeAt(o)?(t="&",o++):(t=null,0===s&&u('"&"')),null===t&&(61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(36===n.charCodeAt(o)?(t="$",o++):(t=null,0===s&&u('"$"')),null===t&&(44===n.charCodeAt(o)?(t=",",o++):(t=null,0===s&&u('","')))))));null!==t;)e.push(t),null===(t=T())&&null===(t=S())&&(38===n.charCodeAt(o)?(t="&",o++):(t=null,0===s&&u('"&"')),null===t&&(61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')),null===t&&(36===n.charCodeAt(o)?(t="$",o++):(t=null,0===s&&u('"$"')),null===t&&(44===n.charCodeAt(o)?(t=",",o++):(t=null,0===s&&u('","')))))));return null!==e&&(i=r,e=void(Fn.password=n.substring(o,i))),null===e&&(o=r),e}function se(){var e,t,r,i,a;return i=o,null!==(e=ae())?(a=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=ge())?t=[t,r]:(t=null,o=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=i)):(e=null,o=i),e}function ae(){var e,t,r;return t=o,null===(e=le())&&null===(e=pe())&&(e=de()),null!==e&&(r=t,Fn.host=n.substring(o,r).toLowerCase(),e=Fn.host),null===e&&(o=t),e}function le(){var e,t,r,i,a,l,c;for(i=o,a=o,e=[],l=o,null!==(t=ue())?(46===n.charCodeAt(o)?(r=".",o++):(r=null,0===s&&u('"."')),null!==r?t=[t,r]:(t=null,o=l)):(t=null,o=l);null!==t;)e.push(t),l=o,null!==(t=ue())?(46===n.charCodeAt(o)?(r=".",o++):(r=null,0===s&&u('"."')),null!==r?t=[t,r]:(t=null,o=l)):(t=null,o=l);return null!==e&&null!==(t=ce())?(46===n.charCodeAt(o)?(r=".",o++):(r=null,0===s&&u('"."')),null!==(r=null!==r?r:"")?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(c=i,Fn.host_type="domain",e=n.substring(o,c)),null===e&&(o=i),e}function ue(){var e,t,r,i;if(i=o,null!==(e=y())){for(t=[],null===(r=y())&&(45===n.charCodeAt(o)?(r="-",o++):(r=null,0===s&&u('"-"')),null===r&&(95===n.charCodeAt(o)?(r="_",o++):(r=null,0===s&&u('"_"'))));null!==r;)t.push(r),null===(r=y())&&(45===n.charCodeAt(o)?(r="-",o++):(r=null,0===s&&u('"-"')),null===r&&(95===n.charCodeAt(o)?(r="_",o++):(r=null,0===s&&u('"_"'))));null!==t?e=[e,t]:(e=null,o=i)}else e=null,o=i;return e}function ce(){var e,t,r,i;if(i=o,null!==(e=h())){for(t=[],null===(r=y())&&(45===n.charCodeAt(o)?(r="-",o++):(r=null,0===s&&u('"-"')),null===r&&(95===n.charCodeAt(o)?(r="_",o++):(r=null,0===s&&u('"_"'))));null!==r;)t.push(r),null===(r=y())&&(45===n.charCodeAt(o)?(r="-",o++):(r=null,0===s&&u('"-"')),null===r&&(95===n.charCodeAt(o)?(r="_",o++):(r=null,0===s&&u('"_"'))));null!==t?e=[e,t]:(e=null,o=i)}else e=null,o=i;return e}function de(){var e,t,r,i,a,l;return i=o,a=o,91===n.charCodeAt(o)?(e="[",o++):(e=null,0===s&&u('"["')),null!==e&&null!==(t=he())?(93===n.charCodeAt(o)?(r="]",o++):(r=null,0===s&&u('"]"')),null!==r?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(l=i,Fn.host_type="IPv6",e=n.substring(o,l)),null===e&&(o=i),e}function he(){var e,t,r,i,a,l,c,d,h,f,_,p,v,g,m,y,b;return g=o,m=o,null!==(e=fe())?(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?(58===n.charCodeAt(o)?(i=":",o++):(i=null,0===s&&u('":"')),null!==i&&null!==(a=fe())?(58===n.charCodeAt(o)?(l=":",o++):(l=null,0===s&&u('":"')),null!==l&&null!==(c=fe())?(58===n.charCodeAt(o)?(d=":",o++):(d=null,0===s&&u('":"')),null!==d&&null!==(h=fe())?(58===n.charCodeAt(o)?(f=":",o++):(f=null,0===s&&u('":"')),null!==f&&null!==(_=fe())?(58===n.charCodeAt(o)?(p=":",o++):(p=null,0===s&&u('":"')),null!==p&&null!==(v=_e())?e=[e,t,r,i,a,l,c,d,h,f,_,p,v]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,"::"===n.substr(o,2)?(e="::",o+=2):(e=null,0===s&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=fe())?(58===n.charCodeAt(o)?(c=":",o++):(c=null,0===s&&u('":"')),null!==c&&null!==(d=fe())?(58===n.charCodeAt(o)?(h=":",o++):(h=null,0===s&&u('":"')),null!==h&&null!==(f=fe())?(58===n.charCodeAt(o)?(_=":",o++):(_=null,0===s&&u('":"')),null!==_&&null!==(p=_e())?e=[e,t,r,i,a,l,c,d,h,f,_,p]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,"::"===n.substr(o,2)?(e="::",o+=2):(e=null,0===s&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=fe())?(58===n.charCodeAt(o)?(c=":",o++):(c=null,0===s&&u('":"')),null!==c&&null!==(d=fe())?(58===n.charCodeAt(o)?(h=":",o++):(h=null,0===s&&u('":"')),null!==h&&null!==(f=_e())?e=[e,t,r,i,a,l,c,d,h,f]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,"::"===n.substr(o,2)?(e="::",o+=2):(e=null,0===s&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=fe())?(58===n.charCodeAt(o)?(c=":",o++):(c=null,0===s&&u('":"')),null!==c&&null!==(d=_e())?e=[e,t,r,i,a,l,c,d]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,"::"===n.substr(o,2)?(e="::",o+=2):(e=null,0===s&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=_e())?e=[e,t,r,i,a,l]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,"::"===n.substr(o,2)?(e="::",o+=2):(e=null,0===s&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=_e())?e=[e,t,r,i]:(e=null,o=m)):(e=null,o=m),null===e&&(m=o,"::"===n.substr(o,2)?(e="::",o+=2):(e=null,0===s&&u('"::"')),null!==e&&null!==(t=_e())?e=[e,t]:(e=null,o=m),null===e&&(m=o,"::"===n.substr(o,2)?(e="::",o+=2):(e=null,0===s&&u('"::"')),null!==e&&null!==(t=fe())?e=[e,t]:(e=null,o=m),null===e&&(m=o,null!==(e=fe())?("::"===n.substr(o,2)?(t="::",o+=2):(t=null,0===s&&u('"::"')),null!==t&&null!==(r=fe())?(58===n.charCodeAt(o)?(i=":",o++):(i=null,0===s&&u('":"')),null!==i&&null!==(a=fe())?(58===n.charCodeAt(o)?(l=":",o++):(l=null,0===s&&u('":"')),null!==l&&null!==(c=fe())?(58===n.charCodeAt(o)?(d=":",o++):(d=null,0===s&&u('":"')),null!==d&&null!==(h=fe())?(58===n.charCodeAt(o)?(f=":",o++):(f=null,0===s&&u('":"')),null!==f&&null!==(_=_e())?e=[e,t,r,i,a,l,c,d,h,f,_]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,null!==(e=fe())?(y=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,o=y),null!==(t=null!==t?t:"")?("::"===n.substr(o,2)?(r="::",o+=2):(r=null,0===s&&u('"::"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=fe())?(58===n.charCodeAt(o)?(c=":",o++):(c=null,0===s&&u('":"')),null!==c&&null!==(d=fe())?(58===n.charCodeAt(o)?(h=":",o++):(h=null,0===s&&u('":"')),null!==h&&null!==(f=_e())?e=[e,t,r,i,a,l,c,d,h,f]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,null!==(e=fe())?(y=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,o=y),null!==(t=null!==t?t:"")?(y=o,58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,o=y),null!==(r=null!==r?r:"")?("::"===n.substr(o,2)?(i="::",o+=2):(i=null,0===s&&u('"::"')),null!==i&&null!==(a=fe())?(58===n.charCodeAt(o)?(l=":",o++):(l=null,0===s&&u('":"')),null!==l&&null!==(c=fe())?(58===n.charCodeAt(o)?(d=":",o++):(d=null,0===s&&u('":"')),null!==d&&null!==(h=_e())?e=[e,t,r,i,a,l,c,d,h]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,null!==(e=fe())?(y=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,o=y),null!==(t=null!==t?t:"")?(y=o,58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,o=y),null!==(r=null!==r?r:"")?(y=o,58===n.charCodeAt(o)?(i=":",o++):(i=null,0===s&&u('":"')),null!==i&&null!==(a=fe())?i=[i,a]:(i=null,o=y),null!==(i=null!==i?i:"")?("::"===n.substr(o,2)?(a="::",o+=2):(a=null,0===s&&u('"::"')),null!==a&&null!==(l=fe())?(58===n.charCodeAt(o)?(c=":",o++):(c=null,0===s&&u('":"')),null!==c&&null!==(d=_e())?e=[e,t,r,i,a,l,c,d]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,null!==(e=fe())?(y=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,o=y),null!==(t=null!==t?t:"")?(y=o,58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,o=y),null!==(r=null!==r?r:"")?(y=o,58===n.charCodeAt(o)?(i=":",o++):(i=null,0===s&&u('":"')),null!==i&&null!==(a=fe())?i=[i,a]:(i=null,o=y),null!==(i=null!==i?i:"")?(y=o,58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=fe())?a=[a,l]:(a=null,o=y),null!==(a=null!==a?a:"")?("::"===n.substr(o,2)?(l="::",o+=2):(l=null,0===s&&u('"::"')),null!==l&&null!==(c=_e())?e=[e,t,r,i,a,l,c]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,null!==(e=fe())?(y=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,o=y),null!==(t=null!==t?t:"")?(y=o,58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,o=y),null!==(r=null!==r?r:"")?(y=o,58===n.charCodeAt(o)?(i=":",o++):(i=null,0===s&&u('":"')),null!==i&&null!==(a=fe())?i=[i,a]:(i=null,o=y),null!==(i=null!==i?i:"")?(y=o,58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=fe())?a=[a,l]:(a=null,o=y),null!==(a=null!==a?a:"")?(y=o,58===n.charCodeAt(o)?(l=":",o++):(l=null,0===s&&u('":"')),null!==l&&null!==(c=fe())?l=[l,c]:(l=null,o=y),null!==(l=null!==l?l:"")?("::"===n.substr(o,2)?(c="::",o+=2):(c=null,0===s&&u('"::"')),null!==c&&null!==(d=fe())?e=[e,t,r,i,a,l,c,d]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m),null===e&&(m=o,null!==(e=fe())?(y=o,58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,o=y),null!==(t=null!==t?t:"")?(y=o,58===n.charCodeAt(o)?(r=":",o++):(r=null,0===s&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,o=y),null!==(r=null!==r?r:"")?(y=o,58===n.charCodeAt(o)?(i=":",o++):(i=null,0===s&&u('":"')),null!==i&&null!==(a=fe())?i=[i,a]:(i=null,o=y),null!==(i=null!==i?i:"")?(y=o,58===n.charCodeAt(o)?(a=":",o++):(a=null,0===s&&u('":"')),null!==a&&null!==(l=fe())?a=[a,l]:(a=null,o=y),null!==(a=null!==a?a:"")?(y=o,58===n.charCodeAt(o)?(l=":",o++):(l=null,0===s&&u('":"')),null!==l&&null!==(c=fe())?l=[l,c]:(l=null,o=y),null!==(l=null!==l?l:"")?(y=o,58===n.charCodeAt(o)?(c=":",o++):(c=null,0===s&&u('":"')),null!==c&&null!==(d=fe())?c=[c,d]:(c=null,o=y),null!==(c=null!==c?c:"")?("::"===n.substr(o,2)?(d="::",o+=2):(d=null,0===s&&u('"::"')),null!==d?e=[e,t,r,i,a,l,c,d]:(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m)):(e=null,o=m))))))))))))))),null!==e&&(b=g,Fn.host_type="IPv6",e=n.substring(o,b)),null===e&&(o=g),e}function fe(){var e,t,n,r,i;return i=o,null!==(e=f())&&null!==(t=null!==(t=f())?t:"")&&null!==(n=null!==(n=f())?n:"")&&null!==(r=null!==(r=f())?r:"")?e=[e,t,n,r]:(e=null,o=i),e}function _e(){var e,t,r,i;return i=o,null!==(e=fe())?(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t&&null!==(r=fe())?e=[e,t,r]:(e=null,o=i)):(e=null,o=i),null===e&&(e=pe()),e}function pe(){var e,t,r,i,a,l,c,d,h,f;return d=o,h=o,null!==(e=ve())?(46===n.charCodeAt(o)?(t=".",o++):(t=null,0===s&&u('"."')),null!==t&&null!==(r=ve())?(46===n.charCodeAt(o)?(i=".",o++):(i=null,0===s&&u('"."')),null!==i&&null!==(a=ve())?(46===n.charCodeAt(o)?(l=".",o++):(l=null,0===s&&u('"."')),null!==l&&null!==(c=ve())?e=[e,t,r,i,a,l,c]:(e=null,o=h)):(e=null,o=h)):(e=null,o=h)):(e=null,o=h),null!==e&&(f=d,Fn.host_type="IPv4",e=n.substring(o,f)),null===e&&(o=d),e}function ve(){var e,t,r,i;return i=o,"25"===n.substr(o,2)?(e="25",o+=2):(e=null,0===s&&u('"25"')),null!==e?(/^[0-5]/.test(n.charAt(o))?(t=n.charAt(o),o++):(t=null,0===s&&u("[0-5]")),null!==t?e=[e,t]:(e=null,o=i)):(e=null,o=i),null===e&&(i=o,50===n.charCodeAt(o)?(e="2",o++):(e=null,0===s&&u('"2"')),null!==e?(/^[0-4]/.test(n.charAt(o))?(t=n.charAt(o),o++):(t=null,0===s&&u("[0-4]")),null!==t&&null!==(r=d())?e=[e,t,r]:(e=null,o=i)):(e=null,o=i),null===e&&(i=o,49===n.charCodeAt(o)?(e="1",o++):(e=null,0===s&&u('"1"')),null!==e&&null!==(t=d())&&null!==(r=d())?e=[e,t,r]:(e=null,o=i),null===e&&(i=o,/^[1-9]/.test(n.charAt(o))?(e=n.charAt(o),o++):(e=null,0===s&&u("[1-9]")),null!==e&&null!==(t=d())?e=[e,t]:(e=null,o=i),null===e&&(e=d())))),e}function ge(){var e,t,n,r,i,s,a,l;return s=o,a=o,null!==(e=null!==(e=d())?e:"")&&null!==(t=null!==(t=d())?t:"")&&null!==(n=null!==(n=d())?n:"")&&null!==(r=null!==(r=d())?r:"")&&null!==(i=null!==(i=d())?i:"")?e=[e,t,n,r,i]:(e=null,o=a),null!==e&&(l=e,l=parseInt(l.join("")),Fn.port=l,e=l),null===e&&(o=s),e}function me(){var e,t,r,i;for(e=[],i=o,59===n.charCodeAt(o)?(t=";",o++):(t=null,0===s&&u('";"')),null!==t&&null!==(r=ye())?t=[t,r]:(t=null,o=i);null!==t;)e.push(t),i=o,59===n.charCodeAt(o)?(t=";",o++):(t=null,0===s&&u('";"')),null!==t&&null!==(r=ye())?t=[t,r]:(t=null,o=i);return e}function ye(){var e;return null===(e=be())&&null===(e=Te())&&null===(e=Ce())&&null===(e=Se())&&null===(e=Ae())&&null===(e=we())&&(e=Ee()),e}function be(){var e,t,r,i,a;return r=o,i=o,"transport="===n.substr(o,10).toLowerCase()?(e=n.substr(o,10),o+=10):(e=null,0===s&&u('"transport="')),null!==e?("udp"===n.substr(o,3).toLowerCase()?(t=n.substr(o,3),o+=3):(t=null,0===s&&u('"udp"')),null===t&&("tcp"===n.substr(o,3).toLowerCase()?(t=n.substr(o,3),o+=3):(t=null,0===s&&u('"tcp"')),null===t&&("sctp"===n.substr(o,4).toLowerCase()?(t=n.substr(o,4),o+=4):(t=null,0===s&&u('"sctp"')),null===t&&("tls"===n.substr(o,3).toLowerCase()?(t=n.substr(o,3),o+=3):(t=null,0===s&&u('"tls"')),null===t&&(t=P())))),null!==t?e=[e,t]:(e=null,o=i)):(e=null,o=i),null!==e&&(a=e[1],Fn.uri_params||(Fn.uri_params={}),e=void(Fn.uri_params.transport=a.toLowerCase())),null===e&&(o=r),e}function Te(){var e,t,r,i,a;return r=o,i=o,"user="===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"user="')),null!==e?("phone"===n.substr(o,5).toLowerCase()?(t=n.substr(o,5),o+=5):(t=null,0===s&&u('"phone"')),null===t&&("ip"===n.substr(o,2).toLowerCase()?(t=n.substr(o,2),o+=2):(t=null,0===s&&u('"ip"')),null===t&&(t=P())),null!==t?e=[e,t]:(e=null,o=i)):(e=null,o=i),null!==e&&(a=e[1],Fn.uri_params||(Fn.uri_params={}),e=void(Fn.uri_params.user=a.toLowerCase())),null===e&&(o=r),e}function Ce(){var e,t,r,i,a;return r=o,i=o,"method="===n.substr(o,7).toLowerCase()?(e=n.substr(o,7),o+=7):(e=null,0===s&&u('"method="')),null!==e&&null!==(t=ct())?e=[e,t]:(e=null,o=i),null!==e&&(a=e[1],Fn.uri_params||(Fn.uri_params={}),e=void(Fn.uri_params.method=a)),null===e&&(o=r),e}function Se(){var e,t,r,i,a;return r=o,i=o,"ttl="===n.substr(o,4).toLowerCase()?(e=n.substr(o,4),o+=4):(e=null,0===s&&u('"ttl="')),null!==e&&null!==(t=wn())?e=[e,t]:(e=null,o=i),null!==e&&(a=e[1],Fn.params||(Fn.params={}),e=void(Fn.params.ttl=a)),null===e&&(o=r),e}function Ae(){var e,t,r,i,a;return r=o,i=o,"maddr="===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"maddr="')),null!==e&&null!==(t=ae())?e=[e,t]:(e=null,o=i),null!==e&&(a=e[1],Fn.uri_params||(Fn.uri_params={}),e=void(Fn.uri_params.maddr=a)),null===e&&(o=r),e}function we(){var e,t,r,i,a,l;return i=o,a=o,"lr"===n.substr(o,2).toLowerCase()?(e=n.substr(o,2),o+=2):(e=null,0===s&&u('"lr"')),null!==e?(l=o,61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null!==t&&null!==(r=P())?t=[t,r]:(t=null,o=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=a)):(e=null,o=a),null!==e&&(Fn.uri_params||(Fn.uri_params={}),e=void(Fn.uri_params.lr=void 0)),null===e&&(o=i),e}function Ee(){var e,t,r,i,a,l,c,d;return i=o,a=o,null!==(e=Re())?(l=o,61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null!==t&&null!==(r=Ie())?t=[t,r]:(t=null,o=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=a)):(e=null,o=a),null!==e&&(c=e[0],d=e[1],Fn.uri_params||(Fn.uri_params={}),d=void 0===d?void 0:d[1],e=void(Fn.uri_params[c.toLowerCase()]=d)),null===e&&(o=i),e}function Re(){var e,t,n;if(n=o,null!==(t=ke()))for(e=[];null!==t;)e.push(t),t=ke();else e=null;return null!==e&&(e=e.join("")),null===e&&(o=n),e}function Ie(){var e,t,n;if(n=o,null!==(t=ke()))for(e=[];null!==t;)e.push(t),t=ke();else e=null;return null!==e&&(e=e.join("")),null===e&&(o=n),e}function ke(){var e;return null===(e=Oe())&&null===(e=T())&&(e=S()),e}function Oe(){var e;return 91===n.charCodeAt(o)?(e="[",o++):(e=null,0===s&&u('"["')),null===e&&(93===n.charCodeAt(o)?(e="]",o++):(e=null,0===s&&u('"]"')),null===e&&(47===n.charCodeAt(o)?(e="/",o++):(e=null,0===s&&u('"/"')),null===e&&(58===n.charCodeAt(o)?(e=":",o++):(e=null,0===s&&u('":"')),null===e&&(38===n.charCodeAt(o)?(e="&",o++):(e=null,0===s&&u('"&"')),null===e&&(43===n.charCodeAt(o)?(e="+",o++):(e=null,0===s&&u('"+"')),null===e&&(36===n.charCodeAt(o)?(e="$",o++):(e=null,0===s&&u('"$"')))))))),e}function Pe(){var e,t,r,i,a,l,c;if(l=o,63===n.charCodeAt(o)?(e="?",o++):(e=null,0===s&&u('"?"')),null!==e)if(null!==(t=Ne())){for(r=[],c=o,38===n.charCodeAt(o)?(i="&",o++):(i=null,0===s&&u('"&"')),null!==i&&null!==(a=Ne())?i=[i,a]:(i=null,o=c);null!==i;)r.push(i),c=o,38===n.charCodeAt(o)?(i="&",o++):(i=null,0===s&&u('"&"')),null!==i&&null!==(a=Ne())?i=[i,a]:(i=null,o=c);null!==r?e=[e,t,r]:(e=null,o=l)}else e=null,o=l;else e=null,o=l;return e}function Ne(){var e,t,r,i,a,l,c;return i=o,a=o,null!==(e=xe())?(61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null!==t&&null!==(r=Ue())?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(l=e[0],c=e[2],l=l.join("").toLowerCase(),c=c.join(""),Fn.uri_headers||(Fn.uri_headers={}),e=void(Fn.uri_headers[l]?Fn.uri_headers[l].push(c):Fn.uri_headers[l]=[c])),null===e&&(o=i),e}function xe(){var e,t;if(null===(t=De())&&null===(t=T())&&(t=S()),null!==t)for(e=[];null!==t;)e.push(t),null===(t=De())&&null===(t=T())&&(t=S());else e=null;return e}function Ue(){var e,t;for(e=[],null===(t=De())&&null===(t=T())&&(t=S());null!==t;)e.push(t),null===(t=De())&&null===(t=T())&&(t=S());return e}function De(){var e;return 91===n.charCodeAt(o)?(e="[",o++):(e=null,0===s&&u('"["')),null===e&&(93===n.charCodeAt(o)?(e="]",o++):(e=null,0===s&&u('"]"')),null===e&&(47===n.charCodeAt(o)?(e="/",o++):(e=null,0===s&&u('"/"')),null===e&&(63===n.charCodeAt(o)?(e="?",o++):(e=null,0===s&&u('"?"')),null===e&&(58===n.charCodeAt(o)?(e=":",o++):(e=null,0===s&&u('":"')),null===e&&(43===n.charCodeAt(o)?(e="+",o++):(e=null,0===s&&u('"+"')),null===e&&(36===n.charCodeAt(o)?(e="$",o++):(e=null,0===s&&u('"$"')))))))),e}function Me(){var e,t,n,r,i,s;return s=o,null!==(e=ct())&&null!==(t=g())&&null!==(n=Le())&&null!==(r=g())&&null!==(i=et())?e=[e,t,n,r,i]:(e=null,o=s),e}function Le(){var e;return null===(e=Q())&&(e=je()),e}function je(){var e,t,r,i;return i=o,null!==(e=Je())?(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null!==t?(null===(r=He())&&(r=Ve()),null!==r?e=[e,t,r]:(e=null,o=i)):(e=null,o=i)):(e=null,o=i),e}function He(){var e,t,r,i,a;return i=o,null===(e=qe())&&(e=Fe()),null!==e?(a=o,63===n.charCodeAt(o)?(t="?",o++):(t=null,0===s&&u('"?"')),null!==t&&null!==(r=Ze())?t=[t,r]:(t=null,o=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=i)):(e=null,o=i),e}function qe(){var e,t,r,i;return i=o,"//"===n.substr(o,2)?(e="//",o+=2):(e=null,0===s&&u('"//"')),null!==e&&null!==(t=$e())&&null!==(r=null!==(r=Fe())?r:"")?e=[e,t,r]:(e=null,o=i),e}function Fe(){var e,t,r;return r=o,47===n.charCodeAt(o)?(e="/",o++):(e=null,0===s&&u('"/"')),null!==e&&null!==(t=Ge())?e=[e,t]:(e=null,o=r),e}function Ve(){var e,t,n,r;if(r=o,null!==(e=We())){for(t=[],n=Be();null!==n;)t.push(n),n=Be();null!==t?e=[e,t]:(e=null,o=r)}else e=null,o=r;return e}function Be(){var e;return null===(e=b())&&null===(e=T())&&(e=S()),e}function We(){var e;return null===(e=T())&&null===(e=S())&&(59===n.charCodeAt(o)?(e=";",o++):(e=null,0===s&&u('";"')),null===e&&(63===n.charCodeAt(o)?(e="?",o++):(e=null,0===s&&u('"?"')),null===e&&(58===n.charCodeAt(o)?(e=":",o++):(e=null,0===s&&u('":"')),null===e&&(64===n.charCodeAt(o)?(e="@",o++):(e=null,0===s&&u('"@"')),null===e&&(38===n.charCodeAt(o)?(e="&",o++):(e=null,0===s&&u('"&"')),null===e&&(61===n.charCodeAt(o)?(e="=",o++):(e=null,0===s&&u('"="')),null===e&&(43===n.charCodeAt(o)?(e="+",o++):(e=null,0===s&&u('"+"')),null===e&&(36===n.charCodeAt(o)?(e="$",o++):(e=null,0===s&&u('"$"')),null===e&&(44===n.charCodeAt(o)?(e=",",o++):(e=null,0===s&&u('","'))))))))))),e}function Ge(){var e,t,r,i,a,l;if(a=o,null!==(e=ze())){for(t=[],l=o,47===n.charCodeAt(o)?(r="/",o++):(r=null,0===s&&u('"/"')),null!==r&&null!==(i=ze())?r=[r,i]:(r=null,o=l);null!==r;)t.push(r),l=o,47===n.charCodeAt(o)?(r="/",o++):(r=null,0===s&&u('"/"')),null!==r&&null!==(i=ze())?r=[r,i]:(r=null,o=l);null!==t?e=[e,t]:(e=null,o=a)}else e=null,o=a;return e}function ze(){var e,t,r,i,a,l;for(a=o,e=[],t=Ke();null!==t;)e.push(t),t=Ke();if(null!==e){for(t=[],l=o,59===n.charCodeAt(o)?(r=";",o++):(r=null,0===s&&u('";"')),null!==r&&null!==(i=Ye())?r=[r,i]:(r=null,o=l);null!==r;)t.push(r),l=o,59===n.charCodeAt(o)?(r=";",o++):(r=null,0===s&&u('";"')),null!==r&&null!==(i=Ye())?r=[r,i]:(r=null,o=l);null!==t?e=[e,t]:(e=null,o=a)}else e=null,o=a;return e}function Ye(){var e,t;for(e=[],t=Ke();null!==t;)e.push(t),t=Ke();return e}function Ke(){var e;return null===(e=T())&&null===(e=S())&&(58===n.charCodeAt(o)?(e=":",o++):(e=null,0===s&&u('":"')),null===e&&(64===n.charCodeAt(o)?(e="@",o++):(e=null,0===s&&u('"@"')),null===e&&(38===n.charCodeAt(o)?(e="&",o++):(e=null,0===s&&u('"&"')),null===e&&(61===n.charCodeAt(o)?(e="=",o++):(e=null,0===s&&u('"="')),null===e&&(43===n.charCodeAt(o)?(e="+",o++):(e=null,0===s&&u('"+"')),null===e&&(36===n.charCodeAt(o)?(e="$",o++):(e=null,0===s&&u('"$"')),null===e&&(44===n.charCodeAt(o)?(e=",",o++):(e=null,0===s&&u('","'))))))))),e}function Je(){var e,t,r,i,a,l;if(i=o,a=o,null!==(e=h())){for(t=[],null===(r=h())&&null===(r=d())&&(43===n.charCodeAt(o)?(r="+",o++):(r=null,0===s&&u('"+"')),null===r&&(45===n.charCodeAt(o)?(r="-",o++):(r=null,0===s&&u('"-"')),null===r&&(46===n.charCodeAt(o)?(r=".",o++):(r=null,0===s&&u('"."')))));null!==r;)t.push(r),null===(r=h())&&null===(r=d())&&(43===n.charCodeAt(o)?(r="+",o++):(r=null,0===s&&u('"+"')),null===r&&(45===n.charCodeAt(o)?(r="-",o++):(r=null,0===s&&u('"-"')),null===r&&(46===n.charCodeAt(o)?(r=".",o++):(r=null,0===s&&u('"."')))));null!==t?e=[e,t]:(e=null,o=a)}else e=null,o=a;return null!==e&&(l=i,e=void(Fn.scheme=n.substring(o,l))),null===e&&(o=i),e}function $e(){var e;return null===(e=Xe())&&(e=Qe()),e}function Xe(){var e,t,r,i;return r=o,i=o,null!==(e=ne())?(64===n.charCodeAt(o)?(t="@",o++):(t=null,0===s&&u('"@"')),null!==t?e=[e,t]:(e=null,o=i)):(e=null,o=i),null!==(e=null!==e?e:"")&&null!==(t=se())?e=[e,t]:(e=null,o=r),e=null!==e?e:""}function Qe(){var e,t;if(null===(t=T())&&null===(t=S())&&(36===n.charCodeAt(o)?(t="$",o++):(t=null,0===s&&u('"$"')),null===t&&(44===n.charCodeAt(o)?(t=",",o++):(t=null,0===s&&u('","')),null===t&&(59===n.charCodeAt(o)?(t=";",o++):(t=null,0===s&&u('";"')),null===t&&(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null===t&&(64===n.charCodeAt(o)?(t="@",o++):(t=null,0===s&&u('"@"')),null===t&&(38===n.charCodeAt(o)?(t="&",o++):(t=null,0===s&&u('"&"')),null===t&&(61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"')))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=T())&&null===(t=S())&&(36===n.charCodeAt(o)?(t="$",o++):(t=null,0===s&&u('"$"')),null===t&&(44===n.charCodeAt(o)?(t=",",o++):(t=null,0===s&&u('","')),null===t&&(59===n.charCodeAt(o)?(t=";",o++):(t=null,0===s&&u('";"')),null===t&&(58===n.charCodeAt(o)?(t=":",o++):(t=null,0===s&&u('":"')),null===t&&(64===n.charCodeAt(o)?(t="@",o++):(t=null,0===s&&u('"@"')),null===t&&(38===n.charCodeAt(o)?(t="&",o++):(t=null,0===s&&u('"&"')),null===t&&(61===n.charCodeAt(o)?(t="=",o++):(t=null,0===s&&u('"="')),null===t&&(43===n.charCodeAt(o)?(t="+",o++):(t=null,0===s&&u('"+"'))))))))));else e=null;return e}function Ze(){var e,t;for(e=[],t=Be();null!==t;)e.push(t),t=Be();return e}function et(){var e,t,r,i,a,l,c,h,f;if(c=o,h=o,"sip"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"SIP"')),null!==e)if(47===n.charCodeAt(o)?(t="/",o++):(t=null,0===s&&u('"/"')),null!==t){if(null!==(i=d()))for(r=[];null!==i;)r.push(i),i=d();else r=null;if(null!==r)if(46===n.charCodeAt(o)?(i=".",o++):(i=null,0===s&&u('"."')),null!==i){if(null!==(l=d()))for(a=[];null!==l;)a.push(l),l=d();else a=null;null!==a?e=[e,t,r,i,a]:(e=null,o=h)}else e=null,o=h;else e=null,o=h}else e=null,o=h;else e=null,o=h;return null!==e&&(f=c,e=void(Fn.sip_version=n.substring(o,f))),null===e&&(o=c),e}function tt(){var e;return"INVITE"===n.substr(o,6)?(e="INVITE",o+=6):(e=null,0===s&&u('"INVITE"')),e}function nt(){var e;return"ACK"===n.substr(o,3)?(e="ACK",o+=3):(e=null,0===s&&u('"ACK"')),e}function rt(){var e;return"OPTIONS"===n.substr(o,7)?(e="OPTIONS",o+=7):(e=null,0===s&&u('"OPTIONS"')),e}function it(){var e;return"BYE"===n.substr(o,3)?(e="BYE",o+=3):(e=null,0===s&&u('"BYE"')),e}function ot(){var e;return"CANCEL"===n.substr(o,6)?(e="CANCEL",o+=6):(e=null,0===s&&u('"CANCEL"')),e}function st(){var e;return"REGISTER"===n.substr(o,8)?(e="REGISTER",o+=8):(e=null,0===s&&u('"REGISTER"')),e}function at(){var e;return"SUBSCRIBE"===n.substr(o,9)?(e="SUBSCRIBE",o+=9):(e=null,0===s&&u('"SUBSCRIBE"')),e}function lt(){var e;return"NOTIFY"===n.substr(o,6)?(e="NOTIFY",o+=6):(e=null,0===s&&u('"NOTIFY"')),e}function ut(){var e;return"REFER"===n.substr(o,5)?(e="REFER",o+=5):(e=null,0===s&&u('"REFER"')),e}function ct(){var e,t,r;return t=o,null===(e=tt())&&null===(e=nt())&&null===(e=rt())&&null===(e=it())&&null===(e=ot())&&null===(e=st())&&null===(e=at())&&null===(e=lt())&&null===(e=ut())&&(e=P()),null!==e&&(r=t,Fn.method=n.substring(o,r),e=Fn.method),null===e&&(o=t),e}function dt(){var e,t,n,r,i,s;return s=o,null!==(e=et())&&null!==(t=g())&&null!==(n=ht())&&null!==(r=g())&&null!==(i=_t())?e=[e,t,n,r,i]:(e=null,o=s),e}function ht(){var e,t,n;return t=o,null!==(e=ft())&&(n=e,e=void(Fn.status_code=parseInt(n.join("")))),null===e&&(o=t),e}function ft(){var e,t,n,r;return r=o,null!==(e=d())&&null!==(t=d())&&null!==(n=d())?e=[e,t,n]:(e=null,o=r),e}function _t(){var e,t,r,i;for(r=o,e=[],null===(t=b())&&null===(t=T())&&null===(t=S())&&null===(t=k())&&null===(t=O())&&null===(t=g())&&(t=m());null!==t;)e.push(t),null===(t=b())&&null===(t=T())&&null===(t=S())&&null===(t=k())&&null===(t=O())&&null===(t=g())&&(t=m());return null!==e&&(i=r,e=void(Fn.reason_phrase=n.substring(o,i))),null===e&&(o=r),e}function pt(){var e,t,n,r,i,s,a;if(i=o,s=o,null===(e=X())&&(e=vt()),null!==e){for(t=[],a=o,null!==(n=V())&&null!==(r=mt())?n=[n,r]:(n=null,o=a);null!==n;)t.push(n),a=o,null!==(n=V())&&null!==(r=mt())?n=[n,r]:(n=null,o=a);null!==t?e=[e,t]:(e=null,o=s)}else e=null,o=s;return null!==e&&(e=function(e){var t;Fn.multi_header||(Fn.multi_header=[]);try{t=new qn(Fn.uri,Fn.display_name,Fn.params),delete Fn.uri,delete Fn.display_name,delete Fn.params}catch(e){t=null}Fn.multi_header.push({possition:o,offset:e,parsed:t})}(i)),null===e&&(o=i),e}function vt(){var e,t,n,r,i;return i=o,null!==(e=null!==(e=gt())?e:"")&&null!==(t=q())&&null!==(n=Q())&&null!==(r=H())?e=[e,t,n,r]:(e=null,o=i),e}function gt(){var e,t,n,r,i,s,a,l;if(i=o,s=o,null!==(e=P())){for(t=[],a=o,null!==(n=A())&&null!==(r=P())?n=[n,r]:(n=null,o=a);null!==n;)t.push(n),a=o,null!==(n=A())&&null!==(r=P())?n=[n,r]:(n=null,o=a);null!==t?e=[e,t]:(e=null,o=s)}else e=null,o=s;return null===e&&(e=K()),null!==e&&(l=e,e=void(Fn.display_name="string"==typeof l?l:l[1].reduce(function(e,t){return e+t[0]+t[1]},l[0]))),null===e&&(o=i),e}function mt(){var e;return null===(e=yt())&&null===(e=bt())&&(e=St()),e}function yt(){var e,t,r,i,a,l;return i=o,a=o,"q"===n.substr(o,1).toLowerCase()?(e=n.substr(o,1),o++):(e=null,0===s&&u('"q"')),null!==e&&null!==(t=M())&&null!==(r=Ct())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],Fn.params||(Fn.params={}),e=void(Fn.params.q=l)),null===e&&(o=i),e}function bt(){var e,t,r,i,a,l;return i=o,a=o,"expires"===n.substr(o,7).toLowerCase()?(e=n.substr(o,7),o+=7):(e=null,0===s&&u('"expires"')),null!==e&&null!==(t=M())&&null!==(r=Tt())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],Fn.params||(Fn.params={}),e=void(Fn.params.expires=l)),null===e&&(o=i),e}function Tt(){var e,t,n;if(n=o,null!==(t=d()))for(e=[];null!==t;)e.push(t),t=d();else e=null;return null!==e&&(e=parseInt(e.join(""))),null===e&&(o=n),e}function Ct(){var e,t,r,i,a,l,c,h,f;return l=o,c=o,48===n.charCodeAt(o)?(e="0",o++):(e=null,0===s&&u('"0"')),null!==e?(h=o,46===n.charCodeAt(o)?(t=".",o++):(t=null,0===s&&u('"."')),null!==t&&null!==(r=null!==(r=d())?r:"")&&null!==(i=null!==(i=d())?i:"")&&null!==(a=null!==(a=d())?a:"")?t=[t,r,i,a]:(t=null,o=h),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=c)):(e=null,o=c),null!==e&&(f=l,e=parseFloat(n.substring(o,f))),null===e&&(o=l),e}function St(){var e,t,n,r,i,s,a,l;return r=o,i=o,null!==(e=P())?(s=o,null!==(t=M())&&null!==(n=At())?t=[t,n]:(t=null,o=s),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=i)):(e=null,o=i),null!==e&&(a=e[0],l=e[1],Fn.params||(Fn.params={}),l=void 0===l?void 0:l[1],e=void(Fn.params[a.toLowerCase()]=l)),null===e&&(o=r),e}function At(){var e;return null===(e=P())&&null===(e=ae())&&(e=Y()),e}function wt(){var e;return"render"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"render"')),null===e&&("session"===n.substr(o,7).toLowerCase()?(e=n.substr(o,7),o+=7):(e=null,0===s&&u('"session"')),null===e&&("icon"===n.substr(o,4).toLowerCase()?(e=n.substr(o,4),o+=4):(e=null,0===s&&u('"icon"')),null===e&&("alert"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"alert"')),null===e&&(e=P())))),e}function Et(){var e;return null===(e=Rt())&&(e=St()),e}function Rt(){var e,t,r,i;return i=o,"handling"===n.substr(o,8).toLowerCase()?(e=n.substr(o,8),o+=8):(e=null,0===s&&u('"handling"')),null!==e&&null!==(t=M())?("optional"===n.substr(o,8).toLowerCase()?(r=n.substr(o,8),o+=8):(r=null,0===s&&u('"optional"')),null===r&&("required"===n.substr(o,8).toLowerCase()?(r=n.substr(o,8),o+=8):(r=null,0===s&&u('"required"')),null===r&&(r=P())),null!==r?e=[e,t,r]:(e=null,o=i)):(e=null,o=i),e}function It(){var e,t,n,r,i,s,a,l;if(a=o,null!==(e=kt()))if(null!==(t=D()))if(null!==(n=Ut())){for(r=[],l=o,null!==(i=V())&&null!==(s=Dt())?i=[i,s]:(i=null,o=l);null!==i;)r.push(i),l=o,null!==(i=V())&&null!==(s=Dt())?i=[i,s]:(i=null,o=l);null!==r?e=[e,t,n,r]:(e=null,o=a)}else e=null,o=a;else e=null,o=a;else e=null,o=a;return e}function kt(){var e;return null===(e=Ot())&&(e=Pt()),e}function Ot(){var e;return"text"===n.substr(o,4).toLowerCase()?(e=n.substr(o,4),o+=4):(e=null,0===s&&u('"text"')),null===e&&("image"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"image"')),null===e&&("audio"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"audio"')),null===e&&("video"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"video"')),null===e&&("application"===n.substr(o,11).toLowerCase()?(e=n.substr(o,11),o+=11):(e=null,0===s&&u('"application"')),null===e&&(e=Nt()))))),e}function Pt(){var e;return"message"===n.substr(o,7).toLowerCase()?(e=n.substr(o,7),o+=7):(e=null,0===s&&u('"message"')),null===e&&("multipart"===n.substr(o,9).toLowerCase()?(e=n.substr(o,9),o+=9):(e=null,0===s&&u('"multipart"')),null===e&&(e=Nt())),e}function Nt(){var e;return null===(e=P())&&(e=xt()),e}function xt(){var e,t,r;return r=o,"x-"===n.substr(o,2).toLowerCase()?(e=n.substr(o,2),o+=2):(e=null,0===s&&u('"x-"')),null!==e&&null!==(t=P())?e=[e,t]:(e=null,o=r),e}function Ut(){var e;return null===(e=Nt())&&(e=P()),e}function Dt(){var e,t,n,r;return r=o,null!==(e=P())&&null!==(t=M())&&null!==(n=Mt())?e=[e,t,n]:(e=null,o=r),e}function Mt(){var e;return null===(e=P())&&(e=Y()),e}function Lt(){var e,t,n,r;if(n=o,null!==(t=d()))for(e=[];null!==t;)e.push(t),t=d();else e=null;return null!==e&&(r=e,e=void(Fn.value=parseInt(r.join("")))),null===e&&(o=n),e}function jt(){var e,t,r,i,a,l;if(a=o,null!==(e=N())){for(t=[],l=o,46===n.charCodeAt(o)?(r=".",o++):(r=null,0===s&&u('"."')),null!==r&&null!==(i=N())?r=[r,i]:(r=null,o=l);null!==r;)t.push(r),l=o,46===n.charCodeAt(o)?(r=".",o++):(r=null,0===s&&u('"."')),null!==r&&null!==(i=N())?r=[r,i]:(r=null,o=l);null!==t?e=[e,t]:(e=null,o=a)}else e=null,o=a;return e}function Ht(){var e;return null===(e=qt())&&(e=St()),e}function qt(){var e,t,r,i,a,l;return i=o,a=o,"tag"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"tag"')),null!==e&&null!==(t=M())&&null!==(r=P())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.tag=l)),null===e&&(o=i),e}function Ft(){var e,t,r,i,a,l,c,d;if(c=o,"digest"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"Digest"')),null!==e)if(null!==(t=A()))if(null!==(r=Wt())){for(i=[],d=o,null!==(a=F())&&null!==(l=Wt())?a=[a,l]:(a=null,o=d);null!==a;)i.push(a),d=o,null!==(a=F())&&null!==(l=Wt())?a=[a,l]:(a=null,o=d);null!==i?e=[e,t,r,i]:(e=null,o=c)}else e=null,o=c;else e=null,o=c;else e=null,o=c;return null===e&&(e=Vt()),e}function Vt(){var e,t,n,r,i,s,a,l;if(a=o,null!==(e=P()))if(null!==(t=A()))if(null!==(n=Bt())){for(r=[],l=o,null!==(i=F())&&null!==(s=Bt())?i=[i,s]:(i=null,o=l);null!==i;)r.push(i),l=o,null!==(i=F())&&null!==(s=Bt())?i=[i,s]:(i=null,o=l);null!==r?e=[e,t,n,r]:(e=null,o=a)}else e=null,o=a;else e=null,o=a;else e=null,o=a;return e}function Bt(){var e,t,n,r;return r=o,null!==(e=P())&&null!==(t=M())?(null===(n=P())&&(n=Y()),null!==n?e=[e,t,n]:(e=null,o=r)):(e=null,o=r),e}function Wt(){var e;return null===(e=Gt())&&null===(e=Yt())&&null===(e=Jt())&&null===(e=Xt())&&null===(e=Qt())&&null===(e=Zt())&&null===(e=en())&&(e=Bt()),e}function Gt(){var e,t,r,i;return i=o,"realm"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"realm"')),null!==e&&null!==(t=M())&&null!==(r=zt())?e=[e,t,r]:(e=null,o=i),e}function zt(){var e,t,n;return t=o,null!==(e=K())&&(n=e,e=void(Fn.realm=n)),null===e&&(o=t),e}function Yt(){var e,t,r,i,a,l,c,d,h;if(d=o,"domain"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"domain"')),null!==e)if(null!==(t=M()))if(null!==(r=W()))if(null!==(i=Kt())){if(a=[],h=o,null!==(c=g()))for(l=[];null!==c;)l.push(c),c=g();else l=null;for(null!==l&&null!==(c=Kt())?l=[l,c]:(l=null,o=h);null!==l;){if(a.push(l),h=o,null!==(c=g()))for(l=[];null!==c;)l.push(c),c=g();else l=null;null!==l&&null!==(c=Kt())?l=[l,c]:(l=null,o=h)}null!==a&&null!==(l=G())?e=[e,t,r,i,a,l]:(e=null,o=d)}else e=null,o=d;else e=null,o=d;else e=null,o=d;else e=null,o=d;return e}function Kt(){var e;return null===(e=je())&&(e=Fe()),e}function Jt(){var e,t,r,i;return i=o,"nonce"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"nonce"')),null!==e&&null!==(t=M())&&null!==(r=$t())?e=[e,t,r]:(e=null,o=i),e}function $t(){var e,t,n;return t=o,null!==(e=K())&&(n=e,e=void(Fn.nonce=n)),null===e&&(o=t),e}function Xt(){var e,t,r,i,a,l;return i=o,a=o,"opaque"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"opaque"')),null!==e&&null!==(t=M())&&null!==(r=K())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.opaque=l)),null===e&&(o=i),e}function Qt(){var e,t,r,i,a;return i=o,"stale"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"stale"')),null!==e&&null!==(t=M())?(a=o,"true"===n.substr(o,4).toLowerCase()?(r=n.substr(o,4),o+=4):(r=null,0===s&&u('"true"')),null!==r&&(r=void(Fn.stale=!0)),null===r&&(o=a),null===r&&(a=o,"false"===n.substr(o,5).toLowerCase()?(r=n.substr(o,5),o+=5):(r=null,0===s&&u('"false"')),null!==r&&(r=void(Fn.stale=!1)),null===r&&(o=a)),null!==r?e=[e,t,r]:(e=null,o=i)):(e=null,o=i),e}function Zt(){var e,t,r,i,a,l;return i=o,a=o,"algorithm"===n.substr(o,9).toLowerCase()?(e=n.substr(o,9),o+=9):(e=null,0===s&&u('"algorithm"')),null!==e&&null!==(t=M())?("md5"===n.substr(o,3).toLowerCase()?(r=n.substr(o,3),o+=3):(r=null,0===s&&u('"MD5"')),null===r&&("md5-sess"===n.substr(o,8).toLowerCase()?(r=n.substr(o,8),o+=8):(r=null,0===s&&u('"MD5-sess"')),null===r&&(r=P())),null!==r?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.algorithm=l.toUpperCase())),null===e&&(o=i),e}function en(){var e,t,r,i,a,l,c,d,h,f;if(d=o,"qop"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"qop"')),null!==e)if(null!==(t=M()))if(null!==(r=W())){if(h=o,null!==(i=tn())){for(a=[],f=o,44===n.charCodeAt(o)?(l=",",o++):(l=null,0===s&&u('","')),null!==l&&null!==(c=tn())?l=[l,c]:(l=null,o=f);null!==l;)a.push(l),f=o,44===n.charCodeAt(o)?(l=",",o++):(l=null,0===s&&u('","')),null!==l&&null!==(c=tn())?l=[l,c]:(l=null,o=f);null!==a?i=[i,a]:(i=null,o=h)}else i=null,o=h;null!==i&&null!==(a=G())?e=[e,t,r,i,a]:(e=null,o=d)}else e=null,o=d;else e=null,o=d;else e=null,o=d;return e}function tn(){var e,t,r;return t=o,"auth-int"===n.substr(o,8).toLowerCase()?(e=n.substr(o,8),o+=8):(e=null,0===s&&u('"auth-int"')),null===e&&("auth"===n.substr(o,4).toLowerCase()?(e=n.substr(o,4),o+=4):(e=null,0===s&&u('"auth"')),null===e&&(e=P())),null!==e&&(r=e,Fn.qop||(Fn.qop=[]),e=void Fn.qop.push(r.toLowerCase())),null===e&&(o=t),e}function nn(){var e,t,n,r,i,s,a;if(i=o,s=o,null!==(e=vt())){for(t=[],a=o,null!==(n=V())&&null!==(r=St())?n=[n,r]:(n=null,o=a);null!==n;)t.push(n),a=o,null!==(n=V())&&null!==(r=St())?n=[n,r]:(n=null,o=a);null!==t?e=[e,t]:(e=null,o=s)}else e=null,o=s;return null!==e&&(e=function(e){var t;Fn.multi_header||(Fn.multi_header=[]);try{t=new qn(Fn.uri,Fn.display_name,Fn.params),delete Fn.uri,delete Fn.display_name,delete Fn.params}catch(e){t=null}Fn.multi_header.push({possition:o,offset:e,parsed:t})}(i)),null===e&&(o=i),e}function rn(){var e;return null===(e=on())&&(e=St()),e}function on(){var e,t,r,i,a,l,c;if(a=o,l=o,"cause"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"cause"')),null!==e)if(null!==(t=M())){if(null!==(i=d()))for(r=[];null!==i;)r.push(i),i=d();else r=null;null!==r?e=[e,t,r]:(e=null,o=l)}else e=null,o=l;else e=null,o=l;return null!==e&&(c=e[2],e=void(Fn.cause=parseInt(c.join("")))),null===e&&(o=a),e}function sn(){var e,t,n,r,i,s;if(i=o,null!==(e=vt())){for(t=[],s=o,null!==(n=V())&&null!==(r=St())?n=[n,r]:(n=null,o=s);null!==n;)t.push(n),s=o,null!==(n=V())&&null!==(r=St())?n=[n,r]:(n=null,o=s);null!==t?e=[e,t]:(e=null,o=i)}else e=null,o=i;return e}function an(){var e,t,r;return t=o,"active"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"active"')),null===e&&("pending"===n.substr(o,7).toLowerCase()?(e=n.substr(o,7),o+=7):(e=null,0===s&&u('"pending"')),null===e&&("terminated"===n.substr(o,10).toLowerCase()?(e=n.substr(o,10),o+=10):(e=null,0===s&&u('"terminated"')),null===e&&(e=P()))),null!==e&&(r=t,e=void(Fn.state=n.substring(o,r))),null===e&&(o=t),e}function ln(){var e,t,r,i,a,l,c,d;return i=o,a=o,"reason"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"reason"')),null!==e&&null!==(t=M())&&null!==(r=un())?e=[e,t,r]:(e=null,o=a),null!==e&&(e=void(void 0!==(l=e[2])&&(Fn.reason=l))),null===e&&(o=i),null===e&&(i=o,a=o,"expires"===n.substr(o,7).toLowerCase()?(e=n.substr(o,7),o+=7):(e=null,0===s&&u('"expires"')),null!==e&&null!==(t=M())&&null!==(r=Tt())?e=[e,t,r]:(e=null,o=a),null!==e&&(e=void(void 0!==(d=e[2])&&(Fn.expires=d))),null===e&&(o=i),null===e&&(i=o,a=o,"retry_after"===n.substr(o,11).toLowerCase()?(e=n.substr(o,11),o+=11):(e=null,0===s&&u('"retry_after"')),null!==e&&null!==(t=M())&&null!==(r=Tt())?e=[e,t,r]:(e=null,o=a),null!==e&&(e=void(void 0!==(c=e[2])&&(Fn.retry_after=c))),null===e&&(o=i),null===e&&(e=St()))),e}function un(){var e;return"deactivated"===n.substr(o,11).toLowerCase()?(e=n.substr(o,11),o+=11):(e=null,0===s&&u('"deactivated"')),null===e&&("probation"===n.substr(o,9).toLowerCase()?(e=n.substr(o,9),o+=9):(e=null,0===s&&u('"probation"')),null===e&&("rejected"===n.substr(o,8).toLowerCase()?(e=n.substr(o,8),o+=8):(e=null,0===s&&u('"rejected"')),null===e&&("timeout"===n.substr(o,7).toLowerCase()?(e=n.substr(o,7),o+=7):(e=null,0===s&&u('"timeout"')),null===e&&("giveup"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"giveup"')),null===e&&("noresource"===n.substr(o,10).toLowerCase()?(e=n.substr(o,10),o+=10):(e=null,0===s&&u('"noresource"')),null===e&&("invariant"===n.substr(o,9).toLowerCase()?(e=n.substr(o,9),o+=9):(e=null,0===s&&u('"invariant"')),null===e&&(e=P()))))))),e}function cn(){var e;return null===(e=qt())&&(e=St()),e}function dn(){var e,t,n,r,i,s,a,l;if(a=o,null!==(e=yn()))if(null!==(t=A()))if(null!==(n=Cn())){for(r=[],l=o,null!==(i=V())&&null!==(s=hn())?i=[i,s]:(i=null,o=l);null!==i;)r.push(i),l=o,null!==(i=V())&&null!==(s=hn())?i=[i,s]:(i=null,o=l);null!==r?e=[e,t,n,r]:(e=null,o=a)}else e=null,o=a;else e=null,o=a;else e=null,o=a;return e}function hn(){var e;return null===(e=fn())&&null===(e=_n())&&null===(e=pn())&&null===(e=vn())&&null===(e=gn())&&(e=St()),e}function fn(){var e,t,r,i,a,l;return i=o,a=o,"ttl"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"ttl"')),null!==e&&null!==(t=M())&&null!==(r=wn())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.ttl=l)),null===e&&(o=i),e}function _n(){var e,t,r,i,a,l;return i=o,a=o,"maddr"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"maddr"')),null!==e&&null!==(t=M())&&null!==(r=ae())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.maddr=l)),null===e&&(o=i),e}function pn(){var e,t,r,i,a,l;return i=o,a=o,"received"===n.substr(o,8).toLowerCase()?(e=n.substr(o,8),o+=8):(e=null,0===s&&u('"received"')),null!==e&&null!==(t=M())?(null===(r=pe())&&(r=he()),null!==r?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.received=l)),null===e&&(o=i),e}function vn(){var e,t,r,i,a,l;return i=o,a=o,"branch"===n.substr(o,6).toLowerCase()?(e=n.substr(o,6),o+=6):(e=null,0===s&&u('"branch"')),null!==e&&null!==(t=M())&&null!==(r=P())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.branch=l)),null===e&&(o=i),e}function gn(){var e,t,r,i,a;return i=o,"rport"===n.substr(o,5).toLowerCase()?(e=n.substr(o,5),o+=5):(e=null,0===s&&u('"rport"')),null!==e?(a=o,null!==(t=M())&&null!==(r=mn())?t=[t,r]:(t=null,o=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=i)):(e=null,o=i),e}function mn(){var e,t,n,r,i,s,a,l;return s=o,a=o,null!==(e=null!==(e=d())?e:"")&&null!==(t=null!==(t=d())?t:"")&&null!==(n=null!==(n=d())?n:"")&&null!==(r=null!==(r=d())?r:"")&&null!==(i=null!==(i=d())?i:"")?e=[e,t,n,r,i]:(e=null,o=a),null!==e&&(l=e,e=void(Fn.rport=parseInt(l.join("")))),null===e&&(o=s),e}function yn(){var e,t,n,r,i,s;return s=o,null!==(e=bn())&&null!==(t=D())&&null!==(n=P())&&null!==(r=D())&&null!==(i=Tn())?e=[e,t,n,r,i]:(e=null,o=s),e}function bn(){var e,t,r;return t=o,"sip"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"SIP"')),null===e&&(e=P()),null!==e&&(r=e,e=void(Fn.protocol=r)),null===e&&(o=t),e}function Tn(){var e,t,r;return t=o,"udp"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"UDP"')),null===e&&("tcp"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"TCP"')),null===e&&("tls"===n.substr(o,3).toLowerCase()?(e=n.substr(o,3),o+=3):(e=null,0===s&&u('"TLS"')),null===e&&("sctp"===n.substr(o,4).toLowerCase()?(e=n.substr(o,4),o+=4):(e=null,0===s&&u('"SCTP"')),null===e&&(e=P())))),null!==e&&(r=e,e=void(Fn.transport=r)),null===e&&(o=t),e}function Cn(){var e,t,n,r,i;return r=o,null!==(e=Sn())?(i=o,null!==(t=B())&&null!==(n=An())?t=[t,n]:(t=null,o=i),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=r)):(e=null,o=r),e}function Sn(){var e,t,r;return t=o,null===(e=pe())&&null===(e=de())&&(e=le()),null!==e&&(r=t,e=void(Fn.host=n.substring(o,r))),null===e&&(o=t),e}function An(){var e,t,n,r,i,s,a,l;return s=o,a=o,null!==(e=null!==(e=d())?e:"")&&null!==(t=null!==(t=d())?t:"")&&null!==(n=null!==(n=d())?n:"")&&null!==(r=null!==(r=d())?r:"")&&null!==(i=null!==(i=d())?i:"")?e=[e,t,n,r,i]:(e=null,o=a),null!==e&&(l=e,e=void(Fn.port=parseInt(l.join("")))),null===e&&(o=s),e}function wn(){var e,t,n,r,i;return r=o,i=o,null!==(e=d())&&null!==(t=null!==(t=d())?t:"")&&null!==(n=null!==(n=d())?n:"")?e=[e,t,n]:(e=null,o=i),null!==e&&(e=parseInt(e.join(""))),null===e&&(o=r),e}function En(){var e,t,n;return t=o,null!==(e=Tt())&&(n=e,e=void(Fn.expires=n)),null===e&&(o=t),e}function Rn(){var e;return null===(e=In())&&(e=St()),e}function In(){var e,t,r,i,a,l;return i=o,a=o,"refresher"===n.substr(o,9).toLowerCase()?(e=n.substr(o,9),o+=9):(e=null,0===s&&u('"refresher"')),null!==e&&null!==(t=M())?("uac"===n.substr(o,3).toLowerCase()?(r=n.substr(o,3),o+=3):(r=null,0===s&&u('"uac"')),null===r&&("uas"===n.substr(o,3).toLowerCase()?(r=n.substr(o,3),o+=3):(r=null,0===s&&u('"uas"'))),null!==r?e=[e,t,r]:(e=null,o=a)):(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.refresher=l.toLowerCase())),null===e&&(o=i),e}function kn(){var e,t;for(e=[],null===(t=I())&&null===(t=O())&&(t=A());null!==t;)e.push(t),null===(t=I())&&null===(t=O())&&(t=A());return e}function On(){var e,t,r,i,a,l,c,d,h,f,_,p;return f=o,_=o,null!==(e=Nn())?(45===n.charCodeAt(o)?(t="-",o++):(t=null,0===s&&u('"-"')),null!==t&&null!==(r=Pn())?(45===n.charCodeAt(o)?(i="-",o++):(i=null,0===s&&u('"-"')),null!==i&&null!==(a=Pn())?(45===n.charCodeAt(o)?(l="-",o++):(l=null,0===s&&u('"-"')),null!==l&&null!==(c=Pn())?(45===n.charCodeAt(o)?(d="-",o++):(d=null,0===s&&u('"-"')),null!==d&&null!==(h=xn())?e=[e,t,r,i,a,l,c,d,h]:(e=null,o=_)):(e=null,o=_)):(e=null,o=_)):(e=null,o=_)):(e=null,o=_),null!==e&&(p=f,e[0],e=void(Fn=n.substring(o+5,p))),null===e&&(o=f),e}function Pn(){var e,t,n,r,i;return i=o,null!==(e=f())&&null!==(t=f())&&null!==(n=f())&&null!==(r=f())?e=[e,t,n,r]:(e=null,o=i),e}function Nn(){var e,t,n;return n=o,null!==(e=Pn())&&null!==(t=Pn())?e=[e,t]:(e=null,o=n),e}function xn(){var e,t,n,r;return r=o,null!==(e=Pn())&&null!==(t=Pn())&&null!==(n=Pn())?e=[e,t,n]:(e=null,o=r),e}function Un(){var e,t,r,i,a,l,c;return i=o,a=o,null!==(e=x())?(l=o,64===n.charCodeAt(o)?(t="@",o++):(t=null,0===s&&u('"@"')),null!==t&&null!==(r=x())?t=[t,r]:(t=null,o=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,o=a)):(e=null,o=a),null!==e&&(c=i,e=void(Fn.call_id=n.substring(o,c))),null===e&&(o=i),e}function Dn(){var e;return null===(e=Mn())&&null===(e=Ln())&&null===(e=jn())&&(e=St()),e}function Mn(){var e,t,r,i,a,l;return i=o,a=o,"to-tag"===n.substr(o,6)?(e="to-tag",o+=6):(e=null,0===s&&u('"to-tag"')),null!==e&&null!==(t=M())&&null!==(r=P())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.to_tag=l)),null===e&&(o=i),e}function Ln(){var e,t,r,i,a,l;return i=o,a=o,"from-tag"===n.substr(o,8)?(e="from-tag",o+=8):(e=null,0===s&&u('"from-tag"')),null!==e&&null!==(t=M())&&null!==(r=P())?e=[e,t,r]:(e=null,o=a),null!==e&&(l=e[2],e=void(Fn.from_tag=l)),null===e&&(o=i),e}function jn(){var e,t;return t=o,"early-only"===n.substr(o,10)?(e="early-only",o+=10):(e=null,0===s&&u('"early-only"')),null!==e&&(e=void(Fn.early_only=!0)),null===e&&(o=t),e}var Hn=e("./URI"),qn=e("./NameAddrHeader"),Fn={};if(null===i[r]()||o!==n.length){var Vn=Math.max(o,a),Bn=Vn2&&void 0!==arguments[2]?arguments[2]:{},i=e;if(void 0===e||void 0===t)throw new TypeError("Not enough arguments");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(i));var o=h.cloneArray(r.extraHeaders),s=h.cloneObject(r.eventHandlers),a=r.contentType||"text/plain",l={};for(var u in r.fromUserName&&(l.from_uri=new p("sip",r.fromUserName,this._ua.configuration.uri.host),o.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()))),r.fromDisplayName&&(l.from_display_name=r.fromDisplayName),s)Object.prototype.hasOwnProperty.call(s,u)&&this.on(u,s[u]);o.push("Content-Type: ".concat(a)),this._request=new d.OutgoingRequest(c.MESSAGE,e,this._ua,l,o),t&&(this._request.body=t);var _=new f(this._ua,this._request,{onRequestTimeout:function(){n._onRequestTimeout()},onTransportError:function(){n._onTransportError()},onReceiveResponse:function(e){n._receiveResponse(e)}});this._newMessage("local",this._request),_.send()}},{key:"init_incoming",value:function(e){this._request=e,this._newMessage("remote",e),this._is_replied||(this._is_replied=!0,e.reply(200)),this._close()}},{key:"accept",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=h.cloneArray(e.extraHeaders),n=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"accept" not supported for outgoing Message');if(this._is_replied)throw new Error("incoming Message already replied");this._is_replied=!0,this._request.reply(200,null,t,n)}},{key:"reject",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.status_code||480,n=e.reason_phrase,r=h.cloneArray(e.extraHeaders),i=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"reject" not supported for outgoing Message');if(this._is_replied)throw new Error("incoming Message already replied");if(t<300||t>=700)throw new TypeError("Invalid status_code: ".concat(t));this._is_replied=!0,this._request.reply(t,n,r,i)}},{key:"_receiveResponse",value:function(e){if(!this._closed)switch(!0){case/^1[0-9]{2}$/.test(e.status_code):break;case/^2[0-9]{2}$/.test(e.status_code):this._succeeded("remote",e);break;default:var t=h.sipErrorCause(e.status_code);this._failed("remote",e,t)}}},{key:"_onRequestTimeout",value:function(){this._closed||this._failed("system",null,c.causes.REQUEST_TIMEOUT)}},{key:"_onTransportError",value:function(){this._closed||this._failed("system",null,c.causes.CONNECTION_ERROR)}},{key:"_close",value:function(){this._closed=!0,this._ua.destroyMessage(this)}},{key:"_newMessage",value:function(e,t){"remote"===e?(this._direction="incoming",this._local_identity=t.to,this._remote_identity=t.from):"local"===e&&(this._direction="outgoing",this._local_identity=t.from,this._remote_identity=t.to),this._ua.newMessage(this,{originator:e,message:this,request:t})}},{key:"_failed",value:function(e,t,n){v.debug("MESSAGE failed"),this._close(),v.debug('emit "failed"'),this.emit("failed",{originator:e,response:t||null,cause:n})}},{key:"_succeeded",value:function(e,t){v.debug("MESSAGE succeeded"),this._close(),v.debug('emit "succeeded"'),this.emit("succeeded",{originator:e,response:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./URI":29,"./Utils":30,events:33}],11:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n"),this._parameters)Object.prototype.hasOwnProperty.call(this._parameters,t)&&(e+=";".concat(t),null!==this._parameters[t]&&(e+="=".concat(this._parameters[t])));return e}}])&&r(t.prototype,n),s&&r(t,s),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Grammar":7,"./URI":29}],12:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n"),i._headers.push(i._contact)),s&&i._headers.push("Allow-Events: ".concat(s)),i._target=t.from.uri.user,t.to_tag=h.newTag();var v=new f(a(i),t,"UAS");if(v.error)throw _.warn(v.error),new Error("SUBSCRIBE missed Contact");return i._dialog=v,i._expires>0&&i._setExpiresTimer(),i}return t=c,r=[{key:"C",get:function(){return p}}],(n=[{key:"C",get:function(){return p}},{key:"receiveRequest",value:function(e){if(e.method===d.SUBSCRIBE){var t=e.getHeader("expires");void 0!==t&&null!==t||(t="900",_.debug("Missed expires header. Set by default ".concat(t))),this._expires=parseInt(t),e.reply(200,null,["Expires: ".concat(this._expires),"".concat(this._contact)]);var n=e.body,r=e.getHeader("content-type"),i=0===this._expires;i||this._setExpiresTimer(),_.debug('emit "subscribe"'),this.emit("subscribe",i,e,n,r),i&&this._dialogTerminated(p.RECEIVE_UNSUBSCRIBE)}else e.reply(405)}},{key:"start",value:function(){_.debug("start()"),this.receiveRequest(this._initial_subscribe)}},{key:"setActiveState",value:function(){_.debug("setActiveState()"),this._state===p.STATE_PENDING&&(this._state=p.STATE_ACTIVE)}},{key:"notify",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(_.debug("notify()"),this._dialog){var n=this._stateNumberToString(this._state);if(this._state!==p.STATE_TERMINATED){var r=Math.floor((this._expires_timestamp-(new Date).getTime())/1e3);r<0&&(r=0),n+=";expires=".concat(r)}else this._terminated_reason&&(n+=";reason=".concat(this._terminated_reason)),null!==this._terminated_retry_after&&(n+=";retry-after=".concat(this._terminated_retry_after));var i=this._headers.slice();i.push("Subscription-State: ".concat(n)),t&&i.push("Content-Type: ".concat(this._content_type)),this._dialog.sendRequest(d.NOTIFY,{body:t,extraHeaders:i,eventHandlers:{onRequestTimeout:function(){e._dialogTerminated(p.NOTIFY_RESPONSE_TIMEOUT)},onTransportError:function(){e._dialogTerminated(p.NOTIFY_TRANSPORT_ERROR)},onErrorResponse:function(t){401===t.status_code||407===t.status_code?e._dialogTerminated(p.NOTIFY_FAILED_AUTHENTICATION):e._dialogTerminated(p.NOTIFY_NON_OK_RESPONSE)},onDialogError:function(){e._dialogTerminated(p.NOTIFY_NON_OK_RESPONSE)}}})}else _.warn("final notify has sent")}},{key:"terminate",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;_.debug("terminate()"),this._state=p.STATE_TERMINATED,this._terminated_reason=t,this._terminated_retry_after=n,this.notify(e),this._dialogTerminated(p.SEND_FINAL_NOTIFY)}},{key:"state",get:function(){return this._state}},{key:"id",get:function(){return this._dialog?this._dialog.id:null}},{key:"_dialogTerminated",value:function(e){if(this._dialog){this._state=p.STATE_TERMINATED,clearTimeout(this._expires_timer),this._dialog&&(this._dialog.terminate(),this._dialog=null);var t=e===p.SUBSCRIPTION_EXPIRED;_.debug('emit "terminated" code='.concat(e,", send final notify=").concat(t)),this.emit("terminated",e,t)}}},{key:"_setExpiresTimer",value:function(){var e=this;this._expires_timestamp=(new Date).getTime()+1e3*this._expires,clearTimeout(this._expires_timer),this._expires_timer=setTimeout(function(){e._dialog&&(e._terminated_reason="timeout",e.notify(),e._dialogTerminated(p.SUBSCRIPTION_EXPIRED))},1e3*this._expires)}},{key:"_stateNumberToString",value:function(e){switch(e){case p.STATE_PENDING:return"pending";case p.STATE_ACTIVE:return"active";case p.STATE_TERMINATED:return"terminated";default:throw new TypeError("wrong state value")}}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),c}()},{"./Constants":2,"./Dialog":3,"./Logger":9,"./Utils":30,events:33}],13:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{},i=e;if(void 0===e)throw new TypeError("A target is required for OPTIONS");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(i));var o=h.cloneArray(r.extraHeaders),s=h.cloneObject(r.eventHandlers),a=r.contentType||"application/sdp";for(var l in s)Object.prototype.hasOwnProperty.call(s,l)&&this.on(l,s[l]);o.push("Content-Type: ".concat(a)),this._request=new d.OutgoingRequest(c.OPTIONS,e,this._ua,null,o),t&&(this._request.body=t);var u=new f(this._ua,this._request,{onRequestTimeout:function(){n._onRequestTimeout()},onTransportError:function(){n._onTransportError()},onReceiveResponse:function(e){n._receiveResponse(e)}});this._newOptions("local",this._request),u.send()}},{key:"init_incoming",value:function(e){this._request=e,this._newOptions("remote",e),this._is_replied||(this._is_replied=!0,e.reply(200)),this._close()}},{key:"accept",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=h.cloneArray(e.extraHeaders),n=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"accept" not supported for outgoing Options');if(this._is_replied)throw new Error("incoming Options already replied");this._is_replied=!0,this._request.reply(200,null,t,n)}},{key:"reject",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.status_code||480,n=e.reason_phrase,r=h.cloneArray(e.extraHeaders),i=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"reject" not supported for outgoing Options');if(this._is_replied)throw new Error("incoming Options already replied");if(t<300||t>=700)throw new TypeError("Invalid status_code: ".concat(t));this._is_replied=!0,this._request.reply(t,n,r,i)}},{key:"_receiveResponse",value:function(e){if(!this._closed)switch(!0){case/^1[0-9]{2}$/.test(e.status_code):break;case/^2[0-9]{2}$/.test(e.status_code):this._succeeded("remote",e);break;default:var t=h.sipErrorCause(e.status_code);this._failed("remote",e,t)}}},{key:"_onRequestTimeout",value:function(){this._closed||this._failed("system",null,c.causes.REQUEST_TIMEOUT)}},{key:"_onTransportError",value:function(){this._closed||this._failed("system",null,c.causes.CONNECTION_ERROR)}},{key:"_close",value:function(){this._closed=!0,this._ua.destroyMessage(this)}},{key:"_newOptions",value:function(e,t){"remote"===e?(this._direction="incoming",this._local_identity=t.to,this._remote_identity=t.from):"local"===e&&(this._direction="outgoing",this._local_identity=t.from,this._remote_identity=t.to),this._ua.newOptions(this,{originator:e,message:this,request:t})}},{key:"_failed",value:function(e,t,n){p.debug("OPTIONS failed"),this._close(),p.debug('emit "failed"'),this.emit("failed",{originator:e,response:t||null,cause:n})}},{key:"_succeeded",value:function(e,t){p.debug("OPTIONS succeeded"),this._close(),p.debug('emit "succeeded"'),this.emit("succeeded",{originator:e,response:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,events:33}],14:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;E.debug("connect()");var r=e,i=v.cloneObject(t.eventHandlers),o=v.cloneArray(t.extraHeaders),s=v.cloneObject(t.mediaConstraints,{audio:!0,video:!0}),a=t.mediaStream||null,l=v.cloneObject(t.pcConfig,{iceServers:[]}),u=t.rtcConstraints||null,c=t.rtcOfferConstraints||null;if(this._rtcOfferConstraints=c,this._rtcAnswerConstraints=t.rtcAnswerConstraints||null,this._data=t.data||this._data,void 0===e)throw new TypeError("Not enough arguments");if(this._status!==R.STATUS_NULL)throw new _.InvalidStateError(this._status);if(!window.RTCPeerConnection)throw new _.NotSupportedError("WebRTC not supported");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(r));for(var d in this._sessionTimers.enabled&&v.isDecimal(t.sessionTimersExpires)&&(t.sessionTimersExpires>=f.MIN_SESSION_EXPIRES?this._sessionTimers.defaultExpires=t.sessionTimersExpires:this._sessionTimers.defaultExpires=f.SESSION_EXPIRES),i)Object.prototype.hasOwnProperty.call(i,d)&&this.on(d,i[d]);this._from_tag=v.newTag();var h=t.anonymous||!1,p={from_tag:this._from_tag};this._contact=this._ua.contact.toString({anonymous:h,outbound:!0}),h?(p.from_display_name="Anonymous",p.from_uri=new w("sip","anonymous","anonymous.invalid"),o.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString())),o.push("Privacy: id")):t.fromUserName&&(p.from_uri=new w("sip",t.fromUserName,this._ua.configuration.uri.host),o.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()))),t.fromDisplayName&&(p.from_display_name=t.fromDisplayName),o.push("Contact: ".concat(this._contact)),o.push("Content-Type: application/sdp"),this._sessionTimers.enabled&&o.push("Session-Expires: ".concat(this._sessionTimers.defaultExpires).concat(this._ua.configuration.session_timers_force_refresher?";refresher=uac":"")),this._request=new m.InitialOutgoingInviteRequest(e,this._ua,p,o),this._id=this._request.call_id+this._from_tag,this._createRTCConnection(l,u),this._direction="outgoing",this._local_identity=this._request.from,this._remote_identity=this._request.to,n&&n(this),this._newRTCSession("local",this._request),this._sendInitialRequest(s,c,a)}},{key:"init_incoming",value:function(e,t){var n,r=this;E.debug("init_incoming()");var i=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0;if(e.body&&"application/sdp"!==i)e.reply(415);else if(this._status=R.STATUS_INVITE_RECEIVED,this._from_tag=e.from_tag,this._id=e.call_id+this._from_tag,this._request=e,this._contact=this._ua.contact.toString(),e.hasHeader("expires")&&(n=1e3*e.getHeader("expires")),e.to_tag=v.newTag(),this._createDialog(e,"UAS",!0)){if(e.body?this._late_sdp=!1:this._late_sdp=!0,this._status=R.STATUS_WAITING_FOR_ANSWER,this._timers.userNoAnswerTimer=setTimeout(function(){e.reply(408),r._failed("local",null,f.causes.NO_ANSWER)},this._ua.configuration.no_answer_timeout),n&&(this._timers.expiresTimer=setTimeout(function(){r._status===R.STATUS_WAITING_FOR_ANSWER&&(e.reply(487),r._failed("system",null,f.causes.EXPIRES))},n)),this._direction="incoming",this._local_identity=e.to,this._remote_identity=e.from,t&&t(this),this._newRTCSession("remote",e),this._status!==R.STATUS_TERMINATED){var o=["Contact: ".concat(this._contact)],s=this._ua.modes.ringing_header_mode;void 0!==s&&(Array.isArray(s)?o=o.concat(s):o.push(s)),e.reply(180,null,o),this._progress("local",null)}}else e.reply(500,"Missing Contact header field")}},{key:"answer",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};E.debug("answer()");var n=this._request,r=v.cloneArray(t.extraHeaders),o=v.cloneObject(t.mediaConstraints),s=t.mediaStream||null,a=v.cloneObject(t.pcConfig,{iceServers:[]}),l=t.rtcConstraints||null,u=t.rtcAnswerConstraints||null,c=v.cloneObject(t.rtcOfferConstraints),d=!1,h=!1,p=!1,g=!1;if(this._rtcAnswerConstraints=u,this._rtcOfferConstraints=t.rtcOfferConstraints||null,this._data=t.data||this._data,"incoming"!==this._direction)throw new _.NotSupportedError('"answer" not supported for outgoing RTCSession');if(this._status!==R.STATUS_WAITING_FOR_ANSWER)throw new _.InvalidStateError(this._status);if(this._sessionTimers.enabled&&v.isDecimal(t.sessionTimersExpires)&&(t.sessionTimersExpires>=f.MIN_SESSION_EXPIRES?this._sessionTimers.defaultExpires=t.sessionTimersExpires:this._sessionTimers.defaultExpires=f.SESSION_EXPIRES),this._status=R.STATUS_ANSWERED,this._createDialog(n,"UAS")){clearTimeout(this._timers.userNoAnswerTimer),r.unshift("Contact: ".concat(this._contact));var m=n.parseSDP();Array.isArray(m.media)||(m.media=[m.media]);var y,b=i(m.media);try{for(b.s();!(y=b.n()).done;){var T=y.value;"audio"===T.type&&(d=!0,T.direction&&"sendrecv"!==T.direction||(p=!0)),"video"===T.type&&(h=!0,T.direction&&"sendrecv"!==T.direction||(g=!0))}}catch(e){b.e(e)}finally{b.f()}if(s&&!1===o.audio){var C,S=i(s.getAudioTracks());try{for(S.s();!(C=S.n()).done;){var A=C.value;s.removeTrack(A)}}catch(e){S.e(e)}finally{S.f()}}if(s&&!1===o.video){var w,I=i(s.getVideoTracks());try{for(I.s();!(w=I.n()).done;){var k=w.value;s.removeTrack(k)}}catch(e){I.e(e)}finally{I.f()}}s||void 0!==o.audio||(o.audio=p),s||void 0!==o.video||(o.video=g),s||d||c.offerToReceiveAudio||(o.audio=!1),s||h||c.offerToReceiveVideo||(o.video=!1),this._createRTCConnection(a,l),Promise.resolve().then(function(){return s||(o.audio||o.video?(e._localMediaStreamLocallyGenerated=!0,navigator.mediaDevices.getUserMedia(o).catch(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");throw n.reply(480),e._failed("local",null,f.causes.USER_DENIED_MEDIA_ACCESS),E.warn('emit "getusermediafailed" [error:%o]',t),e.emit("getusermediafailed",t),new Error("getUserMedia() failed")})):void 0)}).then(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");e._localMediaStream=t,t&&t.getTracks().forEach(function(n){e._connection.addTrack(n,t)})}).then(function(){if(!e._late_sdp){var t={originator:"remote",type:"offer",sdp:n.body};E.debug('emit "sdp"'),e.emit("sdp",t);var r=new RTCSessionDescription({type:"offer",sdp:t.sdp});return e._connectionPromiseQueue=e._connectionPromiseQueue.then(function(){return e._connection.setRemoteDescription(r)}).catch(function(t){throw n.reply(488),e._failed("system",null,f.causes.WEBRTC_ERROR),E.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',t),e.emit("peerconnection:setremotedescriptionfailed",t),new Error("peerconnection.setRemoteDescription() failed")}),e._connectionPromiseQueue}}).then(function(){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");return e._connecting(n),e._late_sdp?e._createLocalDescription("offer",e._rtcOfferConstraints).catch(function(){throw n.reply(500),new Error("_createLocalDescription() failed")}):e._createLocalDescription("answer",u).catch(function(){throw n.reply(500),new Error("_createLocalDescription() failed")})}).then(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");e._handleSessionTimersInIncomingRequest(n,r),n.reply(200,null,r,t,function(){e._status=R.STATUS_WAITING_FOR_ACK,e._setInvite2xxTimer(n,t),e._setACKTimer(),e._accepted("local")},function(){e._failed("system",null,f.causes.CONNECTION_ERROR)})}).catch(function(t){e._status!==R.STATUS_TERMINATED&&E.warn(t)})}else n.reply(500,"Error creating dialog")}},{key:"terminate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};E.debug("terminate()");var n,r=t.cause||f.causes.BYE,i=v.cloneArray(t.extraHeaders),o=t.body,s=t.status_code,a=t.reason_phrase;if(this._status===R.STATUS_TERMINATED)throw new _.InvalidStateError(this._status);switch(this._status){case R.STATUS_NULL:case R.STATUS_INVITE_SENT:case R.STATUS_1XX_RECEIVED:if(E.debug("canceling session"),s&&(s<200||s>=700))throw new TypeError("Invalid status_code: ".concat(s));s&&(a=a||f.REASON_PHRASE[s]||"",n="SIP ;cause=".concat(s,' ;text="').concat(a,'"')),this._status===R.STATUS_NULL||this._status===R.STATUS_INVITE_SENT?(this._is_canceled=!0,this._cancel_reason=n):this._status===R.STATUS_1XX_RECEIVED&&this._request.cancel(n),this._status=R.STATUS_CANCELED,this._failed("local",null,f.causes.CANCELED);break;case R.STATUS_WAITING_FOR_ANSWER:case R.STATUS_ANSWERED:if(E.debug("rejecting session"),(s=s||480)<300||s>=700)throw new TypeError("Invalid status_code: ".concat(s));this._request.reply(s,a,i,o),this._failed("local",null,f.causes.REJECTED);break;case R.STATUS_WAITING_FOR_ACK:case R.STATUS_CONFIRMED:if(E.debug("terminating session"),a=t.reason_phrase||f.REASON_PHRASE[s]||"",s&&(s<200||s>=700))throw new TypeError("Invalid status_code: ".concat(s));if(s&&i.push("Reason: SIP ;cause=".concat(s,'; text="').concat(a,'"')),this._status===R.STATUS_WAITING_FOR_ACK&&"incoming"===this._direction&&this._request.server_transaction.state!==p.C.STATUS_TERMINATED){var l=this._dialog;this.receiveRequest=function(t){t.method===f.ACK&&(e.sendRequest(f.BYE,{extraHeaders:i,body:o}),l.terminate())},this._request.server_transaction.on("stateChanged",function(){e._request.server_transaction.state===p.C.STATUS_TERMINATED&&(e.sendRequest(f.BYE,{extraHeaders:i,body:o}),l.terminate())}),this._ended("local",null,r),this._dialog=l,this._ua.newDialog(l)}else this.sendRequest(f.BYE,{extraHeaders:i,body:o}),this._ended("local",null,r)}}},{key:"sendDTMF",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};E.debug("sendDTMF() | tones: %s",e);var n=0,r=t.duration||null,i=t.interToneGap||null,o=t.transportType||f.DTMF_TRANSPORT.INFO;if(void 0===e)throw new TypeError("Not enough arguments");if(this._status!==R.STATUS_CONFIRMED&&this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_1XX_RECEIVED)throw new _.InvalidStateError(this._status);if(o!==f.DTMF_TRANSPORT.INFO&&o!==f.DTMF_TRANSPORT.RFC2833)throw new TypeError("invalid transportType: ".concat(o));if("number"==typeof e&&(e=e.toString()),!e||"string"!=typeof e||!e.match(/^[0-9A-DR#*,]+$/i))throw new TypeError("Invalid tones: ".concat(e));if(r&&!v.isDecimal(r))throw new TypeError("Invalid tone duration: ".concat(r));if(r?rT.C.MAX_DURATION?(E.debug('"duration" value is greater than the maximum allowed, setting it to '.concat(T.C.MAX_DURATION," milliseconds")),r=T.C.MAX_DURATION):r=Math.abs(r):r=T.C.DEFAULT_DURATION,t.duration=r,i&&!v.isDecimal(i))throw new TypeError("Invalid interToneGap: ".concat(i));if(i?i=this._tones.length)return void(this._tones=null);var a=this._tones[n];n+=1;if(","===a)s=2e3;else{var l=new T(this);t.eventHandlers={onFailed:function(){o._tones=null}},l.send(a,t),s=r+i}setTimeout(e.bind(this),s)}.call(this));else{var s=this._getDTMFRTPSender();s&&(e=s.toneBuffer+e,s.insertDTMF(e,r,i))}}},{key:"sendInfo",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(E.debug("sendInfo()"),this._status!==R.STATUS_CONFIRMED&&this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_1XX_RECEIVED)throw new _.InvalidStateError(this._status);new C(this).send(e,t,n)}},{key:"mute",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{audio:!0,video:!1};E.debug("mute()");var t=!1,n=!1;!1===this._audioMuted&&e.audio&&(t=!0,this._audioMuted=!0,this._toggleMuteAudio(!0)),!1===this._videoMuted&&e.video&&(n=!0,this._videoMuted=!0,this._toggleMuteVideo(!0)),!0!==t&&!0!==n||this._onmute({audio:t,video:n})}},{key:"unmute",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{audio:!0,video:!0};E.debug("unmute()");var t=!1,n=!1;!0===this._audioMuted&&e.audio&&(t=!0,this._audioMuted=!1,!1===this._localHold&&this._toggleMuteAudio(!1)),!0===this._videoMuted&&e.video&&(n=!0,this._videoMuted=!1,!1===this._localHold&&this._toggleMuteVideo(!1)),!0!==t&&!0!==n||this._onunmute({audio:t,video:n})}},{key:"hold",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(E.debug("hold()"),this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!0===this._localHold)return!1;if(!this._isReadyToReOffer())return!1;this._localHold=!0,this._onhold("local");var r={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Hold Failed"})}};return t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:r,extraHeaders:t.extraHeaders}),!0}},{key:"unhold",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(E.debug("unhold()"),this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!1===this._localHold)return!1;if(!this._isReadyToReOffer())return!1;this._localHold=!1,this._onunhold("local");var r={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Unhold Failed"})}};return t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:r,extraHeaders:t.extraHeaders}),!0}},{key:"renegotiate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;E.debug("renegotiate()");var r=t.rtcOfferConstraints||null;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!this._isReadyToReOffer())return!1;var i={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Media Renegotiation Failed"})}};return this._setLocalMediaStatus(),t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:i,rtcOfferConstraints:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:i,rtcOfferConstraints:r,extraHeaders:t.extraHeaders}),!0}},{key:"refer",value:function(e,t){var n=this;E.debug("refer()");var r=e;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(r));var i=new A(this);i.sendRefer(e,t);var o=i.id;return this._referSubscribers[o]=i,i.on("requestFailed",function(){delete n._referSubscribers[o]}),i.on("accepted",function(){delete n._referSubscribers[o]}),i.on("failed",function(){delete n._referSubscribers[o]}),i}},{key:"sendRequest",value:function(e,t){return E.debug("sendRequest()"),this._dialog.sendRequest(e,t)}},{key:"receiveRequest",value:function(e){var t=this;if(E.debug("receiveRequest()"),e.method===f.CANCEL)this._status!==R.STATUS_WAITING_FOR_ANSWER&&this._status!==R.STATUS_ANSWERED||(this._status=R.STATUS_CANCELED,this._request.reply(487),this._failed("remote",e,f.causes.CANCELED));else switch(e.method){case f.ACK:if(this._status!==R.STATUS_WAITING_FOR_ACK)return;if(this._status=R.STATUS_CONFIRMED,clearTimeout(this._timers.ackTimer),clearTimeout(this._timers.invite2xxTimer),this._late_sdp){if(!e.body){this.terminate({cause:f.causes.MISSING_SDP,status_code:400});break}var n={originator:"remote",type:"answer",sdp:e.body};E.debug('emit "sdp"'),this.emit("sdp",n);var r=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(r)}).then(function(){t._is_confirmed||t._confirmed("remote",e)}).catch(function(e){t.terminate({cause:f.causes.BAD_MEDIA_DESCRIPTION,status_code:488}),E.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}else this._is_confirmed||this._confirmed("remote",e);break;case f.BYE:this._status===R.STATUS_CONFIRMED||this._status===R.STATUS_WAITING_FOR_ACK?(e.reply(200),this._ended("remote",e,f.causes.BYE)):this._status===R.STATUS_INVITE_RECEIVED||this._status===R.STATUS_WAITING_FOR_ANSWER?(e.reply(200),this._request.reply(487,"BYE Received"),this._ended("remote",e,f.causes.BYE)):e.reply(403,"Wrong Status");break;case f.INVITE:this._status===R.STATUS_CONFIRMED?e.hasHeader("replaces")?this._receiveReplaces(e):this._receiveReinvite(e):e.reply(403,"Wrong Status");break;case f.INFO:if(this._status===R.STATUS_1XX_RECEIVED||this._status===R.STATUS_WAITING_FOR_ANSWER||this._status===R.STATUS_ANSWERED||this._status===R.STATUS_WAITING_FOR_ACK||this._status===R.STATUS_CONFIRMED){var i=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0;i&&i.match(/^application\/dtmf-relay/i)?new T(this).init_incoming(e):void 0!==i?new C(this).init_incoming(e):e.reply(415)}else e.reply(403,"Wrong Status");break;case f.UPDATE:this._status===R.STATUS_CONFIRMED?this._receiveUpdate(e):e.reply(403,"Wrong Status");break;case f.REFER:this._status===R.STATUS_CONFIRMED?this._receiveRefer(e):e.reply(403,"Wrong Status");break;case f.NOTIFY:var o={event:e.event,request:e,taken:!1};if(this.emit("sipEvent",o),o.taken){e.reply(200);break}this._status===R.STATUS_CONFIRMED?this._receiveNotify(e):e.reply(403,"Wrong Status");break;default:e.reply(501)}}},{key:"onTransportError",value:function(){E.warn("onTransportError()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:500,reason_phrase:f.causes.CONNECTION_ERROR,cause:f.causes.CONNECTION_ERROR})}},{key:"onRequestTimeout",value:function(){E.warn("onRequestTimeout()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:408,reason_phrase:f.causes.REQUEST_TIMEOUT,cause:f.causes.REQUEST_TIMEOUT})}},{key:"onDialogError",value:function(){E.warn("onDialogError()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:500,reason_phrase:f.causes.DIALOG_ERROR,cause:f.causes.DIALOG_ERROR})}},{key:"newDTMF",value:function(e){E.debug("newDTMF()"),this.emit("newDTMF",e)}},{key:"newInfo",value:function(e){E.debug("newInfo()"),this.emit("newInfo",e)}},{key:"_isReadyToReOffer",value:function(){return this._rtcReady?this._dialog?!0!==this._dialog.uac_pending_reply&&!0!==this._dialog.uas_pending_reply||(E.debug("_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress"),!1):(E.debug("_isReadyToReOffer() | session not established yet"),!1):(E.debug("_isReadyToReOffer() | internal WebRTC status not ready"),!1)}},{key:"_close",value:function(){if(E.debug("close()"),this._localMediaStream&&this._localMediaStreamLocallyGenerated&&(E.debug("close() | closing local MediaStream"),v.closeMediaStream(this._localMediaStream)),this._status!==R.STATUS_TERMINATED){if(this._status=R.STATUS_TERMINATED,this._connection)try{this._connection.close()}catch(e){E.warn("close() | error closing the RTCPeerConnection: %o",e)}for(var e in this._timers)Object.prototype.hasOwnProperty.call(this._timers,e)&&clearTimeout(this._timers[e]);for(var t in clearTimeout(this._sessionTimers.timer),this._dialog&&(this._dialog.terminate(),delete this._dialog),this._earlyDialogs)Object.prototype.hasOwnProperty.call(this._earlyDialogs,t)&&(this._earlyDialogs[t].terminate(),delete this._earlyDialogs[t]);for(var n in this._referSubscribers)Object.prototype.hasOwnProperty.call(this._referSubscribers,n)&&delete this._referSubscribers[n];this._ua.destroyRTCSession(this)}}},{key:"_setInvite2xxTimer",value:function(e,t){var n=g.T1;this._timers.invite2xxTimer=setTimeout(function r(){this._status===R.STATUS_WAITING_FOR_ACK&&(e.reply(200,null,["Contact: ".concat(this._contact)],t),ng.T2&&(n=g.T2),this._timers.invite2xxTimer=setTimeout(r.bind(this),n))}.bind(this),n)}},{key:"_setACKTimer",value:function(){var e=this;this._timers.ackTimer=setTimeout(function(){e._status===R.STATUS_WAITING_FOR_ACK&&(E.debug("no ACK received, terminating the session"),clearTimeout(e._timers.invite2xxTimer),e.sendRequest(f.BYE),e._ended("remote",null,f.causes.NO_ACK))},g.TIMER_H)}},{key:"_createRTCConnection",value:function(e,t){var n=this;this._connection=new RTCPeerConnection(e,t),this._connection.addEventListener("iceconnectionstatechange",function(){var e=n._connection.iceConnectionState;if("failed"===e&&n.terminate({cause:f.causes.RTP_TIMEOUT,status_code:408,reason_phrase:f.causes.RTP_TIMEOUT}),void 0!==n._ua.modes.chrome_rtp_timeout_fix&&navigator.webkitGetUserMedia&&"disconnected"===e){var t=n._ua.modes.chrome_rtp_timeout_fix;E.debug("AC: Chrome RTP timeout fix: iceConnectionState==disconnected: check that this will continue for ".concat(t," seconds..."));!function e(){"disconnected"===n._connection.iceConnectionState?t-- >0?setTimeout(function(){return e()},1e3):(E.debug("AC: Chrome RTP timeout fix: Hangup call"),n.terminate({cause:f.causes.RTP_TIMEOUT,status_code:408,reason_phrase:f.causes.RTP_TIMEOUT})):E.debug("AC: Chrome RTP timeout fix: iceConnectionState=".concat(n._connection.iceConnectionState))}()}}),E.debug('emit "peerconnection"'),this.emit("peerconnection",{peerconnection:this._connection})}},{key:"_createLocalDescription",value:function(e,t){var n=this;if(E.debug("createLocalDescription()"),"offer"!==e&&"answer"!==e)throw new Error('createLocalDescription() | invalid type "'.concat(e,'"'));var r=this._connection;return this._rtcReady=!1,Promise.resolve().then(function(){return"offer"===e?r.createOffer(t).catch(function(e){return E.warn('emit "peerconnection:createofferfailed" [error:%o]',e),n.emit("peerconnection:createofferfailed",e),Promise.reject(e)}):r.createAnswer(t).catch(function(e){return E.warn('emit "peerconnection:createanswerfailed" [error:%o]',e),n.emit("peerconnection:createanswerfailed",e),Promise.reject(e)})}).then(function(e){return r.setLocalDescription(e).catch(function(e){return n._rtcReady=!0,E.warn('emit "peerconnection:setlocaldescriptionfailed" [error:%o]',e),n.emit("peerconnection:setlocaldescriptionfailed",e),Promise.reject(e)})}).then(function(){var i=t&&t.iceRestart;if("complete"===r.iceGatheringState&&!i||"gathering"===r.iceGatheringState&&n._iceReady){n._rtcReady=!0;var o={originator:"local",type:e,sdp:r.localDescription.sdp};return E.debug('emit "sdp"'),n.emit("sdp",o),Promise.resolve(o.sdp)}return new Promise(function(t){var i,o,s=!1;n._iceReady=!1;var a=function(){r.removeEventListener("icecandidate",i),r.removeEventListener("icegatheringstatechange",o),s=!0,n._rtcReady=!0,n._iceReady=!0;var a={originator:"local",type:e,sdp:r.localDescription.sdp};E.debug('emit "sdp"'),n.emit("sdp",a),t(a.sdp)};r.addEventListener("icecandidate",i=function(e){var t=e.candidate;t?n.emit("icecandidate",{candidate:t,ready:a}):s||a()}),r.addEventListener("icegatheringstatechange",o=function(){"complete"!==r.iceGatheringState||s||a()}),void 0!==n._ua.modes.ice_timeout_fix&&setTimeout(function(){s||(E.debug("AC: ICE gathering timeout fix"),a())},n._ua.modes.ice_timeout_fix)})})}},{key:"_createDialog",value:function(e,t,n){var r="UAS"===t?e.to_tag:e.from_tag,i="UAS"===t?e.from_tag:e.to_tag,o=e.call_id+r+i,s=this._earlyDialogs[o];if(n)return!!s||((s=new y(this,e,t,y.C.STATUS_EARLY)).error?(E.debug(s.error),this._failed("remote",e,f.causes.INTERNAL_ERROR),!1):(this._earlyDialogs[o]=s,!0));if(this._from_tag=e.from_tag,this._to_tag=e.to_tag,s)return s.update(e,t),this._dialog=s,delete this._earlyDialogs[o],!0;var a=new y(this,e,t);return a.error?(E.debug(a.error),this._failed("remote",e,f.causes.INTERNAL_ERROR),!1):(this._dialog=a,!0)}},{key:"_receiveReinvite",value:function(e){var t=this;E.debug("receiveReinvite()");var n=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,r={request:e,callback:void 0,reject:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i=!0;var n=t.status_code||403,r=t.reason_phrase||"",o=v.cloneArray(t.extraHeaders);if(this._status!==R.STATUS_CONFIRMED)return!1;if(n<300||n>=700)throw new TypeError("Invalid status_code: ".concat(n));e.reply(n,r,o)}.bind(this)},i=!1;if(this.emit("reinvite",r),!i){if(this._late_sdp=!1,!e.body)return this._late_sdp=!0,this._remoteHold&&(this._remoteHold=!1,this._onunhold("remote")),void(this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._createLocalDescription("offer",t._rtcOfferConstraints)}).then(function(e){o.call(t,e)}).catch(function(){e.reply(500)}));if("application/sdp"!==n)return E.debug("invalid Content-Type"),void e.reply(415);this._processInDialogSdpOffer(e).then(function(e){t._status!==R.STATUS_TERMINATED&&o.call(t,e)}).catch(function(e){E.warn(e)})}function o(t){var n=this,i=["Contact: ".concat(this._contact)];this._handleSessionTimersInIncomingRequest(e,i),this._late_sdp&&(t=this._mangleOffer(t)),e.reply(200,null,i,t,function(){n._status=R.STATUS_WAITING_FOR_ACK,n._setInvite2xxTimer(e,t),n._setACKTimer()}),"function"==typeof r.callback&&r.callback()}}},{key:"_receiveUpdate",value:function(e){var t=this;E.debug("receiveUpdate()");var n=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,r={request:e,callback:void 0,reject:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i=!0;var n=t.status_code||403,r=t.reason_phrase||"",o=v.cloneArray(t.extraHeaders);if(this._status!==R.STATUS_CONFIRMED)return!1;if(n<300||n>=700)throw new TypeError("Invalid status_code: ".concat(n));e.reply(n,r,o)}.bind(this)},i=!1;if(this.emit("update",r),!i)if(e.body){if("application/sdp"!==n)return E.debug("invalid Content-Type"),void e.reply(415);this._processInDialogSdpOffer(e).then(function(e){t._status!==R.STATUS_TERMINATED&&o.call(t,e)}).catch(function(e){E.warn(e)})}else o.call(this,null);function o(t){var n=["Contact: ".concat(this._contact)];this._handleSessionTimersInIncomingRequest(e,n),e.reply(200,null,n,t),"function"==typeof r.callback&&r.callback()}}},{key:"_processInDialogSdpOffer",value:function(e){var t=this;E.debug("_processInDialogSdpOffer()");var n,r=e.parseSDP(),o=!1,s=i(r.media);try{for(s.s();!(n=s.n()).done;){var a=n.value;if(-1!==I.indexOf(a.type)){var l=a.direction||r.direction||"sendrecv";if("sendonly"!==l&&"inactive"!==l){o=!1;break}o=!0}}}catch(e){s.e(e)}finally{s.f()}var u={originator:"remote",type:"offer",sdp:e.body};E.debug('emit "sdp"'),this.emit("sdp",u);var c=new RTCSessionDescription({type:"offer",sdp:u.sdp});return this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");return t._connection.setRemoteDescription(c).catch(function(n){throw e.reply(488),E.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',n),t.emit("peerconnection:setremotedescriptionfailed",n),n})}).then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");!0===t._remoteHold&&!1===o?(t._remoteHold=!1,t._onunhold("remote")):!1===t._remoteHold&&!0===o&&(t._remoteHold=!0,t._onhold("remote"))}).then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");return t._createLocalDescription("answer",t._rtcAnswerConstraints).catch(function(t){throw e.reply(500),E.warn('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]',t),t})}).catch(function(e){E.warn("_processInDialogSdpOffer() failed [error: %o]",e)}),this._connectionPromiseQueue}},{key:"_receiveRefer",value:function(e){var t=this;if(E.debug("receiveRefer()"),!e.refer_to)return E.debug("no Refer-To header field present in REFER"),void e.reply(400);if(e.refer_to.uri.scheme!==f.SIP)return E.debug("Refer-To header field points to a non-SIP URI scheme"),void e.reply(416);e.reply(202);var n=new S(this,e.cseq);E.debug('emit "refer"'),this.emit("refer",{request:e,accept:function(r,i){(function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t="function"==typeof t?t:null,this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;var i=new u(this._ua);if(i.on("progress",function(e){var t=e.response;n.notify(t.status_code,t.reason_phrase)}),i.on("accepted",function(e){var t=e.response;n.notify(t.status_code,t.reason_phrase)}),i.on("_failed",function(e){var t=e.message,r=e.cause;t?n.notify(t.status_code,t.reason_phrase):n.notify(487,r)}),e.refer_to.uri.hasHeader("replaces")){var o=decodeURIComponent(e.refer_to.uri.getHeader("replaces"));r.extraHeaders=v.cloneArray(r.extraHeaders),r.extraHeaders.push("Replaces: ".concat(o))}i.connect(e.refer_to.uri.toAor(),r,t)}).call(t,r,i)},reject:function(){(function(){n.notify(603)}).call(t)}})}},{key:"_receiveNotify",value:function(e){switch(E.debug("receiveNotify()"),e.event||e.reply(400),e.event.event){case"refer":var t,n;if(e.event.params&&e.event.params.id)t=e.event.params.id,n=this._referSubscribers[t];else{if(1!==Object.keys(this._referSubscribers).length)return void e.reply(400,"Missing event id parameter");n=this._referSubscribers[Object.keys(this._referSubscribers)[0]]}if(!n)return void e.reply(481,"Subscription does not exist");n.receiveNotify(e),e.reply(200);break;default:e.reply(489)}}},{key:"_receiveReplaces",value:function(e){var t=this;E.debug("receiveReplaces()"),this.emit("replaces",{request:e,accept:function(n){(function(t){var n=this;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;var r=new u(this._ua);r.on("confirmed",function(){n.terminate()}),r.init_incoming(e,t)}).call(t,n)},reject:function(){(function(){E.debug("Replaced INVITE rejected by the user"),e.reply(486)}).call(t)}})}},{key:"_sendInitialRequest",value:function(e,t,n){var r=this,i=new b(this._ua,this._request,{onRequestTimeout:function(){r.onRequestTimeout()},onTransportError:function(){r.onTransportError()},onAuthenticated:function(e){r._request=e},onReceiveResponse:function(e){r._receiveInviteResponse(e)}});Promise.resolve().then(function(){return n||(e.audio||e.video?(r._localMediaStreamLocallyGenerated=!0,navigator.mediaDevices.getUserMedia(e).catch(function(e){if(r._status===R.STATUS_TERMINATED)throw new Error("terminated");throw r._failed("local",null,f.causes.USER_DENIED_MEDIA_ACCESS),E.warn('emit "getusermediafailed" [error:%o]',e),r.emit("getusermediafailed",e),e})):void 0)}).then(function(e){if(r._status===R.STATUS_TERMINATED)throw new Error("terminated");return r._localMediaStream=e,e&&e.getTracks().forEach(function(t){r._connection.addTrack(t,e)}),r._connecting(r._request),r._createLocalDescription("offer",t).catch(function(e){throw r._failed("local",null,f.causes.WEBRTC_ERROR),e})}).then(function(e){if(r._is_canceled||r._status===R.STATUS_TERMINATED)throw new Error("terminated");r._request.body=e,r._status=R.STATUS_INVITE_SENT,E.debug('emit "sending" [request:%o]',r._request),r.emit("sending",{request:r._request}),i.send()}).catch(function(e){r._status!==R.STATUS_TERMINATED&&E.warn(e)})}},{key:"_getDTMFRTPSender",value:function(){var e=this._connection.getSenders().find(function(e){return e.track&&"audio"===e.track.kind});if(e&&e.dtmf)return e.dtmf;E.warn("sendDTMF() | no local audio track to send DTMF with")}},{key:"_receiveInviteResponse",value:function(e){var t=this;if(E.debug("receiveInviteResponse()"),this._dialog&&e.status_code>=200&&e.status_code<=299){if(this._dialog.id.call_id===e.call_id&&this._dialog.id.local_tag===e.from_tag&&this._dialog.id.remote_tag===e.to_tag)return void this.sendRequest(f.ACK);var n=new y(this,e,"UAC");return void 0!==n.error?void E.debug(n.error):(this.sendRequest(f.ACK),void this.sendRequest(f.BYE))}if(this._is_canceled)e.status_code>=100&&e.status_code<200?this._request.cancel(this._cancel_reason):e.status_code>=200&&e.status_code<299&&this._acceptAndTerminate(e);else if(this._status===R.STATUS_INVITE_SENT||this._status===R.STATUS_1XX_RECEIVED)switch(!0){case/^100$/.test(e.status_code):this._status=R.STATUS_1XX_RECEIVED;break;case/^1[0-9]{2}$/.test(e.status_code):if(!e.to_tag){E.debug("1xx response received without to tag");break}if(e.hasHeader("contact")&&!this._createDialog(e,"UAC",!0))break;if(this._status=R.STATUS_1XX_RECEIVED,!e.body){this._progress("remote",e);break}var r={originator:"remote",type:"answer",sdp:e.body};E.debug('emit "sdp"'),this.emit("sdp",r);var i=new RTCSessionDescription({type:"answer",sdp:r.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){return t._progress("remote",e)}).catch(function(e){E.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)});break;case/^2[0-9]{2}$/.test(e.status_code):if(this._status=R.STATUS_CONFIRMED,!e.body){this._acceptAndTerminate(e,400,f.causes.MISSING_SDP),this._failed("remote",e,f.causes.BAD_MEDIA_DESCRIPTION);break}if(!this._createDialog(e,"UAC"))break;var o={originator:"remote",type:"answer",sdp:e.body};E.debug('emit "sdp"'),this.emit("sdp",o);var s=new RTCSessionDescription({type:"answer",sdp:o.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){if("stable"===t._connection.signalingState)return t._connection.createOffer(t._rtcOfferConstraints).then(function(e){return t._connection.setLocalDescription(e)}).catch(function(n){t._acceptAndTerminate(e,500,n.toString()),t._failed("local",e,f.causes.WEBRTC_ERROR)})}).then(function(){t._connection.setRemoteDescription(s).then(function(){t._handleSessionTimersInIncomingResponse(e),t._accepted("remote",e),t.sendRequest(f.ACK),t._confirmed("local",null)}).catch(function(n){t._acceptAndTerminate(e,488,"Not Acceptable Here"),t._failed("remote",e,f.causes.BAD_MEDIA_DESCRIPTION),E.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',n),t.emit("peerconnection:setremotedescriptionfailed",n)})});break;default:var a=v.sipErrorCause(e.status_code);this._failed("remote",e,a)}}},{key:"_sendReinvite",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};E.debug("sendReinvite()");var n=v.cloneArray(t.extraHeaders),r=v.cloneObject(t.eventHandlers),i=t.rtcOfferConstraints||this._rtcOfferConstraints||null,o=!1;function s(e){r.failed&&r.failed(e)}n.push("Contact: ".concat(this._contact)),n.push("Content-Type: application/sdp"),this._sessionTimers.running&&n.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(this._sessionTimers.refresher?"uac":"uas")),this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return e._createLocalDescription("offer",i)}).then(function(t){var i={originator:"local",type:"offer",sdp:t=e._mangleOffer(t)};E.debug('emit "sdp"'),e.emit("sdp",i),e.sendRequest(f.INVITE,{extraHeaders:n,body:t,eventHandlers:{onSuccessResponse:function(t){(function(e){var t=this;if(this._status===R.STATUS_TERMINATED)return;if(this.sendRequest(f.ACK),o)return;if(this._handleSessionTimersInIncomingResponse(e),!e.body)return void s.call(this);if(!e.hasHeader("Content-Type")||"application/sdp"!==e.getHeader("Content-Type").toLowerCase())return void s.call(this);var n={originator:"remote",type:"answer",sdp:e.body};E.debug('emit "sdp"'),this.emit("sdp",n);var i=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){r.succeeded&&r.succeeded(e)}).catch(function(e){s.call(t),E.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}).call(e,t),o=!0},onErrorResponse:function(t){s.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}).catch(function(){s()})}},{key:"_sendUpdate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};E.debug("sendUpdate()");var n=v.cloneArray(t.extraHeaders),r=v.cloneObject(t.eventHandlers),i=t.rtcOfferConstraints||this._rtcOfferConstraints||null,o=t.sdpOffer||!1,s=!1;function a(e){var t=this;if(this._status!==R.STATUS_TERMINATED&&!s)if(this._handleSessionTimersInIncomingResponse(e),o){if(!e.body)return void l.call(this);if(!e.hasHeader("Content-Type")||"application/sdp"!==e.getHeader("Content-Type").toLowerCase())return void l.call(this);var n={originator:"remote",type:"answer",sdp:e.body};E.debug('emit "sdp"'),this.emit("sdp",n);var i=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){r.succeeded&&r.succeeded(e)}).catch(function(e){l.call(t),E.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}else r.succeeded&&r.succeeded(e)}function l(e){r.failed&&r.failed(e)}n.push("Contact: ".concat(this._contact)),this._sessionTimers.running&&n.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(this._sessionTimers.refresher?"uac":"uas")),o?(n.push("Content-Type: application/sdp"),this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return e._createLocalDescription("offer",i)}).then(function(t){var r={originator:"local",type:"offer",sdp:t=e._mangleOffer(t)};E.debug('emit "sdp"'),e.emit("sdp",r),e.sendRequest(f.UPDATE,{extraHeaders:n,body:t,eventHandlers:{onSuccessResponse:function(t){a.call(e,t),s=!0},onErrorResponse:function(t){l.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}).catch(function(){l.call(e)})):this.sendRequest(f.UPDATE,{extraHeaders:n,eventHandlers:{onSuccessResponse:function(t){a.call(e,t)},onErrorResponse:function(t){l.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}},{key:"_acceptAndTerminate",value:function(e,t,n){E.debug("acceptAndTerminate()");var r=[];t&&(n=n||f.REASON_PHRASE[t]||"",r.push("Reason: SIP ;cause=".concat(t,'; text="').concat(n,'"'))),(this._dialog||this._createDialog(e,"UAC"))&&(this.sendRequest(f.ACK),this.sendRequest(f.BYE,{extraHeaders:r})),this._status=R.STATUS_TERMINATED}},{key:"_mangleOffer",value:function(e){if(!this._localHold&&!this._remoteHold)return e;if(e=d.parse(e),this._localHold&&!this._remoteHold){E.debug("mangleOffer() | me on hold, mangling offer");var t,n=i(e.media);try{for(n.s();!(t=n.n()).done;){var r=t.value;-1!==I.indexOf(r.type)&&(r.direction?"sendrecv"===r.direction?r.direction="sendonly":"recvonly"===r.direction&&(r.direction="inactive"):r.direction="sendonly")}}catch(e){n.e(e)}finally{n.f()}}else if(this._localHold&&this._remoteHold){E.debug("mangleOffer() | both on hold, mangling offer");var o,s=i(e.media);try{for(s.s();!(o=s.n()).done;){var a=o.value;-1!==I.indexOf(a.type)&&(a.direction="inactive")}}catch(e){s.e(e)}finally{s.f()}}else if(this._remoteHold){E.debug("mangleOffer() | remote on hold, mangling offer");var l,u=i(e.media);try{for(u.s();!(l=u.n()).done;){var c=l.value;-1!==I.indexOf(c.type)&&(c.direction?"sendrecv"===c.direction?c.direction="recvonly":"recvonly"===c.direction&&(c.direction="inactive"):c.direction="recvonly")}}catch(e){u.e(e)}finally{u.f()}}return d.write(e)}},{key:"_setLocalMediaStatus",value:function(){var e=!0,t=!0;(this._localHold||this._remoteHold)&&(e=!1,t=!1),this._audioMuted&&(e=!1),this._videoMuted&&(t=!1),this._toggleMuteAudio(!e),this._toggleMuteVideo(!t)}},{key:"_handleSessionTimersInIncomingRequest",value:function(e,t){var n;this._sessionTimers.enabled&&(e.session_expires&&e.session_expires>=f.MIN_SESSION_EXPIRES?(this._sessionTimers.currentExpires=e.session_expires,n=e.session_expires_refresher||"uas"):(this._sessionTimers.currentExpires=this._sessionTimers.defaultExpires,n="uas"),t.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(n)),this._sessionTimers.refresher="uas"===n,this._runSessionTimer())}},{key:"_handleSessionTimersInIncomingResponse",value:function(e){var t;this._sessionTimers.enabled&&(e.session_expires&&e.session_expires>=f.MIN_SESSION_EXPIRES?(this._sessionTimers.currentExpires=e.session_expires,t=e.session_expires_refresher||"uac"):(this._sessionTimers.currentExpires=this._sessionTimers.defaultExpires,t="uac"),this._sessionTimers.refresher="uac"===t,this._runSessionTimer())}},{key:"_runSessionTimer",value:function(){var e=this,t=this._sessionTimers.currentExpires;this._sessionTimers.running=!0,clearTimeout(this._sessionTimers.timer),this._sessionTimers.refresher?this._sessionTimers.timer=setTimeout(function(){e._status!==R.STATUS_TERMINATED&&e._isReadyToReOffer()&&(E.debug("runSessionTimer() | sending session refresh request"),e._sessionTimers.refreshMethod===f.UPDATE?e._sendUpdate():e._sendReinvite())},500*t):this._sessionTimers.timer=setTimeout(function(){e._status!==R.STATUS_TERMINATED&&(E.warn("runSessionTimer() | timer expired, terminating the session"),e.terminate({cause:f.causes.REQUEST_TIMEOUT,status_code:408,reason_phrase:"Session Timer Expired"}))},1100*t)}},{key:"_toggleMuteAudio",value:function(e){var t,n=i(this._connection.getSenders().filter(function(e){return e.track&&"audio"===e.track.kind}));try{for(n.s();!(t=n.n()).done;){t.value.track.enabled=!e}}catch(e){n.e(e)}finally{n.f()}}},{key:"_toggleMuteVideo",value:function(e){var t,n=i(this._connection.getSenders().filter(function(e){return e.track&&"video"===e.track.kind}));try{for(n.s();!(t=n.n()).done;){t.value.track.enabled=!e}}catch(e){n.e(e)}finally{n.f()}}},{key:"_newRTCSession",value:function(e,t){E.debug("newRTCSession()"),this._ua.newRTCSession(this,{originator:e,session:this,request:t})}},{key:"_connecting",value:function(e){E.debug("session connecting"),E.debug('emit "connecting"'),this.emit("connecting",{request:e})}},{key:"_progress",value:function(e,t){E.debug("session progress"),E.debug('emit "progress"'),this.emit("progress",{originator:e,response:t||null})}},{key:"_accepted",value:function(e,t){E.debug("session accepted"),this._start_time=new Date,E.debug('emit "accepted"'),this.emit("accepted",{originator:e,response:t||null})}},{key:"_confirmed",value:function(e,t){E.debug("session confirmed"),this._is_confirmed=!0,E.debug('emit "confirmed"'),this.emit("confirmed",{originator:e,ack:t||null})}},{key:"_ended",value:function(e,t,n){E.debug("session ended"),this._end_time=new Date,this._close(),E.debug('emit "ended"'),this.emit("ended",{originator:e,message:t||null,cause:n})}},{key:"_failed",value:function(e,t,n){E.debug("session failed"),E.debug('emit "_failed"'),this.emit("_failed",{originator:e,message:t||null,cause:n}),this._close(),E.debug('emit "failed"'),this.emit("failed",{originator:e,message:t||null,cause:n})}},{key:"_onhold",value:function(e){E.debug("session onhold"),this._setLocalMediaStatus(),E.debug('emit "hold"'),this.emit("hold",{originator:e})}},{key:"_onunhold",value:function(e){E.debug("session onunhold"),this._setLocalMediaStatus(),E.debug('emit "unhold"'),this.emit("unhold",{originator:e})}},{key:"_onmute",value:function(e){var t=e.audio,n=e.video;E.debug("session onmute"),this._setLocalMediaStatus(),E.debug('emit "muted"'),this.emit("muted",{audio:t,video:n})}},{key:"_onunmute",value:function(e){var t=e.audio,n=e.video;E.debug("session onunmute"),this._setLocalMediaStatus(),E.debug('emit "unmuted"'),this.emit("unmuted",{audio:t,video:n})}}])&&s(t.prototype,n),r&&s(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Dialog":3,"./Exceptions":6,"./Logger":9,"./RTCSession/DTMF":16,"./RTCSession/Info":17,"./RTCSession/ReferNotifier":18,"./RTCSession/ReferSubscriber":19,"./RequestSender":21,"./SIPMessage":22,"./Timers":25,"./Transactions":26,"./URI":29,"./Utils":30,events:33,"sdp-transform":39}],16:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};if(void 0===e)throw new TypeError("Not enough arguments");if(this._direction="outgoing",this._session.status!==this._session.C.STATUS_CONFIRMED&&this._session.status!==this._session.C.STATUS_WAITING_FOR_ACK)throw new d.InvalidStateError(this._session.status);var r=h.cloneArray(n.extraHeaders);if(this.eventHandlers=h.cloneObject(n.eventHandlers),"string"==typeof e)e=e.toUpperCase();else{if("number"!=typeof e)throw new TypeError("Invalid tone: ".concat(e));e=e.toString()}if(!e.match(/^[0-9A-DR#*]$/))throw new TypeError("Invalid tone: ".concat(e));this._tone=e,this._duration=n.duration,r.push("Content-Type: application/dtmf-relay");var i="Signal=".concat(this._tone,"\r\n");i+="Duration=".concat(this._duration),this._session.newDTMF({originator:"local",dtmf:this,request:this._request}),this._session.sendRequest(c.INFO,{extraHeaders:r,eventHandlers:{onSuccessResponse:function(e){t.emit("succeeded",{originator:"remote",response:e})},onErrorResponse:function(e){t.eventHandlers.onFailed&&t.eventHandlers.onFailed(),t.emit("failed",{originator:"remote",response:e})},onRequestTimeout:function(){t._session.onRequestTimeout()},onTransportError:function(){t._session.onTransportError()},onDialogError:function(){t._session.onDialogError()}},body:i})}},{key:"init_incoming",value:function(e){var t=/^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/,n=/^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;if(this._direction="incoming",this._request=e,e.reply(200),e.body){var r=e.body.split("\n");r.length>=1&&t.test(r[0])&&(this._tone=r[0].replace(t,"$2")),r.length>=2&&n.test(r[1])&&(this._duration=parseInt(r[1].replace(n,"$2"),10))}this._duration||(this._duration=_.DEFAULT_DURATION),this._tone?this._session.newDTMF({originator:"remote",dtmf:this,request:e}):f.debug("invalid INFO DTMF received, discarded")}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}(),t.exports.C=_},{"../Constants":2,"../Exceptions":6,"../Logger":9,"../Utils":30,events:33}],17:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{};if(this._direction="outgoing",t&&void 0===e)throw new TypeError("Not enough arguments");if(this._session.status!==this._session.C.STATUS_CONFIRMED&&this._session.status!==this._session.C.STATUS_WAITING_FOR_ACK)throw new c.InvalidStateError(this._session.status);this._contentType=e,this._body=t;var i=d.cloneArray(r.extraHeaders);e&&i.push("Content-Type: ".concat(e)),this._session.newInfo({originator:"local",info:this,request:this.request}),this._session.sendRequest(u.INFO,{extraHeaders:i,eventHandlers:{onSuccessResponse:function(e){n.emit("succeeded",{originator:"remote",response:e})},onErrorResponse:function(e){n.emit("failed",{originator:"remote",response:e})},onTransportError:function(){n._session.onTransportError()},onRequestTimeout:function(){n._session.onRequestTimeout()},onDialogError:function(){n._session.onDialogError()}},body:t})}},{key:"init_incoming",value:function(e){this._direction="incoming",this.request=e,e.reply(200),this._contentType=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,this._body=e.body,this._session.newInfo({originator:"remote",info:this,request:e})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),h}()},{"../Constants":2,"../Exceptions":6,"../Utils":30,events:33}],18:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=200?"terminated;reason=noresource":"active;expires=".concat(this._expires);try{this._session.sendRequest(o.NOTIFY,{extraHeaders:["Event: ".concat(a.event_type,";id=").concat(this._id),"Subscription-State: ".concat(n),"Content-Type: ".concat(a.body_type)],body:"SIP/2.0 ".concat(e," ").concat(t),eventHandlers:{onErrorResponse:function(){this._active=!1}}})}catch(e){s.debug("send NOTIFY exception [ignored]")}}}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"../Constants":2,"../Logger":9}],19:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};f.debug("sendRefer()");var r=h.cloneArray(n.extraHeaders),i=h.cloneObject(n.eventHandlers);for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&this.on(o,i[o]);var s=null;n.replaces&&(s=n.replaces._request.call_id,s+=";to-tag=".concat(n.replaces._to_tag),s+=";from-tag=".concat(n.replaces._from_tag),s=encodeURIComponent(s));var a="Refer-To: <".concat(e).concat(s?"?Replaces=".concat(s):"",">");if(r.push(a),!r.some(function(e){return e.toLowerCase().startsWith("referred-by:")})){var l="Referred-By: <".concat(this._session._ua._configuration.uri._scheme,":").concat(this._session._ua._configuration.uri._user,"@").concat(this._session._ua._configuration.uri._host,">");r.push(l)}r.push("Contact: ".concat(this._session.contact));var u=this._session.sendRequest(c.REFER,{extraHeaders:r,eventHandlers:{onSuccessResponse:function(e){t._requestSucceeded(e)},onErrorResponse:function(e){t._requestFailed(e,c.causes.REJECTED)},onTransportError:function(){t._requestFailed(null,c.causes.CONNECTION_ERROR)},onRequestTimeout:function(){t._requestFailed(null,c.causes.REQUEST_TIMEOUT)},onDialogError:function(){t._requestFailed(null,c.causes.DIALOG_ERROR)}}});this._id=u.cseq}},{key:"receiveNotify",value:function(e){if(f.debug("receiveNotify()"),e.body){var t=d.parse(e.body.trim().split("\r\n",1)[0],"Status_Line");if(-1!==t)switch(!0){case/^100$/.test(t.status_code):this.emit("trying",{request:e,status_line:t});break;case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",{request:e,status_line:t});break;case/^2[0-9]{2}$/.test(t.status_code):this.emit("accepted",{request:e,status_line:t});break;default:this.emit("failed",{request:e,status_line:t})}else f.debug('receiveNotify() | error parsing NOTIFY body: "'.concat(e.body,'"'))}}},{key:"_requestSucceeded",value:function(e){f.debug("REFER succeeded"),f.debug('emit "requestSucceeded"'),this.emit("requestSucceeded",{response:e})}},{key:"_requestFailed",value:function(e,t){f.debug("REFER failed"),f.debug('emit "requestFailed"'),this.emit("requestFailed",{response:e||null,cause:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"../Constants":2,"../Grammar":7,"../Logger":9,"../Utils":30,events:33}],20:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n"'),this._contact+=";reg-id=".concat(this._reg_id),this._contact+=";+sip.instance=".concat(this._sipInstance),this._auth=null}var t,n,i;return t=e,(n=[{key:"registered",get:function(){return this._registered}},{key:"setExtraHeaders",value:function(e){Array.isArray(e)||(e=[]),this._extraHeaders=e.slice()}},{key:"setExtraContactParams",value:function(e){for(var t in e instanceof Object||(e={}),this._extraContactParams="",e)if(Object.prototype.hasOwnProperty.call(e,t)){var n=e[t];this._extraContactParams+=";".concat(t),n&&(this._extraContactParams+="=".concat(n))}}},{key:"register",value:function(){var e=this;if(this._registering)u.debug("Register request in progress...");else{var t=this._extraHeaders.slice();t.push("Contact: ".concat(this._contact,";expires=").concat(this._expires).concat(this._extraContactParams)),t.push("Expires: ".concat(this._expires)),this._auth&&t.push(this._auth);var n=new a.OutgoingRequest(s.REGISTER,this._registrar,this._ua,{to_uri:this._to_uri,call_id:this._call_id,cseq:this._cseq+=1},t),r=new l(this._ua,n,{onRequestTimeout:function(){e._registrationFailure(null,s.causes.REQUEST_TIMEOUT)},onTransportError:function(){e._registrationFailure(null,s.causes.CONNECTION_ERROR)},onAuthenticated:function(t){var n,r;(e._cseq+=1,e._ua.modes.cache_register_auth_mode)&&((r=t.getHeader(n="Authorization"))?e._auth="".concat(n,": ").concat(r):(r=t.getHeader(n="Proxy-Authorization"))&&(e._auth="".concat(n,": ").concat(r)))},onReceiveResponse:function(t){if(t.cseq===e._cseq)switch(null!==e._registrationTimer&&(clearTimeout(e._registrationTimer),e._registrationTimer=null),!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):if(e._registering=!1,!t.hasHeader("Contact")){u.debug("no Contact header in response to REGISTER, response ignored");break}var n=t.headers.Contact.reduce(function(e,t){return e.concat(t.parsed)},[]),r=n.find(function(t){return e._sipInstance===t.getParam("+sip.instance")&&e._reg_id===parseInt(t.getParam("reg-id"))});if(r||(r=n.find(function(t){return t.uri.user===e._ua.contact.uri.user})),!r){u.debug("no Contact header pointing to us, response ignored");break}var i=r.getParam("expires");!i&&t.hasHeader("expires")&&(i=t.getHeader("expires")),i||(i=e._expires),(i=Number(i))<10&&(i=10);var a=i>=140?1e3*i/2+Math.floor(1e3*(i/2-70)*Math.random()):1e3*i-5e3;e._registrationTimer=setTimeout(function(){e._registrationTimer=null,0===e._ua.listeners("registrationExpiring").length?e.register():e._ua.emit("registrationExpiring")},a),r.hasParam("temp-gruu")&&(e._ua.contact.temp_gruu=r.getParam("temp-gruu").replace(/"/g,"")),r.hasParam("pub-gruu")&&(e._ua.contact.pub_gruu=r.getParam("pub-gruu").replace(/"/g,"")),e._registered||(e._registered=!0,e._ua.registered({response:t}));break;case/^423$/.test(t.status_code):t.hasHeader("min-expires")?(e._expires=Number(t.getHeader("min-expires")),e._expires<10&&(e._expires=10),e.register()):(u.debug("423 response received for REGISTER without Min-Expires"),e._registrationFailure(t,s.causes.SIP_FAILURE_CODE));break;default:var l=o.sipErrorCause(t.status_code);e._registrationFailure(t,l)}}});this._registering=!0,r.send()}}},{key:"unregister",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(this._registered){this._registered=!1,null!==this._registrationTimer&&(clearTimeout(this._registrationTimer),this._registrationTimer=null);var n=this._extraHeaders.slice();t.all?n.push("Contact: *".concat(this._extraContactParams)):n.push("Contact: ".concat(this._contact,";expires=0").concat(this._extraContactParams)),n.push("Expires: 0"),this._auth&&n.push(this._auth);var r=new a.OutgoingRequest(s.REGISTER,this._registrar,this._ua,{to_uri:this._to_uri,call_id:this._call_id,cseq:this._cseq+=1},n);new l(this._ua,r,{onRequestTimeout:function(){e._unregistered(null,s.causes.REQUEST_TIMEOUT)},onTransportError:function(){e._unregistered(null,s.causes.CONNECTION_ERROR)},onAuthenticated:function(){e._cseq+=1},onReceiveResponse:function(t){switch(!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):e._unregistered(t);break;default:var n=o.sipErrorCause(t.status_code);e._unregistered(t,n)}}}).send(),this._auth=null}else u.debug("already unregistered")}},{key:"close",value:function(){this._registered&&this.unregister()}},{key:"onTransportClosed",value:function(){this._registering=!1,null!==this._registrationTimer&&(clearTimeout(this._registrationTimer),this._registrationTimer=null),this._registered&&(this._registered=!1,this._ua.unregistered({}))}},{key:"_registrationFailure",value:function(e,t){this._registering=!1,this._ua.registrationFailed({response:e||null,cause:t}),this._registered&&(this._registered=!1,this._ua.unregistered({response:e||null,cause:t}))}},{key:"_unregistered",value:function(e,t){this._registering=!1,this._registered=!1,this._ua.unregistered({response:e||null,cause:t||null})}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30}],21:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,s=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){a=!0,o=e},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw o}}}}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n")),this.setHeader("via",""),this.setHeader("max-forwards",p.MAX_FORWARDS);var a=i.to_uri||n,l=i.to_tag?{tag:i.to_tag}:null,u=void 0!==i.to_display_name?i.to_display_name:null;this.to=new g(a,u,l),this.setHeader("to",this.to.toString());var d,h=i.from_uri||r.configuration.uri,f={tag:i.from_tag||v.newTag()};d=void 0!==i.from_display_name?i.from_display_name:r.configuration.display_name?r.configuration.display_name:null,this.from=new g(h,d,f),this.setHeader("from",this.from.toString());var _=i.call_id||r.configuration.jssip_id+v.createRandomToken(15);this.call_id=_,this.setHeader("call-id",_);var m=i.cseq||Math.floor(1e4*Math.random());this.cseq=m,this.setHeader("cseq","".concat(m," ").concat(t))}return h(e,[{key:"setHeader",value:function(e,t){for(var n=new RegExp("^\\s*".concat(e,"\\s*:"),"i"),r=0;r1&&void 0!==arguments[1]?arguments[1]:0;if(e=v.headerize(e),this.headers[e]){if(!(t>=this.headers[e].length)){var n=this.headers[e][t],r=n.raw;if(n.parsed)return n.parsed;var i=m.parse(r,e.replace(/-/g,"_"));return-1===i?(this.headers[e].splice(t,1),void y.debug('error parsing "'.concat(e,'" header field with value "').concat(r,'"'))):(n.parsed=i,i)}y.debug('not so many "'.concat(e,'" headers present'))}else y.debug('header "'.concat(e,'" not present'))}},{key:"s",value:function(e,t){return this.parseHeader(e,t)}},{key:"setHeader",value:function(e,t){var n={raw:t};this.headers[v.headerize(e)]=[n]}},{key:"parseSDP",value:function(e){return!e&&this.sdp?this.sdp:(this.sdp=f.parse(this.body||""),this.sdp)}},{key:"toString",value:function(){return this.data}}]),e}(),S=function(e){i(n,C);var t=s(n);function n(e){var r;return c(this,n),(r=t.call(this)).ua=e,r.headers={},r.ruri=null,r.transport=null,r.server_transaction=null,r}return h(n,[{key:"reply",value:function(e,t,n,r,i,o){var s=[],a=this.getHeader("To");if(e=e||null,t=t||null,!e||e<100||e>699)throw new TypeError("Invalid status_code: ".concat(e));if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: ".concat(t));t=t||p.REASON_PHRASE[e]||"",n=v.cloneArray(n),this.ua.configuration.extra_headers&&(n=n.concat(this.ua.configuration.extra_headers));var u="SIP/2.0 ".concat(e," ").concat(t,"\r\n");if(this.method===p.INVITE&&e>100&&e<=200){var c,d=l(this.getHeaders("record-route"));try{for(d.s();!(c=d.n()).done;){var h=c.value;u+="Record-Route: ".concat(h,"\r\n")}}catch(e){d.e(e)}finally{d.f()}}var f,_=l(this.getHeaders("via"));try{for(_.s();!(f=_.n()).done;){var g=f.value;u+="Via: ".concat(g,"\r\n")}}catch(e){_.e(e)}finally{_.f()}!this.to_tag&&e>100?a+=";tag=".concat(v.newTag()):this.to_tag&&!this.s("to").hasParam("tag")&&(a+=";tag=".concat(this.to_tag)),u+="To: ".concat(a,"\r\n"),u+="From: ".concat(this.getHeader("From"),"\r\n"),u+="Call-ID: ".concat(this.call_id,"\r\n"),u+="CSeq: ".concat(this.cseq," ").concat(this.method,"\r\n");var m,y=l(n);try{for(y.s();!(m=y.n()).done;){var b=m.value;u+="".concat(b.trim(),"\r\n")}}catch(e){y.e(e)}finally{y.f()}switch(this.method){case p.INVITE:this.ua.configuration.session_timers&&s.push("timer"),(this.ua.contact.pub_gruu||this.ua.contact.temp_gruu)&&s.push("gruu"),s.push("ice","replaces");break;case p.UPDATE:this.ua.configuration.session_timers&&s.push("timer"),r&&s.push("ice"),s.push("replaces")}if(s.push("outbound"),this.method===p.OPTIONS?(u+="Allow: ".concat(p.ALLOWED_METHODS,"\r\n"),u+="Accept: ".concat(p.ACCEPTED_BODY_TYPES,"\r\n")):405===e?u+="Allow: ".concat(p.ALLOWED_METHODS,"\r\n"):415===e&&(u+="Accept: ".concat(p.ACCEPTED_BODY_TYPES,"\r\n")),u+="Supported: ".concat(s,"\r\n"),r){var T=v.str_utf8_length(r);u+="Content-Type: application/sdp\r\n",u+="Content-Length: ".concat(T,"\r\n\r\n"),u+=r}else u+="Content-Length: ".concat(0,"\r\n\r\n");this.server_transaction.receiveResponse(e,u,i,o)}},{key:"reply_sl",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=this.getHeaders("via");if(!e||e<100||e>699)throw new TypeError("Invalid status_code: ".concat(e));if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: ".concat(t));t=t||p.REASON_PHRASE[e]||"";var r,i="SIP/2.0 ".concat(e," ").concat(t,"\r\n"),o=l(n);try{for(o.s();!(r=o.n()).done;){var s=r.value;i+="Via: ".concat(s,"\r\n")}}catch(e){o.e(e)}finally{o.f()}var a=this.getHeader("To");if(!this.to_tag&&e>100?a+=";tag=".concat(v.newTag()):this.to_tag&&!this.s("to").hasParam("tag")&&(a+=";tag=".concat(this.to_tag)),i+="To: ".concat(a,"\r\n"),i+="From: ".concat(this.getHeader("From"),"\r\n"),i+="Call-ID: ".concat(this.call_id,"\r\n"),i+="CSeq: ".concat(this.cseq," ").concat(this.method,"\r\n"),this.ua.configuration.extra_headers){var u,c=l(this.ua.configuration.extra_headers);try{for(c.s();!(u=c.n()).done;){var d=u.value;i+="".concat(d.trim(),"\r\n")}}catch(e){c.e(e)}finally{c.f()}}i+="Content-Length: ".concat(0,"\r\n\r\n"),this.transport.send(i)}}]),n}(),A=function(e){i(n,C);var t=s(n);function n(){var e;return c(this,n),(e=t.call(this)).headers={},e.status_code=null,e.reason_phrase=null,e}return h(n)}();t.exports={OutgoingRequest:b,InitialOutgoingInviteRequest:T,IncomingRequest:S,IncomingResponse:A}},{"./Constants":2,"./Grammar":7,"./Logger":9,"./NameAddrHeader":11,"./Utils":30,"sdp-transform":39}],23:[function(e,t,n){"use strict";var r=e("./Logger"),i=e("./Utils"),o=e("./Grammar"),s=new r("Socket");n.isSocket=function(e){if(Array.isArray(e))return!1;if(void 0===e)return s.warn("undefined JsSIP.Socket instance"),!1;try{if(!i.isString(e.url))throw s.warn("missing or invalid JsSIP.Socket url property"),new Error("Missing or invalid JsSIP.Socket url property");if(!i.isString(e.via_transport))throw s.warn("missing or invalid JsSIP.Socket via_transport property"),new Error("Missing or invalid JsSIP.Socket via_transport property");if(-1===o.parse(e.sip_uri,"SIP_URI"))throw s.warn("missing or invalid JsSIP.Socket sip_uri property"),new Error("missing or invalid JsSIP.Socket sip_uri property")}catch(e){return!1}try{["connect","disconnect","send"].forEach(function(t){if(!i.isFunction(e[t]))throw s.warn("missing or invalid JsSIP.Socket method: ".concat(t)),new Error("Missing or invalid JsSIP.Socket method: ".concat(t))})}catch(e){return!1}return!0}},{"./Grammar":7,"./Logger":9,"./Utils":30}],24:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return o(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return o(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n2e3&&(m.debug("update sending re-SUBSCRIBE time"),this._scheduleSubscribe(a))}s!==y.STATE_PENDING&&o===y.STATE_PENDING?(m.debug('emit "pending"'),this.emit("pending")):s!==y.STATE_ACTIVE&&o===y.STATE_ACTIVE&&(m.debug('emit "active"'),this.emit("active"));var u=e.body,c=o===y.STATE_TERMINATED;if(u){var d=e.getHeader("content-type");m.debug('emit "notify"'),this.emit("notify",c,e,u,d)}if(c){var f=i.reason,_=void 0;i.params&&void 0!==i.params["retry-after"]&&(_=parseInt(i.params["retry-after"])),this._dialogTerminated(y.RECEIVE_FINAL_NOTIFY,f,_)}}},{key:"subscribe",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;m.debug("subscribe()"),this._state===y.STATE_INIT?this._sendInitialSubscribe(e,this._headers):this._sendSubsequentSubscribe(e,this._headers)}},{key:"terminate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(m.debug("terminate()"),!this._terminated){this._terminated=!0;var n=this._headers.map(function(e){return e.startsWith("Expires")?"Expires: 0":e});this._state===y.STATE_INIT?this._sendInitialSubscribe(t,n):this._sendSubsequentSubscribe(t,n);this._unsubscribe_timeout_timer=setTimeout(function(){e._dialogTerminated(y.UNSUBSCRIBE_TIMEOUT)},3e4)}}},{key:"state",get:function(){return this._state}},{key:"id",get:function(){return this._dialog?this._dialog.id:null}},{key:"_sendInitialSubscribe",value:function(e,t){var n=this;if(e){if(!this._content_type)throw new TypeError("content_type is undefined");(t=t.slice()).push("Content-Type: ".concat(this._content_type))}this._state=y.STATE_NOTIFY_WAIT;var r=new p.OutgoingRequest(h.SUBSCRIBE,this._ua.normalizeTarget(this._target),this._ua,this._params,t,e);new v(this._ua,r,{onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},onReceiveResponse:function(e){n._receiveSubscribeResponse(e)}}).send()}},{key:"_receiveSubscribeResponse",value:function(e){if(e.status_code>=200&&e.status_code<300){if(null===this._dialog){var t=new g(this,e,"UAC");if(t.error)return m.warn(t.error),void this._dialogTerminated(y.SUBSCRIBE_BAD_OK_RESPONSE);this._dialog=t,m.debug('emit "accepted"'),this.emit("accepted");var n,r=i(this._queue);try{for(r.s();!(n=r.n()).done;){var o=n.value;m.debug("dequeue subscribe"),this._sendSubsequentSubscribe(o.body,o.headers)}}catch(e){r.e(e)}finally{r.f()}}var s=e.getHeader("expires");0===s||s||(m.warn("response without Expires header"),s="900");var a=parseInt(s);a>0&&this._scheduleSubscribe(a)}else 401===e.status_code||407===e.status_code?this._dialogTerminated(y.SUBSCRIBE_FAILED_AUTHENTICATION):e.status_code>=300&&this._dialogTerminated(y.SUBSCRIBE_NON_OK_RESPONSE)}},{key:"_sendSubsequentSubscribe",value:function(e,t){var n=this;if(this._state!==y.STATE_TERMINATED){if(!this._dialog)return m.debug("enqueue subscribe"),void this._queue.push({body:e,headers:t.slice()});if(e){if(!this._content_type)throw new TypeError("content_type is undefined");(t=t.slice()).push("Content-Type: ".concat(this._content_type))}this._dialog.sendRequest(h.SUBSCRIBE,{body:e,extraHeaders:t,eventHandlers:{onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},onSuccessResponse:function(e){n._receiveSubscribeResponse(e)},onErrorResponse:function(e){n._receiveSubscribeResponse(e)},onDialogError:function(e){n._receiveSubscribeResponse(e)}}})}}},{key:"_dialogTerminated",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:void 0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0;this._state!==y.STATE_TERMINATED&&(this._state=y.STATE_TERMINATED,clearTimeout(this._expires_timer),clearTimeout(this._unsubscribe_timeout_timer),this._dialog&&(this._dialog.terminate(),this._dialog=null),m.debug('emit "terminated" code='.concat(e)),this.emit("terminated",e,t,n))}},{key:"_scheduleSubscribe",value:function(e){var t=this,n=e>=140?1e3*e/2+Math.floor(1e3*(e/2-70)*Math.random()):1e3*e-5e3;this._expires_timestamp=(new Date).getTime()+1e3*e,m.debug("next SUBSCRIBE will be sent in ".concat(Math.floor(n/1e3)," sec")),clearTimeout(this._expires_timer),this._expires_timer=setTimeout(function(){t._expires_timer=null,t._sendSubsequentSubscribe(null,t._headers)},n)}},{key:"_stateStringToNumber",value:function(e){switch(e){case"pending":return y.STATE_PENDING;case"active":return y.STATE_ACTIVE;case"terminated":return y.STATE_TERMINATED;case"init":return y.STATE_INIT;case"notify_wait":return y.STATE_NOTIFY_WAIT;default:throw new TypeError("wrong state value")}}}])&&s(t.prototype,n),r&&s(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Dialog":3,"./Grammar":7,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,events:33}],25:[function(e,t,n){"use strict";var r=500;t.exports={T1:r,T2:4e3,T4:5e3,TIMER_B:32e3,TIMER_D:0,TIMER_F:32e3,TIMER_H:32e3,TIMER_I:0,TIMER_J:0,TIMER_K:0,TIMER_L:32e3,TIMER_M:32e3,PROVISIONAL_RESPONSE_INTERVAL:6e4}},{}],26:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){for(var n=0;n=100&&n<=199)switch(this.state){case C.STATUS_CALLING:this.stateChanged(C.STATUS_PROCEEDING),this.eventHandlers.onReceiveResponse(e);break;case C.STATUS_PROCEEDING:this.eventHandlers.onReceiveResponse(e)}else if(n>=200&&n<=299)switch(this.state){case C.STATUS_CALLING:case C.STATUS_PROCEEDING:this.stateChanged(C.STATUS_ACCEPTED),this.M=setTimeout(function(){t.timer_M()},v.TIMER_M),this.eventHandlers.onReceiveResponse(e);break;case C.STATUS_ACCEPTED:this.eventHandlers.onReceiveResponse(e)}else if(n>=300&&n<=699)switch(this.state){case C.STATUS_CALLING:case C.STATUS_PROCEEDING:this.stateChanged(C.STATUS_COMPLETED),this.sendACK(e),this.eventHandlers.onReceiveResponse(e);break;case C.STATUS_COMPLETED:this.sendACK(e)}}}]),n}(),w=function(e){a(n,h);var t=u(n);function n(e,r,o,s){var a;i(this,n),(a=t.call(this)).id="z9hG4bK".concat(Math.floor(1e7*Math.random())),a.transport=r,a.request=o,a.eventHandlers=s;var l="SIP/2.0/".concat(r.via_transport);return l+=" ".concat(e.configuration.via_host,";branch=").concat(a.id),a.request.setHeader("via",l),a}return s(n,[{key:"C",get:function(){return C}},{key:"send",value:function(){this.transport.send(this.request)||this.onTransportError()}},{key:"onTransportError",value:function(){y.debug("transport error occurred for transaction ".concat(this.id)),this.eventHandlers.onTransportError()}}]),n}(),E=function(e){a(n,h);var t=u(n);function n(e,r,o){var s;return i(this,n),(s=t.call(this)).type=C.NON_INVITE_SERVER,s.id=o.via_branch,s.ua=e,s.transport=r,s.request=o,s.last_response="",o.server_transaction=c(s),s.state=C.STATUS_TRYING,e.newTransaction(c(s)),s}return s(n,[{key:"C",get:function(){return C}},{key:"stateChanged",value:function(e){this.state=e,this.emit("stateChanged")}},{key:"timer_J",value:function(){b.debug("Timer J expired for transaction ".concat(this.id)),this.stateChanged(C.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"onTransportError",value:function(){this.transportError||(this.transportError=!0,b.debug("transport error occurred, deleting transaction ".concat(this.id)),this.stateChanged(C.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"receiveResponse",value:function(e,t,n,r){if(100===e)switch(this.state){case C.STATUS_TRYING:this.stateChanged(C.STATUS_PROCEEDING),this.transport.send(t)||this.onTransportError();break;case C.STATUS_PROCEEDING:this.last_response=t,this.transport.send(t)?n&&n():(this.onTransportError(),r&&r())}else if(e>=200&&e<=699)switch(this.state){case C.STATUS_TRYING:case C.STATUS_PROCEEDING:this.stateChanged(C.STATUS_COMPLETED),this.last_response=t,this.timer_J(),this.transport.send(t)?n&&n():(this.onTransportError(),r&&r());break;case C.STATUS_COMPLETED:}}}]),n}(),R=function(e){a(n,h);var t=u(n);function n(e,r,o){var s;return i(this,n),(s=t.call(this)).type=C.INVITE_SERVER,s.id=o.via_branch,s.ua=e,s.transport=r,s.request=o,s.last_response="",o.server_transaction=c(s),s.state=C.STATUS_PROCEEDING,e.newTransaction(c(s)),s.resendProvisionalTimer=null,o.reply(100),s}return s(n,[{key:"C",get:function(){return C}},{key:"stateChanged",value:function(e){this.state=e,this.emit("stateChanged")}},{key:"timer_H",value:function(){T.debug("Timer H expired for transaction ".concat(this.id)),this.state===C.STATUS_COMPLETED&&T.debug("ACK not received, dialog will be terminated"),this.stateChanged(C.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"timer_I",value:function(){this.stateChanged(C.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"timer_L",value:function(){T.debug("Timer L expired for transaction ".concat(this.id)),this.state===C.STATUS_ACCEPTED&&(this.stateChanged(C.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"onTransportError",value:function(){this.transportError||(this.transportError=!0,T.debug("transport error occurred, deleting transaction ".concat(this.id)),null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),clearTimeout(this.L),clearTimeout(this.H),this.stateChanged(C.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"resend_provisional",value:function(){this.transport.send(this.last_response)||this.onTransportError()}},{key:"receiveResponse",value:function(e,t,n,r){var i=this;if(e>=100&&e<=199)switch(this.state){case C.STATUS_PROCEEDING:this.transport.send(t)||this.onTransportError(),this.last_response=t}if(e>100&&e<=199&&this.state===C.STATUS_PROCEEDING)null===this.resendProvisionalTimer&&(this.resendProvisionalTimer=setInterval(function(){i.resend_provisional()},v.PROVISIONAL_RESPONSE_INTERVAL));else if(e>=200&&e<=299)switch(this.state){case C.STATUS_PROCEEDING:this.stateChanged(C.STATUS_ACCEPTED),this.last_response=t,this.L=setTimeout(function(){i.timer_L()},v.TIMER_L),null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null);case C.STATUS_ACCEPTED:this.transport.send(t)?n&&n():(this.onTransportError(),r&&r())}else if(e>=300&&e<=699)switch(this.state){case C.STATUS_PROCEEDING:null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),this.transport.send(t)?(this.stateChanged(C.STATUS_COMPLETED),this.H=setTimeout(function(){i.timer_H()},v.TIMER_H),n&&n()):(this.onTransportError(),r&&r())}}}]),n}();t.exports={C:C,NonInviteClientTransaction:S,InviteClientTransaction:A,AckClientTransaction:w,NonInviteServerTransaction:E,InviteServerTransaction:R,checkTransaction:function(e,t){var n,r=e._transactions;switch(t.method){case _.INVITE:if(n=r.ist[t.via_branch]){switch(n.state){case C.STATUS_PROCEEDING:n.transport.send(n.last_response);break;case C.STATUS_ACCEPTED:}return!0}break;case _.ACK:if(!(n=r.ist[t.via_branch]))return!1;if(n.state===C.STATUS_ACCEPTED)return!1;if(n.state===C.STATUS_COMPLETED)return n.state=C.STATUS_CONFIRMED,n.timer_I(),!0;break;case _.CANCEL:return(n=r.ist[t.via_branch])?(t.reply_sl(200),n.state!==C.STATUS_PROCEEDING):(t.reply_sl(481),!0);default:if(n=r.nist[t.via_branch]){switch(n.state){case C.STATUS_TRYING:break;case C.STATUS_PROCEEDING:case C.STATUS_COMPLETED:n.transport.send(n.last_response)}return!0}}}}},{"./Constants":2,"./Logger":9,"./SIPMessage":22,"./Timers":25,events:33}],27:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n2&&void 0!==arguments[2]?arguments[2]:c.recovery_options;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),u.debug("new()"),this._ua=t,this.status=c.STATUS_DISCONNECTED,this.socket=null,this.sockets=[],this.recovery_options=r,this.recover_attempts=0,this.recovery_timer=null,this.close_requested=!1;try{this.textDecoder=new TextDecoder("utf8")}catch(e){u.warn("cannot use TextDecoder: ".concat(e))}if(void 0===n)throw new TypeError("Invalid argument. undefined 'sockets' argument");n instanceof Array||(n=[n]),n.forEach(function(e){if(!a.isSocket(e.socket))throw new TypeError("Invalid argument. invalid 'JsSIP.Socket' instance");if(e.weight&&!Number(e.weight))throw new TypeError("Invalid argument. 'weight' attribute is not a number");this.sockets.push({socket:e.socket,weight:e.weight||0,status:c.SOCKET_STATUS_READY})},this),this._getSocket()}var t,n,i;return t=e,(n=[{key:"via_transport",get:function(){return this.socket.via_transport}},{key:"url",get:function(){return this.socket.url}},{key:"sip_uri",get:function(){return this.socket.sip_uri}},{key:"connect",value:function(){u.debug("connect()"),this.isConnected()?u.debug("Transport is already connected"):this.isConnecting()?u.debug("Transport is connecting"):(this.close_requested=!1,this.status=c.STATUS_CONNECTING,this.onconnecting({socket:this.socket,attempts:this.recover_attempts}),this.close_requested||(this.socket.onconnect=this._onConnect.bind(this),this.socket.ondisconnect=this._onDisconnect.bind(this),this.socket.ondata=this._onData.bind(this),this.socket.connect()))}},{key:"disconnect",value:function(){u.debug("close()"),this.close_requested=!0,this.recover_attempts=0,this.status=c.STATUS_DISCONNECTED,null!==this.recovery_timer&&(clearTimeout(this.recovery_timer),this.recovery_timer=null),this.socket.onconnect=function(){},this.socket.ondisconnect=function(){},this.socket.ondata=function(){},this.socket.disconnect(),this.ondisconnect({socket:this.socket,error:!1})}},{key:"send",value:function(e){if(u.debug("send()"),!this.isConnected())return u.warn("unable to send message, transport is not connected"),!1;var t=e.toString();return u.debug("sending message:\n\n".concat(t,"\n")),this.socket.send(t)}},{key:"isConnected",value:function(){return this.status===c.STATUS_CONNECTED}},{key:"isConnecting",value:function(){return this.status===c.STATUS_CONNECTING}},{key:"_get_number_of_sbc",value:function(){return this.sockets.length}},{key:"_switch_sbc",value:function(){var e=this.ondisconnect;this.ondisconnect=function(){},this.disconnect(),this.ondisconnect=e,this.close_requested=!1,this.sockets.forEach(function(e){this.socket===e.socket&&(e.status=c.SOCKET_STATUS_ERROR)},this),this._getSocket(),this.connect()}},{key:"_register_redirect",value:function(e){var t,n=null,i=r(this.sockets);try{for(i.s();!(t=i.n()).done;){var o=t.value;if(o.socket.url===e){n=o.socket;break}}}catch(e){i.e(e)}finally{i.f()}if(null===n&&!e.includes(":",6)){e+=":443";var s,a=r(this.sockets);try{for(a.s();!(s=a.n()).done;){var l=s.value;if(l.socket.url===e){n=l.socket;break}}}catch(e){a.e(e)}finally{a.f()}}if(null===n)return!1;var u=this.ondisconnect;return this.ondisconnect=function(){},this.disconnect(),this.ondisconnect=u,this.socket=n,this.connect(),!0}},{key:"_reconnect",value:function(){var e=this;this.recover_attempts+=1;var t=Math.floor(Math.random()*Math.pow(2,this.recover_attempts)+1);tthis.recovery_options.max_interval&&(t=this.recovery_options.max_interval),u.debug("reconnection attempt: ".concat(this.recover_attempts,". next connection attempt in ").concat(t," seconds")),this.recovery_timer=setTimeout(function(){e.close_requested||e.isConnected()||e.isConnecting()||(e._getSocket(),e.connect())},1e3*t)}},{key:"_getSocket",value:function(){var e=[];if(this.sockets.forEach(function(t){t.status!==c.SOCKET_STATUS_ERROR&&(0===e.length?e.push(t):t.weight>e[0].weight?e=[t]:t.weight===e[0].weight&&e.push(t))}),0===e.length)return this.sockets.forEach(function(e){e.status=c.SOCKET_STATUS_READY}),void this._getSocket();var t=Math.floor(Math.random()*e.length);this.socket=e[t].socket}},{key:"_onConnect",value:function(){this.recover_attempts=0,this._ha_connect_time=void 0,this.status=c.STATUS_CONNECTED,null!==this.recovery_timer&&(clearTimeout(this.recovery_timer),this.recovery_timer=null),this.onconnect({socket:this})}},{key:"_onDisconnect",value:function(e,t,n){var r=this.status;if(this.status=c.STATUS_DISCONNECTED,this.ondisconnect({socket:this.socket,error:e,code:t,reason:n}),!this.close_requested){if(void 0!==this._ua.modes.sbc_ha_pairs_mode){if(r===c.STATUS_CONNECTED)return u.debug("AC: SBC HA pairs mode: Reconnect to the same SBC ".concat(this._ua.modes.sbc_ha_pairs_mode," seconds left")),this._ha_connect_time=(new Date).getTime()+1e3*this._ua.modes.sbc_ha_pairs_mode,void this._connect2();if(void 0!==this._ha_connect_time){var i=this._ha_connect_time-(new Date).getTime();if(i>0)return u.debug("AC: SBC HA pairs mode: Repeat ".concat(i/1e3," seconds left")),void this._connect2();u.debug("AC: SBC HA pairs mode: Failed"),this._ha_connect_time=void 0}}this.sockets.forEach(function(e){this.socket===e.socket&&(e.status=c.SOCKET_STATUS_ERROR)},this),this._reconnect()}}},{key:"_connect2",value:function(){var e=this,t=0;if(this._ha_last_connect){var n=(new Date).getTime()-this._ha_last_connect;t=n>500?0:500-n}this.recovery_timer=setTimeout(function(){e.close_requested||e.isConnected()||e.isConnecting()||(e._ha_last_connect=(new Date).getTime(),e.connect())},t)}},{key:"_onData",value:function(e){if("\r\n"!==e){if("string"!=typeof e){try{e=this.textDecoder?this.textDecoder.decode(e):String.fromCharCode.apply(null,new Uint8Array(e))}catch(e){return void u.debug("received binary message failed to be converted into string, message discarded")}u.debug("received binary message:\n\n".concat(e,"\n"))}else u.debug("received text message:\n\n".concat(e,"\n"));this.ondata({transport:this,message:e})}else u.debug("received message with CRLF Keep Alive response")}}])&&o(t.prototype,n),i&&o(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Logger":9,"./Socket":23}],28:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{},t=e.anonymous||null,n=e.outbound||null,r="<";return r+=t?this.temp_gruu||"sip:anonymous@anonymous.invalid;transport=ws":this.pub_gruu||this.uri.toString(),!n||(t?this.temp_gruu:this.pub_gruu)||(r+=";ob"),r+=">"}};var r=["authorization_user","password","realm","ha1","authorization_jwt","display_name","register"];for(var i in this._configuration)Object.prototype.hasOwnProperty.call(this._configuration,i)&&(-1!==r.indexOf(i)?Object.defineProperty(this._configuration,i,{writable:!0,configurable:!1}):Object.defineProperty(this._configuration,i,{writable:!1,configurable:!1}));for(var o in R.debug("configuration parameters after validation:"),this._configuration)if(Object.prototype.hasOwnProperty.call(E.settings,o))switch(o){case"uri":case"registrar_server":R.debug("- ".concat(o,": ").concat(this._configuration[o]));break;case"password":case"ha1":case"authorization_jwt":R.debug("- ".concat(o,": NOT SHOWN"));break;default:R.debug("- ".concat(o,": ").concat(JSON.stringify(this._configuration[o])))}}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),c}()},{"./Config":1,"./Constants":2,"./Exceptions":6,"./Logger":9,"./Message":10,"./Notifier":12,"./Options":13,"./Parser":14,"./RTCSession":15,"./Registrator":20,"./SIPMessage":22,"./Subscriber":24,"./Transactions":26,"./Transport":27,"./URI":29,"./Utils":30,"./sanityCheck":32,events:33}],29:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n4&&void 0!==arguments[4]?arguments[4]:{},a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{};if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),!r)throw new TypeError('missing or invalid "host" parameter');for(var l in this._parameters={},this._headers={},this._scheme=t||s.SIP,this._user=n,this._host=r,this._port=i,o)Object.prototype.hasOwnProperty.call(o,l)&&this.setParam(l,o[l]);for(var u in a)Object.prototype.hasOwnProperty.call(a,u)&&this.setHeader(u,a[u])}var t,n,i;return t=e,i=[{key:"parse",value:function(e){return-1!==(e=l.parse(e,"SIP_URI"))?e:void 0}}],(n=[{key:"scheme",get:function(){return this._scheme},set:function(e){this._scheme=e.toLowerCase()}},{key:"user",get:function(){return this._user},set:function(e){this._user=e}},{key:"host",get:function(){return this._host},set:function(e){this._host=e.toLowerCase()}},{key:"port",get:function(){return this._port},set:function(e){this._port=0===e?e:parseInt(e,10)||null}},{key:"setParam",value:function(e,t){e&&(this._parameters[e.toLowerCase()]=void 0===t||null===t?null:t.toString())}},{key:"getParam",value:function(e){if(e)return this._parameters[e.toLowerCase()]}},{key:"hasParam",value:function(e){if(e)return!!this._parameters.hasOwnProperty(e.toLowerCase())}},{key:"deleteParam",value:function(e){if(e=e.toLowerCase(),this._parameters.hasOwnProperty(e)){var t=this._parameters[e];return delete this._parameters[e],t}}},{key:"clearParams",value:function(){this._parameters={}}},{key:"setHeader",value:function(e,t){this._headers[a.headerize(e)]=Array.isArray(t)?t:[t]}},{key:"getHeader",value:function(e){if(e)return this._headers[a.headerize(e)]}},{key:"hasHeader",value:function(e){if(e)return!!this._headers.hasOwnProperty(a.headerize(e))}},{key:"deleteHeader",value:function(e){if(e=a.headerize(e),this._headers.hasOwnProperty(e)){var t=this._headers[e];return delete this._headers[e],t}}},{key:"clearHeaders",value:function(){this._headers={}}},{key:"clone",value:function(){return new e(this._scheme,this._user,this._host,this._port,JSON.parse(JSON.stringify(this._parameters)),JSON.parse(JSON.stringify(this._headers)))}},{key:"toString",value:function(){var e=[],t="".concat(this._scheme,":");for(var n in this._user&&(t+="".concat(a.escapeUser(this._user),"@")),t+=this._host,(this._port||0===this._port)&&(t+=":".concat(this._port)),this._parameters)Object.prototype.hasOwnProperty.call(this._parameters,n)&&(t+=";".concat(n),null!==this._parameters[n]&&(t+="=".concat(this._parameters[n])));for(var i in this._headers)if(Object.prototype.hasOwnProperty.call(this._headers,i)){var o,s=r(this._headers[i]);try{for(s.s();!(o=s.n()).done;){var l=o.value;e.push("".concat(i,"=").concat(l))}}catch(e){s.e(e)}finally{s.f()}}return e.length>0&&(t+="?".concat(e.join("&"))),t}},{key:"toAor",value:function(e){var t="".concat(this._scheme,":");return this._user&&(t+="".concat(a.escapeUser(this._user),"@")),t+=this._host,e&&(this._port||0===this._port)&&(t+=":".concat(this._port)),t}}])&&o(t.prototype,n),i&&o(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Grammar":7,"./Utils":30}],30:[function(e,t,n){"use strict";function r(e){"@babel/helpers - typeof";return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return o(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return o(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:32,r="";for(t=0;t>>32-t}function n(e,t){var n=2147483648&e,r=2147483648&t,i=1073741824&e,o=1073741824&t,s=(1073741823&e)+(1073741823&t);return i&o?2147483648^s^n^r:i|o?1073741824&s?3221225472^s^n^r:1073741824^s^n^r:s^n^r}function r(e,r,i,o,s,a,l){return n(t(e=n(e,n(n(function(e,t,n){return e&t|~e&n}(r,i,o),s),l)),a),r)}function i(e,r,i,o,s,a,l){return n(t(e=n(e,n(n(function(e,t,n){return e&n|t&~n}(r,i,o),s),l)),a),r)}function o(e,r,i,o,s,a,l){return n(t(e=n(e,n(n(function(e,t,n){return e^t^n}(r,i,o),s),l)),a),r)}function s(e,r,i,o,s,a,l){return n(t(e=n(e,n(n(function(e,t,n){return t^(e|~n)}(r,i,o),s),l)),a),r)}function a(e){var t,n="",r="";for(t=0;t<=3;t++)n+=(r="0".concat((e>>>8*t&255).toString(16))).substr(r.length-2,2);return n}var l,u,c,d,h,f,_,p,v,g;for(l=function(e){for(var t,n=e.length,r=n+8,i=16*((r-r%64)/64+1),o=new Array(i-1),s=0,a=0;a>>29,o}(e=function(e){for(var t="",n=0;n127&&r<2048?(t+=String.fromCharCode(r>>6|192),t+=String.fromCharCode(63&r|128)):(t+=String.fromCharCode(r>>12|224),t+=String.fromCharCode(r>>6&63|128),t+=String.fromCharCode(63&r|128))}return t}(e)),_=1732584193,p=4023233417,v=2562383102,g=271733878,u=0;u1&&void 0!==arguments[1]?arguments[1]:{};return e&&Object.assign({},e)||t}},{"./Constants":2,"./Grammar":7,"./URI":29}],31:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){l=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(l)throw s}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1)return h.debug("more than one Via header field present in the response, dropping the response"),!1},function(){var e=d.str_utf8_length(o.body),t=o.getHeader("content-length");if(e0&&a.length>o){a.warned=!0;var l=new Error("Possible EventEmitter memory leak detected. "+a.length+' "'+String(t)+'" listeners added. Use emitter.setMaxListeners() to increase limit.');l.name="MaxListenersExceededWarning",l.emitter=e,l.type=t,l.count=a.length,"object"==typeof console&&console.warn&&console.warn("%s: %s",l.name,l.message)}}else a=s[t]=n,++e._eventsCount;return e}function h(){if(!this.fired)switch(this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length){case 0:return this.listener.call(this.target);case 1:return this.listener.call(this.target,arguments[0]);case 2:return this.listener.call(this.target,arguments[0],arguments[1]);case 3:return this.listener.call(this.target,arguments[0],arguments[1],arguments[2]);default:for(var e=new Array(arguments.length),t=0;t1&&(t=arguments[1]),t instanceof Error)throw t;var l=new Error('Unhandled "error" event. ('+t+")");throw l.context=t,l}if(!(n=s[e]))return!1;var u="function"==typeof n;switch(r=arguments.length){case 1:!function(e,t,n){if(t)e.call(n);else for(var r=e.length,i=v(e,r),o=0;o=0;s--)if(n[s]===t||n[s].listener===t){a=n[s].listener,o=s;break}if(o<0)return this;0===o?n.shift():function(e,t){for(var n=t,r=n+1,i=e.length;r=0;o--)this.removeListener(e,t[o]);return this},s.prototype.listeners=function(e){return _(this,e,!0)},s.prototype.rawListeners=function(e){return _(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):p.call(e,t)},s.prototype.listenerCount=p,s.prototype.eventNames=function(){return this._eventsCount>0?Reflect.ownKeys(this._events):[]}},{}],34:[function(e,t,n){(function(r){(function(){n.formatArgs=function(e){if(e[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+e[0]+(this.useColors?"%c ":" ")+"+"+t.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;e.splice(1,0,n,"color: inherit");let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,e=>{"%%"!==e&&"%c"===e&&(i=++r)}),e.splice(i,0,n)},n.save=function(e){try{e?n.storage.setItem("debug",e):n.storage.removeItem("debug")}catch(e){}},n.load=function(){let e;try{e=n.storage.getItem("debug")}catch(e){}!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG);return e},n.useColors=function(){if("undefined"!=typeof window&&window.process&&("renderer"===window.process.type||window.process.__nwjs))return!0;if("undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;return"undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},n.storage=function(){try{return localStorage}catch(e){}}(),n.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),n.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],n.log=console.debug||console.log||(()=>{}),t.exports=e("./common")(n);const{formatters:i}=t.exports;i.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}}).call(this)}).call(this,e("_process"))},{"./common":35,_process:37}],35:[function(e,t,n){t.exports=function(t){function n(e){let t,i,o,s=null;function a(...e){if(!a.enabled)return;const r=a,i=Number(new Date),o=i-(t||i);r.diff=o,r.prev=t,r.curr=i,t=i,e[0]=n.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let s=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(t,i)=>{if("%%"===t)return"%";s++;const o=n.formatters[i];if("function"==typeof o){const n=e[s];t=o.call(r,n),e.splice(s,1),s--}return t}),n.formatArgs.call(r,e),(r.log||n.log).apply(r,e)}return a.namespace=e,a.useColors=n.useColors(),a.color=n.selectColor(e),a.extend=r,a.destroy=n.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(i!==n.namespaces&&(i=n.namespaces,o=n.enabled(e)),o),set:e=>{s=e}}),"function"==typeof n.init&&n.init(a),a}function r(e,t){const r=n(this.namespace+(void 0===t?":":t)+e);return r.log=this.log,r}function i(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return n.debug=n,n.default=n,n.coerce=function(e){return e instanceof Error?e.stack||e.message:e},n.disable=function(){const e=[...n.names.map(i),...n.skips.map(i).map(e=>"-"+e)].join(",");return n.enable(""),e},n.enable=function(e){let t;n.save(e),n.namespaces=e,n.names=[],n.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),i=r.length;for(t=0;t{n[e]=t[e]}),n.names=[],n.skips=[],n.formatters={},n.selectColor=function(e){let t=0;for(let n=0;n=1.5*n;return Math.round(e/n)+" "+r+(i?"s":"")}t.exports=function(e,t){t=t||{};var n=typeof e;if("string"===n&&e.length>0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var n=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return n*l;case"weeks":case"week":case"w":return n*a;case"days":case"day":case"d":return n*s;case"hours":case"hour":case"hrs":case"hr":case"h":return n*o;case"minutes":case"minute":case"mins":case"min":case"m":return n*i;case"seconds":case"second":case"secs":case"sec":case"s":return n*r;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}(e);if("number"===n&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=s)return u(e,t,s,"day");if(t>=o)return u(e,t,o,"hour");if(t>=i)return u(e,t,i,"minute");if(t>=r)return u(e,t,r,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=s)return Math.round(e/s)+"d";if(t>=o)return Math.round(e/o)+"h";if(t>=i)return Math.round(e/i)+"m";if(t>=r)return Math.round(e/r)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],37:[function(e,t,n){var r,i,o=t.exports={};function s(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function l(e){if(r===setTimeout)return setTimeout(e,0);if((r===s||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch(t){try{return r.call(null,e,0)}catch(t){return r.call(this,e,0)}}}!function(){try{r="function"==typeof setTimeout?setTimeout:s}catch(e){r=s}try{i="function"==typeof clearTimeout?clearTimeout:a}catch(e){i=a}}();var u,c=[],d=!1,h=-1;function f(){d&&u&&(d=!1,u.length?c=u.concat(c):h=-1,c.length&&_())}function _(){if(!d){var e=l(f);d=!0;for(var t=c.length;t;){for(u=c,c=[];++h1)for(var n=1;n1&&(e[n[0]]=void 0),e};n.parseParams=function(e){return e.split(/;\s?/).reduce(a,{})},n.parseFmtpConfig=n.parseParams,n.parsePayloads=function(e){return e.toString().split(" ").map(Number)},n.parseRemoteCandidates=function(e){for(var t=[],n=e.split(" ").map(r),i=0;i=r)return e;var i=n[t];switch(t+=1,e){case"%%":return"%";case"%s":return String(i);case"%d":return Number(i);case"%v":return""}})}.apply(null,r)},s=["v","o","s","i","u","e","p","c","b","t","r","z","a"],a=["i","c","b","a"];t.exports=function(e,t){t=t||{},null==e.version&&(e.version=0),null==e.name&&(e.name=" "),e.media.forEach(function(e){null==e.payloads&&(e.payloads="")});var n=t.outerOrder||s,i=t.innerOrder||a,l=[];return n.forEach(function(t){r[t].forEach(function(n){n.name in e&&null!=e[n.name]?l.push(o(t,n,e)):n.push in e&&null!=e[n.push]&&e[n.push].forEach(function(e){l.push(o(t,n,e))})})}),e.media.forEach(function(e){l.push(o("m",r.m[0],e)),i.forEach(function(t){r[t].forEach(function(n){n.name in e&&null!=e[n.name]?l.push(o(t,n,e)):n.push in e&&null!=e[n.push]&&e[n.push].forEach(function(e){l.push(o(t,n,e))})})})}),l.join("\r\n")+"\r\n"}},{"./grammar":38}],42:[function(e,t,n){t.exports={name:"jssip",title:"JsSIP",description:"the Javascript SIP library",version:"3.10.0",homepage:"https://jssip.net",contributors:["José Luis Millán (https://github.com/jmillan)","Iñaki Baz Castillo (https://inakibaz.me)"],types:"lib/JsSIP.d.ts",main:"lib-es5/JsSIP.js",keywords:["sip","websocket","webrtc","node","browser","library"],license:"MIT",repository:{type:"git",url:"https://github.com/versatica/JsSIP.git"},bugs:{url:"https://github.com/versatica/JsSIP/issues"},dependencies:{"@types/events":"^3.0.0","@types/debug":"^4.1.7",debug:"^4.3.1",events:"^3.3.0","sdp-transform":"^2.14.1"},devDependencies:{"@babel/core":"^7.19.6","@babel/preset-env":"^7.19.4","ansi-colors":"^3.2.4",browserify:"^16.5.1",eslint:"^5.16.0","fancy-log":"^1.3.3",gulp:"^4.0.2","gulp-babel":"^8.0.0","gulp-eslint":"^5.0.0","gulp-expect-file":"^1.0.2","gulp-header":"^2.0.9","gulp-nodeunit-runner":"^0.2.2","gulp-plumber":"^1.2.1","gulp-rename":"^1.4.0","gulp-uglify-es":"^1.0.4",pegjs:"^0.7.0","vinyl-buffer":"^1.0.1","vinyl-source-stream":"^2.0.0"},scripts:{lint:"node npm-scripts.js lint",test:"node npm-scripts.js test",prepublish:"node npm-scripts.js prepublish",release:"node npm-scripts.js release"}}},{}]},{},[8])(8)});"use strict"; +/* + * AudioCodes WebRTC API v1.19.0 + * © 2023 AudioCodes Ltd. All rights reserved. + * + */function _toConsumableArray(e){return _arrayWithoutHoles(e)||_iterableToArray(e)||_unsupportedIterableToArray(e)||_nonIterableSpread()}function _nonIterableSpread(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _iterableToArray(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}function _arrayWithoutHoles(e){if(Array.isArray(e))return _arrayLikeToArray(e)}function _typeof(e){"@babel/helpers - typeof";return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_unsupportedIterableToArray(e,t)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _iterableToArrayLimit(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,i,o=[],s=!0,a=!1;try{for(n=n.call(e);!(s=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);s=!0);}catch(e){a=!0,i=e}finally{try{s||null==n.return||n.return()}finally{if(a)throw i}}return o}}function _arrayWithHoles(e){if(Array.isArray(e))return e}function _createForOfIteratorHelper(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=_unsupportedIterableToArray(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,s=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){a=!0,o=e},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw o}}}}function _unsupportedIterableToArray(e,t){if(e){if("string"==typeof e)return _arrayLikeToArray(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_arrayLikeToArray(e,t):void 0}}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1])||arguments[1];this.oauthToken=e,this.oauthTokenUseInInvite=t,this.setRegisterExtraHeaders(this.registerExtraHeaders)}},{key:"setUserAgent",value:function(e){this.u17=e}},{key:"setConstraints",value:function(t,n,r){var i=this.browser,o=this.browser+"|"+this.os;if(null===t||t===i||t===o){if(e.ac_log("AC: setConstraints ".concat(t," ").concat(n," ").concat(JSON.stringify(r))),"audio"!==n&&"video"!==n)throw new TypeError("Wrong type: ".concat(n));this.constraints[n]=r}else e.ac_log("AC: setConstraints ".concat(t," - ignored, no current browser"))}},{key:"setConstraint",value:function(t,n,r){if(null!==r&&void 0!==r?e.ac_log("AC: setConstraint ".concat(t," ").concat(n,"=").concat(JSON.stringify(r))):e.ac_log("AC: setConstraint remove ".concat(t," ").concat(n)),"audio"!==t&&"video"!==t)throw new TypeError("Wrong type: ".concat(t));null!==r&&void 0!==r?(!0===this.constraints[t]&&(this.constraints[t]={}),this.constraints[t][n]=r):!0!==this.constraints[t]&&!1!==this.constraints[t]&&(delete this.constraints[t][n],0===Object.keys(this.constraints[t]).length&&(this.constraints[t]=!0))}},{key:"setBrowsersConstraints",value:function(e){var t=this.browser,n=this.browser+"|"+this.os;for(var r in e)if(r===t||r===n){var i=e[r];void 0!==i.audio&&this.setConstraints(r,"audio",i.audio),void 0!==i.video&&this.setConstraints(r,"video",i.video)}}},{key:"setCodecFilter",value:function(t){t&&(e.ac_log("AC: setCodecFilter ".concat(JSON.stringify(t))),this.codecFilter=this._cf_unpack(t))}},{key:"setServerConfig",value:function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];this.serverConfig={addresses:t,domain:n,iceServers:this._convertIceList(r)},e.ac_log("AC: setServerConfig() ".concat(JSON.stringify(this.serverConfig)))}},{key:"setReconnectIntervals",value:function(t,n){e.ac_log("AC: setReconnectIntervals min=".concat(t," max=").concat(n)),this.reconnectMin=t,this.reconnectMax=n}},{key:"setAccount",value:function(e,t,n,r){void 0!==t&&null!==t&&0!==t.length||(t=void 0),void 0!==r&&null!==r&&0!==r.length||(r=e);var i=this.account;i.user=e,i.displayName=t,i.password=n,i.authUser=r}},{key:"setRegisterExpires",value:function(t){e.ac_log("AC: setRegisterExpires=".concat(t)),this.account.registerExpires=t}},{key:"setUseSessionTimer",value:function(t){e.ac_log("AC: setUseSessionTimer=".concat(t)),this.account.useSessionTimer=t}},{key:"setDtmfOptions",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;e.ac_log("AC: setDtmfOptions useWebRTC=".concat(t," duration=").concat(n," interToneGap=").concat(r)),this.dtmfUseWebRTC=t,null!==n&&(this.dtmfDuration=n),null!==r&&(this.dtmfInterToneGap=r)}},{key:"setEnableAddVideo",value:function(t){e.ac_log("AC: setEnableAddVideo=".concat(t)),this.enableAddVideo=t}},{key:"getEnableAddVideo",value:function(){return this.enableAddVideo}},{key:"getAccount",value:function(){return this.account}},{key:"setListeners",value:function(t){e.ac_log("AC: setListeners()");for(var n=0,r=["loginStateChanged","outgoingCallProgress","callTerminated","callConfirmed","callShowStreams","incomingCall","callHoldStateChanged"];n0&&void 0!==arguments[0]?arguments[0]:{};e.ac_log("AC: setModes() ".concat(JSON.stringify(t))),Object.assign(this.modes,t),this._normalizeModes()}},{key:"_normalizeModes",value:function(){function e(e,t){return"number"==typeof e&&e<=t?void 0:e}var t=this.modes;t.sbc_ha_pairs_mode=e(t.sbc_ha_pairs_mode,0),t.chrome_rtp_timeout_fix=e(t.chrome_rtp_timeout_fix,0)}},{key:"init",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(e.ac_log("AC: init() autoLogin=".concat(t)),!this._isInitialized){this._isInitialized=!0,JsSIP.debug.enable("JsSIP:*"),JsSIP.debug.formatArgs=function(){e.js_log&&(this.log=e.js_log)};var n,r=[],i=_createForOfIteratorHelper(this.serverConfig.addresses);try{for(i.s();!(n=i.n()).done;){var o=n.value;o instanceof Array?r.push({socket:new JsSIP.WebSocketInterface(o[0]),weight:o[1]}):r.push(new JsSIP.WebSocketInterface(o))}}catch(e){i.e(e)}finally{i.f()}var s={sockets:r,uri:"sip:"+this.account.user+"@"+this.serverConfig.domain,contact_uri:"sip:"+this.account.user+"@"+this._randomToken(12)+".invalid;transport=ws",authorization_user:this.account.authUser,password:this.account.password,register:t,session_timers:this.account.useSessionTimer,register_expires:this.account.registerExpires,user_agent:this.u17,connection_recovery_min_interval:this.reconnectMin,connection_recovery_max_interval:this.reconnectMax};this.account.displayName&&this.account.displayName.length>0&&(s.display_name=this.account.displayName),this.jssipUA=new JsSIP.UA(s),this.setRegisterExtraHeaders(this.registerExtraHeaders),this._setUACallbacks(),e.ac_log("AC: applied SDK modes: ".concat(JSON.stringify(this.modes,function(e,t){return void 0===t?"":t}))),this.jssipUA.modes=this.modes;var a,l=_createForOfIteratorHelper(this.credentials);try{for(l.s();!(a=l.n()).done;){var u=a.value;this.jssipUA.addCredential(u)}}catch(e){l.e(e)}finally{l.f()}this.credentials=[],this.jssipUA.start()}}},{key:"deinit",value:function(){this._isInitialized=!1,this.jssipUA&&this.jssipUA.stop()}},{key:"setRegisterExtraHeaders",value:function(e){if(this.registerExtraHeaders=e,this.jssipUA){var t=null!==e?e:[];null!==this.oauthToken&&(t=t.slice()).push("Authorization: Bearer ".concat(this.oauthToken)),this.jssipUA.registrator().setExtraHeaders(t)}}},{key:"getRegisterExtraHeaders",value:function(){return this.registerExtraHeaders}},{key:"login",value:function(){e.ac_log("AC: login()"),this.jssipUA.register()}},{key:"logout",value:function(){e.ac_log("AC: logout()"),this.jssipUA.isRegistered()&&this.jssipUA.unregister()}},{key:"switchSBC",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return e.ac_log("AC: switchSBC()"),this.jssipUA.switchSBC(t)}},{key:"getNumberOfSBC",value:function(){return this.jssipUA.getNumberOfSBC()}},{key:"setWebSocketKeepAlive",value:function(t){var n,r=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,s=arguments.length>4&&void 0!==arguments[4]&&arguments[4];if(e.ac_log("AC: setWebSocketKeepAlive pingInterval=".concat(t," pongTimeout=").concat(r)+" timerThrottlingBestEffort=".concat(JSON.stringify(i)," pongReport=").concat(o," pongDist=").concat(s)),"number"!=typeof t||"boolean"!=typeof r)throw new TypeError("setWebSocketKeepAlive: wrong type of first or second argument");this.wsPingMs=this.wsOrigPingMs=1e3*t,this.wsPongTimeout=r,this.wsPongReport=o,this.wsPongDist=s,this.wsPongReportCounter=0,this.wsIsThrottling=!1;var a=(n=!0===i?{log:0,chrome:{interval:1,visibility:!0,call:!0,log:1}}:!1===i?{log:0}:i)[this.browser];this.wsThrottlingPingMs=a&&void 0!==a.interval?1e3*a.interval:0,this.wsVisibility=!(!a||void 0===a.visibility)&&a.visibility,this.wsCall=!(!a||void 0===a.call)&&a.call,this.wsLog=a&&void 0!==a.log?a.log:n.log,this.wsPongDelays=new Array(this.wsPongReport>0?this.wsPongReport:50),this.wsPongDelaysIx=0,0!==this.wsOrigPingMs&&0!==this.wsThrottlingPingMs&&this.wsVisibility&&document.addEventListener("visibilitychange",this._onVisibilityChange.bind(this))}},{key:"_pingLog",value:function(){return" (ping=".concat(this.wsPingMs/1e3," sec)")}},{key:"_visibilityLog",value:function(t){var n="AC: keep-alive: Page is "+(document.hidden?"hidden":"visible");document.hidden&&(this.wsCall&&(n+=", "+(0===this.activeCalls?"no active call":"active call")),n+=" and "+(this.wsIsThrottling?"was":"was not")+" trottling"),t&&(n+=this._pingLog()),e.ac_log(n)}},{key:"_activeCallsLog",value:function(t){var n="AC: keep-alive: ".concat(0===this.activeCalls?"Call ended":"Call started");0===this.activeCalls&&(this.wsVisibility&&(n+=", page is "+(document.hidden?"hidden":"visible")),n+=" and "+(this.wsIsThrottling?"was":"was not")+" trottling"),t&&(n+=this._pingLog()),e.ac_log(n)}},{key:"_onActiveCallsChange",value:function(t){if(this.activeCalls+=t,this.wsCall&&0!==this.wsPingMs&&0!==this.wsThrottlingPingMs)if(this.activeCalls<0&&e.ac_log("Warning: keep-alive: activeCalls < 0"),0===this.activeCalls){if((!this.wsVisibility||document.hidden)&&this.wsIsThrottling&&this.wsPingMs=2&&this._activeCallsLog(!1)}else if(1===this.activeCalls&&t>0){if(this.wsPingMs>this.wsOrigPingMs)return this.wsPingMs=this.wsOrigPingMs,void this._activeCallsLog(!0);this.wsLog>=2&&this._activeCallsLog(!1)}}},{key:"_onVisibilityChange",value:function(){if(this.wsVisibility&&0!==this.wsPingMs&&0!==this.wsThrottlingPingMs)if(document.hidden){if(this.wsCall&&0===this.activeCalls&&this.wsIsThrottling&&this.wsPingMs=2&&this._visibilityLog(!1)}else{if(this.wsPingMs>this.wsOrigPingMs)return this.wsPingMs=this.wsOrigPingMs,void this._visibilityLog(!0);this.wsLog>=2&&this._visibilityLog(!1)}}},{key:"_onMessageHook",value:function(e){"\r\n"===e.data?this._onPong():this.wsOnMessage(e)}},{key:"_onPong",value:function(){if(this.wsPingStarted){var t;this.wsPongReceived=!0,null===this.wsPongSupported&&(e.ac_log("AC: keep-alive: Server supports CRLF pong"),this.wsPongSupported=!0),null!==this.wsPongTimeoutTime?(t=Date.now()-this.wsPongTimeoutTime,this.wsPongTimeoutTime=null,e.ac_log("AC: keep-alive: Received pong that exceeded the timeout, delay=".concat(t))):t=Date.now()-this.wsPingTime;var n=this.wsPingMs-t;n<0&&(e.ac_log("AC: nextPing calculated to ".concat(n,"ms, so resetting to 0ms.")),n=0),null!==this.wsPingJob&&clearTimeout(this.wsPingJob),this.wsPingJob=setTimeout(this._sendPing.bind(this),n),this.wsPongDelays[this.wsPongDelaysIx]=t,this.wsPongDelaysIx=this.wsPongDelaysIx+1,this.wsPongDelaysIx===this.wsPongDelays.length&&(this.wsPongDelaysIx=0),this.wsPongReport>0&&this.wsPongReportCounter++}}},{key:"_onPongTimeout",value:function(t){if(e.ac_log("AC: keep-alive: Pong timeout (not received within ".concat(t/1e3," seconds)")),e.ac_log("AC: keep-alive: Previous pongs statistics: ".concat(this._createPongReport(!0))),this.wsPongTimeout){e.ac_log("AC: keep-alive: Close websocket connection"),this._stopWsKeepAlive();var n=this.wsSocket;n.onopen=void 0,n.onerror=void 0,n.onclose=void 0,n.onmessage=void 0,setTimeout(function(){try{n.close()}catch(t){e.ac_log("AC: Close websocket error",t)}},0),this.wsWebSocketInterface._ws=null,this.wsWebSocketInterface._onClose.call(this.wsWebSocketInterface,{wasClean:!1,code:1001,reason:"Going Away"})}else e.ac_log("AC: keep-alive: Warning: websocket is not closed, because pongTimeout=false")}},{key:"_sendPing",value:function(){try{var t=Date.now();if(null!==this.wsPingTime){var n=t-this.wsNextPingTime;this.wsLog>=3&&e.ac_log("AC: keep-alive: timer deviation (ms): ".concat(n));var r=this.wsPingMs;if(Math.abs(n)>=1e4&&((this.wsLog>0||!this.wsIsThrottling)&&(e.ac_log("AC: keep-alive detected timer throttling: ".concat(Math.round(n/1e3)," seconds ").concat(n>0?"later":"earlier")),0===this.wsLog&&e.ac_log("AC: keep-alive: The next timer throttling will not be shown in the logs, because log==0")),this.wsIsThrottling=!0,this.wsPingMso&&(o=l),e)){var u=Math.floor(l/250);u>=t.length&&(u=t.length-1,r=!0),t[u]++}}if(e){n="\r\npongs distribution (1/4 second step): ";for(var c=0;c>: loginStateChanged: isLogin=false "connected"'),t._startWsKeepAlive(),t.listeners.loginStateChanged(!1,"connected",null)}),this.jssipUA.on("disconnected",function(){t._stopWsKeepAlive(),e.ac_log('AC>>: loginStateChanged: isLogin=false "disconnected"'),t.listeners.loginStateChanged(!1,"disconnected",null)}),this.jssipUA.on("registered",function(n){e.ac_log('AC>>: loginStateChanged: isLogin=true "login"'),t.listeners.loginStateChanged(!0,"login",n.response)}),this.jssipUA.on("unregistered",function(n){e.ac_log('AC>>: loginStateChanged: isLogin=false "logout"'),t.listeners.loginStateChanged(!1,"logout",n.response)}),this.jssipUA.on("registrationFailed",function(n){var r=n.response?n.response.status_code:0;if(r>=300&&r<400){var i=n.response.parseHeader("contact");if(i){var o=i.uri,s="wss://"+o.host;if(o.port&&443!==o.port&&(s+=":"+o.port.toString()),e.ac_log('AC: registerRedirect("'.concat(s,'")')),t.jssipUA.registerRedirect(s))return}else e.ac_log('AC: 3xx response without "Contact" is ignored')}else if(r>=500&&r<600&&e.instance.modes.sbc_switch_register5xx_mode&&e.instance.switchSBC(!1))return;e.ac_log('AC>>: loginStateChanged: isLogin=false "login failed"'),t.listeners.loginStateChanged(!1,"login failed",n.response?n.response:null)}),this.listeners.incomingMessage&&this.jssipUA.on("newMessage",function(n){"remote"===n.originator&&(e.ac_log("AC>>: incomingMessage",n),t.listeners.incomingMessage(null,e.instance._get_from(n.request),e.instance._get_content_type(n.request),n.request.body,n.request))}),this.listeners.incomingNotify&&this.jssipUA.on("sipEvent",function(n){e.ac_log("AC>>: incoming out of dialog NOTIFY",n),t.listeners.incomingNotify(null,n.event?n.event.event:null,e.instance._get_from(n.request),e.instance._get_content_type(n.request),n.request.body,n.request)||n.request.reply(481)}),this.listeners.incomingSubscribe&&this.jssipUA.on("newSubscribe",function(n){var r=n.request,i=r.parseHeader("event"),o=r.getHeaders("accept");e.ac_log("AC>>: incomingSubscribe",r,i.event,o);var s=t.listeners.incomingSubscribe(r,i.event,o);s>0&&r.reply(s)}),this.jssipUA.on("newRTCSession",function(t){e.ac_log("AC: event ".concat("remote"===t.originator?"incoming":"outgoing",' "newRTCSession"'),t);var n,r=new AudioCodesSession(t.session);if(r.js_session.on("sipEvent",function(t){if(e.instance.listeners.incomingNotify){var n=this.data.ac_session;e.ac_log("AC>>: incoming NOTIFY",n,t),t.taken=e.instance.listeners.incomingNotify(n,t.event?t.event.event:null,e.instance._get_from(t.request),e.instance._get_content_type(t.request),t.request.body,t.request)}}),r.js_session.on("newInfo",function(t){if(e.instance.listeners.incomingInfo&&"local"!==t.originator){var n=this.data.ac_session;e.ac_log("AC>>: incoming INFO",n,t),e.instance.listeners.incomingInfo(n,e.instance._get_from(t.request),e.instance._get_content_type(t.request),t.request.body,t.request)}}),r.js_session.on("replaces",function(t){e.instance.replacedCall=this.data.ac_session,e.ac_log("AC>>: incoming INVITE with Replaces. This call will be replaced:",this.data.ac_session),t.accept()}),r.js_session.on("sdp",function(t){e.instance._sdp_checking(this,t)}),r.js_session.on("connecting",function(t){e.ac_log("AC>>: connecting");var n=e.instance.codecFilter;n&&(e.instance._cf_filter("audio",this.data.ac_session,n.audio),e.instance._cf_filter("video",this.data.ac_session,n.video))}),r.js_session.on("reinvite",function(t){if(e.instance.listeners.callIncomingReinvite){var n=this.data.ac_session;e.ac_log("AC>>: callIncomingReinvite start"),e.instance.listeners.callIncomingReinvite(n,!0,t.request),t.callback=function(){e.ac_log("AC>>: callIncomingIncomingReinvite end"),e.instance.listeners.callIncomingReinvite(n,!1,null)}}}),r.js_session.on("hold",function(t){var n=this.data.ac_session,r="remote"===t.originator;e.ac_log("AC>>: callHoldStateChanged isHold=true isRemote=".concat(r," session:"),n),e.instance.listeners.callHoldStateChanged(n,!0,r)}),r.js_session.on("unhold",function(t){var n=this.data.ac_session,r="remote"===t.originator;e.ac_log("AC>>: callHoldStateChanged isHold=false isRemote=".concat(r," session:"),n),e.instance.listeners.callHoldStateChanged(n,!1,r)}),r.js_session.on("progress",function(t){if("remote"===t.originator){var n=this.data.ac_session;e.ac_log("AC>>: outgoingCallProgress",n),e.instance.listeners.outgoingCallProgress(n,t.response)}}),r.js_session.on("failed",function(t){var n=this.data.ac_session,r=null;if("Redirected"===t.cause&&t.message&&t.message.headers){var i=t.message.parseHeader("Contact");i&&(r=i.uri.toString())}e.ac_log("AC>>: callTerminated (failed)",n,t.cause,r),e.instance.listeners.callTerminated(n,t.message,t.cause,r)}),r.js_session.on("accepted",function(e){var t=this.data.ac_session;t.data._accepted=!0,"remote"===e.originator&&(t.data._ok_response=e.response)}),"remote"===t.originator&&null!==e.instance.replacedCall&&r.js_session.removeAllListeners("confirmed"),r.js_session.on("confirmed",function(){var t,n=this.data.ac_session,i=null;"_ok_response"in n.data?(i=n.data._ok_response,delete n.data._ok_response,t="ACK sent"):t="ACK received",r.data._video_call_audio_answer_firefox&&(r.data._video_call_audio_answer_firefox=!1,e.ac_log("AC: [video call/audio answer] Firefox workaround. Send re-INVITE"),r.sendReInvite({showStreams:!0})),e.ac_log("AC>>: callConfirmed",n,t),e.instance._onActiveCallsChange.call(e.instance,1),e.instance.listeners.callConfirmed(n,i,t)}),r.js_session.on("ended",function(t){var n=this.data.ac_session;n.data._screenSharing&&n._onEndedScreenSharing.call(n,"call terminated"),e.ac_log("AC>>: callTerminated (ended)",n,t.cause),e.instance._onActiveCallsChange.call(e.instance,-1),e.instance.listeners.callTerminated(n,t.message,t.cause)}),r.js_session.on("refer",function(t){if(e.instance.listeners.transfereeCreatedCall){var n=this.data.ac_session;if(!e.instance.listeners.transfereeRefer||e.instance.listeners.transfereeRefer(n,t.request)){var r;e.ac_log("AC>>: incoming REFER accepted"),r=n.isScreenSharing()?n.doesScreenSharingReplaceCamera():n.hasSendVideo();var i=e.instance._callOptions(r,!0);t.accept(function(e){e.data._created_by_refer=n},i)}else e.ac_log("AC>>: incoming REFER rejected"),t.reject()}else e.ac_log("AC>>: incoming REFER rejected, because transfereeCreatedCall is not set"),t.reject()}),r._setEnabledReceiveVideo(e.instance.enableAddVideo),r.js_session.connection?(e.instance._set_connection_listener(r),e.ac_log('AC: connection exists, set "track" listener')):(e.ac_log("AC: peer connection does not exist, wait creation"),r.js_session.on("peerconnection",function(){e.instance._set_connection_listener(r),e.ac_log('AC: [event connection] connection created, set "track" listener')})),n="remote"===t.originator?t.request.from:t.request.to,r.data._user=n.uri.user,r.data._host=n.uri.host,r.data._display_name=n.display_name,r.data._create_time=new Date,"remote"===t.originator){var i,o,s,a=null;if(null!==e.instance.replacedCall&&(a=e.instance.replacedCall,e.instance.replacedCall=null),t.request.body){s=!0;var l=new AudioCodesSDP(t.request.body).getMediaDirection("video",!0),u=_slicedToArray(l,2);i=u[0],o=u[1]}else s=!1,r.data._incoming_invite_without_sdp=!0,i=o=!0,e.ac_log("AC: warning incoming INVITE without SDP");r._setVideoState(i,o),e.ac_log("AC>>: incomingCall ".concat(r.hasVideo()?"video":"audio",' from "').concat(r.data._display_name,'" ').concat(r.data._user),r,a),e.instance.listeners.incomingCall(r,t.request,a,s)}else r.js_session.data._created_by_refer?(e.ac_log("AC>>: outgoing call created by REFER"),r.data._created_by_refer=r.js_session.data._created_by_refer,e.instance.listeners.transfereeCreatedCall(r)):e.ac_log("AC>>: outgoing call created by phone.call()")})}},{key:"_get_from",value:function(e){return{user:e.from.uri.user,host:e.from.uri.host,displayName:e.from.display_name?e.from.display_name:null}}},{key:"_get_content_type",value:function(e){var t=e.headers["Content-Type"];return t&&t.length>0?t[0].parsed:null}},{key:"_set_connection_listener",value:function(t){e.instance.getWR().connection.addEventListener(t.js_session.connection,"track",function(n){if(e.ac_log('AC>>: "track" event kind= '.concat(n.track.kind),n),n.streams.length>0){var r=n.streams[0];e.ac_log("AC: set call remote stream id=".concat(r.id),t),t.data._remoteMediaStream=r}else e.ac_log('AC: Warning "track" event without stream');if("video"!==n.track.kind){var i=t.getRTCLocalStream(),o=t.getRTCRemoteStream();e.ac_log("AC>>: callShowStreams",t,i,o),e.instance.listeners.callShowStreams(t,i,o)}else{if(!t.hasEnabledReceiveVideo()){t.data._video_call_audio_answer_safari&&(n.track.onmute=function(){e.ac_log('AC: [video call/audio answer] Safari fix. Fired video track "mute" event. Call callShowStream'),n.track.onmute=null;var r=t.getRTCLocalStream(),i=t.getRTCRemoteStream();e.ac_log("AC>>: callShowStreams",t,r,i),e.instance.listeners.callShowStreams(t,r,i)},e.ac_log('AC: [video call/audio answer] Safari fix. Set video track "mute" event listener'),t.data._video_call_audio_answer_safari=!1),e.ac_log('AC>>: event "track" video and !hasEnabledReceiveVideo therefore change transceiver direction.',t);var s=e.instance.getWR().connection.getTransceiver(t.js_session.connection,"video");if(null!==s){var a=t.hasEnabledSendVideo()?"sendonly":"inactive";e.instance.getWR().transceiver.setDirection(s,a)}}e.instance.codecFilter&&e.instance._cf_filter("video",t,e.instance.codecFilter.video)}})}},{key:"_check_remote_sdp",value:function(t,n){try{n.codec_map||(n.codec_map={});var r=t.getMedia("audio");e.instance._check_remote_m(r,n.codec_map);var i=t.getMedia("video");i&&e.instance._check_remote_m(i,n.codec_map)}catch(t){e.ac_log("AC:SDP exception",t)}}},{key:"_check_remote_m",value:function(t,n){var r={};function i(e,t){var n=t.indexOf(" ",e);return-1===n?["?","?"]:[t.substring(e,n),t.substring(n+1).toLowerCase()]}var o,s=_createForOfIteratorHelper(t);try{for(s.s();!(o=s.n()).done;){var a=o.value;if(a.startsWith("a=rtpmap:")){var l=i(9,a),u=_slicedToArray(l,2),c=u[0],d=u[1];r[c]||(r[c]={}),r[c].rtpmap=d}else if(a.startsWith("a=fmtp:")){var h=i(7,a),f=_slicedToArray(h,2),_=f[0],p=f[1];r[_]||(r[_]={}),r[_].fmtp=p}}}catch(e){s.e(e)}finally{s.f()}for(var v=0,g=Object.keys(r);v0){var f=h.length;(h=h.filter(function(t){return!e.instance._cf_match(t,r.remove)})).length0){var _,p=[],v=_createForOfIteratorHelper(r.priority);try{var g=function(){var t=_.value,n=e.instance._cf_find(t,h);if(0===n.length)return"continue";p=p.concat(n),h=h.filter(function(e){return!n.includes(e)})};for(v.s();!(_=v.n()).done;)g()}catch(e){v.e(e)}finally{v.f()}h=p.concat(h),e.ac_log("AC: ".concat(t," codec-filter changed priority: ").concat(e.instance._cf_str(h)))}return void o.setCodecPreferences(h)}catch(t){return void e.ac_log("AC: codec filter exception",t)}}},{key:"_convertIceList",value:function(e){var t,n=[],r=_createForOfIteratorHelper(e);try{for(r.s();!(t=r.n()).done;){var i=t.value;"string"==typeof i&&(i={urls:"stun:"+i}),n.push(i)}}catch(e){r.e(e)}finally{r.f()}return n}},{key:"_randomToken",value:function(e){for(var t="",n=0;n2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,o={},s=e.instance;return"chrome"===s.browser&&s.networkPriority&&(o={rtcConstraints:{optional:[{googDscp:!0}]}}),null!==i&&Object.assign(o,i),o.mediaConstraints=s._mediaConstraints(t),void 0===o.pcConfig&&(o.pcConfig={}),o.pcConfig.iceServers=s.serverConfig.iceServers,null!==r&&(r=r.slice()),null!==s.oauthToken&&s.oauthTokenUseInInvite&&n&&(null===r&&(r=[]),r.push("Authorization: Bearer "+s.oauthToken)),null!==r&&(o.extraHeaders=r),o}},{key:"call",value:function(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;if(!1===t?t=e.instance.AUDIO:!0===t&&(t=e.instance.VIDEO),"symbol"!==_typeof(t)||![e.instance.AUDIO,e.instance.VIDEO].includes(t))throw new TypeError("Illegal videoOption=".concat(t.toString()));n=n.replace(/\s+/g,""),e.ac_log("AC: call ".concat(t.description," to ").concat(n));var o=this._callOptions(t===e.instance.VIDEO,!0,r,i),s=this.jssipUA.call(n,o);o.mediaStream&&(s._localMediaStreamLocallyGenerated=!0);var a=s.data.ac_session;return a._setEnabledSendVideo(t===e.instance.VIDEO),t===e.instance.VIDEO&&a._setEnabledReceiveVideo(!0),a}},{key:"sendMessage",value:function(t,n){var r=this,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"text/plain";return e.ac_log("AC: sendMessage to: ".concat(t,' "').concat(n,'"')),new Promise(function(e,o){var s={contentType:i,eventHandlers:{succeeded:function(t){return e(t)},failed:function(e){return o(e)}}};r.jssipUA.sendMessage(t,n,s)})}},{key:"isScreenSharingSupported",value:function(){return e.instance.getWR().hasDisplayMedia()}},{key:"openScreenSharing",value:function(){return this.isScreenSharingSupported()?(e.ac_log("AC: openScreenSharing()"),e.instance.getWR().getDisplayMedia().then(function(e){return e}).catch(function(t){throw e.ac_log("AC: openScreenSharing() error",t),t})):(e.ac_log("AC: openScreenSharing: screen sharing is not supported in the browser"),Promise.reject("Screen sharing is not supported"))}},{key:"closeScreenSharing",value:function(t){if(e.ac_log("AC: closeScreenSharing()"),t){var n=t.getVideoTracks();if(0==n.length)return;var r=n[0];"live"===r.readyState&&(r.stop(),r.dispatchEvent(new Event("ended")))}}},{key:"setNetworkPriority",value:function(t){if(e.ac_log("AC: setNetworkPriority ".concat(t)),void 0!==t&&"high"!==t&&"medium"!==t&&"low"!==t&&"very-low"!==t)throw new TypeError("setNetworkPriority: illegal value: ".concat(t));this.networkPriority=t}},{key:"subscribe",value:function(){var e;return(e=this.jssipUA).subscribe.apply(e,arguments)}},{key:"notify",value:function(){var e;return(e=this.jssipUA).notify.apply(e,arguments)}},{key:"addCredential",value:function(e){if(!e.realm||!e.password||!e.username)throw new TypeError("wrong credential structure");this.credentials.push(e)}}],[{key:"getSessionStatusName",value:function(e){switch(e){case 0:return"NULL (0)";case 1:return"INVITE_SENT (1)";case 2:return"1XX_RECEIVED (2)";case 3:return"INVITE_RECEIVED (3)";case 4:return"WAITING_FOR_ANSWER (4)";case 5:return"ANSWERED (5)";case 6:return"WAITING_FOR_ACK (6)";case 7:return"CANCELED (7)";case 8:return"TERMINATED (8)";case 9:return"CONFIRMED (9)";default:return"Unknown ("+e+")"}}}]),e}(),AudioCodesSession=function(){function e(t){_classCallCheck(this,e),this.js_session=t,this.data={_user:null,_display_name:null,_create_time:null,_initial:!0,_remoteMediaStream:null,_wasUsedSendVideo:!1,_screenSharing:null,_video:{send:!1,receive:!1,enabledSend:!1,enabledReceive:!1}},t.data.ac_session=this}return _createClass(e,[{key:"getRTCPeerConnection",value:function(){return this.js_session.connection}},{key:"getRTCLocalStream",value:function(){return this.js_session._localMediaStream}},{key:"getRTCRemoteStream",value:function(){return this.data._remoteMediaStream}},{key:"isEstablished",value:function(){return this.js_session.isEstablished()}},{key:"isTerminated",value:function(){return this.js_session.isEnded()}},{key:"isOutgoing",value:function(){return"outgoing"===this.js_session.direction}},{key:"isAudioMuted",value:function(){return this.js_session.isMuted().audio}},{key:"isVideoMuted",value:function(){return this.js_session.isMuted().video}},{key:"wasAccepted",value:function(){return!0===this.data._accepted}},{key:"getReplacesHeader",value:function(){if(!this.js_session.isEstablished()||!this.js_session._dialog)return AudioCodesUA.ac_log("getReplacesHeader(): call is not established"),null;var e=this.js_session._dialog.id;return"".concat(e.call_id,";to-tag=").concat(e.remote_tag,";from-tag=").concat(e.local_tag)}},{key:"muteAudio",value:function(e){AudioCodesUA.ac_log("AC: muteAudio() arg=".concat(e," ")),e?this.js_session.mute({audio:!0,video:!1}):this.js_session.unmute({audio:!0,video:!1})}},{key:"muteVideo",value:function(e){AudioCodesUA.ac_log("AC: muteVideo() arg=".concat(e," ")),e?this.js_session.mute({audio:!1,video:!0}):this.js_session.unmute({audio:!1,video:!0})}},{key:"sendDTMF",value:function(e){var t=AudioCodesUA.instance.dtmfUseWebRTC;t&&"safari"===AudioCodesUA.instance.browser&&(void 0===AudioCodesUA.instance.getWR().connection.getDTMFSender(this.js_session.connection)&&(t=!1));AudioCodesUA.ac_log("AC: sendDTMF() tone=".concat(e," ").concat(t?"[RFC2833]":"[INFO]"));var n={duration:AudioCodesUA.instance.dtmfDuration,interToneGap:AudioCodesUA.instance.dtmfInterToneGap,transportType:t?"RFC2833":"INFO"};this.js_session.sendDTMF(e,n)}},{key:"sendInfo",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;AudioCodesUA.ac_log("AC: sendInfo()",e,t,n);var r=null!==n?{extraHeaders:n}:void 0;this.js_session.sendInfo(t,e,r)}},{key:"duration",value:function(){var e=this.js_session.start_time;if(!e)return 0;var t=this.js_session.end_time;return t||(t=new Date),Math.floor((t.getTime()-e.getTime())/1e3)}},{key:"hasSendVideo",value:function(){return this.data._video.send}},{key:"hasReceiveVideo",value:function(){return this.data._video.receive}},{key:"hasVideo",value:function(){return this.hasSendVideo()&&this.hasReceiveVideo()}},{key:"getVideoState",value:function(){return this.hasSendVideo()&&this.hasReceiveVideo()?"sendrecv":this.hasSendVideo()?"sendonly":this.hasReceiveVideo()?"recvonly":"inactive"}},{key:"_setVideoState",value:function(e,t){AudioCodesUA.ac_log("AC: _setVideoState(send=".concat(e,", receive=").concat(t,")")),this.data._video.send=e,this.data._video.receive=t}},{key:"hasEnabledSendVideo",value:function(){return this.data._video.enabledSend}},{key:"hasEnabledReceiveVideo",value:function(){return this.data._video.enabledReceive}},{key:"getEnabledVideoState",value:function(){return this.hasEnabledSendVideo()&&this.hasEnabledReceiveVideo()?"sendrecv":this.hasEnabledSendVideo()?"sendonly":this.hasEnabledReceiveVideo()?"recvonly":"inactive"}},{key:"_setEnabledSendVideo",value:function(e){AudioCodesUA.ac_log("AC: _setEnabledSendVideo(".concat(e,")")),this.data._video.enabledSend=e}},{key:"_setEnabledReceiveVideo",value:function(e){AudioCodesUA.ac_log("AC: _setEnabledReceiveVideo(".concat(e,")")),this.data._video.enabledReceive=e}},{key:"answer",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(this.data._answer_called)AudioCodesUA.ac_log("AC: answer() is already called. [Ignored]");else{if(this.data._answer_called=!0,!1===e?e=AudioCodesUA.instance.AUDIO:!0===e&&(e=AudioCodesUA.instance.VIDEO),"symbol"!==_typeof(e)||![AudioCodesUA.instance.AUDIO,AudioCodesUA.instance.RECVONLY_VIDEO,AudioCodesUA.instance.VIDEO].includes(e))throw new TypeError("Illegal videoOption=".concat(e.toString()));if(AudioCodesUA.ac_log("AC: ".concat(e.description," answer")),this.hasVideo()||e!==AudioCodesUA.instance.RECVONLY_VIDEO&&e!==AudioCodesUA.instance.VIDEO||(AudioCodesUA.ac_log('AC: incoming INVITE without video, so answer can be only "audio"'),e=AudioCodesUA.instance.AUDIO),this.hasVideo()&&e===AudioCodesUA.instance.AUDIO){var i=AudioCodesUA.instance,o=i.browser,s=i.modes,a=i.browserVersion;"firefox"===o&&s.video_call_audio_answer_firefox_fix?this.data._video_call_audio_answer_firefox=!0:"safari"===o&&(!0===s.video_call_audio_answer_safari_fix&&a<14||"force"===s.video_call_audio_answer_safari_fix)&&(this.data._video_call_audio_answer_safari=!0)}switch(e){case AudioCodesUA.instance.AUDIO:this._setEnabledSendVideo(!1),this.data._incoming_invite_without_sdp?this._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo):this._setEnabledReceiveVideo(!this.hasVideo()&&AudioCodesUA.instance.enableAddVideo),this._setVideoState(!1,!1);break;case AudioCodesUA.instance.VIDEO:this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(!0),this._setVideoState(!0,!0);break;case AudioCodesUA.instance.RECVONLY_VIDEO:this._setEnabledSendVideo(!1),this._setEnabledReceiveVideo(!0),this._setVideoState(!1,!0)}var l=AudioCodesUA.instance._callOptions(e===AudioCodesUA.instance.VIDEO,!1,n,r);Promise.resolve().then(function(){return l.mediaStream?l.mediaStream:AudioCodesUA.instance.getWR().getUserMedia(l.mediaConstraints)}).then(function(e){l.mediaStream=e,t.js_session._localMediaStreamLocallyGenerated=!0,AudioCodesUA.ac_log("AC: answer options:",l),t.js_session.answer(l)}).catch(function(e){AudioCodesUA.ac_log("AC: getUserMedia failure",e),t.reject(488)})}}},{key:"reject",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:486,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;AudioCodesUA.ac_log("AC: reject()");try{var n={status_code:e};t&&(n.extraHeaders=t),this.js_session.terminate(n)}catch(e){AudioCodesUA.ac_log("AC: call reject error:",e)}}},{key:"terminate",value:function(){AudioCodesUA.ac_log("AC: terminate()");try{this.js_session.terminate()}catch(e){AudioCodesUA.ac_log("AC: call terminate error:",e)}}},{key:"redirect",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:302,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;AudioCodesUA.ac_log("AC: redirect() callTo=".concat(e));try{var r,i={status_code:t,extraHeaders:["Contact: "+AudioCodesUA.instance.jssipUA.normalizeTarget(e)]};if(n)(r=i.extraHeaders).push.apply(r,_toConsumableArray(n));this.js_session.terminate(i)}catch(e){AudioCodesUA.ac_log("AC: call redirect error:",e)}}},{key:"isLocalHold",value:function(){return this.js_session.isOnHold().local}},{key:"isRemoteHold",value:function(){return this.js_session.isOnHold().remote}},{key:"isReadyToReOffer",value:function(){return this.js_session._isReadyToReOffer()}},{key:"hold",value:function(e){var t=this;return AudioCodesUA.ac_log("AC: hold(".concat(e,")")),new Promise(function(n,r){(e?t.js_session.hold:t.js_session.unhold).call(t.js_session,{},function(){AudioCodesUA.ac_log("AC: hold()/unhold() is completed"),n()})||(AudioCodesUA.ac_log("AC: hold()/unhold() failed"),r())})}},{key:"enableReceiveVideo",value:function(e){this._setEnabledReceiveVideo(e);var t=this.getRTCPeerConnection(),n=AudioCodesUA.instance.getWR().connection.getTransceiver(t,"video");if(null!==n){var r=this.getEnabledVideoState();AudioCodesUA.instance.getWR().transceiver.setDirection(n,r)}return AudioCodesUA.ac_log("AC: enableReceiveVideo(".concat(e,") ").concat(null!==n?"":"No video transceiver")),null!==n}},{key:"startSendingVideo",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t&&!1!==t.enabledReceiveVideo;return this.hasEnabledSendVideo()?(AudioCodesUA.ac_log("AC: startSendingVideo(). Already started"),Promise.reject("video already started")):(AudioCodesUA.ac_log("AC: startSendingVideo()"),AudioCodesUA.instance.getWR().getUserMedia({video:AudioCodesUA.instance.constraints.video}).catch(function(e){throw AudioCodesUA.ac_log("AC: startSendingVideo() getUserMedia failure",e),e}).then(function(t){var r=t.getVideoTracks()[0];e.getRTCLocalStream().addTrack(r),e._setEnabledSendVideo(!0),e._setEnabledReceiveVideo(n);var i=e.data._wasUsedSendVideo;return AudioCodesUA.instance.getWR().connection.addVideo(e.getRTCPeerConnection(),e.getRTCLocalStream(),r,e.hasEnabledReceiveVideo(),i).then(function(){!i&&AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",e,AudioCodesUA.instance.codecFilter.video)}).catch(function(e){throw AudioCodesUA.ac_log("AC: startSendingVideo(). Adding video error",e),e})}).then(function(){return e._renegotiate(t)}))}},{key:"stopSendingVideo",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return this.hasEnabledSendVideo()?(AudioCodesUA.ac_log("AC: stopSendingVideo()"),AudioCodesUA.instance.getWR().connection.removeVideo(this.getRTCPeerConnection(),this.getRTCLocalStream()).catch(function(e){throw AudioCodesUA.ac_log("AC: stopSendingVideo(). Remove video error",e),e}).then(function(){return e._setEnabledSendVideo(!1),e.data._wasUsedSendVideo=!0,e._renegotiate(t)})):(AudioCodesUA.ac_log("AC: stopSendingVideo(). Already stopped"),Promise.reject("video already stopped"))}},{key:"_doRenegotiate",value:function(e){var t=this;return this.js_session.isEnded()?Promise.reject("call is ended"):new Promise(function(n){if(!t.js_session.renegotiate(e,function(){return n(!0)}))return n(!1)})}},{key:"_renegotiate",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:30,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:500;return AudioCodesUA.ac_log("AC: _renegotiate() attemptsLeft=".concat(n)),this._doRenegotiate(e).then(function(i){if(i)return AudioCodesUA.ac_log("AC: Renegotiation success"),!0;if(n<=1)throw new Error("Too many attempts");return new Promise(function(e){return setTimeout(e,r)}).then(function(){return t._renegotiate(e,n-1,r)})}).catch(function(e){throw AudioCodesUA.ac_log("AC: Renegotiation failed",e),e})}},{key:"sendReInvite",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return AudioCodesUA.ac_log("AC: sendReInvite()"),this._renegotiate(t).then(function(){if(t.showStreams){var n=e.getRTCLocalStream(),r=e.getRTCRemoteStream();AudioCodesUA.ac_log("AC>>: [after send re-INVITE] callShowStreams",e,n,r),AudioCodesUA.instance.listeners.callShowStreams(e,n,r)}})}},{key:"startScreenSharing",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{localScreenSharing:!0,enabledReceiveVideo:!0,separateVideo:!1};if(AudioCodesUA.ac_log("AC: startScreenSharing"),!e)return Promise.reject("missed stream argument");if(this.data._screenSharing)return Promise.reject("the call is already using screen-sharing");var r=n&&!1!==n.enabledReceiveVideo,i=e.getVideoTracks()[0],o=void 0;n.localScreenSharing&&(o=this._onEndedScreenSharingTrack.bind(this),i.addEventListener("ended",o)),this.data._screenSharing={stream:e,onended:o,hadSendVideo:this.hasSendVideo()};var s=this.data._wasUsedSendVideo;return this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(r),AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(),this.getRTCLocalStream(),i,this.hasEnabledReceiveVideo(),s).then(function(){!s&&AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",t,AudioCodesUA.instance.codecFilter.video)}).catch(function(e){throw AudioCodesUA.ac_log("AC: startScreenSharing() error",e),t.data._screenSharing=null,e}).then(function(){return t._renegotiate({extraHeaders:["X-Screen-Sharing: on"]})})}},{key:"stopScreenSharing",value:function(){return AudioCodesUA.ac_log("AC: stopScreenSharing"),this.data._screenSharing?this._onEndedScreenSharing("called stopScreenSharing()"):Promise.reject("the call does not use screen-sharing")}},{key:"isScreenSharing",value:function(){return!!this.data._screenSharing}},{key:"doesScreenSharingReplaceCamera",value:function(){var e=this.data._screenSharing;return e&&e.hadSendVideo}},{key:"_onEndedScreenSharingTrack",value:function(){return this._onEndedScreenSharing("track ended")}},{key:"_onEndedScreenSharing",value:function(e){var t=this,n=this.data._screenSharing;this.data._screenSharing=null;var r=n.stream,i=n.onended;r&&i&&r.getVideoTracks()[0].removeEventListener("ended",i);return Promise.resolve().then(function(){if(!t.isTerminated()){var e=t.getRTCPeerConnection(),r=t.getRTCLocalStream(),i={extraHeaders:["X-Screen-Sharing: off"]};return n.hadSendVideo?(AudioCodesUA.ac_log("AC: screen sharing stopped - restore previously sending video track"),AudioCodesUA.instance.getWR().connection.replaceSenderTrack(e,"video",r),t._renegotiate(i)):(AudioCodesUA.ac_log("AC: screen sharing stopped - stop send video"),t.stopSendingVideo(i))}}).then(function(){AudioCodesUA.instance.listeners.callScreenSharingEnded&&(AudioCodesUA.ac_log('AC>>: callScreenSharingEnded "'.concat(e,'"'),t,r),AudioCodesUA.instance.listeners.callScreenSharingEnded(t,r))})}},{key:"setRemoteHoldState",value:function(){this.js_session._remoteHold=!0}},{key:"sendRefer",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!AudioCodesUA.instance.listeners.transferorNotification)throw new Error("transferorNotification listener is missed");var n=this,r={eventHandlers:{requestSucceeded:function(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [REFER accepted]"),AudioCodesUA.instance.listeners.transferorNotification(n,0)},requestFailed:function(){AudioCodesUA.ac_log("AC>>: transferorNotification failed [REFER failed]"),AudioCodesUA.instance.listeners.transferorNotification(n,-1)},trying:function(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [NOTIFY 1xx]"),AudioCodesUA.instance.listeners.transferorNotification(n,0)},progress:function(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [NOTIFY 1xx]"),AudioCodesUA.instance.listeners.transferorNotification(n,0)},accepted:function(){AudioCodesUA.ac_log("AC>>: transferorNotification success [NOTIFY 2xx]"),AudioCodesUA.instance.listeners.transferorNotification(n,1)},failed:function(){AudioCodesUA.ac_log("AC>>: transferorNotification failed [NOTIFY >= 300]"),AudioCodesUA.instance.listeners.transferorNotification(n,-1)}}};null!==t&&(r.replaces=t.js_session),this.js_session.refer(e,r)}}]),e}(),AudioCodesSDP=function(){function e(t){_classCallCheck(this,e),this.start=[],this.media=[];var n,r=t.split("\n").map(function(e){return e.trim()}).filter(function(e){return e.length>0}),i=this.start,o=_createForOfIteratorHelper(r);try{for(o.s();!(n=o.n()).done;){var s=n.value;s.startsWith("m=")&&(i=[],this.media.push(i)),i.push(s)}}catch(e){o.e(e)}finally{o.f()}}return _createClass(e,[{key:"getMedia",value:function(e){var t,n=_createForOfIteratorHelper(this.media);try{for(n.s();!(t=n.n()).done;){var r=t.value;if(r.length>0&&r[0].startsWith("m="+e))return r}}catch(e){n.e(e)}finally{n.f()}return null}},{key:"checkSendRecv",value:function(e){switch(e){case"a=sendrecv":return"sendrecv";case"a=sendonly":return"sendonly";case"a=recvonly":return"recvonly";case"a=inactive":return"inactive";default:return null}}},{key:"getMediaDirectionValue",value:function(e){var t,n=this.getMedia(e);if(null===n)return null;var r,i="sendrecv",o=_createForOfIteratorHelper(this.start);try{for(o.s();!(r=o.n()).done;){var s=r.value;if(null!==(t=this.checkSendRecv(s))){i=t;break}}}catch(e){o.e(e)}finally{o.f()}var a,l=_createForOfIteratorHelper(n);try{for(l.s();!(a=l.n()).done;){var u=a.value;if(null!==(t=this.checkSendRecv(u))){i=t;break}}}catch(e){l.e(e)}finally{l.f()}return i}},{key:"getMediaDirection",value:function(e,t){var n=this.getMediaDirectionValue(e);switch(n){case"sendrecv":return[!0,!0,n];case"sendonly":return t?[!1,!0,n]:[!0,!1,n];case"recvonly":return t?[!0,!1,n]:[!1,!0,n];case null:case"inactive":return[!1,!1,n]}}},{key:"toString",value:function(){var e,t=this.start,n=_createForOfIteratorHelper(this.media);try{for(n.s();!(e=n.n()).done;){var r=e.value;t=t.concat(r)}}catch(e){n.e(e)}finally{n.f()}return t.join("\r\n")+"\r\n"}}]),e}(),AudioCodesWebRTCWrapper={getUserMedia:function(e){return AudioCodesUA.ac_log("[webrtc] getUserMedia constraints=".concat(JSON.stringify(e))),navigator.mediaDevices.getUserMedia(e)},hasDisplayMedia:function(){return navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia},getDisplayMedia:function(){return AudioCodesUA.ac_log("[webrtc] getDisplayMedia"),navigator.mediaDevices.getDisplayMedia({video:!0})},mediaDevices:{enumerateDevices:function(){return navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices?navigator.mediaDevices.enumerateDevices():Promise.reject("WebRTC is not supported")},addDeviceChangeListener:function(e){navigator.mediaDevices&&navigator.mediaDevices.addEventListener("devicechange",e)},removeDeviceChangeListener:function(e){navigator.mediaDevices&&navigator.mediaDevices.removeEventListener("devicechange",e)}},checkAvailableDevices:function(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia)return Promise.reject("WebRTC is not supported");var e=!1,t=!1,n=!1;return navigator.mediaDevices.enumerateDevices().then(function(r){return r.forEach(function(r){switch(r.kind){case"videoinput":e=!0;break;case"audioinput":t=!0;break;case"audiooutput":n=!0}}),void 0===navigator.webkitGetUserMedia&&(n=!0),n?t?Promise.resolve(e):Promise.reject("Missing a microphone! Please connect one and reload"):Promise.reject("Missing a speaker! Please connect one and reload")})},transceiver:{setDirection:function(e,t){var n="";null!==e.sender.track?n=e.sender.track.kind:null!==e.receiver.track&&(n=e.receiver.track.kind),AudioCodesUA.ac_log("[webrtc] set ".concat(n," transceiver direction=").concat(t)),e.direction=t}},stream:{getInfo:function(e){function t(e){return e.length>0?e[0].enabled.toString():"-"}return null===e?Promise.resolve("stream is null"):Promise.resolve("audio: ".concat(t(e.getAudioTracks())," video: ").concat(t(e.getVideoTracks())))}},connection:{getTransceiversInfo:function(e){function t(e){return null===e?"none":"d=".concat(e.direction," c=").concat(e.currentDirection)}var n=e.getTransceivers(),r=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"audio"),i=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");return Promise.resolve("(".concat(n.length,") audio ").concat(t(r)," video ").concat(t(i)))},getTransceiver:function(e,t){var n,r=_createForOfIteratorHelper(e.getTransceivers());try{for(r.s();!(n=r.n()).done;){var i=n.value;if(null!==i.sender&&null!==i.sender.track&&i.sender.track.kind===t)return i;if(null!==i.receiver&&null!==i.receiver.track&&i.receiver.track.kind===t)return i}}catch(e){r.e(e)}finally{r.f()}return null},addEventListener:function(e,t,n){return AudioCodesUA.ac_log("[webrtc] Connection addEventListener ".concat(t)),"track"!==t?Promise.reject("Wrong event name: ".concat(t)):(e.addEventListener(t,n),Promise.resolve())},getDTMFSender:function(e){var t=e.getSenders().find(function(e){return e.track&&"audio"===e.track.kind});if(t&&t.dtmf)return t.dtmf},addVideo:function(e,t,n,r,i){AudioCodesUA.ac_log("[webrtc] Connection addVideo");var o=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");if(null!==o){var s=r?"sendrecv":"sendonly";AudioCodesUA.instance.getWR().transceiver.setDirection(o,s)}return null===o||null===o.sender.track&&!i?(AudioCodesUA.ac_log("[webrtc] addVideo (connection addTrack)"),e.addTrack(n,t),Promise.resolve(!0)):(AudioCodesUA.ac_log("[webrtc] addVideo (video transceiver sender replaceTrack)"),o.sender.replaceTrack(n).then(function(){return!1}))},removeVideo:function(e,t){AudioCodesUA.ac_log("[webrtc] Connection removeVideo");var n=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");if(null===n)return Promise.reject("no video transceiver found");if(e.removeTrack(n.sender),t){var r,i=_createForOfIteratorHelper(t.getVideoTracks());try{for(i.s();!(r=i.n()).done;){var o=r.value;t.removeTrack(o),o.stop()}}catch(e){i.e(e)}finally{i.f()}}return Promise.resolve()},replaceSenderTrack:function(e,t,n){AudioCodesUA.ac_log("[webrtc] ReplaceSenderTrack ".concat(t));var r,i=null,o=_createForOfIteratorHelper(e.getSenders());try{for(o.s();!(r=o.n()).done;){var s=r.value;if(null!==s.track&&s.track.kind===t){i=s;break}}}catch(e){o.e(e)}finally{o.f()}if(null===i)return Promise.reject("No ".concat(t," sender"));var a="audio"===t?n.getAudioTracks():n.getVideoTracks();return 0===a.length?Promise.reject("No ".concat(t," track")):i.replaceTrack(a[0])},getStats:function(e,t){var n="";return e.getStats(null).then(function(e){return e.forEach(function(e){if(t.includes(e.type)){n+=" {";for(var r=!0,i=0,o=Object.keys(e);i=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,s=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){a=!0,o=e},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw o}}}}function _unsupportedIterableToArray(e,t){if(e){if("string"==typeof e)return _arrayLikeToArray(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_arrayLikeToArray(e,t):void 0}}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:null,r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],i=arguments.length>3&&void 0!==arguments[3]&&arguments[3],o=localStorage.getItem(e),s=null,a=!1,l=!1;return o&&(a=!0,s=JSON.parse(o)),null===s||null!==n&&s.version!==n.version?(a&&(l=!0),a=!1,t=!0,null!==n&&(s=dataDeepCopy(n))):t=dataEquals(s,n),r&&console.log("Used %s %s",null!==s?t?"default":"custom":"null",e),null!==s&&(l||i&&!a)&&localStorage.setItem(e,JSON.stringify(s)),s}function storageSaveConfig(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;null!==n&&dataEquals(t,n)?localStorage.removeItem(e):(null!==n&&n.version&&!t.version&&(t.version=n.version),localStorage.setItem(e,JSON.stringify(t)))}function dataEquals(e,t){if(null===e||null===t)return e===t;for(var n in e){if(e.hasOwnProperty(n)!==t.hasOwnProperty(n))return!1;switch(_typeof(e[n])){case"object":if(!dataEquals(e[n],t[n]))return!1;break;case"function":break;default:if(e[n]!=t[n])return!1}}for(var r in t)if(void 0===e[r])return!1;return!0}function dataDeepCopy(e){if(null===e)return null;var t=Array.isArray(e)?[]:{};for(var n in e)switch(_typeof(e[n])){case"object":t[n]=dataDeepCopy(e[n]);break;case"function":break;default:t[n]=e[n]}return t}var AbstractDb=function(){function e(t,n,r){_classCallCheck(this,e),this.dbName=t,this.storeName=n,this.maxSize=r,this.db=null,this.list=[],this.idSeqNumber=-1}return _createClass(e,[{key:"createId",value:function(e){return this.idSeqNumber=(this.idSeqNumber+1)%1e6,e.toString()+"-"+("00000"+this.idSeqNumber.toString()).slice(-6)}},{key:"open",value:function(){var e=this;return new Promise(function(t,n){var r=indexedDB.open(e.dbName);r.onupgradeneeded=function(t){t.target.result.createObjectStore(e.storeName,{keyPath:"id"})},r.onsuccess=function(){e.db=r.result,t()},r.onerror=r.onblocked=function(){n(r.error)}})}},{key:"load",value:function(){var e=this;return new Promise(function(t,n){if(null!==e.db){var r=e.db.transaction(e.storeName,"readwrite");r.onerror=function(){n(r.error)};var i=r.objectStore(e.storeName);(i.getAll?e._getAllBuiltIn:e._getAllCursor)(i,function(r){e.list=r;var o=e.list.length-e.maxSize;if(o<=0)t();else{var s=i.delete(IDBKeyRange.upperBound(e.list[o-1].id));s.onerror=function(){n(s.error)},s.onsuccess=function(){e.list=e.list.splice(-e.maxSize),t()}}},function(e){n(e)})}else n("db is null")})}},{key:"_getAllBuiltIn",value:function(e,t,n){var r=e.getAll();r.onerror=function(){return n(r.error)},r.onsuccess=function(){return t(r.result)}}},{key:"_getAllCursor",value:function(e,t,n){var r=[],i=e.openCursor();i.onerror=function(){return n(i.error)},i.onsuccess=function(e){var n=e.target.result;n?(r.push(n.value),n.continue()):t(r)}}},{key:"add",value:function(e){var t=this;return new Promise(function(n,r){if(null!==t.db){var i=t.db.transaction(t.storeName,"readwrite");i.onerror=function(){r(i.error)};var o=i.objectStore(t.storeName),s=o.add(e);s.onerror=function(){r(s.error)},s.onsuccess=function(){t.list.push(e);var i=t.list.length-t.maxSize;i<=0?n():((s=o.delete(IDBKeyRange.upperBound(t.list[i-1].id))).onerror=function(){r(s.error)},s.onsuccess=function(){t.list=t.list.splice(-t.maxSize),n()})}}else r("db is null")})}},{key:"update",value:function(e){var t=this.list.findIndex(function(t){return t.id===e.id});return-1==t?Promise.reject("Record is not found"):(this.list[t]=e,this._exec("put",this.storeName,e))}},{key:"delete",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.storeName;if(t===this.storeName){var n=this.list.findIndex(function(t){return t.id===e});if(-1==n)return Promise.reject("Record is not found");this.list.splice(n,1)}return this._exec("delete",t,e)}},{key:"clear",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.storeName;return this.list=[],this._exec("clear",e)}},{key:"get",value:function(e,t){return this._exec("get",t,e)}},{key:"put",value:function(e,t){return this._exec("put",t,e)}},{key:"_exec",value:function(e,t,n){var r=this;return new Promise(function(i,o){if(null!==r.db){var s=r.db.transaction(t,"readwrite");s.onerror=function(){o(s.error)};var a,l=s.objectStore(t);switch(e){case"clear":a=l.clear();break;case"delete":a=l.delete(n);break;case"put":a=l.put(n);break;case"get":a=l.get(n);break;default:return void o("db: wrong request")}a.onerror=function(){o(a.error)},a.onsuccess=function(){i(a.result)}}else o("db is null")})}}]),e}(),CallLogDb=function(e){_inherits(n,AbstractDb);var t=_createSuper(n);function n(e){return _classCallCheck(this,n),t.call(this,"phone","call_log",e)}return _createClass(n)}(),VoiceDb=function(e){_inherits(n,AbstractDb);var t=_createSuper(n);function n(e){return _classCallCheck(this,n),t.call(this,"voice_db","records",e)}return _createClass(n,[{key:"open",value:function(){var e=this;return new Promise(function(t,n){var r=indexedDB.open(e.dbName);r.onupgradeneeded=function(t){t.target.result.createObjectStore(e.storeName,{keyPath:"id"}),t.target.result.createObjectStore("greeting",{keyPath:"id"})},r.onsuccess=function(){e.db=r.result,t()},r.onerror=r.onblocked=function(){n(r.error)}})}}]),n}(),MessageDb=function(e){_inherits(n,AbstractDb);var t=_createSuper(n);function n(e){return _classCallCheck(this,n),t.call(this,"message_db","messages",e)}return _createClass(n)}(),AudioPlayer2=function(){function e(){_classCallCheck(this,e),this.browser=this._browser(),this.speakerDeviceId=void 0,this.ringerDeviceId=void 0,this.useAudioElement=void 0,this.logger=console.log,this.sounds={},this.sound=null,this.ringer=null,this.ssound=null,this.audioCtx=null,this.dtmfTones={1:[{f:[697,1209],t:.2}],2:[{f:[697,1336],t:.2}],3:[{f:[697,1477],t:.2}],4:[{f:[770,1209],t:.2}],5:[{f:[770,1336],t:.2}],6:[{f:[770,1477],t:.2}],7:[{f:[852,1209],t:.2}],8:[{f:[852,1336],t:.2}],9:[{f:[852,1477],t:.2}],"*":[{f:[941,1209],t:.2}],0:[{f:[941,1336],t:.2}],"#":[{f:[941,1477],t:.2}],A:[{f:[697,1633],t:.2}],B:[{f:[770,1633],t:.2}],C:[{f:[852,1633],t:.2}],D:[{f:[941,1633],t:.2}]}}return _createClass(e,[{key:"init",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{logger:null,audioCtx:null,useAudioElement:void 0};this.logger=e.logger?e.logger:console.log,this.audioCtx=e.audioCtx?e.audioCtx:new(window.AudioContext||window.webkitAudioContext),!0===e.useAudioElement||!1===e.useAudioElement?this.useAudioElement=e.useAudioElement:this.useAudioElement=!["safari","safari|ios"].includes(this.browser),this.logger("AudioPlayer2: init ".concat(this.useAudioElement?"AudioElement":"AudioContext"," (").concat(this.browser,")"))}},{key:"setSpeakerId",value:function(e){this.logger("AudioPlayer2: setSpeakerId(".concat(e,")")),this.speakerDeviceId=null!==e?e:""}},{key:"setRingerId",value:function(e){this.logger("AudioPlayer2: setRingerId(".concat(e,")")),this.ringerDeviceId=e||null}},{key:"_browser",value:function(){return/iPad|iPhone|iPod/.test(navigator.userAgent)?"safari|ios":navigator.mozGetUserMedia?"firefox":navigator.webkitGetUserMedia?"chrome":window.safari?"safari":"other"}},{key:"isDisabled",value:function(){return"interrupted"===this.audioCtx.state&&this.logger("AudioPlayer2: isDisabled() state = interrupted ! Hello from iOS"),!!["chrome","safari","safari|ios"].includes(this.browser)&&"suspended"===this.audioCtx.state}},{key:"enable",value:function(){return["chrome","safari","safari|ios"].includes(this.browser)?this.audioCtx.resume():Promise.resolve()}},{key:"downloadSounds",value:function(e,t){this.logger("AudioPlayer2: downloadSounds ".concat(e," ").concat(JSON.stringify(t))),!this.useAudioElement&&["safari","safari|ios"].includes(this.browser)&&this._setDecodeAudioDataShim(this.audioCtx);var n,r=[],i=_createForOfIteratorHelper(t);try{for(i.s();!(n=i.n()).done;){var o=n.value,s=void 0,a=void 0;"string"==typeof o?s=a=o:a=o[s=Object.keys(o)[0]];var l=e+a+".mp3";r.push(this.useAudioElement?this._downloadSound1(s,l):this._downloadSound2(s,l))}}catch(e){i.e(e)}finally{i.f()}return Promise.allSettled(r)}},{key:"generateTonesSuite",value:function(e){this.logger("AudioPlayer2: generateTonesSuite");for(var t=[],n=0,r=Object.keys(e);n1&&void 0!==arguments[1]?arguments[1]:void 0;return this.isDisabled()?(this.logger("AudioPlayer2: play: ".concat(JSON.stringify(e)," [Sound is disabled]")),Promise.resolve()):this.useAudioElement?t?this._playStream1(e,t):this._play1(e):this._play2(e,t)}},{key:"playRing",value:function(e){return this.isDisabled()?(this.logger("AudioPlayer2: playRing: ".concat(JSON.stringify(e)," [Sound is disabled]")),Promise.resolve()):this.useAudioElement?this._playRing1(e):Promise.resolve()}},{key:"stop",value:function(){this.useAudioElement?this._stop1():this._stop2()}},{key:"playShortSound",value:function(e){return this.audioCtx?this.useAudioElement?this._playShortSound1(e):this._playShortSound2(e):Promise.reject("No audio context")}},{key:"_downloadSound1",value:function(e,t){var n=this,r=new Audio(t);return this.sounds[e]={audioElem:r,deviceId:"",source:null,streamDestination:null},new Promise(function(e,t){r.oncanplaythrough=e,["safari","safari|ios"].includes(n.browser)&&(r.oncanplay=e,r.onloadedmetadata=e),r.onerror=t})}},{key:"_generateTone1",value:function(e,t){var n=this;return this._generateTone(t).then(function(t){var r=new Audio,i=n._createBlob1(t);r.src=URL.createObjectURL(i),n.sounds[e]={audioElem:r,deviceId:"",source:null,streamDestination:null}})}},{key:"_createBlob1",value:function(e){function t(e,t,n){for(var r=0;r0&&r[t]?(i.audioElem.currentTime=0,i.audioElem.play().catch(function(e){r.logger("AudioPlayer2 [AudioElement]: play error",e)})):e()},i.audioElem.currentTime=0,i.audioElem.play().catch(function(e){r.logger("AudioPlayer2 [AudioElement]: play error",e)})})}):(this.logger('AudioPlayer2 [AudioElement]: missed sound: "'.concat(e.name,'"')),Promise.reject())}},{key:"_playStream1",value:function(e,t){var n=this;return this.logger("AudioPlayer2 [AudioElement]: play stream: ".concat(JSON.stringify(e))),this._silentStop1(this.sound),this.sound=this.sounds[e.name],this.sound?new Promise(function(r){n.sound.audioElem.volume=void 0!==e.volume?e.volume:1,n.sound.audioElem.loop=!!e.loop&&void 0===e.repeat;var i=void 0!==e.repeat?e.repeat:1;n.sound.audioElem.onended=function(){--i>0&&n.sound?(n.sound.audioElem.currentTime=0,n.sound.audioElem.play().catch(function(e){n.logger("AudioPlayer2 [AudioElement]: streaming error",e)})):(n.logger("AudioPlayer2 [AudioElement]: stopped"),r())},n.sound.audioElem.currentTime=0,n.sound.source||(n.sound.source=n.audioCtx.createMediaElementSource(n.sound.audioElem)),n.sound.streamDestination=t,n.sound.source.connect(n.sound.streamDestination),n.sound.audioElem.play().catch(function(e){n.logger("AudioPlayer2 [AudioElement]: streaming error",e)})}):(this.logger('AudioPlayer2 [AudioElement]: missed media file: "'.concat(e.name,'"')),Promise.reject())}},{key:"_stop1",value:function(){this.logger("AudioPlayer2 [AudioElement]: stop"),this._silentStop1(this.sound),this.sound=null,this._silentStop1(this.ringer),this.ringer=null}},{key:"_silentStop1",value:function(e){if(e&&(e.audioElem.pause(),e.source))try{e.source&&e.source.disconnect(),e.streamDestination&&e.streamDestination.disconnect(),e.streamDestination=null}catch(e){this.logger("AudioPlayer2 [AudioElement]: disconnect AudioContext error",e)}}},{key:"_downloadSound2",value:function(e,t){var n=this;return fetch(t,{credentials:"same-origin"}).then(function(e){if(e.status>=200&&e.status<=299)return e.arrayBuffer().catch(function(){throw"download body error"});throw 404===e.status?"file not found":"download error"}).then(function(e){return n.audioCtx.decodeAudioData(e).catch(function(){throw"decoding error"})}).then(function(t){n.sounds[e]={data:t,source:null,gain:null,streamDestination:null}}).catch(function(e){n.logger("AudioPlayer2 [AudioContext]: "+e+": "+t)})}},{key:"_generateTone2",value:function(e,t){var n=this;return this._generateTone(t).then(function(t){t&&(n.sounds[e]={data:t,source:null,gain:null,streamDestination:null})})}},{key:"_play2",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;this.logger("AudioPlayer2 [AudioContext]: ".concat(n?"playStream":"play",": ").concat(JSON.stringify(e))),this._silentStop2(this.sound);var r=this.sounds[e.name];return r?(this.sound=r=Object.assign({},r),new Promise(function(i,o){try{r.source=t.audioCtx.createBufferSource(),r.source.buffer=r.data,r.source.onended=function(){t.logger("AudioPlayer2 [AudioContext]: onended ".concat(e.name)),t._silentStop2(r),i(!0)},r.source.onerror=function(){t.logger("AudioPlayer2 [AudioContext]: onerror ".concat(e.name)),t._silentStop2(r),o(new Error("onerror callback"))},r.gain=t.audioCtx.createGain();var s=e.volume?e.volume:1;r.gain.gain.setValueAtTime(s,t.audioCtx.currentTime),r.source.connect(r.gain),n?(r.streamDestination=n,r.gain.connect(r.streamDestination)):(r.streamDestination=null,r.gain.connect(t.audioCtx.destination)),(!0===e.loop||e.repeat)&&(r.source.loop=!0,r.source.loopStart=0);var a=null;e.repeat&&(a=t.sound.source.buffer.duration*e.repeat),r.source.start(0,0),a&&r.source.stop(t.audioCtx.currentTime+a)}catch(e){t.logger("AudioPlayer2 [AudioContext]: play error",e),t._silentStop2(r),o(e)}})):(this.logger('AudioPlayer2 [AudioContext]: missed media: "'.concat(e.name,'"')),Promise.reject())}},{key:"_playShortSound2",value:function(e){var t,n,r=this;function i(){try{t&&t.stop(),n&&n.disconnect(),t&&t.disconnect()}catch(e){this.logger("AudioPlayer [AudioContext]: playShortSound: release error",e)}}return new Promise(function(o,s){try{var a=r.sounds[e.name];if(!a)return'AudioPlayer2 [AudioContext]: playShortSound: no sound: "'.concat(e.name,'"'),void s("No sound");(t=r.audioCtx.createBufferSource()).buffer=a.data,t.onended=function(){i(),o()},t.onerror=function(e){i(),s(e)},n=r.audioCtx.createGain();var l=e.volume?e.volume:1;n.gain.setValueAtTime(l,r.audioCtx.currentTime),t.connect(n),n.connect(r.audioCtx.destination),t.start()}catch(e){r.logger("AudioPlayer [AudioContext]: playShortSound error",e),s(e)}})}},{key:"_stop2",value:function(){this.logger("AudioPlayer2 [AudioContext]: stop"),this._silentStop2(this.sound),this.sound=null}},{key:"_silentStop2",value:function(e){if(e&&e.source){try{e.source&&e.source.stop()}catch(e){}try{e.gain&&e.gain.disconnect(),e.source&&e.source.disconnect(),e.streamDestination&&e.streamDestination.disconnect(),e.gain=null,e.source=null,e.streamDestination=null}catch(e){this.logger("AudioPlayer2 [AudioContext]: release resources error",e)}}}},{key:"_setDecodeAudioDataShim",value:function(e){var t=e.decodeAudioData;e.decodeAudioData=function(n){return new Promise(function(r,i){t.call(e,n,function(e){return r(e)},function(e){return i(e)})})}}},{key:"_setStartRenderingShim",value:function(e){var t=e.startRendering;e.startRendering=function(){return new Promise(function(n){e.oncomplete=function(e){n(e.renderedBuffer)},t.call(e)})}}},{key:"_generateTone",value:function(e){function t(e){return void 0===e?[]:Array.isArray(e)?e:[e]}try{var n,r=0,i=0,o=_createForOfIteratorHelper(e);try{for(o.s();!(n=o.n()).done;){var s=n.value;r+=s.t,i=Math.max(i,t(s.f).length)}}catch(e){o.e(e)}finally{o.f()}var a=this.audioCtx.sampleRate,l=a*r,u=new(window.OfflineAudioContext||window.webkitOfflineAudioContext)(1,l,a);"safari"!==this.browser&&"safari|ios"!==this.browser||this._setStartRenderingShim(u);for(var c=new Array(i),d=0;d1&&void 0!==arguments[1]?arguments[1]:null,n=e.getVideoTracks().length>0;t||!n||this.defaultOptions.video||(n=!1,this.logger("Warning: video mime undefined for ".concat(this.browser,", records audio only"))),t||(t=n?this.defaultOptions.video:this.defaultOptions.audio),this.selectedOptions=t,this.logger("MRecorder recorded ".concat(n?'"video"':'"audio"',". Options: ").concat(JSON.stringify(this.selectedOptions))),this.recorder=new MediaRecorder(e,this.selectedOptions)}},{key:"start",value:function(){var e=this;return new Promise(function(t,n){e.chunks=[],e.recorder.ondataavailable=function(t){e.chunks.push(t.data)},e.recorder.onerror=function(e){n(e)},e.recorder.onstop=function(){e.logger("MRecorder: create blob"),t(new Blob(e.chunks,{type:e.selectedOptions.mimeType})),e.chunks=[]},e.recorder.start()})}},{key:"stop",value:function(){this.recorder&&"recording"===this.recorder.state&&(this.logger("MRecorder: stop"),this.recorder.stop())}},{key:"closeStream",value:function(){var e,t=_createForOfIteratorHelper(this.recorder.stream.getTracks());try{for(t.s();!(e=t.n()).done;){e.value.stop()}}catch(e){t.e(e)}finally{t.f()}}}],[{key:"canBeUsed",value:function(){return"function"==typeof MediaRecorder}}]),e}(),AnsweringMachine=function(){function e(){_classCallCheck(this,e),this.use=!0,this.startDelay=16,this.recordDuration=20,this.run=!1,this.logger=null,this.call=null,this.streamDest=null,this.answerTimer=null,this.recordingTimer=null,this.audioPlayer=null,this.recorder=null,this.logger=null}return _createClass(e,[{key:"init",value:function(e,t){this.audioPlayer=e,this.logger=e.logger,this.recorder=t}},{key:"startTimer",value:function(e,t){var n=this;this.call=e,this.stopTimer(),this.answerTimer=setTimeout(function(){n.run=!0,t()},1e3*this.startDelay)}},{key:"stopTimer",value:function(){null!==this.answerTimer&&(clearTimeout(this.answerTimer),this.answerTimer=null)}},{key:"setStreamDestination",value:function(e){this.streamDest=e}},{key:"stop",value:function(e){e===this.call&&(this.stopTimer(),this.recorder.stop(),null!==this.recordingTimer&&(clearTimeout(this.recordingTimer),this.recordingTimer=null),this.run=!1)}},{key:"playGreeting",value:function(){var e=this;return this.audioPlayer.play({name:"greeting",volume:1,startDelay:1.6},this.streamDest).then(function(){return e.audioPlayer.play({name:"beep",volume:.2},e.streamDest)})}},{key:"recordAnswer",value:function(e){var t=this;return this.recorder.create(e),this.recordingTimer=setTimeout(function(){t.logger("AnsweringMachine: maximum recording time reached."),t.recorder.stop()},1e3*this.recordDuration),this.recorder.start().then(function(e){return t.run=!1,e})}}]),e}(),AlertInfo=function(){function e(t){_classCallCheck(this,e),this.parsed=[];try{var n,r=_createForOfIteratorHelper(t.getHeaders("alert-info"));try{for(r.s();!(n=r.n()).done;){var i,o=n.value,s=_createForOfIteratorHelper(o.split(","));try{for(s.s();!(i=s.n()).done;){var a=i.value;this._parseHeader(a)}}catch(e){s.e(e)}finally{s.f()}}}catch(e){r.e(e)}finally{r.f()}}catch(e){console.log("Alert-Info parsing error",e)}}return _createClass(e,[{key:"_parseHeader",value:function(e){var t,n=e.split(";"),r=0;n[0].startsWith("<")&&n[0].endsWith(">")&&(t=n[0].slice(1,-1),r=1);var i,o=new Map,s=_createForOfIteratorHelper(n.slice(r));try{for(s.s();!(i=s.n()).done;){var a=i.value,l=a.indexOf("=");if(-1!==l){var u=a.substring(0,l),c=a.substring(l+1);c.startsWith('"')&&c.endsWith('"')&&(c=c.slice(1,-1)),o.set(u.toLowerCase(),c.toLowerCase())}}}catch(e){s.e(e)}finally{s.f()}this.parsed.push({url:t,params:o})}},{key:"exists",value:function(){return this.parsed.length>0}},{key:"param",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return t>=this.parsed.length?null:this.parsed[t].params.get(e)}},{key:"url",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return this.parsed[e].url}},{key:"getDelay",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,t=this.param("delay",e);return t?parseInt(t):-1}},{key:"hasAutoAnswer",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;return"alert-autoanswer"===this.param("info",e)}}]),e}();function getXVoiceQuality(e){var t=e.getHeader("X-VoiceQuality");if(t){var n=t.trim().split(" ");if(2===n.length){var r=parseInt(n[0]);if(!isNaN(r))return{score:r,color:n[1].trim().toLowerCase()};console.log("X-VoiceQuality header: parsing problem: the first token is not number")}else console.log("X-VoiceQuality header: parsing problem: must be 2 tokens")}}var CallAudioMixer=function(){function e(t,n){_classCallCheck(this,e),this.audioCtx=t,this.dest=this.audioCtx.createMediaStreamDestination(),this.calls=[];var r=this.audioCtx.createMediaStreamSource(n.getRTCLocalStream());r.connect(this.dest),this.calls.push({call:n,source:r})}return _createClass(e,[{key:"close",value:function(){null!==this.dest&&(this.dest.disconnect(),this.dest=null);var e,t=_createForOfIteratorHelper(this.calls);try{for(t.s();!(e=t.n()).done;){e.value.source.disconnect()}}catch(e){t.e(e)}finally{t.f()}this.calls=[]}},{key:"getMix",value:function(){return this.dest.stream}},{key:"add",value:function(e){if(-1!==this.calls.findIndex(function(t){return t.call===e}))return!1;var t=e.getRTCRemoteStream(),n=this.audioCtx.createMediaStreamSource(t);return n.connect(this.dest),this.calls.push({call:e,source:n}),!0}},{key:"remove",value:function(e){var t=this.calls.findIndex(function(t){return t.call===e});return-1!==t&&0!==t&&(this.calls[t].source.disconnect(),this.calls.splice(t,1),!0)}},{key:"toString",value:function(){return"audio mixer "+this.calls.map(function(e){return e.call.data._line_index+1})}}]),e}(),CallVideoMixer=function(){function e(){_classCallCheck(this,e),this.layout="compact",this.run=!1,this.calls=[],this.localVideo=null,this.canvas=null,this.canvasCtx=null,this.canvasBackground="#F5F5F5",this.width=160,this.height=120,this.nVideo=0,this.drawInterval=100,this.remoteVideoId="",this.frame=1,this.data={}}return _createClass(e,[{key:"setElements",value:function(e,t,n){this.canvas=document.getElementById(e),this.canvasCtx=this.canvas.getContext("2d"),this.localVideo=document.getElementById(t),this.remoteVideoId=n}},{key:"setFPS",value:function(e){this.setDrawInterval(1e3/e)}},{key:"setDrawInterval",value:function(e){this.drawInterval=e}},{key:"setLayout",value:function(e){switch(e){case"linear":case"compact":this.layout=e;break;default:throw new TypeError("Unknown layout: ".concat(e))}this.resize()}},{key:"setSize",value:function(e,t){this.width=e,this.height=t,this.resize()}},{key:"setSizes",value:function(e){var t=parseInt(e.width.slice(0,-2)),n=parseInt(e.height.slice(0,-2));this.setSize(t,n)}},{key:"isOn",value:function(){return this.run}},{key:"start",value:function(){this.run||(setTimeout(this._draw.bind(this),this.drawInterval),this.run=!0)}},{key:"stop",value:function(){for(;this.calls.length>0;)this.remove(this.calls[0].call);this.run=!1}},{key:"getMix",value:function(e){var t=this.calls.findIndex(function(t){return t.call===e});return-1!==t?this.calls[t].mix:null}},{key:"add",value:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],r=this.calls.findIndex(function(t){return t.call===e});return-1===r?this._add(e,t,n):this._update(r,t,n)}},{key:"_add",value:function(e,t,n){var r=t?this.canvas.captureStream():null,i=n?document.getElementById(this.remoteVideoId+e.data._line_index):null;return this.calls.push({call:e,elt:i,mix:r,x:0,y:0}),null!==i&&this.resize(),null!==r}},{key:"_update",value:function(e,t,n){var r=this.calls[e],i=!1;if(t)null===r.mix&&(r.mix=this.canvas.captureStream(),i=!0);else if(null!==r.mix){var o,s=_createForOfIteratorHelper(r.mix.getVideoTracks());try{for(s.s();!(o=s.n()).done;){o.value.stop()}}catch(e){s.e(e)}finally{s.f()}r.mix=null,i=!0}return n?null===r.elt&&(r.elt=document.getElementById(this.remoteVideoId+r.call.data._line_index),this.resize()):null!==r.elt&&(r.elt=null,this.resize()),i}},{key:"remove",value:function(e){var t=this.calls.findIndex(function(t){return t.call===e});if(-1===t)return!1;var n=this.calls[t];if(null!==n.mix){var r,i=_createForOfIteratorHelper(n.mix.getVideoTracks());try{for(i.s();!(r=i.n()).done;){r.value.stop()}}catch(e){i.e(e)}finally{i.f()}}return this.calls.splice(t,1),null!==n.elt&&this.resize(),!0}},{key:"_nVideo",value:function(){var e=0;null!==this.localVideo.srcObject&&e++;var t,n=_createForOfIteratorHelper(this.calls);try{for(n.s();!(t=n.n()).done;){null!==t.value.elt&&e++}}catch(e){n.e(e)}finally{n.f()}return e}},{key:"resize",value:function(){switch(this.nVideo=this._nVideo(),this.layout){case"linear":this.canvas.width=(this.width+this.frame)*this.nVideo,this.canvas.height=this.height;break;case"compact":this.nVideo<=2?(this.canvas.width=(this.width+this.frame)*this.nVideo,this.canvas.height=this.height):this.nVideo<=4?(this.canvas.width=2*(this.width+this.frame),this.canvas.height=2*this.height+this.frame):(this.canvas.width=3*this.width,this.canvas.height=2*this.height+this.frame)}this.canvasCtx.fillStyle=this.canvasBackground,this.canvasCtx.fillRect(0,0,this.canvas.width,this.canvas.height),this.calls.sort(function(e,t){return e.call.data._line_index-t.call.data._line_index});var e=0;null!==this.localVideo.srcObject&&e++;var t,n=_createForOfIteratorHelper(this.calls);try{for(n.s();!(t=n.n()).done;){var r=t.value;if(null!==r.elt){var i=this._location(e),o=_slicedToArray(i,2),s=o[0],a=o[1];r.x=s,r.y=a,e++}}}catch(e){n.e(e)}finally{n.f()}}},{key:"_location",value:function(e){var t=this.width+this.frame,n=this.height+this.frame;switch(this.layout){case"linear":return[e*t,0];case"compact":switch(this.nVideo){case 0:case 1:case 2:return[e*t,0];case 3:return e<2?[t,0]:[t*(e-2)+.5*t,n];case 4:return e<2?[t,0]:[t*(e-2),n];case 5:return e<3?[t*e,0]:[t*(e-3)+.5*t,n];case 6:return e<3?[t*e,0]:[t*(e-3),n]}}}},{key:"_draw",value:function(){if(this.run){try{if(this.nVideo>0){null!==this.localVideo.srcObject&&this.canvasCtx.drawImage(this.localVideo,0,0,this.width,this.height);var e,t=_createForOfIteratorHelper(this.calls);try{for(t.s();!(e=t.n()).done;){var n=e.value;null!==n.elt&&this.canvasCtx.drawImage(n.elt,n.x,n.y,this.width,this.height)}}catch(e){t.e(e)}finally{t.f()}}}catch(e){console.log(e)}setTimeout(this._draw.bind(this),this.drawInterval)}}},{key:"toString",value:function(){return this.run?"video mixer "+this.calls.map(function(e){return"".concat(e.call.data._line_index+1).concat(null!==e.mix?"s":"").concat(null!==e.elt?"r":"")}):"video mixer is off"}}]),e}();function loadJavaScript(e){return new Promise(function(t,n){var r=document.createElement("script");r.onload=t,r.onerror=n,r.src=e,document.head.appendChild(r)})}var SelectDevices=function(){function e(){_classCallCheck(this,e),this.defaultPseudoDevice=!0,this.names=[],this.enumerateDevices=AudioCodesUA.instance.getWR().mediaDevices.enumerateDevices,this.browserDefaultLabel="-- browser default--",this.emptyLabel="-- no label --",this.previousSelection=null}return _createClass(e,[{key:"setDevices",value:function(e,t){this.defaultPseudoDevice=e,this.names=[];var n,r=_createForOfIteratorHelper(t);try{for(r.s();!(n=r.n()).done;){var i=n.value;if(!["audioinput","audiooutput","videoinput"].includes(i.kind))throw new TypeException("Illegal kind: ".concat(i.kind));this.names.push(i.name),this[i.name]={kind:i.kind}}}catch(e){r.e(e)}finally{r.f()}}},{key:"setEnumerateDevices",value:function(e){this.enumerateDevices=e}},{key:"enumerate",value:function(e){var t=this,n=null,r=!1;return Promise.resolve().then(function(){return t.doEnumerate()}).then(function(t){return(r=t)&&e?AudioCodesUA.instance.getWR().getUserMedia({audio:!0,video:!0}):Promise.resolve(null)}).then(function(e){if(n=e)return t.doEnumerate()}).then(function(){n&&(r=!1,n.getTracks().forEach(function(e){return e.stop()}))}).then(function(){if(t.previousSelection){var e,n=_createForOfIteratorHelper(t.names);try{for(n.s();!(e=n.n()).done;){var i=e.value;t.findPreviousSelection(i)||r&&t.addPreviousSelection(i)}}catch(e){n.e(e)}finally{n.f()}}})}},{key:"doEnumerate",value:function(){var e=this,t=!1,n=this.emptyLabel;function r(e,r){return r||(t=e.incomplete=!0,n)}var i,o=_createForOfIteratorHelper(this.names);try{for(o.s();!(i=o.n()).done;){var s=i.value,a=this.getDevice(s);a.incomplete=!1,this.defaultPseudoDevice?(a.index=0,a.list=[{deviceId:null,label:this.browserDefaultLabel}]):(a.index=-1,a.list=[])}}catch(e){o.e(e)}finally{o.f()}return this.enumerateDevices().then(function(t){var n,i=_createForOfIteratorHelper(t);try{for(i.s();!(n=i.n()).done;){var o,s=n.value,a=_createForOfIteratorHelper(e.names);try{for(a.s();!(o=a.n()).done;){var l=o.value,u=e.getDevice(l);s.kind===u.kind&&u.list.push({deviceId:s.deviceId,label:r(u,s.label)})}}catch(e){a.e(e)}finally{a.f()}}}catch(e){i.e(e)}finally{i.f()}}).then(function(){return t})}},{key:"findPreviousSelection",value:function(e){var t=this.getDevice(e),n=this.previousSelection&&this.previousSelection[e];if(!n||n.label===this.emptyLabel)return!1;for(var r=0;r=n.list.length)throw new RangeError("setSelectedIndex ".concat(e," index=").concat(t));n.index=t}},{key:"store",value:function(){this.previousSelection=null;var e,t=_createForOfIteratorHelper(this.names);try{for(t.s();!(e=t.n()).done;){var n=e.value,r=this.getDevice(n);0!==r.list.length&&-1!==r.index&&(this.previousSelection||(this.previousSelection={}),this.previousSelection[n]=this.getSelected(n))}}catch(e){t.e(e)}finally{t.f()}return this.previousSelection}},{key:"load",value:function(e){this.previousSelection=e}},{key:"addDeviceChangeListener",value:function(e){AudioCodesUA.instance.getWR().mediaDevices.addDeviceChangeListener(e)}},{key:"removeDeviceChangeListener",value:function(e){AudioCodesUA.instance.getWR().mediaDevices.removeDeviceChangeListener(e)}}]),e}(); diff --git a/js/acapi.1.19.0.js b/js/acapi.1.19.0.js new file mode 100644 index 0000000..4d2a68a --- /dev/null +++ b/js/acapi.1.19.0.js @@ -0,0 +1,2517 @@ +'use strict'; +/* + * AudioCodes WebRTC API v1.19.0 + * © 2023 AudioCodes Ltd. All rights reserved. + * + */ +class AudioCodesUA { + constructor() { + this._isInitialized = false; + this.serverConfig = {}; + this.account = { + user: null, + userAuth: null, + displayName: null, + password: null, + registerExpires: 600, + useSessionTimer: false + }; + // constraints for current browser + this.constraints = { audio: true, video: true }; + + this.chromiumBased = [ + { n: 'Edge', s: 'edg/' }, + { n: 'Opera', s: 'opr/' }, + { n: 'Samsung', s: 'samsungbrowser/' }, + { n: 'Yandex', s: 'yabrowser/' } + ]; + this.modes = { // default values for modes and fixes. + video_call_audio_answer_firefox_fix: true, // use fix + video_call_audio_answer_safari_fix: true, // true: for Safari versions < 14. ('force' for all versions) + ice_timeout_fix: 2000, // ICE gathering timeout (ms) + chrome_rtp_timeout_fix: 13, // Currently Chrome don't set 'failed' status to icestate + sbc_ha_pairs_mode: undefined, // Set e.g. 15 (seconds) when used multiple URL of HA SBC pairs + ringing_header_mode: undefined, // Add extra header(s) to response 180 ringing + sbc_switch_register5xx_mode: true, // Switch SBC if received REGISTER 5xx. + cache_register_auth_mode: true, // Next REGISTER includes authorization header from previous one. + check_remote_sdp_mode: true // Check remote SDP at every re-negotiation, and if need print 'AC:SDP' warning + }; + this.credentials = []; + this.listeners = {}; + this.registerExtraHeaders = null; + this.jssipUA = null; + this.browser = ''; // chrome, firefox, safari, other + this.browserVersion = 0; // version major number. + this.browserName = ''; // name with version + this.os = 'other'; // windows,android,macos,ios,linux,other + this.reconnectMin = 2; + this.reconnectMax = 30; + this.u17 = undefined; + this.activeCalls = 0; + this.wsPingStarted = false; + this.wsSocket = null; + this.wsOnMessage = null; + this.wsPingMs = 0; + this.wsOrigPingMs = 0; + this.wsThrottlingPingMs = 0; + this.wsVisibility = false; + this.wsCall = false; + this.wsLog = 0; + this.wsPongTimeout = true; + this.wsIsThrottling = false; + this.wsPingJob = null; + this.wsPingTime = null; + this.wsNextPingTime = null; + this.wsPongReceived = false; + this.wsPongSupported = null; + this.wsPongTimeoutTime = null; + this.wsPongDelays = null; + this.wsPongDelaysIx = 0; + this.wsPongReport = 0; + this.wsPongReportCounter = 0; + this.wsPongDist = false; + this.wsIsPingDebugLog = false; + this.dtmfUseWebRTC = true; + this.dtmfDuration = 250; + this.dtmfInterToneGap = 250; + this.enableAddVideo = false; + this.oauthToken = null; + this.oauthTokenUseInInvite = true; + this.networkPriority = undefined; + AudioCodesUA.ac_log = console.log; + AudioCodesUA.js_log = null; + if (AudioCodesUA.instance === undefined) + AudioCodesUA.instance = this; + this._detectBrowser(); + this._detectOS(); + this.webrtcapi = AudioCodesWebRTCWrapper; + this.replacedCall = null; + this.codecFilter = null; + this.AUDIO = Symbol('audio'); + this.VIDEO = Symbol('video'); + this.RECVONLY_VIDEO = Symbol('recvonly_video'); + return AudioCodesUA.instance; + } + + version() { return '1.19.0'; } + getBrowserName() { return this.browserName; } + getBrowser() { return this.browser; } + getBrowserVersion() { return this.browserVersion; } + getOS() { return this.os; } + + getWR() { return this.webrtcapi; } + checkAvailableDevices() { return this.getWR().checkAvailableDevices(); } + + getServerAddress() { + if (this.wsSocket === null) + return null; + let url = this.wsSocket.url; + if (url.endsWith('/')) + url = url.slice(0, -1); + return url; + } + + setOAuthToken(token, useInInvite = true) { + this.oauthToken = token; + this.oauthTokenUseInInvite = useInInvite; + this.setRegisterExtraHeaders(this.registerExtraHeaders); + } + + setUserAgent(name) { + this.u17 = name; + } + + setConstraints(browser, type, value) { + let br = this.browser; + let bs = this.browser + '|' + this.os; + if (browser !== null && browser !== br && browser !== bs) { + AudioCodesUA.ac_log(`AC: setConstraints ${browser} - ignored, no current browser`); + return; + } + AudioCodesUA.ac_log(`AC: setConstraints ${browser} ${type} ${JSON.stringify(value)}`); + if (type !== 'audio' && type !== 'video') + throw new TypeError(`Wrong type: ${type}`); + this.constraints[type] = value; + } + + setConstraint(type, name, value) { + if (value !== null && value !== undefined) { + AudioCodesUA.ac_log(`AC: setConstraint ${type} ${name}=${JSON.stringify(value)}`); + } else { + AudioCodesUA.ac_log(`AC: setConstraint remove ${type} ${name}`); + } + if (type !== 'audio' && type !== 'video') + throw new TypeError(`Wrong type: ${type}`); + + if (value !== null && value !== undefined) { + if (this.constraints[type] === true) + this.constraints[type] = {}; + + this.constraints[type][name] = value; + } else { + if (this.constraints[type] !== true && this.constraints[type] !== false) { + delete this.constraints[type][name]; + + if (Object.keys(this.constraints[type]).length === 0) + this.constraints[type] = true; + } + } + } + + setBrowsersConstraints(obj) { + let br = this.browser; + let bs = this.browser + '|' + this.os; + for (let key in obj) { + if (key !== br && key !== bs) + continue; + let val = obj[key]; + if (val.audio !== undefined) + this.setConstraints(key, 'audio', val.audio); + if (val.video !== undefined) + this.setConstraints(key, 'video', val.video); + } + } + + setCodecFilter(obj) { + if (obj) { + AudioCodesUA.ac_log(`AC: setCodecFilter ${JSON.stringify(obj)}`); + this.codecFilter = this._cf_unpack(obj); + } + } + + setServerConfig(serverAddresses, serverDomain, iceServers = []) { + this.serverConfig = { + addresses: serverAddresses, + domain: serverDomain, + iceServers: this._convertIceList(iceServers) + }; + AudioCodesUA.ac_log(`AC: setServerConfig() ${JSON.stringify(this.serverConfig)}`); + } + + setReconnectIntervals(minSeconds, maxSeconds) { + AudioCodesUA.ac_log(`AC: setReconnectIntervals min=${minSeconds} max=${maxSeconds}`); + this.reconnectMin = minSeconds; + this.reconnectMax = maxSeconds; + } + + setAccount(user, displayName, password, authUser) { + if (displayName === undefined || displayName === null || displayName.length === 0) + displayName = undefined; + if (authUser === undefined || authUser === null || authUser.length === 0) + authUser = user; + let a = this.account; + a.user = user; + a.displayName = displayName; + a.password = password; + a.authUser = authUser; + } + + setRegisterExpires(seconds) { + AudioCodesUA.ac_log(`AC: setRegisterExpires=${seconds}`); + this.account.registerExpires = seconds; + } + + setUseSessionTimer(use) { + AudioCodesUA.ac_log(`AC: setUseSessionTimer=${use}`); + this.account.useSessionTimer = use; + } + + // null value means use default (see value set in constructor for dtmfDuration, dtmtInterToneGap, dtmfSendDelay). + setDtmfOptions(useWebRTC, duration = null, interToneGap = null) { + AudioCodesUA.ac_log(`AC: setDtmfOptions useWebRTC=${useWebRTC} duration=${duration} interToneGap=${interToneGap}`); + this.dtmfUseWebRTC = useWebRTC; + if (duration !== null) + this.dtmfDuration = duration; + if (interToneGap !== null) + this.dtmfInterToneGap = interToneGap; + } + + setEnableAddVideo(enable) { + AudioCodesUA.ac_log(`AC: setEnableAddVideo=${enable}`); + this.enableAddVideo = enable; + } + + getEnableAddVideo() { return this.enableAddVideo; } + + getAccount() { return this.account; } + + setListeners(listeners) { + AudioCodesUA.ac_log('AC: setListeners()'); + for (let m of ['loginStateChanged', 'outgoingCallProgress', 'callTerminated', + 'callConfirmed', 'callShowStreams', 'incomingCall', 'callHoldStateChanged']) { + if (m in listeners) + continue; + throw new Error(`${m} listener is missed`); + } + + this.listeners = listeners; + } + + static getSessionStatusName(status) { + switch (status) { + case 0: return 'NULL (0)'; + case 1: return 'INVITE_SENT (1)'; + case 2: return '1XX_RECEIVED (2)'; + case 3: return 'INVITE_RECEIVED (3)'; + case 4: return 'WAITING_FOR_ANSWER (4)'; + case 5: return 'ANSWERED (5)'; + case 6: return 'WAITING_FOR_ACK (6)'; + case 7: return 'CANCELED (7)'; + case 8: return 'TERMINATED (8)'; + case 9: return 'CONFIRMED (9)'; + default: return 'Unknown (' + status + ')'; + } + } + + setAcLogger(loggerFunction) { AudioCodesUA.ac_log = loggerFunction; } + setJsSipLogger(loggerFunction) { AudioCodesUA.js_log = loggerFunction; } + + isInitialized() { return this._isInitialized; } + + setModes(modes = {}) { + AudioCodesUA.ac_log(`AC: setModes() ${JSON.stringify(modes)}`); + Object.assign(this.modes, modes); + this._normalizeModes(); + } + + _normalizeModes() { + function undef(v, m) { return typeof v === 'number' && v <= m ? undefined : v; } + let m = this.modes; + m.sbc_ha_pairs_mode = undef(m.sbc_ha_pairs_mode, 0); + m.chrome_rtp_timeout_fix = undef(m.chrome_rtp_timeout_fix, 0); + } + + init(autoLogin = true) { + AudioCodesUA.ac_log(`AC: init() autoLogin=${autoLogin}`); + if (this._isInitialized) + return; + this._isInitialized = true; + JsSIP.debug.enable('JsSIP:*'); + JsSIP.debug.formatArgs = function () { + if (AudioCodesUA.js_log) + this.log = AudioCodesUA.js_log; + }; + + let sockets = []; + for (let address of this.serverConfig.addresses) { + if (address instanceof Array) { // 'address' or ['address', weight] + sockets.push({ socket: new JsSIP.WebSocketInterface(address[0]), weight: address[1] }); + } else { + sockets.push(new JsSIP.WebSocketInterface(address)); + } + } + + let config = { + sockets: sockets, + uri: 'sip:' + this.account.user + '@' + this.serverConfig.domain, + contact_uri: 'sip:' + this.account.user + '@' + this._randomToken(12) + '.invalid;transport=ws', + authorization_user: this.account.authUser, + password: this.account.password, + register: autoLogin, + session_timers: this.account.useSessionTimer, + register_expires: this.account.registerExpires, + user_agent: this.u17, + connection_recovery_min_interval: this.reconnectMin, + connection_recovery_max_interval: this.reconnectMax + }; + + if (this.account.displayName && this.account.displayName.length > 0) { + config.display_name = this.account.displayName; + } + + this.jssipUA = new JsSIP.UA(config); + this.setRegisterExtraHeaders(this.registerExtraHeaders); + this._setUACallbacks(); + + AudioCodesUA.ac_log(`AC: applied SDK modes: ${JSON.stringify(this.modes, (k, v) => typeof v === 'undefined' ? '' : v)}`); + this.jssipUA.modes = this.modes; + + for (let credential of this.credentials) { + this.jssipUA.addCredential(credential); + } + this.credentials = []; + + this.jssipUA.start(); + } + + deinit() { + this._isInitialized = false; + this.jssipUA && this.jssipUA.stop(); + } + + setRegisterExtraHeaders(extraHeaders) { + this.registerExtraHeaders = extraHeaders; + if (this.jssipUA) { + let headers = extraHeaders !== null ? extraHeaders : []; + if (this.oauthToken !== null) { + headers = headers.slice(); + headers.push(`Authorization: Bearer ${this.oauthToken}`); + } + this.jssipUA.registrator().setExtraHeaders(headers); + } + } + + getRegisterExtraHeaders() { + return this.registerExtraHeaders; + } + + login() { + AudioCodesUA.ac_log('AC: login()'); + this.jssipUA.register(); + } + + logout() { + AudioCodesUA.ac_log('AC: logout()'); + if (this.jssipUA.isRegistered()) { + this.jssipUA.unregister(); + } + } + + switchSBC(unregister = true) { + AudioCodesUA.ac_log('AC: switchSBC()'); + return this.jssipUA.switchSBC(unregister); + } + + getNumberOfSBC() { + return this.jssipUA.getNumberOfSBC(); + } + + // Keep alive websocket ping/pong (CRLF) + setWebSocketKeepAlive(pingInterval, pongTimeout = true, timerThrottlingBestEffort = true, pongReport = 0, pongDist = false) { + AudioCodesUA.ac_log(`AC: setWebSocketKeepAlive pingInterval=${pingInterval} pongTimeout=${pongTimeout}` + + ` timerThrottlingBestEffort=${JSON.stringify(timerThrottlingBestEffort)} pongReport=${pongReport} pongDist=${pongDist}`); + if (typeof pingInterval !== 'number' || typeof pongTimeout !== 'boolean') + throw new TypeError('setWebSocketKeepAlive: wrong type of first or second argument'); + this.wsPingMs = this.wsOrigPingMs = pingInterval * 1000; + this.wsPongTimeout = pongTimeout; + this.wsPongReport = pongReport; + this.wsPongDist = pongDist; + this.wsPongReportCounter = 0; + this.wsIsThrottling = false; + let params; + if (timerThrottlingBestEffort === true) + params = { log: 0, chrome: { interval: 1, visibility: true, call: true, log: 1 } }; + else if (timerThrottlingBestEffort === false) + params = { log: 0 }; + else + params = timerThrottlingBestEffort; + + let p = params[this.browser]; + this.wsThrottlingPingMs = p && p.interval !== undefined ? p.interval * 1000 : 0; + this.wsVisibility = p && p.visibility !== undefined ? p.visibility : false; + this.wsCall = p && p.call !== undefined ? p.call : false; + this.wsLog = p && p.log !== undefined ? p.log : params.log; + + this.wsPongDelays = new Array(this.wsPongReport > 0 ? this.wsPongReport : 50); + this.wsPongDelaysIx = 0; + if (this.wsOrigPingMs !== 0 && this.wsThrottlingPingMs !== 0 && this.wsVisibility) + document.addEventListener('visibilitychange', this._onVisibilityChange.bind(this)); + } + + _pingLog() { + return ` (ping=${this.wsPingMs / 1000} sec)`; + } + + _visibilityLog(changed) { + let m = 'AC: keep-alive: Page is ' + (document.hidden ? 'hidden' : 'visible'); + if (document.hidden) { + if (this.wsCall) + m += ', ' + (this.activeCalls === 0 ? 'no active call' : 'active call'); + m += ' and ' + (this.wsIsThrottling ? 'was' : 'was not') + ' trottling'; + } + if (changed) + m += this._pingLog(); + AudioCodesUA.ac_log(m); + } + + _activeCallsLog(changed) { + let m = `AC: keep-alive: ${this.activeCalls === 0 ? 'Call ended' : 'Call started'}`; + if (this.activeCalls === 0) { + if (this.wsVisibility) + m += ', page is ' + (document.hidden ? 'hidden' : 'visible'); + else + m + ', page visibility is ignored'; + m += ' and ' + (this.wsIsThrottling ? 'was' : 'was not') + ' trottling'; + } + if (changed) + m += this._pingLog(); + AudioCodesUA.ac_log(m); + } + + _onActiveCallsChange(n) { + this.activeCalls += n; + if (!this.wsCall || this.wsPingMs === 0 || this.wsThrottlingPingMs === 0) + return; + if (this.activeCalls < 0) + AudioCodesUA.ac_log('Warning: keep-alive: activeCalls < 0'); + if (this.activeCalls === 0) { // open call -> no call + if ((!this.wsVisibility || document.hidden) && this.wsIsThrottling && this.wsPingMs < this.wsThrottlingPingMs) { + this.wsPingMs = this.wsThrottlingPingMs; + this._activeCallsLog(true); + return; + } + if (this.wsLog >= 2) + this._activeCallsLog(false); + } else if (this.activeCalls === 1 && n > 0) { // no call -> open call + if (this.wsPingMs > this.wsOrigPingMs) { + this.wsPingMs = this.wsOrigPingMs; + this._activeCallsLog(true); + return; + } + if (this.wsLog >= 2) + this._activeCallsLog(false); + } + } + + _onVisibilityChange() { + if (!this.wsVisibility || this.wsPingMs === 0 || this.wsThrottlingPingMs === 0) + return; + if (document.hidden) { + if ((this.wsCall && this.activeCalls === 0) && this.wsIsThrottling && this.wsPingMs < this.wsThrottlingPingMs) { + this.wsPingMs = this.wsThrottlingPingMs; + this._visibilityLog(true); + return; + } + if (this.wsLog >= 2) + this._visibilityLog(false); + } else { + if (this.wsPingMs > this.wsOrigPingMs) { + this.wsPingMs = this.wsOrigPingMs; + this._visibilityLog(true); + return; + } + if (this.wsLog >= 2) + this._visibilityLog(false); + } + } + + _onMessageHook(arg) { + if (arg.data === '\r\n') { + this._onPong(); + } else { + this.wsOnMessage(arg); + } + } + + _onPong() { + if (!this.wsPingStarted) + return; + this.wsPongReceived = true; + if (this.wsPongSupported === null) { + AudioCodesUA.ac_log('AC: keep-alive: Server supports CRLF pong'); + this.wsPongSupported = true; + } + let delay; + if (this.wsPongTimeoutTime !== null) { + delay = Date.now() - this.wsPongTimeoutTime; + this.wsPongTimeoutTime = null; + AudioCodesUA.ac_log(`AC: keep-alive: Received pong that exceeded the timeout, delay=${delay}`); + } else { + delay = Date.now() - this.wsPingTime; + } + + // Reset the ping timer from a networking callback to avoid Chrome timer throttling from causing timers to run once a minute + let nextPing = this.wsPingMs - delay; + if (nextPing < 0) { + AudioCodesUA.ac_log(`AC: nextPing calculated to ${nextPing}ms, so resetting to 0ms.`); + nextPing = 0; + } + if (this.wsPingJob !== null) { + clearTimeout(this.wsPingJob); + } + this.wsPingJob = setTimeout(this._sendPing.bind(this), nextPing); + + // Save pong delays statistics. + this.wsPongDelays[this.wsPongDelaysIx] = delay; + this.wsPongDelaysIx = this.wsPongDelaysIx + 1; + if (this.wsPongDelaysIx === this.wsPongDelays.length) + this.wsPongDelaysIx = 0; + if (this.wsPongReport > 0) + this.wsPongReportCounter++; + } + + _onPongTimeout(pingMs) { + AudioCodesUA.ac_log(`AC: keep-alive: Pong timeout (not received within ${pingMs / 1000} seconds)`); + AudioCodesUA.ac_log(`AC: keep-alive: Previous pongs statistics: ${this._createPongReport(true)}`); + if (this.wsPongTimeout) { + AudioCodesUA.ac_log('AC: keep-alive: Close websocket connection'); + this._stopWsKeepAlive(); + + // If directly call this.wsSocket.close() in Chrome it will take 60 seconds when URL exists and inaccessible. + // Instead we call socket close in not main thread and fire _onClose callback. + let socket = this.wsSocket; + socket.onopen = undefined; + socket.onerror = undefined; + socket.onclose = undefined; + socket.onmessage = undefined; + setTimeout( + () => { + try { + socket.close(); + } catch (e) { + AudioCodesUA.ac_log('AC: Close websocket error', e); + } + }, 0); + this.wsWebSocketInterface._ws = null; + this.wsWebSocketInterface._onClose.call(this.wsWebSocketInterface, { wasClean: false, code: 1001, reason: 'Going Away' }); + } else { + AudioCodesUA.ac_log(`AC: keep-alive: Warning: websocket is not closed, because pongTimeout=false`); + } + } + + _sendPing() { + try { + let now = Date.now(); + if (this.wsPingTime !== null) { + let delay = now - this.wsNextPingTime; + if (this.wsLog >= 3) + AudioCodesUA.ac_log(`AC: keep-alive: timer deviation (ms): ${delay}`); + let pingMs = this.wsPingMs; + if (Math.abs(delay) >= 10000) { + if (this.wsLog > 0 || !this.wsIsThrottling) { + AudioCodesUA.ac_log(`AC: keep-alive detected timer throttling: ${Math.round(delay / 1000)} seconds ${delay > 0 ? 'later' : 'earlier'}`); + if (this.wsLog === 0) + AudioCodesUA.ac_log('AC: keep-alive: The next timer throttling will not be shown in the logs, because log==0'); + } + this.wsIsThrottling = true; + if (this.wsPingMs < this.wsThrottlingPingMs) { + this.wsPingMs = this.wsThrottlingPingMs; + AudioCodesUA.ac_log(`AC: keep-alive: ping interval increased ${this._pingLog()}`); + } + } + if (this.wsPongSupported === null && !this.wsPongReceived) { + AudioCodesUA.ac_log('AC: keep-alive: Server does not support CRLF pong.'); + this.wsPongSupported = false; + } + if (this.wsPongSupported && !this.wsPongReceived && this.wsPongTimeoutTime === null) { + this._onPongTimeout(pingMs); + if (this.wsPongTimeout) + return; + this.wsPongTimeoutTime = this.wsPingTime; + } + } + this.wsPingTime = now; + this.wsNextPingTime = this.wsPingTime + this.wsPingMs; + this.wsPongReceived = false; + if (this.wsSocket.readyState === WebSocket.OPEN) { + if (this.wsIsPingDebugLog) + AudioCodesUA.ac_log('AC: send ping'); + this.wsSocket.send('\r\n\r\n'); + } else { + AudioCodesUA.ac_log(`AC: keep-alive: Warning: Cannot send Ping, websocket state=${this.wsSocket.readyState}`); + } + this.wsPingJob = setTimeout(this._sendPing.bind(this), this.wsPingMs); + if (this.wsPongReport > 0 && this.wsPongReportCounter >= this.wsPongReport) { + this.wsPongReportCounter = 0; + AudioCodesUA.ac_log(`AC: keep-alive: Pong statistics: ${this._createPongReport(this.wsPongDist)}`); + } + } catch (e) { + AudioCodesUA.ac_log('AC: keep-alive: send ping error', e); + } + } + + _startWsKeepAlive() { + let transport = this.jssipUA._transport; + this.wsWebSocketInterface = transport.socket; + this.wsSocket = this.wsWebSocketInterface._ws; + if (this.wsPingMs === 0) + return; + this.wsOnMessage = this.wsSocket.onmessage; + this.wsSocket.onmessage = this._onMessageHook.bind(this); + this._stopWsKeepAlive(); + this.wsPingTime = null; + this.wsPingStarted = true; + this.wsPongSupported = null; + this.wsPingJob = setTimeout(this._sendPing.bind(this), this.wsPingMs); + } + + _stopWsKeepAlive() { + this.wsPingStarted = false; + if (this.wsPingJob !== null) { + clearTimeout(this.wsPingJob); + this.wsPingJob = null; + } + } + + _createPongReport(dist) { + let dval; + let dstr = ''; + let dover = false; + let min = 1000000; + let max = 0; + if (dist) + dval = new Array(this.wsPingMs / 1000 * 4).fill(0); + let pongs = 0; + for (let ix = 0; ix < this.wsPongDelays.length; ix++) { + let delay = this.wsPongDelays[ix]; + if (delay === undefined) + continue; + pongs++; + if (delay < min) + min = delay; + if (delay > max) + max = delay; + if (dist) { + let n = Math.floor(delay / 250); + if (n >= dval.length) { + n = dval.length - 1; + dover = true; + } + dval[n]++; + } + } + if (dist) { + dstr = '\r\npongs distribution (1/4 second step): '; + for (let i = 0; i < dval.length; i++) { + dstr += dval[i].toString(); + if (i !== dval.length - 1) + dstr += (i + 1) % 4 === 0 ? ',' : ' '; + } + if (dover) + dstr += ' (+)'; + } + return `pongs=${pongs} delay=${min}..${max} ms${dstr}`; + } + + setPingDebugLog(isDebug) { + this.wsIsPingDebugLog = isDebug; + } + // end of ping/pong keep-alive + + // Catch some JsSIP events, and call corresponding API callbacks. + _setUACallbacks() { + this.jssipUA.on('connected', () => { + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "connected"'); + this._startWsKeepAlive(); + this.listeners.loginStateChanged(false, 'connected', null); + }); + + this.jssipUA.on('disconnected', () => { + this._stopWsKeepAlive(); + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "disconnected"'); + this.listeners.loginStateChanged(false, 'disconnected', null); + }); + + this.jssipUA.on('registered', (e) => { + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=true "login"'); + this.listeners.loginStateChanged(true, 'login', e.response); + }); + + this.jssipUA.on('unregistered', (e) => { + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "logout"'); + this.listeners.loginStateChanged(false, 'logout', e.response); + }); + + this.jssipUA.on('registrationFailed', (e) => { + let statusCode = e.response ? e.response.status_code : 0; + + if (statusCode >= 300 && statusCode < 400) { + let contact = e.response.parseHeader('contact'); + if (contact) { + let cu = contact.uri; + let url = 'wss://' + cu.host; + if (cu.port && cu.port !== 443) { + url += ':' + cu.port.toString(); + } + AudioCodesUA.ac_log(`AC: registerRedirect("${url}")`); + if (this.jssipUA.registerRedirect(url)) + return; // skip 'login failed' callback + } else { + AudioCodesUA.ac_log('AC: 3xx response without "Contact" is ignored'); + } + } else if (statusCode >= 500 && statusCode < 600 && AudioCodesUA.instance.modes.sbc_switch_register5xx_mode) { + if (AudioCodesUA.instance.switchSBC(false)) + return; // skip 'login failed', 'logout' callbacks + } + + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "login failed"'); + this.listeners.loginStateChanged(false, 'login failed', e.response ? e.response : null); + }); + + if (this.listeners.incomingMessage) { + this.jssipUA.on('newMessage', (e) => { + if (e.originator !== 'remote') + return; // ignore outgoing message. + AudioCodesUA.ac_log('AC>>: incomingMessage', e); + // null, from, content-type?, body?, request + this.listeners.incomingMessage(null, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + }); + } + + if (this.listeners.incomingNotify) { + this.jssipUA.on('sipEvent', (e) => { + AudioCodesUA.ac_log('AC>>: incoming out of dialog NOTIFY', e); + // null, event, from, content-type? , body?, request + let taken = this.listeners.incomingNotify(null, e.event ? e.event.event : null, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + if (!taken) { + e.request.reply(481); + } + }); + } + + if (this.listeners.incomingSubscribe) { + this.jssipUA.on('newSubscribe', (e) => { + let subs = e.request; + let ev = subs.parseHeader('event'); + let accepts = subs.getHeaders('accept'); + AudioCodesUA.ac_log('AC>>: incomingSubscribe', subs, ev.event, accepts); + let code = this.listeners.incomingSubscribe(subs, ev.event, accepts); + if (code > 0) + subs.reply(code); + }); + } + + this.jssipUA.on('newRTCSession', function (e) { + AudioCodesUA.ac_log(`AC: event ${e.originator === 'remote' ? 'incoming' : 'outgoing'} "newRTCSession"`, e); + let call = new AudioCodesSession(e.session); + // In-dialog incoming NOTIFY. + // Works only in modified jssip where added the event + call.js_session.on('sipEvent', function (e) { + if (!AudioCodesUA.instance.listeners.incomingNotify) + return; + let ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: incoming NOTIFY', ac_session, e); + // call?, event, from, content-type? , body?, request. return true when notify accepted. + e.taken = AudioCodesUA.instance.listeners.incomingNotify(ac_session, e.event ? e.event.event : null, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + }); + + call.js_session.on('newInfo', function (e) { + if (!AudioCodesUA.instance.listeners.incomingInfo) + return; + if (e.originator === 'local') + return; + let ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: incoming INFO', ac_session, e); + // call, from, content-type? , body?, request + AudioCodesUA.instance.listeners.incomingInfo(ac_session, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + }); + + call.js_session.on('replaces', function (e) { + AudioCodesUA.instance.replacedCall = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: incoming INVITE with Replaces. This call will be replaced:', this.data.ac_session); + e.accept(); + }); + + call.js_session.on('sdp', function (e) { + AudioCodesUA.instance._sdp_checking(this, e); + }); + + call.js_session.on('connecting', function (r) { + AudioCodesUA.ac_log('AC>>: connecting'); + let filter = AudioCodesUA.instance.codecFilter; + if (filter) { + AudioCodesUA.instance._cf_filter('audio', this.data.ac_session, filter.audio); + AudioCodesUA.instance._cf_filter('video', this.data.ac_session, filter.video); + } + }); + + call.js_session.on('reinvite', function (e) { + if (!AudioCodesUA.instance.listeners.callIncomingReinvite) + return; + let ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: callIncomingReinvite start'); + AudioCodesUA.instance.listeners.callIncomingReinvite(ac_session, true, e.request); + e.callback = function () { + AudioCodesUA.ac_log('AC>>: callIncomingIncomingReinvite end'); + AudioCodesUA.instance.listeners.callIncomingReinvite(ac_session, false, null); + } + }); + + call.js_session.on('hold', function (e) { + let ac_session = this.data.ac_session; + let isRemote = e.originator === 'remote'; + AudioCodesUA.ac_log(`AC>>: callHoldStateChanged isHold=true isRemote=${isRemote} session:`, ac_session); + AudioCodesUA.instance.listeners.callHoldStateChanged(ac_session, true, isRemote); + }); + + call.js_session.on('unhold', function (e) { + let ac_session = this.data.ac_session; + let isRemote = e.originator === 'remote'; + AudioCodesUA.ac_log(`AC>>: callHoldStateChanged isHold=false isRemote=${isRemote} session:`, ac_session); + AudioCodesUA.instance.listeners.callHoldStateChanged(ac_session, false, isRemote); + }); + + call.js_session.on('progress', function (e) { + if (e.originator === 'remote') { + let ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: outgoingCallProgress', ac_session); + AudioCodesUA.instance.listeners.outgoingCallProgress(ac_session, e.response); + } + }); + + call.js_session.on('failed', function (e) { + let ac_session = this.data.ac_session; + let contact = null; + if (e.cause === 'Redirected' && e.message && e.message.headers) { + let nameAddress = e.message.parseHeader('Contact'); + if (nameAddress) { + contact = nameAddress.uri.toString(); + } + } + AudioCodesUA.ac_log('AC>>: callTerminated (failed)', ac_session, e.cause, contact); + AudioCodesUA.instance.listeners.callTerminated(ac_session, e.message, e.cause, contact); + }); + + call.js_session.on('accepted', function (e) { + let ac_session = this.data.ac_session; + ac_session.data['_accepted'] = true; // means sent or received OK + if (e.originator === 'remote') { // Outgoing call + ac_session.data['_ok_response'] = e.response; + } + }); + + // Remove listener that close replaced session when replaces confirmed + if (e.originator === 'remote' && AudioCodesUA.instance.replacedCall !== null) + call.js_session.removeAllListeners('confirmed'); + + call.js_session.on('confirmed', function () { + let ac_session = this.data.ac_session; + let okResponse = null; + let cause; + if ('_ok_response' in ac_session.data) { + okResponse = ac_session.data['_ok_response']; + delete ac_session.data['_ok_response']; + cause = 'ACK sent'; + } else { + cause = 'ACK received'; + } + + // Video call /audio answer, no sound on answer side issue. Firefox workaround + if (call.data['_video_call_audio_answer_firefox']) { + call.data['_video_call_audio_answer_firefox'] = false; + AudioCodesUA.ac_log('AC: [video call/audio answer] Firefox workaround. Send re-INVITE'); + call.sendReInvite({ showStreams: true }); + } + AudioCodesUA.ac_log('AC>>: callConfirmed', ac_session, cause); + AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance, 1); + AudioCodesUA.instance.listeners.callConfirmed(ac_session, okResponse, cause); + }); + + call.js_session.on('ended', function (e) { + let ac_session = this.data.ac_session; + if (ac_session.data['_screenSharing']) { + ac_session._onEndedScreenSharing.call(ac_session, 'call terminated'); + } + AudioCodesUA.ac_log('AC>>: callTerminated (ended)', ac_session, e.cause); + AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance, -1); + AudioCodesUA.instance.listeners.callTerminated(ac_session, e.message, e.cause); + }); + + call.js_session.on('refer', function (e) { + if (!AudioCodesUA.instance.listeners.transfereeCreatedCall) { + AudioCodesUA.ac_log('AC>>: incoming REFER rejected, because transfereeCreatedCall is not set'); + e.reject(); + } else { + let ac_session = this.data.ac_session; + let accept; + if (AudioCodesUA.instance.listeners.transfereeRefer) { + accept = AudioCodesUA.instance.listeners.transfereeRefer(ac_session, e.request); + } else { + accept = true; + } + if (accept) { + AudioCodesUA.ac_log('AC>>: incoming REFER accepted'); + // Set new call video according current call + let sendVideo; + if (ac_session.isScreenSharing()) { + sendVideo = ac_session.doesScreenSharingReplaceCamera(); + } else { + sendVideo = ac_session.hasSendVideo(); + } + let options = AudioCodesUA.instance._callOptions(sendVideo, true); + e.accept((e) => { e.data['_created_by_refer'] = ac_session; }, options); + } else { + AudioCodesUA.ac_log('AC>>: incoming REFER rejected'); + e.reject(); + } + } + }); + + // Set the call flag according phone setting. + call._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo); + + // If connection is already exists set listener. + // otherwise wait until connection will be created. + if (call.js_session.connection) { + AudioCodesUA.instance._set_connection_listener(call); + AudioCodesUA.ac_log('AC: connection exists, set "track" listener'); + } else { + AudioCodesUA.ac_log('AC: peer connection does not exist, wait creation'); + call.js_session.on('peerconnection', () => { + AudioCodesUA.instance._set_connection_listener(call); + AudioCodesUA.ac_log('AC: [event connection] connection created, set "track" listener'); + }); + } + + let remote; + if (e.originator === 'remote') { + remote = e.request.from; + } else { + remote = e.request.to; + } + + // set call data + call.data['_user'] = remote.uri.user; + call.data['_host'] = remote.uri.host; + call.data['_display_name'] = remote.display_name; // optional + call.data['_create_time'] = new Date(); + + if (e.originator === 'remote') { + let replacedCall = null; + if (AudioCodesUA.instance.replacedCall !== null) { + replacedCall = AudioCodesUA.instance.replacedCall; + AudioCodesUA.instance.replacedCall = null; + } + + // Incoming call. Set video flags according m=video in SDP. + let send, recv, hasSDP; + if (e.request.body) { + hasSDP = true; + let sdp = new AudioCodesSDP(e.request.body); + [send, recv] = sdp.getMediaDirection('video', true); + } else { + hasSDP = false; + call.data['_incoming_invite_without_sdp'] = true; + send = recv = true; // to enable answer with or without video. + AudioCodesUA.ac_log('AC: warning incoming INVITE without SDP'); + } + call._setVideoState(send, recv); + + AudioCodesUA.ac_log(`AC>>: incomingCall ${call.hasVideo() ? 'video' : 'audio'} from "${call.data._display_name}" ${call.data._user}`, call, replacedCall); + AudioCodesUA.instance.listeners.incomingCall(call, e.request, replacedCall, hasSDP); + } else { // e.originator === 'local' + if (call.js_session.data['_created_by_refer']) { + AudioCodesUA.ac_log('AC>>: outgoing call created by REFER'); + call.data['_created_by_refer'] = call.js_session.data['_created_by_refer']; + AudioCodesUA.instance.listeners.transfereeCreatedCall(call); + } else { + AudioCodesUA.ac_log('AC>>: outgoing call created by phone.call()'); + } + } + }); + } + + _get_from(msg) { + return { + user: msg.from.uri.user, + host: msg.from.uri.host, + displayName: msg.from.display_name ? msg.from.display_name : null + }; + } + + _get_content_type(msg) { + let ct = msg.headers['Content-Type']; + return (ct && ct.length > 0) ? ct[0].parsed : null; + } + + _set_connection_listener(call) { + AudioCodesUA.instance.getWR().connection.addEventListener(call.js_session.connection, 'track', (e) => { + AudioCodesUA.ac_log(`AC>>: "track" event kind= ${e.track.kind}`, e); + // save call remote stream + if (e.streams.length > 0) { // if track is in stream + let stream = e.streams[0]; + AudioCodesUA.ac_log(`AC: set call remote stream id=${stream.id}`, call); + call.data['_remoteMediaStream'] = stream; + } else { + AudioCodesUA.ac_log('AC: Warning "track" event without stream'); + } + if (e.track.kind === 'video') { + if (!call.hasEnabledReceiveVideo()) { + // Video call - audio answer, no sound on answer side issue. Patch for Safari. + if (call.data['_video_call_audio_answer_safari']) { + e.track.onmute = () => { + AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Fired video track "mute" event. Call callShowStream'); + e.track.onmute = null; + let localStream = call.getRTCLocalStream(); + let remoteStream = call.getRTCRemoteStream(); + AudioCodesUA.ac_log('AC>>: callShowStreams', call, localStream, remoteStream); + AudioCodesUA.instance.listeners.callShowStreams(call, localStream, remoteStream); + } + AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Set video track "mute" event listener'); + call.data['_video_call_audio_answer_safari'] = false; + } + + AudioCodesUA.ac_log('AC>>: event "track" video and !hasEnabledReceiveVideo therefore change transceiver direction.', call); + let vt = AudioCodesUA.instance.getWR().connection.getTransceiver(call.js_session.connection, 'video'); + if (vt !== null) { + let dir = call.hasEnabledSendVideo() ? 'sendonly' : 'inactive'; + AudioCodesUA.instance.getWR().transceiver.setDirection(vt, dir); + } + } + + if (AudioCodesUA.instance.codecFilter) { + AudioCodesUA.instance._cf_filter('video', call, AudioCodesUA.instance.codecFilter.video); + } + + // No call callShowStreams() for event 'track' video, because we use the same stream for audio and video. + // and to prevent calling callShowStreams twice and use wrong video flags. + return; + } + let localStream = call.getRTCLocalStream(); + let remoteStream = call.getRTCRemoteStream(); + AudioCodesUA.ac_log('AC>>: callShowStreams', call, localStream, remoteStream); + AudioCodesUA.instance.listeners.callShowStreams(call, localStream, remoteStream); + }); + } + + /* + SDP may change with every new browser release and modified by SBC + We do not edit the SDP in client to avoid chaos. + However, it could be useful for testing + + // Remove ICE candidates with with a type different from 'relay' + _sdp_editing(sdp) { + for (let mIndex = 0; mIndex < sdp.media.length; mIndex++) { + let media = sdp.media[mIndex]; + let modifiedMedia = []; + for (let i = 0; i < media.length; i++) { + let line = media[i]; + if (line.startsWith('a=candidate:')) { + // a=candidate:1467250027 1 udp 2122260223 192.168.0.196 46243 typ host generation 0 + let tokens = line.split(' '); + if (tokens[7] === 'relay') { + modifiedMedia.push(line); + } else { + AudioCodesUA.ac_log('Removed line:' + line); + } + } else { + modifiedMedia.push(line); + } + } + sdp.media[mIndex] = modifiedMedia; + } + return sdp.toString(); + } + + // Usage: + e.sdp = AudioCodesUA.instance._sdp_editing(sdp); + */ + + /** + * Chrome WebRTC engine check if current SDP compatible with previous SDP. + * Chrome exception is almost unreadable, e.g: + * "Failed to set local answer sdp: Failed to set local audio description recv parameters for m-section with mid='0'" + * The function compare current and previous remote SDP and print warnings. + */ + _check_remote_sdp(sdp, data) { + try { + if (!data.codec_map) { + data.codec_map = {}; + } + let mAudio = sdp.getMedia('audio'); + AudioCodesUA.instance._check_remote_m(mAudio, data.codec_map); + + let mVideo = sdp.getMedia('video'); + if (mVideo) { + AudioCodesUA.instance._check_remote_m(mVideo, data.codec_map); + } + } catch (e) { + AudioCodesUA.ac_log('AC:SDP exception', e); + } + } + + _check_remote_m(m, previous) { + // Collect current SDP information + // pt : { rtpmap:xxx, [fmtp: yyy] } + let current = {}; + function parse(offset, str) { + let ix = str.indexOf(' ', offset); + if (ix === -1) + return ['?', '?']; + return [str.substring(offset, ix), str.substring(ix + 1).toLowerCase()]; + } + + for (let l of m) { + if (l.startsWith('a=rtpmap:')) { + let [pt, rtpmap] = parse(9, l); + if (!current[pt]) + current[pt] = {}; + current[pt].rtpmap = rtpmap; + } else if (l.startsWith('a=fmtp:')) { + let [pt, fmtp] = parse(7, l); + if (!current[pt]) + current[pt] = {}; + current[pt].fmtp = fmtp; + } + } + + // AudioCodesUA.ac_log(`current ` + JSON.stringify(current, null, 2)); + // AudioCodesUA.ac_log(`previous ` + JSON.stringify(previous, null, 2)); + + // Compare current SDP information with previous one. + for (let pt of Object.keys(current)) { + if (previous[pt]) { + if (current[pt].rtpmap === previous[pt].rtpmap) { + if (current[pt].fmtp !== previous[pt].fmtp) { + AudioCodesUA.ac_log(`AC:SDP [The same payload type and codec name, different fmtp] pt=${pt} rtpmap=${current[pt].rtpmap} fmtp=${current[pt].fmtp}, previously was fmtp=${previous[pt].fmtp}`); + } + } else { + // Check that used dynamic payload type or both rtpmat is defined. + if (parseInt(pt) >= 64 || (!!current[pt].rtpmap && !!previous[pt].rtpmap)) { + AudioCodesUA.ac_log(`AC:SDP [The same payload type, different codec names] pt=${pt} rtpmap=${current[pt].rtpmap}, previously was rtpmap=${previous[pt].rtpmap}`); + } + } + } else { + let data = current[pt]; + let foundPt; + for (let [pt1, data1] of Object.entries(previous)) { + if (data.rtpmap === data1.rtpmap && data.fmtp === data1.fmtp) { + foundPt = pt1; + break; + } + } + if (foundPt) { + let prevData = previous[foundPt]; + if (!data.fmtp && !prevData.fmtp) { + AudioCodesUA.ac_log(`AC:SDP [The same codec name used with different payload types] pt=${pt} rtpmap=${data.rtpmap}, previously was pt=${foundPt} rtpmap=${prevData.rtpmap}`); + } else { + AudioCodesUA.ac_log(`AC:SDP [The same codec name used with different payload types] pt=${pt} rtpmap=${data.rtpmap} fmtp=${data.fmtp}, previously was pt=${foundPt} rtpmap=${prevData.rtpmap} fmtp=${prevData.fmtp}`); + } + } else { + previous[pt] = data; + } + } + } + } + + _sdp_checking(js_session, e) { + let type = e.originator + ' ' + e.type; + let ac_session = js_session.data.ac_session; + let sdp, send, recv; + try { + sdp = new AudioCodesSDP(e.sdp); + [send, recv] = sdp.getMediaDirection('video', e.originator === 'remote'); + } catch (e) { + AudioCodesUA.ac_log('AC: cannot parse SDP', e); + return; + } + let initial = ac_session.data._initial; + if (e.type === 'answer') // after 1st answer it's not initial SDP negotiation. + ac_session.data._initial = false; + + AudioCodesUA.ac_log(`AC: Event "sdp" ${initial ? 'initial' : ''} ${type} Session state:${AudioCodesUA.getSessionStatusName(js_session._status)}`); + switch (type) { + case 'remote offer': + if (AudioCodesUA.instance.modes.check_remote_sdp_mode) { + AudioCodesUA.instance._check_remote_sdp(sdp, js_session.data); + } + break; + + case 'remote answer': + if (AudioCodesUA.instance.modes.check_remote_sdp_mode) { + AudioCodesUA.instance._check_remote_sdp(sdp, js_session.data); + } + if (ac_session.isLocalHold() || ac_session.isRemoteHold()) + break; // ignore hold re-INVITE + ac_session._setVideoState(send, recv); + break; + + case 'local offer': + if (AudioCodesUA.instance.networkPriority) { + AudioCodesUA.instance._set_senders_dscp(js_session); + } + break; + + case 'local answer': + if (ac_session.isLocalHold() || ac_session.isRemoteHold()) + break; // ignore hold re-INVITE + if (AudioCodesUA.instance.networkPriority) { + AudioCodesUA.instance._set_senders_dscp(js_session); + } + ac_session._setVideoState(send, recv); + break; + } + } + + _set_senders_dscp(js_session) { + if (AudioCodesUA.instance.browser !== 'chrome') + return; + AudioCodesUA.ac_log('AC: _set_senders_dscp()'); + let priority = AudioCodesUA.instance.networkPriority; + AudioCodesUA.instance._set_dscp(js_session, 'audio', priority); + AudioCodesUA.instance._set_dscp(js_session, 'video', priority); + } + + _set_dscp(js_session, type, priority) { + let conn = js_session.connection; + let tr = AudioCodesUA.instance.getWR().connection.getTransceiver(conn, type); + if (!tr && type === 'video') + return Promise.resolve(false); + return Promise.resolve() + .then(() => { + let params = tr.sender.getParameters(); + if (!params) + throw new Error('sender getParameters() returns undefined'); + let encodings = params.encodings; + if (!encodings) + throw new Error('parameters encodings is undefined'); + if (encodings.length === 0) + throw new Error('parameters encodings is empty array'); + let previous = encodings[0].networkPriority; + if (!previous) + throw new Error('parameters encodings networkPriority is undefined'); + if (previous === priority) + return true; // nothing to do. + encodings[0].networkPriority = priority; + return tr.sender.setParameters(params) + .then(() => { + AudioCodesUA.ac_log(`AC: DSCP: ${type} "${priority}"`); + return true; + }); + }) + .catch(e => { + AudioCodesUA.ac_log(`AC: DSCP: ${type} error: ${e}`); + return false; + }); + } + + // Codec filter + _cf_unpack(obj) { + // Unpack 'pcmu', 'pcmu/8000' 'VP9#profile-id=0' + function unpack(type, s) { + let slash = s.indexOf('/'); + let num = s.indexOf('#'); + let end; + end = (slash !== -1) ? slash : (num !== -1 ? num : undefined); + let res = { mimeType: (type + '/' + s.substring(0, end)).toLowerCase() }; + if (slash !== -1) { + end = (num !== -1) ? num : undefined; + res.clockRate = parseInt(s.substring(slash + 1, end)); + } + if (num !== -1) { + res.sdpFmtpLine = s.substring(num + 1); + } + return res; + } + if (!obj) + return null; + let result = {}; + for (let type in obj) { + result[type] = {}; + for (let op in obj[type]) { + result[type][op] = obj[type][op].map(s => unpack(type, s)); + } + } + return result; + } + + _cf_pack(codecs) { + function pack(c) { + let r = c.mimeType.substring(6).toLowerCase(); + if (c.clockRate) + r += '/' + c.clockRate; + if (c.sdpFmtpLine) + r += '#' + c.sdpFmtpLine; + return r; + } + return codecs.map(c => pack(c)); + } + + _cf_str(codecs) { + return JSON.stringify(AudioCodesUA.instance._cf_pack(codecs)); + } + + _cf_match(codec, filters) { + let mimeType = codec.mimeType.toLowerCase(); + for (let filter of filters) { + if (filter.mimeType === mimeType) { + if (filter.clockRate && filter.clockRate !== codec.clockRate) + continue; + if (filter.sdpFmtpLine && filter.sdpFmtpLine !== codec.sdpFmtpLine) + continue; + return true; + } + } + return false; + } + + _cf_find(filter, codecs) { + let found = []; + for (let codec of codecs) { + let mimeType = codec.mimeType.toLowerCase(); + if (filter.mimeType === mimeType) { + if (filter.clockRate && filter.clockRate !== codec.clockRate) + continue; + if (filter.sdpFmtpLine && filter.sdpFmtpLine !== codec.sdpFmtpLine) + continue; + found.push(codec); + } + } + return found; + } + + _cf_filter(type, call, filter) { + if (!filter) + return; + // Used once for audio and once for video + if (call.data[`_used_${type}_codec_filter`]) + return; + try { + let conn = call.getRTCPeerConnection(); + let transceiver = AudioCodesUA.instance.getWR().connection.getTransceiver(conn, type); + if (!transceiver) { + if (type === 'audio') + AudioCodesUA.ac_log('AC: codec-filter: cannot get audio transceiver'); + return; + } + + call.data[`_used_${type}_codec_filter`] = true; + + if (!RTCRtpSender.getCapabilities || !RTCRtpReceiver.getCapabilities || !transceiver.setCodecPreferences) { + AudioCodesUA.ac_log(`AC: codec-filter is not supported.`); + return; + } + let sndCodecs = RTCRtpSender.getCapabilities(type).codecs; + let rcvCodecs = RTCRtpReceiver.getCapabilities(type).codecs; + + let uniqRcvCodecs = []; + for (let rc of rcvCodecs) { + let ix = sndCodecs.findIndex(sc => rc.mimeType === sc.mimeType && rc.clockRate === sc.clockRate && rc.sdpFmtpLine === sc.sdpFmtpLine); + if (ix === -1) + uniqRcvCodecs.push(rc); + } + + /* + AudioCodesUA.ac_log(`AC: ${type} codec-filter original [sender]: ${AudioCodesUA.instance._cf_str(sndCodecs)}`); + AudioCodesUA.ac_log(`AC: ${type} codec-filter original [receiver]: ${AudioCodesUA.instance._cf_str(rcvCodecs)}`); + AudioCodesUA.ac_log(`AC: ${type} codec-filter original [unique receiver]: ${AudioCodesUA.instance._cf_str(uniqRcvCodecs)}`); + */ + + let codecs = sndCodecs.concat(uniqRcvCodecs); + AudioCodesUA.ac_log(`AC: ${type} codec-filter original: ${AudioCodesUA.instance._cf_str(codecs)}\n(receiver: ${uniqRcvCodecs.length})`); + + if (filter.remove && filter.remove.length > 0) { + let len0 = codecs.length; + codecs = codecs.filter((codec) => !AudioCodesUA.instance._cf_match(codec, filter.remove)); + if (codecs.length < len0) { + AudioCodesUA.ac_log(`AC: ${type} codec-filter remaining: ${AudioCodesUA.instance._cf_str(codecs)}`); + } + } + + if (filter.priority && filter.priority.length > 0) { + let newCodecs = []; + for (let cf of filter.priority) { + let found = AudioCodesUA.instance._cf_find(cf, codecs); + if (found.length === 0) + continue; + newCodecs = newCodecs.concat(found); + codecs = codecs.filter(codec => !found.includes(codec)); + } + codecs = newCodecs.concat(codecs); + AudioCodesUA.ac_log(`AC: ${type} codec-filter changed priority: ${AudioCodesUA.instance._cf_str(codecs)}`); + } + + transceiver.setCodecPreferences(codecs); + return; + } catch (e) { + AudioCodesUA.ac_log('AC: codec filter exception', e); + return; + } + } + // end of codec filter + + _convertIceList(ices) { + let result = []; + for (let entry of ices) { + // convert short form of stun server to object + if (typeof entry === 'string') { + entry = { 'urls': 'stun:' + entry }; + } + result.push(entry); + } + return result; + } + + _randomToken(size) { + let t = ''; + for (let i = 0; i < size; i++) + t += Math.floor(Math.random() * 36).toString(36); + return t; + } + + _detectBrowser() { + try { + let ua = navigator.userAgent; + this.browser = 'other'; + this.browserName = ua; + this.browserVersion = 0; + if (navigator.mozGetUserMedia) { + this.browser = 'firefox' + this.browserName = ua.match(/Firefox\/([.\d]+)$/)[0]; + this.browserVersion = parseInt(ua.match(/Firefox\/(\d+)\./)[1], 10); + } else if (navigator.webkitGetUserMedia) { // Only works for secure connection. + this.browser = 'chrome'; + this.browserName = ua.match(/Chrom(e|ium)\/([\d]+)/)[0]; + this.browserVersion = parseInt(ua.match(/Chrom(e|ium)\/(\d+)\./)[2], 10); + // Detect known Chromium based browsers: Edge, Opera etc - classified as 'chrome' + let ual = ua.toLowerCase(); + for (let ix = 0; ix < this.chromiumBased.length; ix++) { + let s = this.chromiumBased[ix].s; + let f = ual.indexOf(s); + if (f !== -1) { + let v = ual.substring(f + s.length).match(/([.\d]+)/)[1]; + this.browserName += ' (' + this.chromiumBased[ix].n + '/' + v + ')'; + break; + } + } + } else if (window.safari) { + this.browser = 'safari'; + this.browserName = 'Safari/' + ua.match(/Version\/([.\d]+)/)[1]; + this.browserVersion = parseInt(ua.match(/Version\/(\d+)\./)[1], 10); + } else if (ua.indexOf('Edge/') !== -1) { // legacy Edge + this.browser = 'other'; + this.browserName = ua.match(/Edge\/([.\d]+)/)[0]; + this.browserVersion = parseInt(ua.match(/Edge\/(\d+).(\d+)$/)[2], 10); + } + + if (/iPad|iPhone|iPod/.test(ua)) { + this.browserName = ua; + if (ua.includes('CriOS')) { + this.browser = 'chrome'; + this.browserVersion = parseInt(ua.match(/CriOS\/(\d+)\./)[1], 10); + } else if (ua.includes('FxiOS')) { + this.browser = 'firefox'; + this.browserVersion = parseInt(ua.match(/FxiOS\/(\d+)\./)[1], 10); + } else { + this.browser = 'safari'; + this.browserVersion = parseInt(ua.match(/Version\/(\d+)\./)[1], 10); + } + } + } catch (e) { + AudioCodesUA.ac_log('AC: Browser detection error', e); + this.browser = 'other'; + this.browserName = navigator.userAgent; + this.browserVersion = 0; + } + } + + // windows,android,macos,ios,linux,other + _detectOS() { + this._detectOS1(); + if (this.os !== 'other') + return; + this._detectOS2(); + } + + _detectOS1() { + try { + let p = navigator.userAgentData ? navigator.userAgentData.platform : false; + if (!p) + return; + p = p.toLowerCase(); + if (p === 'windows' || p === 'linux' || p === 'android' || p === 'macos') + this.os = p; + } catch (e) { + AudioCodesUA.ac_log('AC: detectOS1 error', e); + this.os = 'other'; + } + } + + _detectOS2() { + try { + let p = navigator.platform; + if (!p) + return; + p = p.toLowerCase(); + if (p.startsWith('win')) { + this.os = 'windows'; + } else if (p.startsWith('android')) { + this.os = 'android'; + } else if (p.startsWith('linux')) { + if (navigator.userAgent.includes('Android')) { + this.os = 'android'; // for Android Firefox + } else { + this.os = 'linux'; + } + } else if (p.startsWith('mac')) { + this.os = 'macos'; + } else if (/ipad|iphone|ipod/.test(p)) { + this.os = 'ios'; + } + } catch (e) { + AudioCodesUA.ac_log('AC: detectOS2 error', e); + this.os = 'other'; + } + } + + _mediaConstraints(sendVideo) { + let inst = AudioCodesUA.instance; + let constraints = { 'audio': inst.constraints.audio }; + if (sendVideo) { + constraints.video = inst.constraints.video; + } + return constraints; + } + + _callOptions(sendVideo, isOutgoing, extraHeaders = null, extraOptions = null) { + let options = {}; + let inst = AudioCodesUA.instance; + + // No need since Chrome 102, see: https://groups.google.com/g/discuss-webrtc/c/85e-f_siCws + if (inst.browser === 'chrome' && inst.networkPriority) { + options = { rtcConstraints: { optional: [{ googDscp: true }] } }; + } + + if (extraOptions !== null) { + Object.assign(options, extraOptions); + } + + options.mediaConstraints = inst._mediaConstraints(sendVideo); + + if (options.pcConfig === undefined) { + options.pcConfig = {}; + } + options.pcConfig.iceServers = inst.serverConfig.iceServers; + + if (extraHeaders !== null) { + extraHeaders = extraHeaders.slice(); + } + if (inst.oauthToken !== null && inst.oauthTokenUseInInvite && isOutgoing) { + if (extraHeaders === null) { + extraHeaders = []; + } + extraHeaders.push('Authorization: Bearer ' + inst.oauthToken); + } + if (extraHeaders !== null) { + options.extraHeaders = extraHeaders; + } + return options; + } + + /** + * videoOption = phone.AUDIO, phone.VIDEO or false(=phone.AUDIO) true(=phone.VIDEO) + */ + call(videoOption, call_to, extraHeaders = null, extraOptions = null) { + // Convert boolean value to Symbol + if (videoOption === false) + videoOption = AudioCodesUA.instance.AUDIO; + else if (videoOption === true) + videoOption = AudioCodesUA.instance.VIDEO; + + if (typeof videoOption !== 'symbol' || ![AudioCodesUA.instance.AUDIO, AudioCodesUA.instance.VIDEO].includes(videoOption)) + throw new TypeError(`Illegal videoOption=${videoOption.toString()}`); + + call_to = call_to.replace(/\s+/g, ''); // remove whitespaces. + AudioCodesUA.ac_log(`AC: call ${videoOption.description} to ${call_to}`); + let options = this._callOptions(videoOption === AudioCodesUA.instance.VIDEO, true, extraHeaders, extraOptions); + let js_session = this.jssipUA.call(call_to, options); + if (options.mediaStream) + js_session._localMediaStreamLocallyGenerated = true; // to enable jssip close the stream + let ac_session = js_session.data.ac_session; + ac_session._setEnabledSendVideo(videoOption === AudioCodesUA.instance.VIDEO); + if (videoOption === AudioCodesUA.instance.VIDEO) + ac_session._setEnabledReceiveVideo(true); + return ac_session; + } + + sendMessage(to, body, contentType = 'text/plain') { + AudioCodesUA.ac_log(`AC: sendMessage to: ${to} "${body}"`); + return new Promise((resolve, reject) => { + let options = { + contentType: contentType, + eventHandlers: { succeeded: (e) => resolve(e), failed: (e) => reject(e) } + } + this.jssipUA.sendMessage(to, body, options); + }); + } + + isScreenSharingSupported() { + return AudioCodesUA.instance.getWR().hasDisplayMedia(); + } + + openScreenSharing() { + if (!this.isScreenSharingSupported()) { + AudioCodesUA.ac_log('AC: openScreenSharing: screen sharing is not supported in the browser'); + return Promise.reject('Screen sharing is not supported'); + } + AudioCodesUA.ac_log('AC: openScreenSharing()'); + return AudioCodesUA.instance.getWR().getDisplayMedia() + .then(stream => { + return stream; + }) + .catch(e => { + AudioCodesUA.ac_log('AC: openScreenSharing() error', e); + throw e; + }); + } + + closeScreenSharing(displayStream) { + AudioCodesUA.ac_log('AC: closeScreenSharing()'); + if (displayStream) { + let tracks = displayStream.getVideoTracks(); + if (tracks.length == 0) + return; + let track = tracks[0]; + if (track.readyState === 'live') { + track.stop(); + track.dispatchEvent(new Event("ended")); + } + } + } + + setNetworkPriority(p) { + AudioCodesUA.ac_log(`AC: setNetworkPriority ${p}`); + if (p !== undefined && p !== 'high' && p !== 'medium' && p !== 'low' && p !== 'very-low') + throw new TypeError(`setNetworkPriority: illegal value: ${p}`); + this.networkPriority = p; + } + + subscribe(...args) { + return this.jssipUA.subscribe(...args); + } + + notify(...args) { + return this.jssipUA.notify(...args); + } + + /** + * Experimental JsSIP extension: another SIP credential. + * Use it before phone.init() if SUBSCRIBE authentication is different from REGISTER + */ + addCredential(credential) { + if (!credential.realm || !credential.password || !credential.username) + throw new TypeError('wrong credential structure'); + this.credentials.push(credential); + } +} + +/* + * Session + */ +class AudioCodesSession { + constructor(js_session) { + this.js_session = js_session; + this.data = { + _user: null, + _display_name: null, + _create_time: null, + _initial: true, + _remoteMediaStream: null, + _wasUsedSendVideo: false, + _screenSharing: null, + _video: { + send: false, + receive: false, + enabledSend: false, + enabledReceive: false + } + }; + js_session.data.ac_session = this; + } + + getRTCPeerConnection() { return this.js_session.connection; } + getRTCLocalStream() { return this.js_session._localMediaStream; } + getRTCRemoteStream() { return this.data['_remoteMediaStream']; } + isEstablished() { return this.js_session.isEstablished(); } + isTerminated() { return this.js_session.isEnded(); } + isOutgoing() { return this.js_session.direction === 'outgoing'; } + isAudioMuted() { return this.js_session.isMuted().audio; } + isVideoMuted() { return this.js_session.isMuted().video; } + wasAccepted() { return this.data['_accepted'] === true; } + + getReplacesHeader() { + if (!this.js_session.isEstablished() || !this.js_session._dialog) { + AudioCodesUA.ac_log('getReplacesHeader(): call is not established'); + return null; + } + let id = this.js_session._dialog.id; + return `${id.call_id};to-tag=${id.remote_tag};from-tag=${id.local_tag}`; + } + + muteAudio(set) { + AudioCodesUA.ac_log(`AC: muteAudio() arg=${set} `); + if (set) { + this.js_session.mute({ audio: true, video: false }); + } else { + this.js_session.unmute({ audio: true, video: false }); + } + } + + muteVideo(set) { + AudioCodesUA.ac_log(`AC: muteVideo() arg=${set} `); + if (set) { + this.js_session.mute({ audio: false, video: true }); + } else { + this.js_session.unmute({ audio: false, video: true }); + } + } + + sendDTMF(tone) { + let useWebRTC = AudioCodesUA.instance.dtmfUseWebRTC; + if (useWebRTC && AudioCodesUA.instance.browser === 'safari') { + let dtmfSender = AudioCodesUA.instance.getWR().connection.getDTMFSender(this.js_session.connection); + if (dtmfSender === undefined) { // If used obsolete Safari send DTMF as SIP INFO + useWebRTC = false; + } + } + AudioCodesUA.ac_log(`AC: sendDTMF() tone=${tone} ${useWebRTC ? '[RFC2833]' : '[INFO]'}`); + let options = { + duration: AudioCodesUA.instance.dtmfDuration, + interToneGap: AudioCodesUA.instance.dtmfInterToneGap, + transportType: useWebRTC ? 'RFC2833' : 'INFO' + }; + this.js_session.sendDTMF(tone, options); + } + + sendInfo(body, contentType, extraHeaders = null) { + AudioCodesUA.ac_log('AC: sendInfo()', body, contentType, extraHeaders); + let options = (extraHeaders !== null) ? { extraHeaders: extraHeaders } : undefined; + this.js_session.sendInfo(contentType, body, options); + } + + duration() { + let start = this.js_session.start_time; + if (!start) + return 0; + let end = this.js_session.end_time; + if (!end) + end = new Date(); + return Math.floor((end.getTime() - start.getTime()) / 1000); + } + + // Call actual video state. + // Set by initial INVITE and re-INVITEs. HOLD re-INVITEs will be ignored. + hasSendVideo() { return this.data._video.send; } + hasReceiveVideo() { return this.data._video.receive; } + hasVideo() { return this.hasSendVideo() && this.hasReceiveVideo(); } + getVideoState() { + if (this.hasSendVideo() && this.hasReceiveVideo()) return "sendrecv"; + if (this.hasSendVideo()) return "sendonly"; + if (this.hasReceiveVideo()) return "recvonly"; + return "inactive"; + } + _setVideoState(send, receive) { + AudioCodesUA.ac_log(`AC: _setVideoState(send=${send}, receive=${receive})`); + this.data._video.send = send; + this.data._video.receive = receive; + } + + // Call enabled to send/receive video + hasEnabledSendVideo() { return this.data._video.enabledSend; } + hasEnabledReceiveVideo() { return this.data._video.enabledReceive; } + getEnabledVideoState() { + if (this.hasEnabledSendVideo() && this.hasEnabledReceiveVideo()) return "sendrecv"; + if (this.hasEnabledSendVideo()) return "sendonly"; + if (this.hasEnabledReceiveVideo()) return "recvonly"; + return "inactive"; + } + _setEnabledSendVideo(enable) { + AudioCodesUA.ac_log(`AC: _setEnabledSendVideo(${enable})`); + this.data._video.enabledSend = enable; + } + _setEnabledReceiveVideo(enable) { + AudioCodesUA.ac_log(`AC: _setEnabledReceiveVideo(${enable})`); + this.data._video.enabledReceive = enable; + } + + /** + * videoOption = phone.AUDIO, phone.VIDEO, phone.RECVONLY_VIDEO + * or false (=phone.AUDIO), true(=phone.VIDEO) + */ + answer(videoOption, extraHeaders = null, extraOptions = null) { + if (this.data['_answer_called']) { + AudioCodesUA.ac_log('AC: answer() is already called. [Ignored]'); + return; + } + this.data['_answer_called'] = true; + + // Convert boolean value to Symbol + if (videoOption === false) + videoOption = AudioCodesUA.instance.AUDIO; + else if (videoOption === true) + videoOption = AudioCodesUA.instance.VIDEO; + + if (typeof videoOption !== 'symbol' || ![AudioCodesUA.instance.AUDIO, AudioCodesUA.instance.RECVONLY_VIDEO, AudioCodesUA.instance.VIDEO].includes(videoOption)) + throw new TypeError(`Illegal videoOption=${videoOption.toString()}`); + + AudioCodesUA.ac_log(`AC: ${videoOption.description} answer`); + + if (!this.hasVideo() && (videoOption === AudioCodesUA.instance.RECVONLY_VIDEO || videoOption === AudioCodesUA.instance.VIDEO)) { + AudioCodesUA.ac_log('AC: incoming INVITE without video, so answer can be only "audio"'); + videoOption = AudioCodesUA.instance.AUDIO; + } + + // video call - audio answer: no sound in answer phone. + if (this.hasVideo() && videoOption === AudioCodesUA.instance.AUDIO) { + let ua = AudioCodesUA.instance; + let br = ua.browser; + let md = ua.modes; + let vr = ua.browserVersion; + if (br === 'firefox' && md.video_call_audio_answer_firefox_fix) { + this.data['_video_call_audio_answer_firefox'] = true; + } else if (br === 'safari') { + if ((md.video_call_audio_answer_safari_fix === true && vr < 14) || md.video_call_audio_answer_safari_fix === 'force') + this.data['_video_call_audio_answer_safari'] = true; + } + } + + // Set enabled and current send/receive video flags + switch (videoOption) { + case AudioCodesUA.instance.AUDIO: + this._setEnabledSendVideo(false); + if (this.data['_incoming_invite_without_sdp']) { + this._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo); + } else { + this._setEnabledReceiveVideo(this.hasVideo() ? false : AudioCodesUA.instance.enableAddVideo); + } + this._setVideoState(false, false); + break; + case AudioCodesUA.instance.VIDEO: + this._setEnabledSendVideo(true); + this._setEnabledReceiveVideo(true); + this._setVideoState(true, true); + break; + case AudioCodesUA.instance.RECVONLY_VIDEO: + this._setEnabledSendVideo(false); + this._setEnabledReceiveVideo(true); + this._setVideoState(false, true); + break; + } + + let options = AudioCodesUA.instance._callOptions(videoOption === AudioCodesUA.instance.VIDEO, false, extraHeaders, extraOptions); + + Promise.resolve() + .then(() => { + if (!options.mediaStream) { + return AudioCodesUA.instance.getWR().getUserMedia(options.mediaConstraints) + } else { + return options.mediaStream; + } + }) + .then((stream) => { + options.mediaStream = stream; + this.js_session._localMediaStreamLocallyGenerated = true; // to enable jssip close the stream + AudioCodesUA.ac_log('AC: answer options:', options); + this.js_session.answer(options); + }) + .catch((e) => { + AudioCodesUA.ac_log('AC: getUserMedia failure', e); + this.reject(488); + }); + } + + reject(statusCode = 486, extraHeaders = null) { + AudioCodesUA.ac_log('AC: reject()'); + try { + let options = { status_code: statusCode } + if (extraHeaders) { + options.extraHeaders = extraHeaders; + } + this.js_session.terminate(options); + } catch (e) { + AudioCodesUA.ac_log('AC: call reject error:', e); + } + } + + terminate() { + AudioCodesUA.ac_log('AC: terminate()'); + try { + this.js_session.terminate(); + } catch (e) { + AudioCodesUA.ac_log('AC: call terminate error:', e); + } + } + + redirect(callTo, statusCode = 302, extraHeaders = null) { + AudioCodesUA.ac_log(`AC: redirect() callTo=${callTo}`); + try { + let contact = 'Contact: ' + AudioCodesUA.instance.jssipUA.normalizeTarget(callTo); + let options = { + status_code: statusCode, + extraHeaders: [contact] + }; + if (extraHeaders) { + options.extraHeaders.push(...extraHeaders); + } + + this.js_session.terminate(options); + } catch (e) { + AudioCodesUA.ac_log('AC: call redirect error:', e); + } + } + + isLocalHold() { return this.js_session.isOnHold().local; } + isRemoteHold() { return this.js_session.isOnHold().remote; } + isReadyToReOffer() { return this.js_session._isReadyToReOffer(); } + + hold(set) { + AudioCodesUA.ac_log(`AC: hold(${set})`); + return new Promise((resolve, reject) => { + let method = set ? this.js_session.hold : this.js_session.unhold; + let result = method.call(this.js_session, {}, () => { + AudioCodesUA.ac_log('AC: hold()/unhold() is completed'); + resolve(); + }); + + if (!result) { + AudioCodesUA.ac_log('AC: hold()/unhold() failed'); + reject(); + } + }); + } + + /* + * To enable/disable receive video + * Set enabledReceiveVideo flag, and set corresponding mode for video transceiver (if exists) + * Returns true if video transceiver exists, in the case call: reInvite({ showStreams: true }) + */ + enableReceiveVideo(enable) { + this._setEnabledReceiveVideo(enable); + let conn = this.getRTCPeerConnection(); + let vt = AudioCodesUA.instance.getWR().connection.getTransceiver(conn, 'video'); + if (vt !== null) { + let dir = this.getEnabledVideoState(); + AudioCodesUA.instance.getWR().transceiver.setDirection(vt, dir); + } + AudioCodesUA.ac_log(`AC: enableReceiveVideo(${enable}) ${vt !== null ? "" : "No video transceiver"}`); + return vt !== null; + } + + /* + * For audio call. Start sending video + Get user media with camera stream. Add video. Send re-INVITE with video. + In re-INVITE can be added extra headers using options.extraHeaders. + By default set enabled to receive video from other side. + to disable set options.enabledReceiveVideo = false; + */ + startSendingVideo(options = {}) { + let enabledReceiveVideo = options && options.enabledReceiveVideo !== false; // undefined | true => true + if (this.hasEnabledSendVideo()) { + AudioCodesUA.ac_log('AC: startSendingVideo(). Already started'); + return Promise.reject('video already started'); + } + AudioCodesUA.ac_log('AC: startSendingVideo()'); + return AudioCodesUA.instance.getWR().getUserMedia({ video: AudioCodesUA.instance.constraints.video }) + .catch(e => { + AudioCodesUA.ac_log('AC: startSendingVideo() getUserMedia failure', e); + throw e; + }) + .then(videoStream => { + // to allow JsSIP automatically stop stream after call termination. + let videoTrack = videoStream.getVideoTracks()[0]; + let localStream = this.getRTCLocalStream(); + localStream.addTrack(videoTrack); + this._setEnabledSendVideo(true); + this._setEnabledReceiveVideo(enabledReceiveVideo); + let wasUsedSendVideo = this.data['_wasUsedSendVideo']; + return AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(), this.getRTCLocalStream(), videoTrack, this.hasEnabledReceiveVideo(), wasUsedSendVideo) + .then(() => { + if (!wasUsedSendVideo && AudioCodesUA.instance.codecFilter) { + AudioCodesUA.instance._cf_filter('video', this, AudioCodesUA.instance.codecFilter.video); + } + }) + .catch(e => { + AudioCodesUA.ac_log('AC: startSendingVideo(). Adding video error', e); + throw e; + }); + }) + .then(() => { + return this._renegotiate(options); + }); + } + + /* + * For video call. + * Stop sending video. Remove video. Send re-INVITE with inactive video. + * Optionally can be used options.extraHeaders + */ + stopSendingVideo(options = {}) { + if (!this.hasEnabledSendVideo()) { + AudioCodesUA.ac_log('AC: stopSendingVideo(). Already stopped'); + return Promise.reject('video already stopped'); + } + AudioCodesUA.ac_log('AC: stopSendingVideo()'); + return AudioCodesUA.instance.getWR().connection.removeVideo(this.getRTCPeerConnection(), this.getRTCLocalStream()) + .catch(e => { + AudioCodesUA.ac_log('AC: stopSendingVideo(). Remove video error', e); + throw e; + }) + .then(() => { + this._setEnabledSendVideo(false); + this.data['_wasUsedSendVideo'] = true; + return this._renegotiate(options); + }); + } + + _doRenegotiate(options) { + if (this.js_session.isEnded()) { + return Promise.reject('call is ended'); + } + return new Promise(resolve => { + if (!this.js_session.renegotiate(options, () => resolve(true))) { + return resolve(false); + } + }); + } + + _renegotiate(options, attemptsLeft = 30, delay = 500) { + AudioCodesUA.ac_log(`AC: _renegotiate() attemptsLeft=${attemptsLeft}`); + return this._doRenegotiate(options) + .then(done => { + if (done) { + AudioCodesUA.ac_log('AC: Renegotiation success'); + return true; + } + if (attemptsLeft <= 1) { + throw new Error('Too many attempts'); + } + return new Promise(resolve => setTimeout(resolve, delay)) + .then(() => { + return this._renegotiate(options, attemptsLeft - 1, delay); + }); + }) + .catch(e => { + AudioCodesUA.ac_log('AC: Renegotiation failed', e); + throw e; + }); + } + + sendReInvite(options = {}) { + AudioCodesUA.ac_log('AC: sendReInvite()'); + return this._renegotiate(options) + .then(() => { + if (options.showStreams) { + let localStream = this.getRTCLocalStream(); + let remoteStream = this.getRTCRemoteStream(); + AudioCodesUA.ac_log('AC>>: [after send re-INVITE] callShowStreams', this, localStream, remoteStream); + AudioCodesUA.instance.listeners.callShowStreams(this, localStream, remoteStream); + } + }); + } + + // screen sharing. + startScreenSharing(stream, modes = { localScreenSharing: true, enabledReceiveVideo: true, separateVideo: false }) { + AudioCodesUA.ac_log('AC: startScreenSharing'); + if (!stream) + return Promise.reject('missed stream argument'); + if (this.data['_screenSharing']) + return Promise.reject('the call is already using screen-sharing'); + let enabledReceiveVideo = modes && modes.enabledReceiveVideo !== false; // undefined | true => true + let track = stream.getVideoTracks()[0]; + let onEnded = undefined; + if (modes.localScreenSharing) { + onEnded = this._onEndedScreenSharingTrack.bind(this); + track.addEventListener('ended', onEnded); + } + this.data['_screenSharing'] = { + stream: stream, // screen sharing video track + onended: onEnded, // callback + hadSendVideo: this.hasSendVideo() // if was video before screen sharing + }; + let wasUsedSendVideo = this.data['_wasUsedSendVideo']; + this._setEnabledSendVideo(true); + this._setEnabledReceiveVideo(enabledReceiveVideo); + + return AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(), this.getRTCLocalStream(), track, this.hasEnabledReceiveVideo(), wasUsedSendVideo) + .then(() => { + if (!wasUsedSendVideo && AudioCodesUA.instance.codecFilter) { + AudioCodesUA.instance._cf_filter('video', this, AudioCodesUA.instance.codecFilter.video); + } + }) + .catch(e => { + AudioCodesUA.ac_log('AC: startScreenSharing() error', e); + this.data['_screenSharing'] = null; + throw e; + }) + .then(() => { + let options = { extraHeaders: ['X-Screen-Sharing: on'] }; + return this._renegotiate(options); + }); + } + + stopScreenSharing() { + AudioCodesUA.ac_log('AC: stopScreenSharing'); + if (!this.data['_screenSharing']) + return Promise.reject('the call does not use screen-sharing'); + return this._onEndedScreenSharing('called stopScreenSharing()'); + } + + isScreenSharing() { + return !!this.data['_screenSharing']; + } + + doesScreenSharingReplaceCamera() { + let sh = this.data['_screenSharing']; + return sh && sh.hadSendVideo; + } + + _onEndedScreenSharingTrack() { + return this._onEndedScreenSharing('track ended'); + } + + _onEndedScreenSharing(reason) { + let screenSharing = this.data['_screenSharing']; + this.data['_screenSharing'] = null; + let stream = screenSharing.stream; + let onended = screenSharing.onended; + if (stream && onended) { + let track = stream.getVideoTracks()[0]; + track.removeEventListener('ended', onended); + } + return Promise.resolve() + .then(() => { + if (!this.isTerminated()) { // Restore previously sending video (if was) and send re-INVITE. + let connection = this.getRTCPeerConnection(); + let localStream = this.getRTCLocalStream(); + let options = { extraHeaders: ['X-Screen-Sharing: off'] }; + if (screenSharing.hadSendVideo) { + AudioCodesUA.ac_log('AC: screen sharing stopped - restore previously sending video track'); + AudioCodesUA.instance.getWR().connection.replaceSenderTrack(connection, 'video', localStream); + return this._renegotiate(options); + } else { + AudioCodesUA.ac_log('AC: screen sharing stopped - stop send video'); + return this.stopSendingVideo(options); + } + } + }) + .then(() => { + if (AudioCodesUA.instance.listeners.callScreenSharingEnded) { + AudioCodesUA.ac_log(`AC>>: callScreenSharingEnded "${reason}"`, this, stream); + AudioCodesUA.instance.listeners.callScreenSharingEnded(this, stream); + } + }); + } + + /* + * To restore call "remote hold" state after page reload. + */ + setRemoteHoldState() { + this.js_session._remoteHold = true; + } + + /* + * Blind or attended transfer + */ + sendRefer(callTo, probeSession = null) { + if (!AudioCodesUA.instance.listeners.transferorNotification) + throw new Error('transferorNotification listener is missed'); + + let ac_session = this; + let options = { + eventHandlers: { + requestSucceeded() { + AudioCodesUA.ac_log('AC>>: transferorNotification progress [REFER accepted]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 0); + }, + requestFailed() { + AudioCodesUA.ac_log('AC>>: transferorNotification failed [REFER failed]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, -1); + }, + trying() { + AudioCodesUA.ac_log('AC>>: transferorNotification progress [NOTIFY 1xx]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 0); + }, + progress() { + AudioCodesUA.ac_log('AC>>: transferorNotification progress [NOTIFY 1xx]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 0); + }, + accepted() { + AudioCodesUA.ac_log('AC>>: transferorNotification success [NOTIFY 2xx]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 1); + }, + failed() { + AudioCodesUA.ac_log('AC>>: transferorNotification failed [NOTIFY >= 300]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, -1); + } + } + }; + + // REFER with header ReferTo with replaces parameter + if (probeSession !== null) { + options.replaces = probeSession.js_session; + } + + this.js_session.refer(callTo, options); + } +} + +// SDP parser +class AudioCodesSDP { + constructor(sdp) { + this.start = []; + this.media = []; + let lines = sdp.split('\n').map(l => l.trim()).filter(l => l.length > 0); + let current = this.start; + for (let line of lines) { + if (line.startsWith('m=')) { + current = []; + this.media.push(current); + } + current.push(line); + } + } + getMedia(type) { + for (let m of this.media) + if (m.length > 0 && m[0].startsWith('m=' + type)) + return m; + return null; + } + checkSendRecv(line) { + switch (line) { + case 'a=sendrecv': + return 'sendrecv'; + case 'a=sendonly': + return 'sendonly'; + case 'a=recvonly': + return 'recvonly'; + case 'a=inactive': + return 'inactive'; + default: + return null; + } + } + getMediaDirectionValue(type) { + let media = this.getMedia(type); + if (media === null) + return null; + + let t; + let result = 'sendrecv'; + for (let line of this.start) { + if ((t = this.checkSendRecv(line)) !== null) { + result = t; + break; + } + } + for (let line of media) { + if ((t = this.checkSendRecv(line)) !== null) { + result = t; + break; + } + } + return result; + } + getMediaDirection(type, remote) { + let dir = this.getMediaDirectionValue(type); + switch (dir) { + case 'sendrecv': + return [true, true, dir]; + case 'sendonly': + return remote ? [false, true, dir] : [true, false, dir]; + case 'recvonly': + return remote ? [true, false, dir] : [false, true, dir]; + case null: + case 'inactive': + return [false, false, dir]; + } + } + toString() { + let result = this.start; + for (let m of this.media) { + result = result.concat(m); + } + return result.join('\r\n') + '\r\n'; + } +} + +// WebRTC Wrapper +let AudioCodesWebRTCWrapper = { + getUserMedia(constraints) { + AudioCodesUA.ac_log(`[webrtc] getUserMedia constraints=${JSON.stringify(constraints)}`); + return navigator.mediaDevices.getUserMedia(constraints); + }, + + hasDisplayMedia() { + return navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia; + }, + + getDisplayMedia() { + AudioCodesUA.ac_log('[webrtc] getDisplayMedia'); + return navigator.mediaDevices.getDisplayMedia({ video: true }); + }, + + mediaDevices: { + enumerateDevices() { + if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) + return Promise.reject('WebRTC is not supported'); + return navigator.mediaDevices.enumerateDevices() + }, + + addDeviceChangeListener(listener) { + if (!navigator.mediaDevices) + return; + navigator.mediaDevices.addEventListener('devicechange', listener); + }, + + removeDeviceChangeListener(listener) { + if (!navigator.mediaDevices) + return; + navigator.mediaDevices.removeEventListener('devicechange', listener); + } + }, + + + // Check WebRTC support. Check presence of microphone and camera + checkAvailableDevices() { + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) + return Promise.reject('WebRTC is not supported'); + let cam = false, + mic = false, + spkr = false; + return navigator.mediaDevices.enumerateDevices() + .then((deviceInfos) => { + deviceInfos.forEach(function (d) { + switch (d.kind) { + case 'videoinput': + cam = true; + break; + case 'audioinput': + mic = true; + break; + case 'audiooutput': + spkr = true; + break; + } + }) + if (navigator.webkitGetUserMedia === undefined) { // Not Chrome + spkr = true; + } + if (!spkr) + return Promise.reject('Missing a speaker! Please connect one and reload'); + if (!mic) + return Promise.reject('Missing a microphone! Please connect one and reload'); + + return Promise.resolve(cam); + }) + }, + + transceiver: + { + setDirection(transceiver, direction) { + let kind = ''; + if (transceiver.sender.track !== null) + kind = transceiver.sender.track.kind; + else if (transceiver.receiver.track !== null) + kind = transceiver.receiver.track.kind; + AudioCodesUA.ac_log(`[webrtc] set ${kind} transceiver direction=${direction}`); + transceiver.direction = direction; + } + }, + + stream: + { + // For logging + getInfo(stream) { + function getTrackInfo(tr) { return tr.length > 0 ? tr[0].enabled.toString() : '-'; } + if (stream === null) + return Promise.resolve('stream is null'); + return Promise.resolve(`audio: ${getTrackInfo(stream.getAudioTracks())} video: ${getTrackInfo(stream.getVideoTracks())}`) + }, + }, + + connection: + { + // For logging + getTransceiversInfo(connection) { + function getTransInfo(t) { return t === null ? 'none' : `d=${t.direction} c=${t.currentDirection}`; } + let ts = connection.getTransceivers(); + let at = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'audio'); + let vt = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'video'); + return Promise.resolve(`(${ts.length}) audio ${getTransInfo(at)} video ${getTransInfo(vt)}`); + }, + + getTransceiver(connection, kind) { + for (let t of connection.getTransceivers()) { + if (t.sender !== null && t.sender.track !== null && t.sender.track.kind === kind) { + return t; + } + if (t.receiver !== null && t.receiver.track !== null && t.receiver.track.kind === kind) { + return t; + } + } + return null; + }, + + addEventListener(connection, eventName, listener) { + AudioCodesUA.ac_log(`[webrtc] Connection addEventListener ${eventName}`); + if (eventName !== 'track') + return Promise.reject(`Wrong event name: ${eventName}`); + connection.addEventListener(eventName, listener); + return Promise.resolve(); + }, + + getDTMFSender(connection) { + let sender = connection.getSenders().find((s) => { + return s.track && s.track.kind === 'audio'; + }); + if (sender && sender.dtmf) + return sender.dtmf; + return undefined; + }, + + addVideo(connection, localStream, videoTrack, enabledReceiveVideo, wasUsedSendVideo) { + AudioCodesUA.ac_log('[webrtc] Connection addVideo'); + let vt = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'video'); + if (vt !== null) { + let dir = enabledReceiveVideo ? 'sendrecv' : 'sendonly'; + AudioCodesUA.instance.getWR().transceiver.setDirection(vt, dir); + } + + if (vt === null || (vt.sender.track === null && !wasUsedSendVideo)) { + AudioCodesUA.ac_log('[webrtc] addVideo (connection addTrack)'); + connection.addTrack(videoTrack, localStream); + return Promise.resolve(true); + } else { + AudioCodesUA.ac_log('[webrtc] addVideo (video transceiver sender replaceTrack)'); + return vt.sender.replaceTrack(videoTrack) + .then(() => { + return false; + }); + } + }, + + removeVideo(connection, localStream) { + AudioCodesUA.ac_log('[webrtc] Connection removeVideo'); + let vt = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'video'); + if (vt === null) + return Promise.reject('no video transceiver found'); + connection.removeTrack(vt.sender); + + if (localStream) { + for (let track of localStream.getVideoTracks()) { + localStream.removeTrack(track); + track.stop(); + } + } + return Promise.resolve(); + }, + + replaceSenderTrack(connection, kind, stream) { + AudioCodesUA.ac_log(`[webrtc] ReplaceSenderTrack ${kind}`); + let foundSender = null; + for (let sender of connection.getSenders()) { + if (sender.track !== null && sender.track.kind === kind) { + foundSender = sender; + break; + } + } + if (foundSender === null) + return Promise.reject(`No ${kind} sender`); + let tracks = (kind === 'audio') ? stream.getAudioTracks() : stream.getVideoTracks(); + if (tracks.length === 0) + return Promise.reject(`No ${kind} track`); + return foundSender.replaceTrack(tracks[0]); + }, + + // "types" example ['outboud-rtp', 'inbound-rtp'] + getStats(connection, types) { + let str = ''; + return connection.getStats(null) + .then(report => { + report.forEach(now => { + if (types.includes(now.type)) { + str += ' {'; + let first = true; + for (let key of Object.keys(now)) { + if (first) first = false; + else str += ','; + str += (key + '=' + now[key]); + } + str += '} \r\n'; + } + }); + return str; + }) + } + } +} \ No newline at end of file diff --git a/js/acapi.1.19.0_es5.js b/js/acapi.1.19.0_es5.js new file mode 100644 index 0000000..c5bb392 --- /dev/null +++ b/js/acapi.1.19.0_es5.js @@ -0,0 +1,2884 @@ +'use strict'; + +/* + * AudioCodes WebRTC API v1.19.0 + * © 2023 AudioCodes Ltd. All rights reserved. + * + */ +function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } +function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } +function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } +function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } +function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var AudioCodesUA = /*#__PURE__*/function () { + function AudioCodesUA() { + _classCallCheck(this, AudioCodesUA); + this._isInitialized = false; + this.serverConfig = {}; + this.account = { + user: null, + userAuth: null, + displayName: null, + password: null, + registerExpires: 600, + useSessionTimer: false + }; + // constraints for current browser + this.constraints = { + audio: true, + video: true + }; + this.chromiumBased = [{ + n: 'Edge', + s: 'edg/' + }, { + n: 'Opera', + s: 'opr/' + }, { + n: 'Samsung', + s: 'samsungbrowser/' + }, { + n: 'Yandex', + s: 'yabrowser/' + }]; + this.modes = { + // default values for modes and fixes. + video_call_audio_answer_firefox_fix: true, + // use fix + video_call_audio_answer_safari_fix: true, + // true: for Safari versions < 14. ('force' for all versions) + ice_timeout_fix: 2000, + // ICE gathering timeout (ms) + chrome_rtp_timeout_fix: 13, + // Currently Chrome don't set 'failed' status to icestate + sbc_ha_pairs_mode: undefined, + // Set e.g. 15 (seconds) when used multiple URL of HA SBC pairs + ringing_header_mode: undefined, + // Add extra header(s) to response 180 ringing + sbc_switch_register5xx_mode: true, + // Switch SBC if received REGISTER 5xx. + cache_register_auth_mode: true, + // Next REGISTER includes authorization header from previous one. + check_remote_sdp_mode: true // Check remote SDP at every re-negotiation, and if need print 'AC:SDP' warning + }; + + this.credentials = []; + this.listeners = {}; + this.registerExtraHeaders = null; + this.jssipUA = null; + this.browser = ''; // chrome, firefox, safari, other + this.browserVersion = 0; // version major number. + this.browserName = ''; // name with version + this.os = 'other'; // windows,android,macos,ios,linux,other + this.reconnectMin = 2; + this.reconnectMax = 30; + this.u17 = undefined; + this.activeCalls = 0; + this.wsPingStarted = false; + this.wsSocket = null; + this.wsOnMessage = null; + this.wsPingMs = 0; + this.wsOrigPingMs = 0; + this.wsThrottlingPingMs = 0; + this.wsVisibility = false; + this.wsCall = false; + this.wsLog = 0; + this.wsPongTimeout = true; + this.wsIsThrottling = false; + this.wsPingJob = null; + this.wsPingTime = null; + this.wsNextPingTime = null; + this.wsPongReceived = false; + this.wsPongSupported = null; + this.wsPongTimeoutTime = null; + this.wsPongDelays = null; + this.wsPongDelaysIx = 0; + this.wsPongReport = 0; + this.wsPongReportCounter = 0; + this.wsPongDist = false; + this.wsIsPingDebugLog = false; + this.dtmfUseWebRTC = true; + this.dtmfDuration = 250; + this.dtmfInterToneGap = 250; + this.enableAddVideo = false; + this.oauthToken = null; + this.oauthTokenUseInInvite = true; + this.networkPriority = undefined; + AudioCodesUA.ac_log = console.log; + AudioCodesUA.js_log = null; + if (AudioCodesUA.instance === undefined) AudioCodesUA.instance = this; + this._detectBrowser(); + this._detectOS(); + this.webrtcapi = AudioCodesWebRTCWrapper; + this.replacedCall = null; + this.codecFilter = null; + this.AUDIO = Symbol('audio'); + this.VIDEO = Symbol('video'); + this.RECVONLY_VIDEO = Symbol('recvonly_video'); + return AudioCodesUA.instance; + } + _createClass(AudioCodesUA, [{ + key: "version", + value: function version() { + return '1.19.0'; + } + }, { + key: "getBrowserName", + value: function getBrowserName() { + return this.browserName; + } + }, { + key: "getBrowser", + value: function getBrowser() { + return this.browser; + } + }, { + key: "getBrowserVersion", + value: function getBrowserVersion() { + return this.browserVersion; + } + }, { + key: "getOS", + value: function getOS() { + return this.os; + } + }, { + key: "getWR", + value: function getWR() { + return this.webrtcapi; + } + }, { + key: "checkAvailableDevices", + value: function checkAvailableDevices() { + return this.getWR().checkAvailableDevices(); + } + }, { + key: "getServerAddress", + value: function getServerAddress() { + if (this.wsSocket === null) return null; + var url = this.wsSocket.url; + if (url.endsWith('/')) url = url.slice(0, -1); + return url; + } + }, { + key: "setOAuthToken", + value: function setOAuthToken(token) { + var useInInvite = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + this.oauthToken = token; + this.oauthTokenUseInInvite = useInInvite; + this.setRegisterExtraHeaders(this.registerExtraHeaders); + } + }, { + key: "setUserAgent", + value: function setUserAgent(name) { + this.u17 = name; + } + }, { + key: "setConstraints", + value: function setConstraints(browser, type, value) { + var br = this.browser; + var bs = this.browser + '|' + this.os; + if (browser !== null && browser !== br && browser !== bs) { + AudioCodesUA.ac_log("AC: setConstraints ".concat(browser, " - ignored, no current browser")); + return; + } + AudioCodesUA.ac_log("AC: setConstraints ".concat(browser, " ").concat(type, " ").concat(JSON.stringify(value))); + if (type !== 'audio' && type !== 'video') throw new TypeError("Wrong type: ".concat(type)); + this.constraints[type] = value; + } + }, { + key: "setConstraint", + value: function setConstraint(type, name, value) { + if (value !== null && value !== undefined) { + AudioCodesUA.ac_log("AC: setConstraint ".concat(type, " ").concat(name, "=").concat(JSON.stringify(value))); + } else { + AudioCodesUA.ac_log("AC: setConstraint remove ".concat(type, " ").concat(name)); + } + if (type !== 'audio' && type !== 'video') throw new TypeError("Wrong type: ".concat(type)); + if (value !== null && value !== undefined) { + if (this.constraints[type] === true) this.constraints[type] = {}; + this.constraints[type][name] = value; + } else { + if (this.constraints[type] !== true && this.constraints[type] !== false) { + delete this.constraints[type][name]; + if (Object.keys(this.constraints[type]).length === 0) this.constraints[type] = true; + } + } + } + }, { + key: "setBrowsersConstraints", + value: function setBrowsersConstraints(obj) { + var br = this.browser; + var bs = this.browser + '|' + this.os; + for (var key in obj) { + if (key !== br && key !== bs) continue; + var val = obj[key]; + if (val.audio !== undefined) this.setConstraints(key, 'audio', val.audio); + if (val.video !== undefined) this.setConstraints(key, 'video', val.video); + } + } + }, { + key: "setCodecFilter", + value: function setCodecFilter(obj) { + if (obj) { + AudioCodesUA.ac_log("AC: setCodecFilter ".concat(JSON.stringify(obj))); + this.codecFilter = this._cf_unpack(obj); + } + } + }, { + key: "setServerConfig", + value: function setServerConfig(serverAddresses, serverDomain) { + var iceServers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; + this.serverConfig = { + addresses: serverAddresses, + domain: serverDomain, + iceServers: this._convertIceList(iceServers) + }; + AudioCodesUA.ac_log("AC: setServerConfig() ".concat(JSON.stringify(this.serverConfig))); + } + }, { + key: "setReconnectIntervals", + value: function setReconnectIntervals(minSeconds, maxSeconds) { + AudioCodesUA.ac_log("AC: setReconnectIntervals min=".concat(minSeconds, " max=").concat(maxSeconds)); + this.reconnectMin = minSeconds; + this.reconnectMax = maxSeconds; + } + }, { + key: "setAccount", + value: function setAccount(user, displayName, password, authUser) { + if (displayName === undefined || displayName === null || displayName.length === 0) displayName = undefined; + if (authUser === undefined || authUser === null || authUser.length === 0) authUser = user; + var a = this.account; + a.user = user; + a.displayName = displayName; + a.password = password; + a.authUser = authUser; + } + }, { + key: "setRegisterExpires", + value: function setRegisterExpires(seconds) { + AudioCodesUA.ac_log("AC: setRegisterExpires=".concat(seconds)); + this.account.registerExpires = seconds; + } + }, { + key: "setUseSessionTimer", + value: function setUseSessionTimer(use) { + AudioCodesUA.ac_log("AC: setUseSessionTimer=".concat(use)); + this.account.useSessionTimer = use; + } + + // null value means use default (see value set in constructor for dtmfDuration, dtmtInterToneGap, dtmfSendDelay). + }, { + key: "setDtmfOptions", + value: function setDtmfOptions(useWebRTC) { + var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var interToneGap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + AudioCodesUA.ac_log("AC: setDtmfOptions useWebRTC=".concat(useWebRTC, " duration=").concat(duration, " interToneGap=").concat(interToneGap)); + this.dtmfUseWebRTC = useWebRTC; + if (duration !== null) this.dtmfDuration = duration; + if (interToneGap !== null) this.dtmfInterToneGap = interToneGap; + } + }, { + key: "setEnableAddVideo", + value: function setEnableAddVideo(enable) { + AudioCodesUA.ac_log("AC: setEnableAddVideo=".concat(enable)); + this.enableAddVideo = enable; + } + }, { + key: "getEnableAddVideo", + value: function getEnableAddVideo() { + return this.enableAddVideo; + } + }, { + key: "getAccount", + value: function getAccount() { + return this.account; + } + }, { + key: "setListeners", + value: function setListeners(listeners) { + AudioCodesUA.ac_log('AC: setListeners()'); + for (var _i = 0, _arr = ['loginStateChanged', 'outgoingCallProgress', 'callTerminated', 'callConfirmed', 'callShowStreams', 'incomingCall', 'callHoldStateChanged']; _i < _arr.length; _i++) { + var m = _arr[_i]; + if (m in listeners) continue; + throw new Error("".concat(m, " listener is missed")); + } + this.listeners = listeners; + } + }, { + key: "setAcLogger", + value: function setAcLogger(loggerFunction) { + AudioCodesUA.ac_log = loggerFunction; + } + }, { + key: "setJsSipLogger", + value: function setJsSipLogger(loggerFunction) { + AudioCodesUA.js_log = loggerFunction; + } + }, { + key: "isInitialized", + value: function isInitialized() { + return this._isInitialized; + } + }, { + key: "setModes", + value: function setModes() { + var modes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + AudioCodesUA.ac_log("AC: setModes() ".concat(JSON.stringify(modes))); + Object.assign(this.modes, modes); + this._normalizeModes(); + } + }, { + key: "_normalizeModes", + value: function _normalizeModes() { + function undef(v, m) { + return typeof v === 'number' && v <= m ? undefined : v; + } + var m = this.modes; + m.sbc_ha_pairs_mode = undef(m.sbc_ha_pairs_mode, 0); + m.chrome_rtp_timeout_fix = undef(m.chrome_rtp_timeout_fix, 0); + } + }, { + key: "init", + value: function init() { + var autoLogin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + AudioCodesUA.ac_log("AC: init() autoLogin=".concat(autoLogin)); + if (this._isInitialized) return; + this._isInitialized = true; + JsSIP.debug.enable('JsSIP:*'); + JsSIP.debug.formatArgs = function () { + if (AudioCodesUA.js_log) this.log = AudioCodesUA.js_log; + }; + var sockets = []; + var _iterator = _createForOfIteratorHelper(this.serverConfig.addresses), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var address = _step.value; + if (address instanceof Array) { + // 'address' or ['address', weight] + sockets.push({ + socket: new JsSIP.WebSocketInterface(address[0]), + weight: address[1] + }); + } else { + sockets.push(new JsSIP.WebSocketInterface(address)); + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + var config = { + sockets: sockets, + uri: 'sip:' + this.account.user + '@' + this.serverConfig.domain, + contact_uri: 'sip:' + this.account.user + '@' + this._randomToken(12) + '.invalid;transport=ws', + authorization_user: this.account.authUser, + password: this.account.password, + register: autoLogin, + session_timers: this.account.useSessionTimer, + register_expires: this.account.registerExpires, + user_agent: this.u17, + connection_recovery_min_interval: this.reconnectMin, + connection_recovery_max_interval: this.reconnectMax + }; + if (this.account.displayName && this.account.displayName.length > 0) { + config.display_name = this.account.displayName; + } + this.jssipUA = new JsSIP.UA(config); + this.setRegisterExtraHeaders(this.registerExtraHeaders); + this._setUACallbacks(); + AudioCodesUA.ac_log("AC: applied SDK modes: ".concat(JSON.stringify(this.modes, function (k, v) { + return typeof v === 'undefined' ? '' : v; + }))); + this.jssipUA.modes = this.modes; + var _iterator2 = _createForOfIteratorHelper(this.credentials), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var credential = _step2.value; + this.jssipUA.addCredential(credential); + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + this.credentials = []; + this.jssipUA.start(); + } + }, { + key: "deinit", + value: function deinit() { + this._isInitialized = false; + this.jssipUA && this.jssipUA.stop(); + } + }, { + key: "setRegisterExtraHeaders", + value: function setRegisterExtraHeaders(extraHeaders) { + this.registerExtraHeaders = extraHeaders; + if (this.jssipUA) { + var headers = extraHeaders !== null ? extraHeaders : []; + if (this.oauthToken !== null) { + headers = headers.slice(); + headers.push("Authorization: Bearer ".concat(this.oauthToken)); + } + this.jssipUA.registrator().setExtraHeaders(headers); + } + } + }, { + key: "getRegisterExtraHeaders", + value: function getRegisterExtraHeaders() { + return this.registerExtraHeaders; + } + }, { + key: "login", + value: function login() { + AudioCodesUA.ac_log('AC: login()'); + this.jssipUA.register(); + } + }, { + key: "logout", + value: function logout() { + AudioCodesUA.ac_log('AC: logout()'); + if (this.jssipUA.isRegistered()) { + this.jssipUA.unregister(); + } + } + }, { + key: "switchSBC", + value: function switchSBC() { + var unregister = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + AudioCodesUA.ac_log('AC: switchSBC()'); + return this.jssipUA.switchSBC(unregister); + } + }, { + key: "getNumberOfSBC", + value: function getNumberOfSBC() { + return this.jssipUA.getNumberOfSBC(); + } + + // Keep alive websocket ping/pong (CRLF) + }, { + key: "setWebSocketKeepAlive", + value: function setWebSocketKeepAlive(pingInterval) { + var pongTimeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var timerThrottlingBestEffort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + var pongReport = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; + var pongDist = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; + AudioCodesUA.ac_log("AC: setWebSocketKeepAlive pingInterval=".concat(pingInterval, " pongTimeout=").concat(pongTimeout) + " timerThrottlingBestEffort=".concat(JSON.stringify(timerThrottlingBestEffort), " pongReport=").concat(pongReport, " pongDist=").concat(pongDist)); + if (typeof pingInterval !== 'number' || typeof pongTimeout !== 'boolean') throw new TypeError('setWebSocketKeepAlive: wrong type of first or second argument'); + this.wsPingMs = this.wsOrigPingMs = pingInterval * 1000; + this.wsPongTimeout = pongTimeout; + this.wsPongReport = pongReport; + this.wsPongDist = pongDist; + this.wsPongReportCounter = 0; + this.wsIsThrottling = false; + var params; + if (timerThrottlingBestEffort === true) params = { + log: 0, + chrome: { + interval: 1, + visibility: true, + call: true, + log: 1 + } + };else if (timerThrottlingBestEffort === false) params = { + log: 0 + };else params = timerThrottlingBestEffort; + var p = params[this.browser]; + this.wsThrottlingPingMs = p && p.interval !== undefined ? p.interval * 1000 : 0; + this.wsVisibility = p && p.visibility !== undefined ? p.visibility : false; + this.wsCall = p && p.call !== undefined ? p.call : false; + this.wsLog = p && p.log !== undefined ? p.log : params.log; + this.wsPongDelays = new Array(this.wsPongReport > 0 ? this.wsPongReport : 50); + this.wsPongDelaysIx = 0; + if (this.wsOrigPingMs !== 0 && this.wsThrottlingPingMs !== 0 && this.wsVisibility) document.addEventListener('visibilitychange', this._onVisibilityChange.bind(this)); + } + }, { + key: "_pingLog", + value: function _pingLog() { + return " (ping=".concat(this.wsPingMs / 1000, " sec)"); + } + }, { + key: "_visibilityLog", + value: function _visibilityLog(changed) { + var m = 'AC: keep-alive: Page is ' + (document.hidden ? 'hidden' : 'visible'); + if (document.hidden) { + if (this.wsCall) m += ', ' + (this.activeCalls === 0 ? 'no active call' : 'active call'); + m += ' and ' + (this.wsIsThrottling ? 'was' : 'was not') + ' trottling'; + } + if (changed) m += this._pingLog(); + AudioCodesUA.ac_log(m); + } + }, { + key: "_activeCallsLog", + value: function _activeCallsLog(changed) { + var m = "AC: keep-alive: ".concat(this.activeCalls === 0 ? 'Call ended' : 'Call started'); + if (this.activeCalls === 0) { + if (this.wsVisibility) m += ', page is ' + (document.hidden ? 'hidden' : 'visible');else m + ', page visibility is ignored'; + m += ' and ' + (this.wsIsThrottling ? 'was' : 'was not') + ' trottling'; + } + if (changed) m += this._pingLog(); + AudioCodesUA.ac_log(m); + } + }, { + key: "_onActiveCallsChange", + value: function _onActiveCallsChange(n) { + this.activeCalls += n; + if (!this.wsCall || this.wsPingMs === 0 || this.wsThrottlingPingMs === 0) return; + if (this.activeCalls < 0) AudioCodesUA.ac_log('Warning: keep-alive: activeCalls < 0'); + if (this.activeCalls === 0) { + // open call -> no call + if ((!this.wsVisibility || document.hidden) && this.wsIsThrottling && this.wsPingMs < this.wsThrottlingPingMs) { + this.wsPingMs = this.wsThrottlingPingMs; + this._activeCallsLog(true); + return; + } + if (this.wsLog >= 2) this._activeCallsLog(false); + } else if (this.activeCalls === 1 && n > 0) { + // no call -> open call + if (this.wsPingMs > this.wsOrigPingMs) { + this.wsPingMs = this.wsOrigPingMs; + this._activeCallsLog(true); + return; + } + if (this.wsLog >= 2) this._activeCallsLog(false); + } + } + }, { + key: "_onVisibilityChange", + value: function _onVisibilityChange() { + if (!this.wsVisibility || this.wsPingMs === 0 || this.wsThrottlingPingMs === 0) return; + if (document.hidden) { + if (this.wsCall && this.activeCalls === 0 && this.wsIsThrottling && this.wsPingMs < this.wsThrottlingPingMs) { + this.wsPingMs = this.wsThrottlingPingMs; + this._visibilityLog(true); + return; + } + if (this.wsLog >= 2) this._visibilityLog(false); + } else { + if (this.wsPingMs > this.wsOrigPingMs) { + this.wsPingMs = this.wsOrigPingMs; + this._visibilityLog(true); + return; + } + if (this.wsLog >= 2) this._visibilityLog(false); + } + } + }, { + key: "_onMessageHook", + value: function _onMessageHook(arg) { + if (arg.data === '\r\n') { + this._onPong(); + } else { + this.wsOnMessage(arg); + } + } + }, { + key: "_onPong", + value: function _onPong() { + if (!this.wsPingStarted) return; + this.wsPongReceived = true; + if (this.wsPongSupported === null) { + AudioCodesUA.ac_log('AC: keep-alive: Server supports CRLF pong'); + this.wsPongSupported = true; + } + var delay; + if (this.wsPongTimeoutTime !== null) { + delay = Date.now() - this.wsPongTimeoutTime; + this.wsPongTimeoutTime = null; + AudioCodesUA.ac_log("AC: keep-alive: Received pong that exceeded the timeout, delay=".concat(delay)); + } else { + delay = Date.now() - this.wsPingTime; + } + + // Reset the ping timer from a networking callback to avoid Chrome timer throttling from causing timers to run once a minute + var nextPing = this.wsPingMs - delay; + if (nextPing < 0) { + AudioCodesUA.ac_log("AC: nextPing calculated to ".concat(nextPing, "ms, so resetting to 0ms.")); + nextPing = 0; + } + if (this.wsPingJob !== null) { + clearTimeout(this.wsPingJob); + } + this.wsPingJob = setTimeout(this._sendPing.bind(this), nextPing); + + // Save pong delays statistics. + this.wsPongDelays[this.wsPongDelaysIx] = delay; + this.wsPongDelaysIx = this.wsPongDelaysIx + 1; + if (this.wsPongDelaysIx === this.wsPongDelays.length) this.wsPongDelaysIx = 0; + if (this.wsPongReport > 0) this.wsPongReportCounter++; + } + }, { + key: "_onPongTimeout", + value: function _onPongTimeout(pingMs) { + AudioCodesUA.ac_log("AC: keep-alive: Pong timeout (not received within ".concat(pingMs / 1000, " seconds)")); + AudioCodesUA.ac_log("AC: keep-alive: Previous pongs statistics: ".concat(this._createPongReport(true))); + if (this.wsPongTimeout) { + AudioCodesUA.ac_log('AC: keep-alive: Close websocket connection'); + this._stopWsKeepAlive(); + + // If directly call this.wsSocket.close() in Chrome it will take 60 seconds when URL exists and inaccessible. + // Instead we call socket close in not main thread and fire _onClose callback. + var socket = this.wsSocket; + socket.onopen = undefined; + socket.onerror = undefined; + socket.onclose = undefined; + socket.onmessage = undefined; + setTimeout(function () { + try { + socket.close(); + } catch (e) { + AudioCodesUA.ac_log('AC: Close websocket error', e); + } + }, 0); + this.wsWebSocketInterface._ws = null; + this.wsWebSocketInterface._onClose.call(this.wsWebSocketInterface, { + wasClean: false, + code: 1001, + reason: 'Going Away' + }); + } else { + AudioCodesUA.ac_log("AC: keep-alive: Warning: websocket is not closed, because pongTimeout=false"); + } + } + }, { + key: "_sendPing", + value: function _sendPing() { + try { + var now = Date.now(); + if (this.wsPingTime !== null) { + var delay = now - this.wsNextPingTime; + if (this.wsLog >= 3) AudioCodesUA.ac_log("AC: keep-alive: timer deviation (ms): ".concat(delay)); + var pingMs = this.wsPingMs; + if (Math.abs(delay) >= 10000) { + if (this.wsLog > 0 || !this.wsIsThrottling) { + AudioCodesUA.ac_log("AC: keep-alive detected timer throttling: ".concat(Math.round(delay / 1000), " seconds ").concat(delay > 0 ? 'later' : 'earlier')); + if (this.wsLog === 0) AudioCodesUA.ac_log('AC: keep-alive: The next timer throttling will not be shown in the logs, because log==0'); + } + this.wsIsThrottling = true; + if (this.wsPingMs < this.wsThrottlingPingMs) { + this.wsPingMs = this.wsThrottlingPingMs; + AudioCodesUA.ac_log("AC: keep-alive: ping interval increased ".concat(this._pingLog())); + } + } + if (this.wsPongSupported === null && !this.wsPongReceived) { + AudioCodesUA.ac_log('AC: keep-alive: Server does not support CRLF pong.'); + this.wsPongSupported = false; + } + if (this.wsPongSupported && !this.wsPongReceived && this.wsPongTimeoutTime === null) { + this._onPongTimeout(pingMs); + if (this.wsPongTimeout) return; + this.wsPongTimeoutTime = this.wsPingTime; + } + } + this.wsPingTime = now; + this.wsNextPingTime = this.wsPingTime + this.wsPingMs; + this.wsPongReceived = false; + if (this.wsSocket.readyState === WebSocket.OPEN) { + if (this.wsIsPingDebugLog) AudioCodesUA.ac_log('AC: send ping'); + this.wsSocket.send('\r\n\r\n'); + } else { + AudioCodesUA.ac_log("AC: keep-alive: Warning: Cannot send Ping, websocket state=".concat(this.wsSocket.readyState)); + } + this.wsPingJob = setTimeout(this._sendPing.bind(this), this.wsPingMs); + if (this.wsPongReport > 0 && this.wsPongReportCounter >= this.wsPongReport) { + this.wsPongReportCounter = 0; + AudioCodesUA.ac_log("AC: keep-alive: Pong statistics: ".concat(this._createPongReport(this.wsPongDist))); + } + } catch (e) { + AudioCodesUA.ac_log('AC: keep-alive: send ping error', e); + } + } + }, { + key: "_startWsKeepAlive", + value: function _startWsKeepAlive() { + var transport = this.jssipUA._transport; + this.wsWebSocketInterface = transport.socket; + this.wsSocket = this.wsWebSocketInterface._ws; + if (this.wsPingMs === 0) return; + this.wsOnMessage = this.wsSocket.onmessage; + this.wsSocket.onmessage = this._onMessageHook.bind(this); + this._stopWsKeepAlive(); + this.wsPingTime = null; + this.wsPingStarted = true; + this.wsPongSupported = null; + this.wsPingJob = setTimeout(this._sendPing.bind(this), this.wsPingMs); + } + }, { + key: "_stopWsKeepAlive", + value: function _stopWsKeepAlive() { + this.wsPingStarted = false; + if (this.wsPingJob !== null) { + clearTimeout(this.wsPingJob); + this.wsPingJob = null; + } + } + }, { + key: "_createPongReport", + value: function _createPongReport(dist) { + var dval; + var dstr = ''; + var dover = false; + var min = 1000000; + var max = 0; + if (dist) dval = new Array(this.wsPingMs / 1000 * 4).fill(0); + var pongs = 0; + for (var ix = 0; ix < this.wsPongDelays.length; ix++) { + var delay = this.wsPongDelays[ix]; + if (delay === undefined) continue; + pongs++; + if (delay < min) min = delay; + if (delay > max) max = delay; + if (dist) { + var n = Math.floor(delay / 250); + if (n >= dval.length) { + n = dval.length - 1; + dover = true; + } + dval[n]++; + } + } + if (dist) { + dstr = '\r\npongs distribution (1/4 second step): '; + for (var i = 0; i < dval.length; i++) { + dstr += dval[i].toString(); + if (i !== dval.length - 1) dstr += (i + 1) % 4 === 0 ? ',' : ' '; + } + if (dover) dstr += ' (+)'; + } + return "pongs=".concat(pongs, " delay=").concat(min, "..").concat(max, " ms").concat(dstr); + } + }, { + key: "setPingDebugLog", + value: function setPingDebugLog(isDebug) { + this.wsIsPingDebugLog = isDebug; + } + // end of ping/pong keep-alive + + // Catch some JsSIP events, and call corresponding API callbacks. + }, { + key: "_setUACallbacks", + value: function _setUACallbacks() { + var _this = this; + this.jssipUA.on('connected', function () { + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "connected"'); + _this._startWsKeepAlive(); + _this.listeners.loginStateChanged(false, 'connected', null); + }); + this.jssipUA.on('disconnected', function () { + _this._stopWsKeepAlive(); + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "disconnected"'); + _this.listeners.loginStateChanged(false, 'disconnected', null); + }); + this.jssipUA.on('registered', function (e) { + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=true "login"'); + _this.listeners.loginStateChanged(true, 'login', e.response); + }); + this.jssipUA.on('unregistered', function (e) { + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "logout"'); + _this.listeners.loginStateChanged(false, 'logout', e.response); + }); + this.jssipUA.on('registrationFailed', function (e) { + var statusCode = e.response ? e.response.status_code : 0; + if (statusCode >= 300 && statusCode < 400) { + var contact = e.response.parseHeader('contact'); + if (contact) { + var cu = contact.uri; + var url = 'wss://' + cu.host; + if (cu.port && cu.port !== 443) { + url += ':' + cu.port.toString(); + } + AudioCodesUA.ac_log("AC: registerRedirect(\"".concat(url, "\")")); + if (_this.jssipUA.registerRedirect(url)) return; // skip 'login failed' callback + } else { + AudioCodesUA.ac_log('AC: 3xx response without "Contact" is ignored'); + } + } else if (statusCode >= 500 && statusCode < 600 && AudioCodesUA.instance.modes.sbc_switch_register5xx_mode) { + if (AudioCodesUA.instance.switchSBC(false)) return; // skip 'login failed', 'logout' callbacks + } + + AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "login failed"'); + _this.listeners.loginStateChanged(false, 'login failed', e.response ? e.response : null); + }); + if (this.listeners.incomingMessage) { + this.jssipUA.on('newMessage', function (e) { + if (e.originator !== 'remote') return; // ignore outgoing message. + AudioCodesUA.ac_log('AC>>: incomingMessage', e); + // null, from, content-type?, body?, request + _this.listeners.incomingMessage(null, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + }); + } + if (this.listeners.incomingNotify) { + this.jssipUA.on('sipEvent', function (e) { + AudioCodesUA.ac_log('AC>>: incoming out of dialog NOTIFY', e); + // null, event, from, content-type? , body?, request + var taken = _this.listeners.incomingNotify(null, e.event ? e.event.event : null, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + if (!taken) { + e.request.reply(481); + } + }); + } + if (this.listeners.incomingSubscribe) { + this.jssipUA.on('newSubscribe', function (e) { + var subs = e.request; + var ev = subs.parseHeader('event'); + var accepts = subs.getHeaders('accept'); + AudioCodesUA.ac_log('AC>>: incomingSubscribe', subs, ev.event, accepts); + var code = _this.listeners.incomingSubscribe(subs, ev.event, accepts); + if (code > 0) subs.reply(code); + }); + } + this.jssipUA.on('newRTCSession', function (e) { + AudioCodesUA.ac_log("AC: event ".concat(e.originator === 'remote' ? 'incoming' : 'outgoing', " \"newRTCSession\""), e); + var call = new AudioCodesSession(e.session); + // In-dialog incoming NOTIFY. + // Works only in modified jssip where added the event + call.js_session.on('sipEvent', function (e) { + if (!AudioCodesUA.instance.listeners.incomingNotify) return; + var ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: incoming NOTIFY', ac_session, e); + // call?, event, from, content-type? , body?, request. return true when notify accepted. + e.taken = AudioCodesUA.instance.listeners.incomingNotify(ac_session, e.event ? e.event.event : null, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + }); + call.js_session.on('newInfo', function (e) { + if (!AudioCodesUA.instance.listeners.incomingInfo) return; + if (e.originator === 'local') return; + var ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: incoming INFO', ac_session, e); + // call, from, content-type? , body?, request + AudioCodesUA.instance.listeners.incomingInfo(ac_session, AudioCodesUA.instance._get_from(e.request), AudioCodesUA.instance._get_content_type(e.request), e.request.body, e.request); + }); + call.js_session.on('replaces', function (e) { + AudioCodesUA.instance.replacedCall = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: incoming INVITE with Replaces. This call will be replaced:', this.data.ac_session); + e.accept(); + }); + call.js_session.on('sdp', function (e) { + AudioCodesUA.instance._sdp_checking(this, e); + }); + call.js_session.on('connecting', function (r) { + AudioCodesUA.ac_log('AC>>: connecting'); + var filter = AudioCodesUA.instance.codecFilter; + if (filter) { + AudioCodesUA.instance._cf_filter('audio', this.data.ac_session, filter.audio); + AudioCodesUA.instance._cf_filter('video', this.data.ac_session, filter.video); + } + }); + call.js_session.on('reinvite', function (e) { + if (!AudioCodesUA.instance.listeners.callIncomingReinvite) return; + var ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: callIncomingReinvite start'); + AudioCodesUA.instance.listeners.callIncomingReinvite(ac_session, true, e.request); + e.callback = function () { + AudioCodesUA.ac_log('AC>>: callIncomingIncomingReinvite end'); + AudioCodesUA.instance.listeners.callIncomingReinvite(ac_session, false, null); + }; + }); + call.js_session.on('hold', function (e) { + var ac_session = this.data.ac_session; + var isRemote = e.originator === 'remote'; + AudioCodesUA.ac_log("AC>>: callHoldStateChanged isHold=true isRemote=".concat(isRemote, " session:"), ac_session); + AudioCodesUA.instance.listeners.callHoldStateChanged(ac_session, true, isRemote); + }); + call.js_session.on('unhold', function (e) { + var ac_session = this.data.ac_session; + var isRemote = e.originator === 'remote'; + AudioCodesUA.ac_log("AC>>: callHoldStateChanged isHold=false isRemote=".concat(isRemote, " session:"), ac_session); + AudioCodesUA.instance.listeners.callHoldStateChanged(ac_session, false, isRemote); + }); + call.js_session.on('progress', function (e) { + if (e.originator === 'remote') { + var ac_session = this.data.ac_session; + AudioCodesUA.ac_log('AC>>: outgoingCallProgress', ac_session); + AudioCodesUA.instance.listeners.outgoingCallProgress(ac_session, e.response); + } + }); + call.js_session.on('failed', function (e) { + var ac_session = this.data.ac_session; + var contact = null; + if (e.cause === 'Redirected' && e.message && e.message.headers) { + var nameAddress = e.message.parseHeader('Contact'); + if (nameAddress) { + contact = nameAddress.uri.toString(); + } + } + AudioCodesUA.ac_log('AC>>: callTerminated (failed)', ac_session, e.cause, contact); + AudioCodesUA.instance.listeners.callTerminated(ac_session, e.message, e.cause, contact); + }); + call.js_session.on('accepted', function (e) { + var ac_session = this.data.ac_session; + ac_session.data['_accepted'] = true; // means sent or received OK + if (e.originator === 'remote') { + // Outgoing call + ac_session.data['_ok_response'] = e.response; + } + }); + + // Remove listener that close replaced session when replaces confirmed + if (e.originator === 'remote' && AudioCodesUA.instance.replacedCall !== null) call.js_session.removeAllListeners('confirmed'); + call.js_session.on('confirmed', function () { + var ac_session = this.data.ac_session; + var okResponse = null; + var cause; + if ('_ok_response' in ac_session.data) { + okResponse = ac_session.data['_ok_response']; + delete ac_session.data['_ok_response']; + cause = 'ACK sent'; + } else { + cause = 'ACK received'; + } + + // Video call /audio answer, no sound on answer side issue. Firefox workaround + if (call.data['_video_call_audio_answer_firefox']) { + call.data['_video_call_audio_answer_firefox'] = false; + AudioCodesUA.ac_log('AC: [video call/audio answer] Firefox workaround. Send re-INVITE'); + call.sendReInvite({ + showStreams: true + }); + } + AudioCodesUA.ac_log('AC>>: callConfirmed', ac_session, cause); + AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance, 1); + AudioCodesUA.instance.listeners.callConfirmed(ac_session, okResponse, cause); + }); + call.js_session.on('ended', function (e) { + var ac_session = this.data.ac_session; + if (ac_session.data['_screenSharing']) { + ac_session._onEndedScreenSharing.call(ac_session, 'call terminated'); + } + AudioCodesUA.ac_log('AC>>: callTerminated (ended)', ac_session, e.cause); + AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance, -1); + AudioCodesUA.instance.listeners.callTerminated(ac_session, e.message, e.cause); + }); + call.js_session.on('refer', function (e) { + if (!AudioCodesUA.instance.listeners.transfereeCreatedCall) { + AudioCodesUA.ac_log('AC>>: incoming REFER rejected, because transfereeCreatedCall is not set'); + e.reject(); + } else { + var ac_session = this.data.ac_session; + var accept; + if (AudioCodesUA.instance.listeners.transfereeRefer) { + accept = AudioCodesUA.instance.listeners.transfereeRefer(ac_session, e.request); + } else { + accept = true; + } + if (accept) { + AudioCodesUA.ac_log('AC>>: incoming REFER accepted'); + // Set new call video according current call + var sendVideo; + if (ac_session.isScreenSharing()) { + sendVideo = ac_session.doesScreenSharingReplaceCamera(); + } else { + sendVideo = ac_session.hasSendVideo(); + } + var options = AudioCodesUA.instance._callOptions(sendVideo, true); + e.accept(function (e) { + e.data['_created_by_refer'] = ac_session; + }, options); + } else { + AudioCodesUA.ac_log('AC>>: incoming REFER rejected'); + e.reject(); + } + } + }); + + // Set the call flag according phone setting. + call._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo); + + // If connection is already exists set listener. + // otherwise wait until connection will be created. + if (call.js_session.connection) { + AudioCodesUA.instance._set_connection_listener(call); + AudioCodesUA.ac_log('AC: connection exists, set "track" listener'); + } else { + AudioCodesUA.ac_log('AC: peer connection does not exist, wait creation'); + call.js_session.on('peerconnection', function () { + AudioCodesUA.instance._set_connection_listener(call); + AudioCodesUA.ac_log('AC: [event connection] connection created, set "track" listener'); + }); + } + var remote; + if (e.originator === 'remote') { + remote = e.request.from; + } else { + remote = e.request.to; + } + + // set call data + call.data['_user'] = remote.uri.user; + call.data['_host'] = remote.uri.host; + call.data['_display_name'] = remote.display_name; // optional + call.data['_create_time'] = new Date(); + if (e.originator === 'remote') { + var replacedCall = null; + if (AudioCodesUA.instance.replacedCall !== null) { + replacedCall = AudioCodesUA.instance.replacedCall; + AudioCodesUA.instance.replacedCall = null; + } + + // Incoming call. Set video flags according m=video in SDP. + var send, recv, hasSDP; + if (e.request.body) { + hasSDP = true; + var sdp = new AudioCodesSDP(e.request.body); + var _sdp$getMediaDirectio = sdp.getMediaDirection('video', true); + var _sdp$getMediaDirectio2 = _slicedToArray(_sdp$getMediaDirectio, 2); + send = _sdp$getMediaDirectio2[0]; + recv = _sdp$getMediaDirectio2[1]; + } else { + hasSDP = false; + call.data['_incoming_invite_without_sdp'] = true; + send = recv = true; // to enable answer with or without video. + AudioCodesUA.ac_log('AC: warning incoming INVITE without SDP'); + } + call._setVideoState(send, recv); + AudioCodesUA.ac_log("AC>>: incomingCall ".concat(call.hasVideo() ? 'video' : 'audio', " from \"").concat(call.data._display_name, "\" ").concat(call.data._user), call, replacedCall); + AudioCodesUA.instance.listeners.incomingCall(call, e.request, replacedCall, hasSDP); + } else { + // e.originator === 'local' + if (call.js_session.data['_created_by_refer']) { + AudioCodesUA.ac_log('AC>>: outgoing call created by REFER'); + call.data['_created_by_refer'] = call.js_session.data['_created_by_refer']; + AudioCodesUA.instance.listeners.transfereeCreatedCall(call); + } else { + AudioCodesUA.ac_log('AC>>: outgoing call created by phone.call()'); + } + } + }); + } + }, { + key: "_get_from", + value: function _get_from(msg) { + return { + user: msg.from.uri.user, + host: msg.from.uri.host, + displayName: msg.from.display_name ? msg.from.display_name : null + }; + } + }, { + key: "_get_content_type", + value: function _get_content_type(msg) { + var ct = msg.headers['Content-Type']; + return ct && ct.length > 0 ? ct[0].parsed : null; + } + }, { + key: "_set_connection_listener", + value: function _set_connection_listener(call) { + AudioCodesUA.instance.getWR().connection.addEventListener(call.js_session.connection, 'track', function (e) { + AudioCodesUA.ac_log("AC>>: \"track\" event kind= ".concat(e.track.kind), e); + // save call remote stream + if (e.streams.length > 0) { + // if track is in stream + var stream = e.streams[0]; + AudioCodesUA.ac_log("AC: set call remote stream id=".concat(stream.id), call); + call.data['_remoteMediaStream'] = stream; + } else { + AudioCodesUA.ac_log('AC: Warning "track" event without stream'); + } + if (e.track.kind === 'video') { + if (!call.hasEnabledReceiveVideo()) { + // Video call - audio answer, no sound on answer side issue. Patch for Safari. + if (call.data['_video_call_audio_answer_safari']) { + e.track.onmute = function () { + AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Fired video track "mute" event. Call callShowStream'); + e.track.onmute = null; + var localStream = call.getRTCLocalStream(); + var remoteStream = call.getRTCRemoteStream(); + AudioCodesUA.ac_log('AC>>: callShowStreams', call, localStream, remoteStream); + AudioCodesUA.instance.listeners.callShowStreams(call, localStream, remoteStream); + }; + AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Set video track "mute" event listener'); + call.data['_video_call_audio_answer_safari'] = false; + } + AudioCodesUA.ac_log('AC>>: event "track" video and !hasEnabledReceiveVideo therefore change transceiver direction.', call); + var vt = AudioCodesUA.instance.getWR().connection.getTransceiver(call.js_session.connection, 'video'); + if (vt !== null) { + var dir = call.hasEnabledSendVideo() ? 'sendonly' : 'inactive'; + AudioCodesUA.instance.getWR().transceiver.setDirection(vt, dir); + } + } + if (AudioCodesUA.instance.codecFilter) { + AudioCodesUA.instance._cf_filter('video', call, AudioCodesUA.instance.codecFilter.video); + } + + // No call callShowStreams() for event 'track' video, because we use the same stream for audio and video. + // and to prevent calling callShowStreams twice and use wrong video flags. + return; + } + var localStream = call.getRTCLocalStream(); + var remoteStream = call.getRTCRemoteStream(); + AudioCodesUA.ac_log('AC>>: callShowStreams', call, localStream, remoteStream); + AudioCodesUA.instance.listeners.callShowStreams(call, localStream, remoteStream); + }); + } + + /* + SDP may change with every new browser release and modified by SBC + We do not edit the SDP in client to avoid chaos. + However, it could be useful for testing + + // Remove ICE candidates with with a type different from 'relay' + _sdp_editing(sdp) { + for (let mIndex = 0; mIndex < sdp.media.length; mIndex++) { + let media = sdp.media[mIndex]; + let modifiedMedia = []; + for (let i = 0; i < media.length; i++) { + let line = media[i]; + if (line.startsWith('a=candidate:')) { + // a=candidate:1467250027 1 udp 2122260223 192.168.0.196 46243 typ host generation 0 + let tokens = line.split(' '); + if (tokens[7] === 'relay') { + modifiedMedia.push(line); + } else { + AudioCodesUA.ac_log('Removed line:' + line); + } + } else { + modifiedMedia.push(line); + } + } + sdp.media[mIndex] = modifiedMedia; + } + return sdp.toString(); + } + + // Usage: + e.sdp = AudioCodesUA.instance._sdp_editing(sdp); + */ + + /** + * Chrome WebRTC engine check if current SDP compatible with previous SDP. + * Chrome exception is almost unreadable, e.g: + * "Failed to set local answer sdp: Failed to set local audio description recv parameters for m-section with mid='0'" + * The function compare current and previous remote SDP and print warnings. + */ + }, { + key: "_check_remote_sdp", + value: function _check_remote_sdp(sdp, data) { + try { + if (!data.codec_map) { + data.codec_map = {}; + } + var mAudio = sdp.getMedia('audio'); + AudioCodesUA.instance._check_remote_m(mAudio, data.codec_map); + var mVideo = sdp.getMedia('video'); + if (mVideo) { + AudioCodesUA.instance._check_remote_m(mVideo, data.codec_map); + } + } catch (e) { + AudioCodesUA.ac_log('AC:SDP exception', e); + } + } + }, { + key: "_check_remote_m", + value: function _check_remote_m(m, previous) { + // Collect current SDP information + // pt : { rtpmap:xxx, [fmtp: yyy] } + var current = {}; + function parse(offset, str) { + var ix = str.indexOf(' ', offset); + if (ix === -1) return ['?', '?']; + return [str.substring(offset, ix), str.substring(ix + 1).toLowerCase()]; + } + var _iterator3 = _createForOfIteratorHelper(m), + _step3; + try { + for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { + var l = _step3.value; + if (l.startsWith('a=rtpmap:')) { + var _parse = parse(9, l), + _parse2 = _slicedToArray(_parse, 2), + _pt = _parse2[0], + rtpmap = _parse2[1]; + if (!current[_pt]) current[_pt] = {}; + current[_pt].rtpmap = rtpmap; + } else if (l.startsWith('a=fmtp:')) { + var _parse3 = parse(7, l), + _parse4 = _slicedToArray(_parse3, 2), + _pt2 = _parse4[0], + fmtp = _parse4[1]; + if (!current[_pt2]) current[_pt2] = {}; + current[_pt2].fmtp = fmtp; + } + } + + // AudioCodesUA.ac_log(`current ` + JSON.stringify(current, null, 2)); + // AudioCodesUA.ac_log(`previous ` + JSON.stringify(previous, null, 2)); + + // Compare current SDP information with previous one. + } catch (err) { + _iterator3.e(err); + } finally { + _iterator3.f(); + } + for (var _i2 = 0, _Object$keys = Object.keys(current); _i2 < _Object$keys.length; _i2++) { + var pt = _Object$keys[_i2]; + if (previous[pt]) { + if (current[pt].rtpmap === previous[pt].rtpmap) { + if (current[pt].fmtp !== previous[pt].fmtp) { + AudioCodesUA.ac_log("AC:SDP [The same payload type and codec name, different fmtp] pt=".concat(pt, " rtpmap=").concat(current[pt].rtpmap, " fmtp=").concat(current[pt].fmtp, ", previously was fmtp=").concat(previous[pt].fmtp)); + } + } else { + // Check that used dynamic payload type or both rtpmat is defined. + if (parseInt(pt) >= 64 || !!current[pt].rtpmap && !!previous[pt].rtpmap) { + AudioCodesUA.ac_log("AC:SDP [The same payload type, different codec names] pt=".concat(pt, " rtpmap=").concat(current[pt].rtpmap, ", previously was rtpmap=").concat(previous[pt].rtpmap)); + } + } + } else { + var data = current[pt]; + var foundPt = void 0; + for (var _i3 = 0, _Object$entries = Object.entries(previous); _i3 < _Object$entries.length; _i3++) { + var _Object$entries$_i = _slicedToArray(_Object$entries[_i3], 2), + pt1 = _Object$entries$_i[0], + data1 = _Object$entries$_i[1]; + if (data.rtpmap === data1.rtpmap && data.fmtp === data1.fmtp) { + foundPt = pt1; + break; + } + } + if (foundPt) { + var prevData = previous[foundPt]; + if (!data.fmtp && !prevData.fmtp) { + AudioCodesUA.ac_log("AC:SDP [The same codec name used with different payload types] pt=".concat(pt, " rtpmap=").concat(data.rtpmap, ", previously was pt=").concat(foundPt, " rtpmap=").concat(prevData.rtpmap)); + } else { + AudioCodesUA.ac_log("AC:SDP [The same codec name used with different payload types] pt=".concat(pt, " rtpmap=").concat(data.rtpmap, " fmtp=").concat(data.fmtp, ", previously was pt=").concat(foundPt, " rtpmap=").concat(prevData.rtpmap, " fmtp=").concat(prevData.fmtp)); + } + } else { + previous[pt] = data; + } + } + } + } + }, { + key: "_sdp_checking", + value: function _sdp_checking(js_session, e) { + var type = e.originator + ' ' + e.type; + var ac_session = js_session.data.ac_session; + var sdp, send, recv; + try { + sdp = new AudioCodesSDP(e.sdp); + var _sdp$getMediaDirectio3 = sdp.getMediaDirection('video', e.originator === 'remote'); + var _sdp$getMediaDirectio4 = _slicedToArray(_sdp$getMediaDirectio3, 2); + send = _sdp$getMediaDirectio4[0]; + recv = _sdp$getMediaDirectio4[1]; + } catch (e) { + AudioCodesUA.ac_log('AC: cannot parse SDP', e); + return; + } + var initial = ac_session.data._initial; + if (e.type === 'answer') + // after 1st answer it's not initial SDP negotiation. + ac_session.data._initial = false; + AudioCodesUA.ac_log("AC: Event \"sdp\" ".concat(initial ? 'initial' : '', " ").concat(type, " Session state:").concat(AudioCodesUA.getSessionStatusName(js_session._status))); + switch (type) { + case 'remote offer': + if (AudioCodesUA.instance.modes.check_remote_sdp_mode) { + AudioCodesUA.instance._check_remote_sdp(sdp, js_session.data); + } + break; + case 'remote answer': + if (AudioCodesUA.instance.modes.check_remote_sdp_mode) { + AudioCodesUA.instance._check_remote_sdp(sdp, js_session.data); + } + if (ac_session.isLocalHold() || ac_session.isRemoteHold()) break; // ignore hold re-INVITE + ac_session._setVideoState(send, recv); + break; + case 'local offer': + if (AudioCodesUA.instance.networkPriority) { + AudioCodesUA.instance._set_senders_dscp(js_session); + } + break; + case 'local answer': + if (ac_session.isLocalHold() || ac_session.isRemoteHold()) break; // ignore hold re-INVITE + if (AudioCodesUA.instance.networkPriority) { + AudioCodesUA.instance._set_senders_dscp(js_session); + } + ac_session._setVideoState(send, recv); + break; + } + } + }, { + key: "_set_senders_dscp", + value: function _set_senders_dscp(js_session) { + if (AudioCodesUA.instance.browser !== 'chrome') return; + AudioCodesUA.ac_log('AC: _set_senders_dscp()'); + var priority = AudioCodesUA.instance.networkPriority; + AudioCodesUA.instance._set_dscp(js_session, 'audio', priority); + AudioCodesUA.instance._set_dscp(js_session, 'video', priority); + } + }, { + key: "_set_dscp", + value: function _set_dscp(js_session, type, priority) { + var conn = js_session.connection; + var tr = AudioCodesUA.instance.getWR().connection.getTransceiver(conn, type); + if (!tr && type === 'video') return Promise.resolve(false); + return Promise.resolve().then(function () { + var params = tr.sender.getParameters(); + if (!params) throw new Error('sender getParameters() returns undefined'); + var encodings = params.encodings; + if (!encodings) throw new Error('parameters encodings is undefined'); + if (encodings.length === 0) throw new Error('parameters encodings is empty array'); + var previous = encodings[0].networkPriority; + if (!previous) throw new Error('parameters encodings networkPriority is undefined'); + if (previous === priority) return true; // nothing to do. + encodings[0].networkPriority = priority; + return tr.sender.setParameters(params).then(function () { + AudioCodesUA.ac_log("AC: DSCP: ".concat(type, " \"").concat(priority, "\"")); + return true; + }); + })["catch"](function (e) { + AudioCodesUA.ac_log("AC: DSCP: ".concat(type, " error: ").concat(e)); + return false; + }); + } + + // Codec filter + }, { + key: "_cf_unpack", + value: function _cf_unpack(obj) { + // Unpack 'pcmu', 'pcmu/8000' 'VP9#profile-id=0' + function unpack(type, s) { + var slash = s.indexOf('/'); + var num = s.indexOf('#'); + var end; + end = slash !== -1 ? slash : num !== -1 ? num : undefined; + var res = { + mimeType: (type + '/' + s.substring(0, end)).toLowerCase() + }; + if (slash !== -1) { + end = num !== -1 ? num : undefined; + res.clockRate = parseInt(s.substring(slash + 1, end)); + } + if (num !== -1) { + res.sdpFmtpLine = s.substring(num + 1); + } + return res; + } + if (!obj) return null; + var result = {}; + var _loop = function _loop(type) { + result[type] = {}; + for (var op in obj[type]) { + result[type][op] = obj[type][op].map(function (s) { + return unpack(type, s); + }); + } + }; + for (var type in obj) { + _loop(type); + } + return result; + } + }, { + key: "_cf_pack", + value: function _cf_pack(codecs) { + function pack(c) { + var r = c.mimeType.substring(6).toLowerCase(); + if (c.clockRate) r += '/' + c.clockRate; + if (c.sdpFmtpLine) r += '#' + c.sdpFmtpLine; + return r; + } + return codecs.map(function (c) { + return pack(c); + }); + } + }, { + key: "_cf_str", + value: function _cf_str(codecs) { + return JSON.stringify(AudioCodesUA.instance._cf_pack(codecs)); + } + }, { + key: "_cf_match", + value: function _cf_match(codec, filters) { + var mimeType = codec.mimeType.toLowerCase(); + var _iterator4 = _createForOfIteratorHelper(filters), + _step4; + try { + for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { + var filter = _step4.value; + if (filter.mimeType === mimeType) { + if (filter.clockRate && filter.clockRate !== codec.clockRate) continue; + if (filter.sdpFmtpLine && filter.sdpFmtpLine !== codec.sdpFmtpLine) continue; + return true; + } + } + } catch (err) { + _iterator4.e(err); + } finally { + _iterator4.f(); + } + return false; + } + }, { + key: "_cf_find", + value: function _cf_find(filter, codecs) { + var found = []; + var _iterator5 = _createForOfIteratorHelper(codecs), + _step5; + try { + for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { + var codec = _step5.value; + var mimeType = codec.mimeType.toLowerCase(); + if (filter.mimeType === mimeType) { + if (filter.clockRate && filter.clockRate !== codec.clockRate) continue; + if (filter.sdpFmtpLine && filter.sdpFmtpLine !== codec.sdpFmtpLine) continue; + found.push(codec); + } + } + } catch (err) { + _iterator5.e(err); + } finally { + _iterator5.f(); + } + return found; + } + }, { + key: "_cf_filter", + value: function _cf_filter(type, call, filter) { + if (!filter) return; + // Used once for audio and once for video + if (call.data["_used_".concat(type, "_codec_filter")]) return; + try { + var conn = call.getRTCPeerConnection(); + var transceiver = AudioCodesUA.instance.getWR().connection.getTransceiver(conn, type); + if (!transceiver) { + if (type === 'audio') AudioCodesUA.ac_log('AC: codec-filter: cannot get audio transceiver'); + return; + } + call.data["_used_".concat(type, "_codec_filter")] = true; + if (!RTCRtpSender.getCapabilities || !RTCRtpReceiver.getCapabilities || !transceiver.setCodecPreferences) { + AudioCodesUA.ac_log("AC: codec-filter is not supported."); + return; + } + var sndCodecs = RTCRtpSender.getCapabilities(type).codecs; + var rcvCodecs = RTCRtpReceiver.getCapabilities(type).codecs; + var uniqRcvCodecs = []; + var _iterator6 = _createForOfIteratorHelper(rcvCodecs), + _step6; + try { + var _loop3 = function _loop3() { + var rc = _step6.value; + var ix = sndCodecs.findIndex(function (sc) { + return rc.mimeType === sc.mimeType && rc.clockRate === sc.clockRate && rc.sdpFmtpLine === sc.sdpFmtpLine; + }); + if (ix === -1) uniqRcvCodecs.push(rc); + }; + for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { + _loop3(); + } + + /* + AudioCodesUA.ac_log(`AC: ${type} codec-filter original [sender]: ${AudioCodesUA.instance._cf_str(sndCodecs)}`); + AudioCodesUA.ac_log(`AC: ${type} codec-filter original [receiver]: ${AudioCodesUA.instance._cf_str(rcvCodecs)}`); + AudioCodesUA.ac_log(`AC: ${type} codec-filter original [unique receiver]: ${AudioCodesUA.instance._cf_str(uniqRcvCodecs)}`); + */ + } catch (err) { + _iterator6.e(err); + } finally { + _iterator6.f(); + } + var codecs = sndCodecs.concat(uniqRcvCodecs); + AudioCodesUA.ac_log("AC: ".concat(type, " codec-filter original: ").concat(AudioCodesUA.instance._cf_str(codecs), "\n(receiver: ").concat(uniqRcvCodecs.length, ")")); + if (filter.remove && filter.remove.length > 0) { + var len0 = codecs.length; + codecs = codecs.filter(function (codec) { + return !AudioCodesUA.instance._cf_match(codec, filter.remove); + }); + if (codecs.length < len0) { + AudioCodesUA.ac_log("AC: ".concat(type, " codec-filter remaining: ").concat(AudioCodesUA.instance._cf_str(codecs))); + } + } + if (filter.priority && filter.priority.length > 0) { + var newCodecs = []; + var _iterator7 = _createForOfIteratorHelper(filter.priority), + _step7; + try { + var _loop2 = function _loop2() { + var cf = _step7.value; + var found = AudioCodesUA.instance._cf_find(cf, codecs); + if (found.length === 0) return "continue"; + newCodecs = newCodecs.concat(found); + codecs = codecs.filter(function (codec) { + return !found.includes(codec); + }); + }; + for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { + var _ret = _loop2(); + if (_ret === "continue") continue; + } + } catch (err) { + _iterator7.e(err); + } finally { + _iterator7.f(); + } + codecs = newCodecs.concat(codecs); + AudioCodesUA.ac_log("AC: ".concat(type, " codec-filter changed priority: ").concat(AudioCodesUA.instance._cf_str(codecs))); + } + transceiver.setCodecPreferences(codecs); + return; + } catch (e) { + AudioCodesUA.ac_log('AC: codec filter exception', e); + return; + } + } + // end of codec filter + }, { + key: "_convertIceList", + value: function _convertIceList(ices) { + var result = []; + var _iterator8 = _createForOfIteratorHelper(ices), + _step8; + try { + for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { + var entry = _step8.value; + // convert short form of stun server to object + if (typeof entry === 'string') { + entry = { + 'urls': 'stun:' + entry + }; + } + result.push(entry); + } + } catch (err) { + _iterator8.e(err); + } finally { + _iterator8.f(); + } + return result; + } + }, { + key: "_randomToken", + value: function _randomToken(size) { + var t = ''; + for (var i = 0; i < size; i++) { + t += Math.floor(Math.random() * 36).toString(36); + } + return t; + } + }, { + key: "_detectBrowser", + value: function _detectBrowser() { + try { + var ua = navigator.userAgent; + this.browser = 'other'; + this.browserName = ua; + this.browserVersion = 0; + if (navigator.mozGetUserMedia) { + this.browser = 'firefox'; + this.browserName = ua.match(/Firefox\/([.\d]+)$/)[0]; + this.browserVersion = parseInt(ua.match(/Firefox\/(\d+)\./)[1], 10); + } else if (navigator.webkitGetUserMedia) { + // Only works for secure connection. + this.browser = 'chrome'; + this.browserName = ua.match(/Chrom(e|ium)\/([\d]+)/)[0]; + this.browserVersion = parseInt(ua.match(/Chrom(e|ium)\/(\d+)\./)[2], 10); + // Detect known Chromium based browsers: Edge, Opera etc - classified as 'chrome' + var ual = ua.toLowerCase(); + for (var ix = 0; ix < this.chromiumBased.length; ix++) { + var s = this.chromiumBased[ix].s; + var f = ual.indexOf(s); + if (f !== -1) { + var v = ual.substring(f + s.length).match(/([.\d]+)/)[1]; + this.browserName += ' (' + this.chromiumBased[ix].n + '/' + v + ')'; + break; + } + } + } else if (window.safari) { + this.browser = 'safari'; + this.browserName = 'Safari/' + ua.match(/Version\/([.\d]+)/)[1]; + this.browserVersion = parseInt(ua.match(/Version\/(\d+)\./)[1], 10); + } else if (ua.indexOf('Edge/') !== -1) { + // legacy Edge + this.browser = 'other'; + this.browserName = ua.match(/Edge\/([.\d]+)/)[0]; + this.browserVersion = parseInt(ua.match(/Edge\/(\d+).(\d+)$/)[2], 10); + } + if (/iPad|iPhone|iPod/.test(ua)) { + this.browserName = ua; + if (ua.includes('CriOS')) { + this.browser = 'chrome'; + this.browserVersion = parseInt(ua.match(/CriOS\/(\d+)\./)[1], 10); + } else if (ua.includes('FxiOS')) { + this.browser = 'firefox'; + this.browserVersion = parseInt(ua.match(/FxiOS\/(\d+)\./)[1], 10); + } else { + this.browser = 'safari'; + this.browserVersion = parseInt(ua.match(/Version\/(\d+)\./)[1], 10); + } + } + } catch (e) { + AudioCodesUA.ac_log('AC: Browser detection error', e); + this.browser = 'other'; + this.browserName = navigator.userAgent; + this.browserVersion = 0; + } + } + + // windows,android,macos,ios,linux,other + }, { + key: "_detectOS", + value: function _detectOS() { + this._detectOS1(); + if (this.os !== 'other') return; + this._detectOS2(); + } + }, { + key: "_detectOS1", + value: function _detectOS1() { + try { + var p = navigator.userAgentData ? navigator.userAgentData.platform : false; + if (!p) return; + p = p.toLowerCase(); + if (p === 'windows' || p === 'linux' || p === 'android' || p === 'macos') this.os = p; + } catch (e) { + AudioCodesUA.ac_log('AC: detectOS1 error', e); + this.os = 'other'; + } + } + }, { + key: "_detectOS2", + value: function _detectOS2() { + try { + var p = navigator.platform; + if (!p) return; + p = p.toLowerCase(); + if (p.startsWith('win')) { + this.os = 'windows'; + } else if (p.startsWith('android')) { + this.os = 'android'; + } else if (p.startsWith('linux')) { + if (navigator.userAgent.includes('Android')) { + this.os = 'android'; // for Android Firefox + } else { + this.os = 'linux'; + } + } else if (p.startsWith('mac')) { + this.os = 'macos'; + } else if (/ipad|iphone|ipod/.test(p)) { + this.os = 'ios'; + } + } catch (e) { + AudioCodesUA.ac_log('AC: detectOS2 error', e); + this.os = 'other'; + } + } + }, { + key: "_mediaConstraints", + value: function _mediaConstraints(sendVideo) { + var inst = AudioCodesUA.instance; + var constraints = { + 'audio': inst.constraints.audio + }; + if (sendVideo) { + constraints.video = inst.constraints.video; + } + return constraints; + } + }, { + key: "_callOptions", + value: function _callOptions(sendVideo, isOutgoing) { + var extraHeaders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + var extraOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + var options = {}; + var inst = AudioCodesUA.instance; + + // No need since Chrome 102, see: https://groups.google.com/g/discuss-webrtc/c/85e-f_siCws + if (inst.browser === 'chrome' && inst.networkPriority) { + options = { + rtcConstraints: { + optional: [{ + googDscp: true + }] + } + }; + } + if (extraOptions !== null) { + Object.assign(options, extraOptions); + } + options.mediaConstraints = inst._mediaConstraints(sendVideo); + if (options.pcConfig === undefined) { + options.pcConfig = {}; + } + options.pcConfig.iceServers = inst.serverConfig.iceServers; + if (extraHeaders !== null) { + extraHeaders = extraHeaders.slice(); + } + if (inst.oauthToken !== null && inst.oauthTokenUseInInvite && isOutgoing) { + if (extraHeaders === null) { + extraHeaders = []; + } + extraHeaders.push('Authorization: Bearer ' + inst.oauthToken); + } + if (extraHeaders !== null) { + options.extraHeaders = extraHeaders; + } + return options; + } + + /** + * videoOption = phone.AUDIO, phone.VIDEO or false(=phone.AUDIO) true(=phone.VIDEO) + */ + }, { + key: "call", + value: function call(videoOption, call_to) { + var extraHeaders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + var extraOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; + // Convert boolean value to Symbol + if (videoOption === false) videoOption = AudioCodesUA.instance.AUDIO;else if (videoOption === true) videoOption = AudioCodesUA.instance.VIDEO; + if (_typeof(videoOption) !== 'symbol' || ![AudioCodesUA.instance.AUDIO, AudioCodesUA.instance.VIDEO].includes(videoOption)) throw new TypeError("Illegal videoOption=".concat(videoOption.toString())); + call_to = call_to.replace(/\s+/g, ''); // remove whitespaces. + AudioCodesUA.ac_log("AC: call ".concat(videoOption.description, " to ").concat(call_to)); + var options = this._callOptions(videoOption === AudioCodesUA.instance.VIDEO, true, extraHeaders, extraOptions); + var js_session = this.jssipUA.call(call_to, options); + if (options.mediaStream) js_session._localMediaStreamLocallyGenerated = true; // to enable jssip close the stream + var ac_session = js_session.data.ac_session; + ac_session._setEnabledSendVideo(videoOption === AudioCodesUA.instance.VIDEO); + if (videoOption === AudioCodesUA.instance.VIDEO) ac_session._setEnabledReceiveVideo(true); + return ac_session; + } + }, { + key: "sendMessage", + value: function sendMessage(to, body) { + var _this2 = this; + var contentType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'text/plain'; + AudioCodesUA.ac_log("AC: sendMessage to: ".concat(to, " \"").concat(body, "\"")); + return new Promise(function (resolve, reject) { + var options = { + contentType: contentType, + eventHandlers: { + succeeded: function succeeded(e) { + return resolve(e); + }, + failed: function failed(e) { + return reject(e); + } + } + }; + _this2.jssipUA.sendMessage(to, body, options); + }); + } + }, { + key: "isScreenSharingSupported", + value: function isScreenSharingSupported() { + return AudioCodesUA.instance.getWR().hasDisplayMedia(); + } + }, { + key: "openScreenSharing", + value: function openScreenSharing() { + if (!this.isScreenSharingSupported()) { + AudioCodesUA.ac_log('AC: openScreenSharing: screen sharing is not supported in the browser'); + return Promise.reject('Screen sharing is not supported'); + } + AudioCodesUA.ac_log('AC: openScreenSharing()'); + return AudioCodesUA.instance.getWR().getDisplayMedia().then(function (stream) { + return stream; + })["catch"](function (e) { + AudioCodesUA.ac_log('AC: openScreenSharing() error', e); + throw e; + }); + } + }, { + key: "closeScreenSharing", + value: function closeScreenSharing(displayStream) { + AudioCodesUA.ac_log('AC: closeScreenSharing()'); + if (displayStream) { + var tracks = displayStream.getVideoTracks(); + if (tracks.length == 0) return; + var track = tracks[0]; + if (track.readyState === 'live') { + track.stop(); + track.dispatchEvent(new Event("ended")); + } + } + } + }, { + key: "setNetworkPriority", + value: function setNetworkPriority(p) { + AudioCodesUA.ac_log("AC: setNetworkPriority ".concat(p)); + if (p !== undefined && p !== 'high' && p !== 'medium' && p !== 'low' && p !== 'very-low') throw new TypeError("setNetworkPriority: illegal value: ".concat(p)); + this.networkPriority = p; + } + }, { + key: "subscribe", + value: function subscribe() { + var _this$jssipUA; + return (_this$jssipUA = this.jssipUA).subscribe.apply(_this$jssipUA, arguments); + } + }, { + key: "notify", + value: function notify() { + var _this$jssipUA2; + return (_this$jssipUA2 = this.jssipUA).notify.apply(_this$jssipUA2, arguments); + } + + /** + * Experimental JsSIP extension: another SIP credential. + * Use it before phone.init() if SUBSCRIBE authentication is different from REGISTER + */ + }, { + key: "addCredential", + value: function addCredential(credential) { + if (!credential.realm || !credential.password || !credential.username) throw new TypeError('wrong credential structure'); + this.credentials.push(credential); + } + }], [{ + key: "getSessionStatusName", + value: function getSessionStatusName(status) { + switch (status) { + case 0: + return 'NULL (0)'; + case 1: + return 'INVITE_SENT (1)'; + case 2: + return '1XX_RECEIVED (2)'; + case 3: + return 'INVITE_RECEIVED (3)'; + case 4: + return 'WAITING_FOR_ANSWER (4)'; + case 5: + return 'ANSWERED (5)'; + case 6: + return 'WAITING_FOR_ACK (6)'; + case 7: + return 'CANCELED (7)'; + case 8: + return 'TERMINATED (8)'; + case 9: + return 'CONFIRMED (9)'; + default: + return 'Unknown (' + status + ')'; + } + } + }]); + return AudioCodesUA; +}(); +/* + * Session + */ +var AudioCodesSession = /*#__PURE__*/function () { + function AudioCodesSession(js_session) { + _classCallCheck(this, AudioCodesSession); + this.js_session = js_session; + this.data = { + _user: null, + _display_name: null, + _create_time: null, + _initial: true, + _remoteMediaStream: null, + _wasUsedSendVideo: false, + _screenSharing: null, + _video: { + send: false, + receive: false, + enabledSend: false, + enabledReceive: false + } + }; + js_session.data.ac_session = this; + } + _createClass(AudioCodesSession, [{ + key: "getRTCPeerConnection", + value: function getRTCPeerConnection() { + return this.js_session.connection; + } + }, { + key: "getRTCLocalStream", + value: function getRTCLocalStream() { + return this.js_session._localMediaStream; + } + }, { + key: "getRTCRemoteStream", + value: function getRTCRemoteStream() { + return this.data['_remoteMediaStream']; + } + }, { + key: "isEstablished", + value: function isEstablished() { + return this.js_session.isEstablished(); + } + }, { + key: "isTerminated", + value: function isTerminated() { + return this.js_session.isEnded(); + } + }, { + key: "isOutgoing", + value: function isOutgoing() { + return this.js_session.direction === 'outgoing'; + } + }, { + key: "isAudioMuted", + value: function isAudioMuted() { + return this.js_session.isMuted().audio; + } + }, { + key: "isVideoMuted", + value: function isVideoMuted() { + return this.js_session.isMuted().video; + } + }, { + key: "wasAccepted", + value: function wasAccepted() { + return this.data['_accepted'] === true; + } + }, { + key: "getReplacesHeader", + value: function getReplacesHeader() { + if (!this.js_session.isEstablished() || !this.js_session._dialog) { + AudioCodesUA.ac_log('getReplacesHeader(): call is not established'); + return null; + } + var id = this.js_session._dialog.id; + return "".concat(id.call_id, ";to-tag=").concat(id.remote_tag, ";from-tag=").concat(id.local_tag); + } + }, { + key: "muteAudio", + value: function muteAudio(set) { + AudioCodesUA.ac_log("AC: muteAudio() arg=".concat(set, " ")); + if (set) { + this.js_session.mute({ + audio: true, + video: false + }); + } else { + this.js_session.unmute({ + audio: true, + video: false + }); + } + } + }, { + key: "muteVideo", + value: function muteVideo(set) { + AudioCodesUA.ac_log("AC: muteVideo() arg=".concat(set, " ")); + if (set) { + this.js_session.mute({ + audio: false, + video: true + }); + } else { + this.js_session.unmute({ + audio: false, + video: true + }); + } + } + }, { + key: "sendDTMF", + value: function sendDTMF(tone) { + var useWebRTC = AudioCodesUA.instance.dtmfUseWebRTC; + if (useWebRTC && AudioCodesUA.instance.browser === 'safari') { + var dtmfSender = AudioCodesUA.instance.getWR().connection.getDTMFSender(this.js_session.connection); + if (dtmfSender === undefined) { + // If used obsolete Safari send DTMF as SIP INFO + useWebRTC = false; + } + } + AudioCodesUA.ac_log("AC: sendDTMF() tone=".concat(tone, " ").concat(useWebRTC ? '[RFC2833]' : '[INFO]')); + var options = { + duration: AudioCodesUA.instance.dtmfDuration, + interToneGap: AudioCodesUA.instance.dtmfInterToneGap, + transportType: useWebRTC ? 'RFC2833' : 'INFO' + }; + this.js_session.sendDTMF(tone, options); + } + }, { + key: "sendInfo", + value: function sendInfo(body, contentType) { + var extraHeaders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + AudioCodesUA.ac_log('AC: sendInfo()', body, contentType, extraHeaders); + var options = extraHeaders !== null ? { + extraHeaders: extraHeaders + } : undefined; + this.js_session.sendInfo(contentType, body, options); + } + }, { + key: "duration", + value: function duration() { + var start = this.js_session.start_time; + if (!start) return 0; + var end = this.js_session.end_time; + if (!end) end = new Date(); + return Math.floor((end.getTime() - start.getTime()) / 1000); + } + + // Call actual video state. + // Set by initial INVITE and re-INVITEs. HOLD re-INVITEs will be ignored. + }, { + key: "hasSendVideo", + value: function hasSendVideo() { + return this.data._video.send; + } + }, { + key: "hasReceiveVideo", + value: function hasReceiveVideo() { + return this.data._video.receive; + } + }, { + key: "hasVideo", + value: function hasVideo() { + return this.hasSendVideo() && this.hasReceiveVideo(); + } + }, { + key: "getVideoState", + value: function getVideoState() { + if (this.hasSendVideo() && this.hasReceiveVideo()) return "sendrecv"; + if (this.hasSendVideo()) return "sendonly"; + if (this.hasReceiveVideo()) return "recvonly"; + return "inactive"; + } + }, { + key: "_setVideoState", + value: function _setVideoState(send, receive) { + AudioCodesUA.ac_log("AC: _setVideoState(send=".concat(send, ", receive=").concat(receive, ")")); + this.data._video.send = send; + this.data._video.receive = receive; + } + + // Call enabled to send/receive video + }, { + key: "hasEnabledSendVideo", + value: function hasEnabledSendVideo() { + return this.data._video.enabledSend; + } + }, { + key: "hasEnabledReceiveVideo", + value: function hasEnabledReceiveVideo() { + return this.data._video.enabledReceive; + } + }, { + key: "getEnabledVideoState", + value: function getEnabledVideoState() { + if (this.hasEnabledSendVideo() && this.hasEnabledReceiveVideo()) return "sendrecv"; + if (this.hasEnabledSendVideo()) return "sendonly"; + if (this.hasEnabledReceiveVideo()) return "recvonly"; + return "inactive"; + } + }, { + key: "_setEnabledSendVideo", + value: function _setEnabledSendVideo(enable) { + AudioCodesUA.ac_log("AC: _setEnabledSendVideo(".concat(enable, ")")); + this.data._video.enabledSend = enable; + } + }, { + key: "_setEnabledReceiveVideo", + value: function _setEnabledReceiveVideo(enable) { + AudioCodesUA.ac_log("AC: _setEnabledReceiveVideo(".concat(enable, ")")); + this.data._video.enabledReceive = enable; + } + + /** + * videoOption = phone.AUDIO, phone.VIDEO, phone.RECVONLY_VIDEO + * or false (=phone.AUDIO), true(=phone.VIDEO) + */ + }, { + key: "answer", + value: function answer(videoOption) { + var _this3 = this; + var extraHeaders = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var extraOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + if (this.data['_answer_called']) { + AudioCodesUA.ac_log('AC: answer() is already called. [Ignored]'); + return; + } + this.data['_answer_called'] = true; + + // Convert boolean value to Symbol + if (videoOption === false) videoOption = AudioCodesUA.instance.AUDIO;else if (videoOption === true) videoOption = AudioCodesUA.instance.VIDEO; + if (_typeof(videoOption) !== 'symbol' || ![AudioCodesUA.instance.AUDIO, AudioCodesUA.instance.RECVONLY_VIDEO, AudioCodesUA.instance.VIDEO].includes(videoOption)) throw new TypeError("Illegal videoOption=".concat(videoOption.toString())); + AudioCodesUA.ac_log("AC: ".concat(videoOption.description, " answer")); + if (!this.hasVideo() && (videoOption === AudioCodesUA.instance.RECVONLY_VIDEO || videoOption === AudioCodesUA.instance.VIDEO)) { + AudioCodesUA.ac_log('AC: incoming INVITE without video, so answer can be only "audio"'); + videoOption = AudioCodesUA.instance.AUDIO; + } + + // video call - audio answer: no sound in answer phone. + if (this.hasVideo() && videoOption === AudioCodesUA.instance.AUDIO) { + var ua = AudioCodesUA.instance; + var br = ua.browser; + var md = ua.modes; + var vr = ua.browserVersion; + if (br === 'firefox' && md.video_call_audio_answer_firefox_fix) { + this.data['_video_call_audio_answer_firefox'] = true; + } else if (br === 'safari') { + if (md.video_call_audio_answer_safari_fix === true && vr < 14 || md.video_call_audio_answer_safari_fix === 'force') this.data['_video_call_audio_answer_safari'] = true; + } + } + + // Set enabled and current send/receive video flags + switch (videoOption) { + case AudioCodesUA.instance.AUDIO: + this._setEnabledSendVideo(false); + if (this.data['_incoming_invite_without_sdp']) { + this._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo); + } else { + this._setEnabledReceiveVideo(this.hasVideo() ? false : AudioCodesUA.instance.enableAddVideo); + } + this._setVideoState(false, false); + break; + case AudioCodesUA.instance.VIDEO: + this._setEnabledSendVideo(true); + this._setEnabledReceiveVideo(true); + this._setVideoState(true, true); + break; + case AudioCodesUA.instance.RECVONLY_VIDEO: + this._setEnabledSendVideo(false); + this._setEnabledReceiveVideo(true); + this._setVideoState(false, true); + break; + } + var options = AudioCodesUA.instance._callOptions(videoOption === AudioCodesUA.instance.VIDEO, false, extraHeaders, extraOptions); + Promise.resolve().then(function () { + if (!options.mediaStream) { + return AudioCodesUA.instance.getWR().getUserMedia(options.mediaConstraints); + } else { + return options.mediaStream; + } + }).then(function (stream) { + options.mediaStream = stream; + _this3.js_session._localMediaStreamLocallyGenerated = true; // to enable jssip close the stream + AudioCodesUA.ac_log('AC: answer options:', options); + _this3.js_session.answer(options); + })["catch"](function (e) { + AudioCodesUA.ac_log('AC: getUserMedia failure', e); + _this3.reject(488); + }); + } + }, { + key: "reject", + value: function reject() { + var statusCode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 486; + var extraHeaders = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + AudioCodesUA.ac_log('AC: reject()'); + try { + var options = { + status_code: statusCode + }; + if (extraHeaders) { + options.extraHeaders = extraHeaders; + } + this.js_session.terminate(options); + } catch (e) { + AudioCodesUA.ac_log('AC: call reject error:', e); + } + } + }, { + key: "terminate", + value: function terminate() { + AudioCodesUA.ac_log('AC: terminate()'); + try { + this.js_session.terminate(); + } catch (e) { + AudioCodesUA.ac_log('AC: call terminate error:', e); + } + } + }, { + key: "redirect", + value: function redirect(callTo) { + var statusCode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 302; + var extraHeaders = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + AudioCodesUA.ac_log("AC: redirect() callTo=".concat(callTo)); + try { + var contact = 'Contact: ' + AudioCodesUA.instance.jssipUA.normalizeTarget(callTo); + var options = { + status_code: statusCode, + extraHeaders: [contact] + }; + if (extraHeaders) { + var _options$extraHeaders; + (_options$extraHeaders = options.extraHeaders).push.apply(_options$extraHeaders, _toConsumableArray(extraHeaders)); + } + this.js_session.terminate(options); + } catch (e) { + AudioCodesUA.ac_log('AC: call redirect error:', e); + } + } + }, { + key: "isLocalHold", + value: function isLocalHold() { + return this.js_session.isOnHold().local; + } + }, { + key: "isRemoteHold", + value: function isRemoteHold() { + return this.js_session.isOnHold().remote; + } + }, { + key: "isReadyToReOffer", + value: function isReadyToReOffer() { + return this.js_session._isReadyToReOffer(); + } + }, { + key: "hold", + value: function hold(set) { + var _this4 = this; + AudioCodesUA.ac_log("AC: hold(".concat(set, ")")); + return new Promise(function (resolve, reject) { + var method = set ? _this4.js_session.hold : _this4.js_session.unhold; + var result = method.call(_this4.js_session, {}, function () { + AudioCodesUA.ac_log('AC: hold()/unhold() is completed'); + resolve(); + }); + if (!result) { + AudioCodesUA.ac_log('AC: hold()/unhold() failed'); + reject(); + } + }); + } + + /* + * To enable/disable receive video + * Set enabledReceiveVideo flag, and set corresponding mode for video transceiver (if exists) + * Returns true if video transceiver exists, in the case call: reInvite({ showStreams: true }) + */ + }, { + key: "enableReceiveVideo", + value: function enableReceiveVideo(enable) { + this._setEnabledReceiveVideo(enable); + var conn = this.getRTCPeerConnection(); + var vt = AudioCodesUA.instance.getWR().connection.getTransceiver(conn, 'video'); + if (vt !== null) { + var dir = this.getEnabledVideoState(); + AudioCodesUA.instance.getWR().transceiver.setDirection(vt, dir); + } + AudioCodesUA.ac_log("AC: enableReceiveVideo(".concat(enable, ") ").concat(vt !== null ? "" : "No video transceiver")); + return vt !== null; + } + + /* + * For audio call. Start sending video + Get user media with camera stream. Add video. Send re-INVITE with video. + In re-INVITE can be added extra headers using options.extraHeaders. + By default set enabled to receive video from other side. + to disable set options.enabledReceiveVideo = false; + */ + }, { + key: "startSendingVideo", + value: function startSendingVideo() { + var _this5 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var enabledReceiveVideo = options && options.enabledReceiveVideo !== false; // undefined | true => true + if (this.hasEnabledSendVideo()) { + AudioCodesUA.ac_log('AC: startSendingVideo(). Already started'); + return Promise.reject('video already started'); + } + AudioCodesUA.ac_log('AC: startSendingVideo()'); + return AudioCodesUA.instance.getWR().getUserMedia({ + video: AudioCodesUA.instance.constraints.video + })["catch"](function (e) { + AudioCodesUA.ac_log('AC: startSendingVideo() getUserMedia failure', e); + throw e; + }).then(function (videoStream) { + // to allow JsSIP automatically stop stream after call termination. + var videoTrack = videoStream.getVideoTracks()[0]; + var localStream = _this5.getRTCLocalStream(); + localStream.addTrack(videoTrack); + _this5._setEnabledSendVideo(true); + _this5._setEnabledReceiveVideo(enabledReceiveVideo); + var wasUsedSendVideo = _this5.data['_wasUsedSendVideo']; + return AudioCodesUA.instance.getWR().connection.addVideo(_this5.getRTCPeerConnection(), _this5.getRTCLocalStream(), videoTrack, _this5.hasEnabledReceiveVideo(), wasUsedSendVideo).then(function () { + if (!wasUsedSendVideo && AudioCodesUA.instance.codecFilter) { + AudioCodesUA.instance._cf_filter('video', _this5, AudioCodesUA.instance.codecFilter.video); + } + })["catch"](function (e) { + AudioCodesUA.ac_log('AC: startSendingVideo(). Adding video error', e); + throw e; + }); + }).then(function () { + return _this5._renegotiate(options); + }); + } + + /* + * For video call. + * Stop sending video. Remove video. Send re-INVITE with inactive video. + * Optionally can be used options.extraHeaders + */ + }, { + key: "stopSendingVideo", + value: function stopSendingVideo() { + var _this6 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + if (!this.hasEnabledSendVideo()) { + AudioCodesUA.ac_log('AC: stopSendingVideo(). Already stopped'); + return Promise.reject('video already stopped'); + } + AudioCodesUA.ac_log('AC: stopSendingVideo()'); + return AudioCodesUA.instance.getWR().connection.removeVideo(this.getRTCPeerConnection(), this.getRTCLocalStream())["catch"](function (e) { + AudioCodesUA.ac_log('AC: stopSendingVideo(). Remove video error', e); + throw e; + }).then(function () { + _this6._setEnabledSendVideo(false); + _this6.data['_wasUsedSendVideo'] = true; + return _this6._renegotiate(options); + }); + } + }, { + key: "_doRenegotiate", + value: function _doRenegotiate(options) { + var _this7 = this; + if (this.js_session.isEnded()) { + return Promise.reject('call is ended'); + } + return new Promise(function (resolve) { + if (!_this7.js_session.renegotiate(options, function () { + return resolve(true); + })) { + return resolve(false); + } + }); + } + }, { + key: "_renegotiate", + value: function _renegotiate(options) { + var _this8 = this; + var attemptsLeft = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 30; + var delay = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 500; + AudioCodesUA.ac_log("AC: _renegotiate() attemptsLeft=".concat(attemptsLeft)); + return this._doRenegotiate(options).then(function (done) { + if (done) { + AudioCodesUA.ac_log('AC: Renegotiation success'); + return true; + } + if (attemptsLeft <= 1) { + throw new Error('Too many attempts'); + } + return new Promise(function (resolve) { + return setTimeout(resolve, delay); + }).then(function () { + return _this8._renegotiate(options, attemptsLeft - 1, delay); + }); + })["catch"](function (e) { + AudioCodesUA.ac_log('AC: Renegotiation failed', e); + throw e; + }); + } + }, { + key: "sendReInvite", + value: function sendReInvite() { + var _this9 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + AudioCodesUA.ac_log('AC: sendReInvite()'); + return this._renegotiate(options).then(function () { + if (options.showStreams) { + var localStream = _this9.getRTCLocalStream(); + var remoteStream = _this9.getRTCRemoteStream(); + AudioCodesUA.ac_log('AC>>: [after send re-INVITE] callShowStreams', _this9, localStream, remoteStream); + AudioCodesUA.instance.listeners.callShowStreams(_this9, localStream, remoteStream); + } + }); + } + + // screen sharing. + }, { + key: "startScreenSharing", + value: function startScreenSharing(stream) { + var _this10 = this; + var modes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + localScreenSharing: true, + enabledReceiveVideo: true, + separateVideo: false + }; + AudioCodesUA.ac_log('AC: startScreenSharing'); + if (!stream) return Promise.reject('missed stream argument'); + if (this.data['_screenSharing']) return Promise.reject('the call is already using screen-sharing'); + var enabledReceiveVideo = modes && modes.enabledReceiveVideo !== false; // undefined | true => true + var track = stream.getVideoTracks()[0]; + var onEnded = undefined; + if (modes.localScreenSharing) { + onEnded = this._onEndedScreenSharingTrack.bind(this); + track.addEventListener('ended', onEnded); + } + this.data['_screenSharing'] = { + stream: stream, + // screen sharing video track + onended: onEnded, + // callback + hadSendVideo: this.hasSendVideo() // if was video before screen sharing + }; + + var wasUsedSendVideo = this.data['_wasUsedSendVideo']; + this._setEnabledSendVideo(true); + this._setEnabledReceiveVideo(enabledReceiveVideo); + return AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(), this.getRTCLocalStream(), track, this.hasEnabledReceiveVideo(), wasUsedSendVideo).then(function () { + if (!wasUsedSendVideo && AudioCodesUA.instance.codecFilter) { + AudioCodesUA.instance._cf_filter('video', _this10, AudioCodesUA.instance.codecFilter.video); + } + })["catch"](function (e) { + AudioCodesUA.ac_log('AC: startScreenSharing() error', e); + _this10.data['_screenSharing'] = null; + throw e; + }).then(function () { + var options = { + extraHeaders: ['X-Screen-Sharing: on'] + }; + return _this10._renegotiate(options); + }); + } + }, { + key: "stopScreenSharing", + value: function stopScreenSharing() { + AudioCodesUA.ac_log('AC: stopScreenSharing'); + if (!this.data['_screenSharing']) return Promise.reject('the call does not use screen-sharing'); + return this._onEndedScreenSharing('called stopScreenSharing()'); + } + }, { + key: "isScreenSharing", + value: function isScreenSharing() { + return !!this.data['_screenSharing']; + } + }, { + key: "doesScreenSharingReplaceCamera", + value: function doesScreenSharingReplaceCamera() { + var sh = this.data['_screenSharing']; + return sh && sh.hadSendVideo; + } + }, { + key: "_onEndedScreenSharingTrack", + value: function _onEndedScreenSharingTrack() { + return this._onEndedScreenSharing('track ended'); + } + }, { + key: "_onEndedScreenSharing", + value: function _onEndedScreenSharing(reason) { + var _this11 = this; + var screenSharing = this.data['_screenSharing']; + this.data['_screenSharing'] = null; + var stream = screenSharing.stream; + var onended = screenSharing.onended; + if (stream && onended) { + var track = stream.getVideoTracks()[0]; + track.removeEventListener('ended', onended); + } + return Promise.resolve().then(function () { + if (!_this11.isTerminated()) { + // Restore previously sending video (if was) and send re-INVITE. + var connection = _this11.getRTCPeerConnection(); + var localStream = _this11.getRTCLocalStream(); + var options = { + extraHeaders: ['X-Screen-Sharing: off'] + }; + if (screenSharing.hadSendVideo) { + AudioCodesUA.ac_log('AC: screen sharing stopped - restore previously sending video track'); + AudioCodesUA.instance.getWR().connection.replaceSenderTrack(connection, 'video', localStream); + return _this11._renegotiate(options); + } else { + AudioCodesUA.ac_log('AC: screen sharing stopped - stop send video'); + return _this11.stopSendingVideo(options); + } + } + }).then(function () { + if (AudioCodesUA.instance.listeners.callScreenSharingEnded) { + AudioCodesUA.ac_log("AC>>: callScreenSharingEnded \"".concat(reason, "\""), _this11, stream); + AudioCodesUA.instance.listeners.callScreenSharingEnded(_this11, stream); + } + }); + } + + /* + * To restore call "remote hold" state after page reload. + */ + }, { + key: "setRemoteHoldState", + value: function setRemoteHoldState() { + this.js_session._remoteHold = true; + } + + /* + * Blind or attended transfer + */ + }, { + key: "sendRefer", + value: function sendRefer(callTo) { + var probeSession = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + if (!AudioCodesUA.instance.listeners.transferorNotification) throw new Error('transferorNotification listener is missed'); + var ac_session = this; + var options = { + eventHandlers: { + requestSucceeded: function requestSucceeded() { + AudioCodesUA.ac_log('AC>>: transferorNotification progress [REFER accepted]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 0); + }, + requestFailed: function requestFailed() { + AudioCodesUA.ac_log('AC>>: transferorNotification failed [REFER failed]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, -1); + }, + trying: function trying() { + AudioCodesUA.ac_log('AC>>: transferorNotification progress [NOTIFY 1xx]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 0); + }, + progress: function progress() { + AudioCodesUA.ac_log('AC>>: transferorNotification progress [NOTIFY 1xx]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 0); + }, + accepted: function accepted() { + AudioCodesUA.ac_log('AC>>: transferorNotification success [NOTIFY 2xx]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, 1); + }, + failed: function failed() { + AudioCodesUA.ac_log('AC>>: transferorNotification failed [NOTIFY >= 300]'); + AudioCodesUA.instance.listeners.transferorNotification(ac_session, -1); + } + } + }; + + // REFER with header ReferTo with replaces parameter + if (probeSession !== null) { + options.replaces = probeSession.js_session; + } + this.js_session.refer(callTo, options); + } + }]); + return AudioCodesSession; +}(); // SDP parser +var AudioCodesSDP = /*#__PURE__*/function () { + function AudioCodesSDP(sdp) { + _classCallCheck(this, AudioCodesSDP); + this.start = []; + this.media = []; + var lines = sdp.split('\n').map(function (l) { + return l.trim(); + }).filter(function (l) { + return l.length > 0; + }); + var current = this.start; + var _iterator9 = _createForOfIteratorHelper(lines), + _step9; + try { + for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) { + var line = _step9.value; + if (line.startsWith('m=')) { + current = []; + this.media.push(current); + } + current.push(line); + } + } catch (err) { + _iterator9.e(err); + } finally { + _iterator9.f(); + } + } + _createClass(AudioCodesSDP, [{ + key: "getMedia", + value: function getMedia(type) { + var _iterator10 = _createForOfIteratorHelper(this.media), + _step10; + try { + for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) { + var m = _step10.value; + if (m.length > 0 && m[0].startsWith('m=' + type)) return m; + } + } catch (err) { + _iterator10.e(err); + } finally { + _iterator10.f(); + } + return null; + } + }, { + key: "checkSendRecv", + value: function checkSendRecv(line) { + switch (line) { + case 'a=sendrecv': + return 'sendrecv'; + case 'a=sendonly': + return 'sendonly'; + case 'a=recvonly': + return 'recvonly'; + case 'a=inactive': + return 'inactive'; + default: + return null; + } + } + }, { + key: "getMediaDirectionValue", + value: function getMediaDirectionValue(type) { + var media = this.getMedia(type); + if (media === null) return null; + var t; + var result = 'sendrecv'; + var _iterator11 = _createForOfIteratorHelper(this.start), + _step11; + try { + for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) { + var line = _step11.value; + if ((t = this.checkSendRecv(line)) !== null) { + result = t; + break; + } + } + } catch (err) { + _iterator11.e(err); + } finally { + _iterator11.f(); + } + var _iterator12 = _createForOfIteratorHelper(media), + _step12; + try { + for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) { + var _line = _step12.value; + if ((t = this.checkSendRecv(_line)) !== null) { + result = t; + break; + } + } + } catch (err) { + _iterator12.e(err); + } finally { + _iterator12.f(); + } + return result; + } + }, { + key: "getMediaDirection", + value: function getMediaDirection(type, remote) { + var dir = this.getMediaDirectionValue(type); + switch (dir) { + case 'sendrecv': + return [true, true, dir]; + case 'sendonly': + return remote ? [false, true, dir] : [true, false, dir]; + case 'recvonly': + return remote ? [true, false, dir] : [false, true, dir]; + case null: + case 'inactive': + return [false, false, dir]; + } + } + }, { + key: "toString", + value: function toString() { + var result = this.start; + var _iterator13 = _createForOfIteratorHelper(this.media), + _step13; + try { + for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) { + var m = _step13.value; + result = result.concat(m); + } + } catch (err) { + _iterator13.e(err); + } finally { + _iterator13.f(); + } + return result.join('\r\n') + '\r\n'; + } + }]); + return AudioCodesSDP; +}(); // WebRTC Wrapper +var AudioCodesWebRTCWrapper = { + getUserMedia: function getUserMedia(constraints) { + AudioCodesUA.ac_log("[webrtc] getUserMedia constraints=".concat(JSON.stringify(constraints))); + return navigator.mediaDevices.getUserMedia(constraints); + }, + hasDisplayMedia: function hasDisplayMedia() { + return navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia; + }, + getDisplayMedia: function getDisplayMedia() { + AudioCodesUA.ac_log('[webrtc] getDisplayMedia'); + return navigator.mediaDevices.getDisplayMedia({ + video: true + }); + }, + mediaDevices: { + enumerateDevices: function enumerateDevices() { + if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) return Promise.reject('WebRTC is not supported'); + return navigator.mediaDevices.enumerateDevices(); + }, + addDeviceChangeListener: function addDeviceChangeListener(listener) { + if (!navigator.mediaDevices) return; + navigator.mediaDevices.addEventListener('devicechange', listener); + }, + removeDeviceChangeListener: function removeDeviceChangeListener(listener) { + if (!navigator.mediaDevices) return; + navigator.mediaDevices.removeEventListener('devicechange', listener); + } + }, + // Check WebRTC support. Check presence of microphone and camera + checkAvailableDevices: function checkAvailableDevices() { + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) return Promise.reject('WebRTC is not supported'); + var cam = false, + mic = false, + spkr = false; + return navigator.mediaDevices.enumerateDevices().then(function (deviceInfos) { + deviceInfos.forEach(function (d) { + switch (d.kind) { + case 'videoinput': + cam = true; + break; + case 'audioinput': + mic = true; + break; + case 'audiooutput': + spkr = true; + break; + } + }); + if (navigator.webkitGetUserMedia === undefined) { + // Not Chrome + spkr = true; + } + if (!spkr) return Promise.reject('Missing a speaker! Please connect one and reload'); + if (!mic) return Promise.reject('Missing a microphone! Please connect one and reload'); + return Promise.resolve(cam); + }); + }, + transceiver: { + setDirection: function setDirection(transceiver, direction) { + var kind = ''; + if (transceiver.sender.track !== null) kind = transceiver.sender.track.kind;else if (transceiver.receiver.track !== null) kind = transceiver.receiver.track.kind; + AudioCodesUA.ac_log("[webrtc] set ".concat(kind, " transceiver direction=").concat(direction)); + transceiver.direction = direction; + } + }, + stream: { + // For logging + getInfo: function getInfo(stream) { + function getTrackInfo(tr) { + return tr.length > 0 ? tr[0].enabled.toString() : '-'; + } + if (stream === null) return Promise.resolve('stream is null'); + return Promise.resolve("audio: ".concat(getTrackInfo(stream.getAudioTracks()), " video: ").concat(getTrackInfo(stream.getVideoTracks()))); + } + }, + connection: { + // For logging + getTransceiversInfo: function getTransceiversInfo(connection) { + function getTransInfo(t) { + return t === null ? 'none' : "d=".concat(t.direction, " c=").concat(t.currentDirection); + } + var ts = connection.getTransceivers(); + var at = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'audio'); + var vt = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'video'); + return Promise.resolve("(".concat(ts.length, ") audio ").concat(getTransInfo(at), " video ").concat(getTransInfo(vt))); + }, + getTransceiver: function getTransceiver(connection, kind) { + var _iterator14 = _createForOfIteratorHelper(connection.getTransceivers()), + _step14; + try { + for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) { + var t = _step14.value; + if (t.sender !== null && t.sender.track !== null && t.sender.track.kind === kind) { + return t; + } + if (t.receiver !== null && t.receiver.track !== null && t.receiver.track.kind === kind) { + return t; + } + } + } catch (err) { + _iterator14.e(err); + } finally { + _iterator14.f(); + } + return null; + }, + addEventListener: function addEventListener(connection, eventName, listener) { + AudioCodesUA.ac_log("[webrtc] Connection addEventListener ".concat(eventName)); + if (eventName !== 'track') return Promise.reject("Wrong event name: ".concat(eventName)); + connection.addEventListener(eventName, listener); + return Promise.resolve(); + }, + getDTMFSender: function getDTMFSender(connection) { + var sender = connection.getSenders().find(function (s) { + return s.track && s.track.kind === 'audio'; + }); + if (sender && sender.dtmf) return sender.dtmf; + return undefined; + }, + addVideo: function addVideo(connection, localStream, videoTrack, enabledReceiveVideo, wasUsedSendVideo) { + AudioCodesUA.ac_log('[webrtc] Connection addVideo'); + var vt = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'video'); + if (vt !== null) { + var dir = enabledReceiveVideo ? 'sendrecv' : 'sendonly'; + AudioCodesUA.instance.getWR().transceiver.setDirection(vt, dir); + } + if (vt === null || vt.sender.track === null && !wasUsedSendVideo) { + AudioCodesUA.ac_log('[webrtc] addVideo (connection addTrack)'); + connection.addTrack(videoTrack, localStream); + return Promise.resolve(true); + } else { + AudioCodesUA.ac_log('[webrtc] addVideo (video transceiver sender replaceTrack)'); + return vt.sender.replaceTrack(videoTrack).then(function () { + return false; + }); + } + }, + removeVideo: function removeVideo(connection, localStream) { + AudioCodesUA.ac_log('[webrtc] Connection removeVideo'); + var vt = AudioCodesUA.instance.getWR().connection.getTransceiver(connection, 'video'); + if (vt === null) return Promise.reject('no video transceiver found'); + connection.removeTrack(vt.sender); + if (localStream) { + var _iterator15 = _createForOfIteratorHelper(localStream.getVideoTracks()), + _step15; + try { + for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) { + var track = _step15.value; + localStream.removeTrack(track); + track.stop(); + } + } catch (err) { + _iterator15.e(err); + } finally { + _iterator15.f(); + } + } + return Promise.resolve(); + }, + replaceSenderTrack: function replaceSenderTrack(connection, kind, stream) { + AudioCodesUA.ac_log("[webrtc] ReplaceSenderTrack ".concat(kind)); + var foundSender = null; + var _iterator16 = _createForOfIteratorHelper(connection.getSenders()), + _step16; + try { + for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) { + var sender = _step16.value; + if (sender.track !== null && sender.track.kind === kind) { + foundSender = sender; + break; + } + } + } catch (err) { + _iterator16.e(err); + } finally { + _iterator16.f(); + } + if (foundSender === null) return Promise.reject("No ".concat(kind, " sender")); + var tracks = kind === 'audio' ? stream.getAudioTracks() : stream.getVideoTracks(); + if (tracks.length === 0) return Promise.reject("No ".concat(kind, " track")); + return foundSender.replaceTrack(tracks[0]); + }, + // "types" example ['outboud-rtp', 'inbound-rtp'] + getStats: function getStats(connection, types) { + var str = ''; + return connection.getStats(null).then(function (report) { + report.forEach(function (now) { + if (types.includes(now.type)) { + str += ' {'; + var first = true; + for (var _i4 = 0, _Object$keys2 = Object.keys(now); _i4 < _Object$keys2.length; _i4++) { + var key = _Object$keys2[_i4]; + if (first) first = false;else str += ','; + str += key + '=' + now[key]; + } + str += '} \r\n'; + } + }); + return str; + }); + } + } +}; \ No newline at end of file diff --git a/js/citrix_ac_webrtc.min.js b/js/citrix_ac_webrtc.min.js new file mode 100644 index 0000000..892f28b --- /dev/null +++ b/js/citrix_ac_webrtc.min.js @@ -0,0 +1,16 @@ +/* + * JsSIP v3.10.0 + * the Javascript SIP library + * Copyright: 2012-2023 + * Homepage: https://jssip.net + * License: MIT + */ + +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JsSIP=e()}}(function(){return function(){return function e(t,n,r){function i(o,l){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!l&&a)return a(o,!0);if(s)return s(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[o]={exports:{}};t[o][0].call(c.exports,function(e){return i(t[o][1][e]||e)},c,c.exports,e,t,n,r)}return n[o].exports}for(var s="function"==typeof require&&require,o=0;o=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0)return t}},connection_recovery_min_interval:function(e){if(s.isDecimal(e)){var t=Number(e);if(t>0)return t}},contact_uri:function(e){if("string"==typeof e){var t=l.parse(e,"SIP_URI");if(-1!==t)return t}},display_name:function(e){return e},instance_id:function(e){return/^uuid:/i.test(e)&&(e=e.substr(5)),-1===l.parse(e,"uuid")?void 0:e},no_answer_timeout:function(e){if(s.isDecimal(e)){var t=Number(e);if(t>0)return t}},session_timers:function(e){if("boolean"==typeof e)return e},session_timers_refresh_method:function(e){if("string"==typeof e&&((e=e.toUpperCase())===o.INVITE||e===o.UPDATE))return e},session_timers_force_refresher:function(e){if("boolean"==typeof e)return e},password:function(e){return String(e)},realm:function(e){return String(e)},ha1:function(e){return String(e)},register:function(e){if("boolean"==typeof e)return e},register_expires:function(e){if(s.isDecimal(e)){var t=Number(e);if(t>0)return t}},registrar_server:function(e){/^sip:/i.test(e)||(e="".concat(o.SIP,":").concat(e));var t=a.parse(e);return t?t.user?void 0:t:void 0},use_preloaded_route:function(e){if("boolean"==typeof e)return e},extra_headers:function(e){var t=[];if(Array.isArray(e)&&e.length){var n,i=r(e);try{for(i.s();!(n=i.n()).done;){var s=n.value;"string"==typeof s&&t.push(s)}}catch(e){i.e(e)}finally{i.f()}return t}}}};n.load=function(e,t){for(var n in h.mandatory){if(!t.hasOwnProperty(n))throw new c.ConfigurationError(n);var r=t[n],i=h.mandatory[n](r);if(void 0===i)throw new c.ConfigurationError(n,r);e[n]=i}for(var o in h.optional)if(t.hasOwnProperty(o)){var l=t[o];if(s.isEmpty(l))continue;var a=h.optional[o](l);if(void 0===a)throw new c.ConfigurationError(o,l);e[o]=a}}},{"./Constants":2,"./Exceptions":6,"./Grammar":7,"./Socket":23,"./URI":29,"./Utils":30}],2:[function(e,t,n){"use strict";var r=e("../package.json");t.exports={USER_AGENT:"".concat(r.title," ").concat(r.version),SIP:"sip",SIPS:"sips",causes:{CONNECTION_ERROR:"Connection Error",REQUEST_TIMEOUT:"Request Timeout",SIP_FAILURE_CODE:"SIP Failure Code",INTERNAL_ERROR:"Internal Error",BUSY:"Busy",REJECTED:"Rejected",REDIRECTED:"Redirected",UNAVAILABLE:"Unavailable",NOT_FOUND:"Not Found",ADDRESS_INCOMPLETE:"Address Incomplete",INCOMPATIBLE_SDP:"Incompatible SDP",MISSING_SDP:"Missing SDP",AUTHENTICATION_ERROR:"Authentication Error",BYE:"Terminated",WEBRTC_ERROR:"WebRTC Error",CANCELED:"Canceled",NO_ANSWER:"No Answer",EXPIRES:"Expires",NO_ACK:"No ACK",DIALOG_ERROR:"Dialog Error",USER_DENIED_MEDIA_ACCESS:"User Denied Media Access",BAD_MEDIA_DESCRIPTION:"Bad Media Description",RTP_TIMEOUT:"RTP Timeout"},SIP_ERROR_CAUSES:{REDIRECTED:[300,301,302,305,380],BUSY:[486,600],REJECTED:[403,603],NOT_FOUND:[404,604],UNAVAILABLE:[480,410,408,430],ADDRESS_INCOMPLETE:[484,424],INCOMPATIBLE_SDP:[488,606],AUTHENTICATION_ERROR:[401,407]},ACK:"ACK",BYE:"BYE",CANCEL:"CANCEL",INFO:"INFO",INVITE:"INVITE",MESSAGE:"MESSAGE",NOTIFY:"NOTIFY",OPTIONS:"OPTIONS",REGISTER:"REGISTER",REFER:"REFER",UPDATE:"UPDATE",SUBSCRIBE:"SUBSCRIBE",DTMF_TRANSPORT:{INFO:"INFO",RFC2833:"RFC2833"},REASON_PHRASE:{100:"Trying",180:"Ringing",181:"Call Is Being Forwarded",182:"Queued",183:"Session Progress",199:"Early Dialog Terminated",200:"OK",202:"Accepted",204:"No Notification",300:"Multiple Choices",301:"Moved Permanently",302:"Moved Temporarily",305:"Use Proxy",380:"Alternative Service",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",410:"Gone",412:"Conditional Request Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Unsupported URI Scheme",417:"Unknown Resource-Priority",420:"Bad Extension",421:"Extension Required",422:"Session Interval Too Small",423:"Interval Too Brief",424:"Bad Location Information",428:"Use Identity Header",429:"Provide Referrer Identity",430:"Flow Failed",433:"Anonymity Disallowed",436:"Bad Identity-Info",437:"Unsupported Certificate",438:"Invalid Identity Header",439:"First Hop Lacks Outbound Support",440:"Max-Breadth Exceeded",469:"Bad Info Package",470:"Consent Needed",478:"Unresolvable Destination",480:"Temporarily Unavailable",481:"Call/Transaction Does Not Exist",482:"Loop Detected",483:"Too Many Hops",484:"Address Incomplete",485:"Ambiguous",486:"Busy Here",487:"Request Terminated",488:"Not Acceptable Here",489:"Bad Event",491:"Request Pending",493:"Undecipherable",494:"Security Agreement Required",500:"JsSIP Internal Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Server Time-out",505:"Version Not Supported",513:"Message Too Large",580:"Precondition Failure",600:"Busy Everywhere",603:"Decline",604:"Does Not Exist Anywhere",606:"Not Acceptable"},ALLOWED_METHODS:"INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO,NOTIFY,SUBSCRIBE",ACCEPTED_BODY_TYPES:"application/sdp, application/dtmf-relay",MAX_FORWARDS:69,SESSION_EXPIRES:90,MIN_SESSION_EXPIRES:60,CONNECTION_RECOVERY_MAX_INTERVAL:30,CONNECTION_RECOVERY_MIN_INTERVAL:2}},{"../package.json":42}],3:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:h.STATUS_CONFIRMED;if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this._owner=t,this._ua=t._ua,this._uac_pending_reply=!1,this._uas_pending_reply=!1,!n.hasHeader("contact"))return{error:"unable to create a Dialog without Contact header field"};n instanceof s.IncomingResponse&&(i=n.status_code<200?h.STATUS_EARLY:h.STATUS_CONFIRMED);var o=n.parseHeader("contact");"UAS"===r?(this._id={call_id:n.call_id,local_tag:n.to_tag,remote_tag:n.from_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this._state=i,this._remote_seqnum=n.cseq,this._local_uri=n.parseHeader("to").uri,this._remote_uri=n.parseHeader("from").uri,this._remote_target=o.uri,this._route_set=n.getHeaders("record-route"),this._ack_seqnum=this._remote_seqnum):"UAC"===r&&(this._id={call_id:n.call_id,local_tag:n.from_tag,remote_tag:n.to_tag,toString:function(){return this.call_id+this.local_tag+this.remote_tag}},this._state=i,this._local_seqnum=n.cseq,this._local_uri=n.parseHeader("from").uri,this._remote_uri=n.parseHeader("to").uri,this._remote_target=o.uri,this._route_set=n.getHeaders("record-route").reverse(),this._ack_seqnum=null),this._ua.newDialog(this),c.debug("new ".concat(r," dialog created with status ").concat(this._state===h.STATUS_EARLY?"EARLY":"CONFIRMED"))}var t,n,i;return t=e,i=[{key:"C",get:function(){return h}}],(n=[{key:"id",get:function(){return this._id}},{key:"local_seqnum",get:function(){return this._local_seqnum},set:function(e){this._local_seqnum=e}},{key:"owner",get:function(){return this._owner}},{key:"uac_pending_reply",get:function(){return this._uac_pending_reply},set:function(e){this._uac_pending_reply=e}},{key:"uas_pending_reply",get:function(){return this._uas_pending_reply}},{key:"isTerminated",value:function(){return this._status===h.STATUS_TERMINATED}},{key:"update",value:function(e,t){this._state=h.STATUS_CONFIRMED,c.debug("dialog ".concat(this._id.toString()," changed to CONFIRMED state")),"UAC"===t&&(this._route_set=e.getHeaders("record-route").reverse())}},{key:"terminate",value:function(){c.debug("dialog ".concat(this._id.toString()," deleted")),this._ua.destroyDialog(this),this._state=h.STATUS_TERMINATED}},{key:"sendRequest",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=u.cloneArray(n.extraHeaders),i=u.cloneObject(n.eventHandlers),s=n.body||null,o=this._createRequest(e,r,s);return i.onAuthenticated=function(){t._local_seqnum+=1},new a(this,o,i).send(),o}},{key:"receiveRequest",value:function(e){this._checkInDialogRequest(e)&&(e.method===o.ACK&&null!==this._ack_seqnum?this._ack_seqnum=null:e.method===o.INVITE&&(this._ack_seqnum=e.cseq),this._owner.receiveRequest(e))}},{key:"_createRequest",value:function(e,t,n){t=u.cloneArray(t),this._local_seqnum||(this._local_seqnum=Math.floor(1e4*Math.random()));var r=e===o.CANCEL||e===o.ACK?this._local_seqnum:this._local_seqnum+=1;return new s.OutgoingRequest(e,this._remote_target,this._ua,{cseq:r,call_id:this._id.call_id,from_uri:this._local_uri,from_tag:this._id.local_tag,to_uri:this._remote_uri,to_tag:this._id.remote_tag,route_set:this._route_set},t,n)}},{key:"_checkInDialogRequest",value:function(e){var t=this;if(this._remote_seqnum)if(e.cseqthis._remote_seqnum&&(this._remote_seqnum=e.cseq);else this._remote_seqnum=e.cseq;if(e.method===o.INVITE||e.method===o.UPDATE&&e.body){if(!0===this._uac_pending_reply)e.reply(491);else{if(!0===this._uas_pending_reply){var n=1+(10*Math.random()|0);return e.reply(500,null,["Retry-After:".concat(n)]),!1}this._uas_pending_reply=!0;e.server_transaction.on("stateChanged",function n(){e.server_transaction.state!==l.C.STATUS_ACCEPTED&&e.server_transaction.state!==l.C.STATUS_COMPLETED&&e.server_transaction.state!==l.C.STATUS_TERMINATED||(e.server_transaction.removeListener("stateChanged",n),t._uas_pending_reply=!1)})}e.hasHeader("contact")&&e.server_transaction.on("stateChanged",function(){e.server_transaction.state===l.C.STATUS_ACCEPTED&&(t._remote_target=e.parseHeader("contact").uri)})}else e.method===o.NOTIFY&&e.hasHeader("contact")&&e.server_transaction.on("stateChanged",function(){e.server_transaction.state===l.C.STATUS_COMPLETED&&(t._remote_target=e.parseHeader("contact").uri)});return!0}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Dialog/RequestSender":4,"./Logger":9,"./SIPMessage":22,"./Transactions":26,"./Utils":30}],4:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=200&&e.status_code<300?this._eventHandlers.onSuccessResponse(e):e.status_code>=300&&this._eventHandlers.onErrorResponse(e):(this._request.cseq=this._dialog.local_seqnum+=1,this._reattemptTimer=setTimeout(function(){t._dialog.isTerminated()||(t._reattempt=!0,t.send())},1e3)):e.status_code>=200&&e.status_code<300?this._eventHandlers.onSuccessResponse(e):e.status_code>=300&&this._eventHandlers.onErrorResponse(e)}}])&&r(t.prototype,n),a&&r(t,a),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"../Constants":2,"../RequestSender":21,"../Transactions":26}],5:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:null;if(this._algorithm=t.algorithm,this._realm=t.realm,this._nonce=t.nonce,this._opaque=t.opaque,this._stale=t.stale,this._algorithm){if("MD5"!==this._algorithm)return o.warn('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted'),!1}else this._algorithm="MD5";if(!this._nonce)return o.warn("authenticate() | challenge without Digest nonce, authentication aborted"),!1;if(!this._realm)return o.warn("authenticate() | challenge without Digest realm, authentication aborted"),!1;if(!this._credentials.password){if(!this._credentials.ha1)return o.warn("authenticate() | no plain SIP password nor ha1 provided, authentication aborted"),!1;if(this._credentials.realm!==this._realm)return o.warn('authenticate() | no plain SIP password, and stored `realm` does not match the given `realm`, cannot authenticate [stored:"%s", given:"%s"]',this._credentials.realm,this._realm),!1}if(t.qop)if(t.qop.indexOf("auth-int")>-1)this._qop="auth-int";else{if(!(t.qop.indexOf("auth")>-1))return o.warn('authenticate() | challenge without Digest qop different than "auth" or "auth-int", authentication aborted'),!1;this._qop="auth"}else this._qop=null;this._method=n,this._uri=r,this._cnonce=l||s.createRandomToken(12),this._nc+=1;var a,u,c=Number(this._nc).toString(16);return this._ncHex="00000000".substr(0,8-c.length)+c,4294967296===this._nc&&(this._nc=1,this._ncHex="00000001"),this._credentials.password?this._ha1=s.calculateMD5("".concat(this._credentials.username,":").concat(this._realm,":").concat(this._credentials.password)):this._ha1=this._credentials.ha1,"auth"===this._qop?(a="".concat(this._method,":").concat(this._uri),u=s.calculateMD5(a),o.debug('authenticate() | using qop=auth [a2:"%s"]',a),this._response=s.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(this._ncHex,":").concat(this._cnonce,":auth:").concat(u))):"auth-int"===this._qop?(a="".concat(this._method,":").concat(this._uri,":").concat(s.calculateMD5(i||"")),u=s.calculateMD5(a),o.debug('authenticate() | using qop=auth-int [a2:"%s"]',a),this._response=s.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(this._ncHex,":").concat(this._cnonce,":auth-int:").concat(u))):null===this._qop&&(a="".concat(this._method,":").concat(this._uri),u=s.calculateMD5(a),o.debug('authenticate() | using qop=null [a2:"%s"]',a),this._response=s.calculateMD5("".concat(this._ha1,":").concat(this._nonce,":").concat(u))),o.debug("authenticate() | response generated"),!0}},{key:"toString",value:function(){var e=[];if(!this._response)throw new Error("response field does not exist, cannot generate Authorization header");return e.push("algorithm=".concat(this._algorithm)),e.push('username="'.concat(this._credentials.username,'"')),e.push('realm="'.concat(this._realm,'"')),e.push('nonce="'.concat(this._nonce,'"')),e.push('uri="'.concat(this._uri,'"')),e.push('response="'.concat(this._response,'"')),this._opaque&&e.push('opaque="'.concat(this._opaque,'"')),this._qop&&(e.push("qop=".concat(this._qop)),e.push('cnonce="'.concat(this._cnonce,'"')),e.push("nc=".concat(this._ncHex))),"Digest ".concat(e.join(", "))}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Logger":9,"./Utils":30}],6:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n",s++):(e=null,0===o&&u('">"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","')),null===e&&(59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(92===n.charCodeAt(s)?(e="\\",s++):(e=null,0===o&&u('"\\\\"')),null===e&&null===(e=m())&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null===e&&(93===n.charCodeAt(s)?(e="]",s++):(e=null,0===o&&u('"]"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(123===n.charCodeAt(s)?(e="{",s++):(e=null,0===o&&u('"{"')),null===e&&(125===n.charCodeAt(s)?(e="}",s++):(e=null,0===o&&u('"}"')),null===e&&null===(e=v())&&(e=g()))))))))))))))));return e},word:x,STAR:U,SLASH:D,EQUAL:M,LPAREN:q,RPAREN:L,RAQUOT:H,LAQUOT:F,COMMA:j,SEMI:B,COLON:G,LDQUOT:V,RDQUOT:W,comment:function e(){var t,n,r;var i;i=s;t=q();if(null!==t){for(n=[],null===(r=Y())&&null===(r=X())&&(r=e());null!==r;)n.push(r),null===(r=Y())&&null===(r=X())&&(r=e());null!==n&&null!==(r=L())?t=[t,n,r]:(t=null,s=i)}else t=null,s=i;return t},ctext:Y,quoted_string:K,quoted_string_clean:z,qdtext:$,quoted_pair:X,SIP_URI_noparams:J,SIP_URI:Q,uri_scheme:Z,uri_scheme_sips:ee,uri_scheme_sip:te,userinfo:ne,user:re,user_unreserved:ie,password:se,hostport:oe,host:le,hostname:ae,domainlabel:ue,toplabel:ce,IPv6reference:he,IPv6address:de,h16:fe,ls32:_e,IPv4address:pe,dec_octet:me,port:ve,uri_parameters:ge,uri_parameter:ye,transport_param:Te,user_param:be,method_param:Se,ttl_param:Ee,maddr_param:Ce,lr_param:Ae,other_param:we,pname:Re,pvalue:Ie,paramchar:Oe,param_unreserved:Ne,headers:ke,header:Pe,hname:xe,hvalue:Ue,hnv_unreserved:De,Request_Response:function(){var e;null===(e=ht())&&(e=Me());return e},Request_Line:Me,Request_URI:qe,absoluteURI:Le,hier_part:He,net_path:Fe,abs_path:je,opaque_part:Be,uric:Ge,uric_no_slash:Ve,path_segments:We,segment:Ye,param:Ke,pchar:ze,scheme:$e,authority:Xe,srvr:Je,reg_name:Qe,query:Ze,SIP_Version:et,INVITEm:tt,ACKm:nt,OPTIONSm:rt,BYEm:it,CANCELm:st,REGISTERm:ot,SUBSCRIBEm:lt,NOTIFYm:at,REFERm:ut,Method:ct,Status_Line:ht,Status_Code:dt,extension_code:ft,Reason_Phrase:_t,Allow_Events:function(){var e,t,n,r,i,o;if(i=s,null!==(e=Lt())){for(t=[],o=s,null!==(n=j())&&null!==(r=Lt())?n=[n,r]:(n=null,s=o);null!==n;)t.push(n),o=s,null!==(n=j())&&null!==(r=Lt())?n=[n,r]:(n=null,s=o);null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e},Call_ID:function(){var e,t,r,i,l,a;i=s,l=s,null!==(e=x())?(a=s,64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null!==t&&null!==(r=x())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l);null!==e&&(c=i,e=void(jn=n.substring(s,c)));var c;null===e&&(s=i);return e},Contact:function(){var e,t,n,r,i,o,l;if(i=s,null===(e=U()))if(o=s,null!==(e=pt())){for(t=[],l=s,null!==(n=j())&&null!==(r=pt())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=j())&&null!==(r=pt())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;null!==e&&(e=function(e){var t,n;for(n=jn.multi_header.length,t=0;tl&&(l=s,a=[]),a.push(e))}function c(){var e;return"\r\n"===n.substr(s,2)?(e="\r\n",s+=2):(e=null,0===o&&u('"\\r\\n"')),e}function h(){var e;return/^[0-9]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[0-9]")),e}function d(){var e;return/^[a-zA-Z]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[a-zA-Z]")),e}function f(){var e;return/^[0-9a-fA-F]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[0-9a-fA-F]")),e}function _(){var e;return null===(e=v())&&(e=g()),e}function p(){var e;return/^[\0-\xFF]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\0-\\xFF]")),e}function m(){var e;return/^["]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u('["]')),e}function v(){var e;return 32===n.charCodeAt(s)?(e=" ",s++):(e=null,0===o&&u('" "')),e}function g(){var e;return 9===n.charCodeAt(s)?(e="\t",s++):(e=null,0===o&&u('"\\t"')),e}function y(){var e;return/^[a-zA-Z0-9]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[a-zA-Z0-9]")),e}function T(){var e;return 59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","'))))))))))),e}function b(){var e;return null===(e=y())&&(e=S()),e}function S(){var e;return 45===n.charCodeAt(s)?(e="-",s++):(e=null,0===o&&u('"-"')),null===e&&(95===n.charCodeAt(s)?(e="_",s++):(e=null,0===o&&u('"_"')),null===e&&(46===n.charCodeAt(s)?(e=".",s++):(e=null,0===o&&u('"."')),null===e&&(33===n.charCodeAt(s)?(e="!",s++):(e=null,0===o&&u('"!"')),null===e&&(126===n.charCodeAt(s)?(e="~",s++):(e=null,0===o&&u('"~"')),null===e&&(42===n.charCodeAt(s)?(e="*",s++):(e=null,0===o&&u('"*"')),null===e&&(39===n.charCodeAt(s)?(e="'",s++):(e=null,0===o&&u('"\'"')),null===e&&(40===n.charCodeAt(s)?(e="(",s++):(e=null,0===o&&u('"("')),null===e&&(41===n.charCodeAt(s)?(e=")",s++):(e=null,0===o&&u('")"')))))))))),e}function E(){var e,t,r,i,l;return i=s,l=s,37===n.charCodeAt(s)?(e="%",s++):(e=null,0===o&&u('"%"')),null!==e&&null!==(t=f())&&null!==(r=f())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=e.join("")),null===e&&(s=i),e}function C(){var e,t,n,r,i,o;for(r=s,i=s,o=s,e=[],t=_();null!==t;)e.push(t),t=_();if(null!==e&&null!==(t=c())?e=[e,t]:(e=null,s=o),null!==(e=null!==e?e:"")){if(null!==(n=_()))for(t=[];null!==n;)t.push(n),n=_();else t=null;null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return null!==e&&(e=" "),null===e&&(s=r),e}function A(){var e;return e=null!==(e=C())?e:""}function w(){var e,t,r,i,l;for(i=s,l=s,e=[],null===(t=v())&&(t=g());null!==t;)e.push(t),null===(t=v())&&(t=g());return null!==e?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=":"),null===e&&(s=i),e}function R(){var e,t,r,i,o,l,a,u;if(o=s,l=s,null!==(t=I()))for(e=[];null!==t;)e.push(t),t=I();else e=null;if(null!==e){for(t=[],a=s,r=[],i=C();null!==i;)r.push(i),i=C();for(null!==r&&null!==(i=I())?r=[r,i]:(r=null,s=a);null!==r;){for(t.push(r),a=s,r=[],i=C();null!==i;)r.push(i),i=C();null!==r&&null!==(i=I())?r=[r,i]:(r=null,s=a)}null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return null!==e&&(u=o,e=n.substring(s,u)),null===e&&(s=o),e}function I(){var e;return/^[!-~]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[!-~]")),null===e&&(e=O()),e}function O(){var e;return/^[\x80-\uFFFF]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\x80-\\uFFFF]")),e}function N(){var e;return/^[\x80-\xBF]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\x80-\\xBF]")),e}function k(){var e,t,r,i;if(r=s,null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"'))))))))))));else e=null;return null!==e&&(i=r,e=n.substring(s,i)),null===e&&(s=r),e}function P(){var e,t,r,i;if(r=s,null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"'))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')))))))))));else e=null;return null!==e&&(i=r,e=n.substring(s,i)),null===e&&(s=r),e}function x(){var e,t,r,i;if(r=s,null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')),null===t&&(40===n.charCodeAt(s)?(t="(",s++):(t=null,0===o&&u('"("')),null===t&&(41===n.charCodeAt(s)?(t=")",s++):(t=null,0===o&&u('")"')),null===t&&(60===n.charCodeAt(s)?(t="<",s++):(t=null,0===o&&u('"<"')),null===t&&(62===n.charCodeAt(s)?(t=">",s++):(t=null,0===o&&u('">"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(92===n.charCodeAt(s)?(t="\\",s++):(t=null,0===o&&u('"\\\\"')),null===t&&null===(t=m())&&(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null===t&&(91===n.charCodeAt(s)?(t="[",s++):(t=null,0===o&&u('"["')),null===t&&(93===n.charCodeAt(s)?(t="]",s++):(t=null,0===o&&u('"]"')),null===t&&(63===n.charCodeAt(s)?(t="?",s++):(t=null,0===o&&u('"?"')),null===t&&(123===n.charCodeAt(s)?(t="{",s++):(t=null,0===o&&u('"{"')),null===t&&(125===n.charCodeAt(s)?(t="}",s++):(t=null,0===o&&u('"}"')))))))))))))))))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=y())&&(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null===t&&(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null===t&&(33===n.charCodeAt(s)?(t="!",s++):(t=null,0===o&&u('"!"')),null===t&&(37===n.charCodeAt(s)?(t="%",s++):(t=null,0===o&&u('"%"')),null===t&&(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null===t&&(95===n.charCodeAt(s)?(t="_",s++):(t=null,0===o&&u('"_"')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(96===n.charCodeAt(s)?(t="`",s++):(t=null,0===o&&u('"`"')),null===t&&(39===n.charCodeAt(s)?(t="'",s++):(t=null,0===o&&u('"\'"')),null===t&&(126===n.charCodeAt(s)?(t="~",s++):(t=null,0===o&&u('"~"')),null===t&&(40===n.charCodeAt(s)?(t="(",s++):(t=null,0===o&&u('"("')),null===t&&(41===n.charCodeAt(s)?(t=")",s++):(t=null,0===o&&u('")"')),null===t&&(60===n.charCodeAt(s)?(t="<",s++):(t=null,0===o&&u('"<"')),null===t&&(62===n.charCodeAt(s)?(t=">",s++):(t=null,0===o&&u('">"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(92===n.charCodeAt(s)?(t="\\",s++):(t=null,0===o&&u('"\\\\"')),null===t&&null===(t=m())&&(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null===t&&(91===n.charCodeAt(s)?(t="[",s++):(t=null,0===o&&u('"["')),null===t&&(93===n.charCodeAt(s)?(t="]",s++):(t=null,0===o&&u('"]"')),null===t&&(63===n.charCodeAt(s)?(t="?",s++):(t=null,0===o&&u('"?"')),null===t&&(123===n.charCodeAt(s)?(t="{",s++):(t=null,0===o&&u('"{"')),null===t&&(125===n.charCodeAt(s)?(t="}",s++):(t=null,0===o&&u('"}"'))))))))))))))))))))))));else e=null;return null!==e&&(i=r,e=n.substring(s,i)),null===e&&(s=r),e}function U(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(42===n.charCodeAt(s)?(t="*",s++):(t=null,0===o&&u('"*"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="*"),null===e&&(s=i),e}function D(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="/"),null===e&&(s=i),e}function M(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="="),null===e&&(s=i),e}function q(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(40===n.charCodeAt(s)?(t="(",s++):(t=null,0===o&&u('"("')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e="("),null===e&&(s=i),e}function L(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(41===n.charCodeAt(s)?(t=")",s++):(t=null,0===o&&u('")"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=")"),null===e&&(s=i),e}function H(){var e,t,r,i;return r=s,i=s,62===n.charCodeAt(s)?(e=">",s++):(e=null,0===o&&u('">"')),null!==e&&null!==(t=A())?e=[e,t]:(e=null,s=i),null!==e&&(e=">"),null===e&&(s=r),e}function F(){var e,t,r,i;return r=s,i=s,null!==(e=A())?(60===n.charCodeAt(s)?(t="<",s++):(t=null,0===o&&u('"<"')),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(e="<"),null===e&&(s=r),e}function j(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=","),null===e&&(s=i),e}function B(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=";"),null===e&&(s=i),e}function G(){var e,t,r,i,l;return i=s,l=s,null!==(e=A())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=A())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(e=":"),null===e&&(s=i),e}function V(){var e,t,n,r;return n=s,r=s,null!==(e=A())&&null!==(t=m())?e=[e,t]:(e=null,s=r),null!==e&&(e='"'),null===e&&(s=n),e}function W(){var e,t,n,r;return n=s,r=s,null!==(e=m())&&null!==(t=A())?e=[e,t]:(e=null,s=r),null!==e&&(e='"'),null===e&&(s=n),e}function Y(){var e;return/^[!-']/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[!-']")),null===e&&(/^[*-[]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[*-[]")),null===e&&(/^[\]-~]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\]-~]")),null===e&&null===(e=O())&&(e=C()))),e}function K(){var e,t,r,i,o,l,a;if(o=s,l=s,null!==(e=A()))if(null!==(t=m())){for(r=[],null===(i=$())&&(i=X());null!==i;)r.push(i),null===(i=$())&&(i=X());null!==r&&null!==(i=m())?e=[e,t,r,i]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;return null!==e&&(a=o,e=n.substring(s,a)),null===e&&(s=o),e}function z(){var e,t,r,i,o,l,a,u;if(o=s,l=s,null!==(e=A()))if(null!==(t=m())){for(r=[],null===(i=$())&&(i=X());null!==i;)r.push(i),null===(i=$())&&(i=X());null!==r&&null!==(i=m())?e=[e,t,r,i]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;return null!==e&&(a=o,e=(u=n.substring(s,a).trim()).substring(1,u.length-1).replace(/\\([\x00-\x09\x0b-\x0c\x0e-\x7f])/g,"$1")),null===e&&(s=o),e}function $(){var e;return null===(e=C())&&(33===n.charCodeAt(s)?(e="!",s++):(e=null,0===o&&u('"!"')),null===e&&(/^[#-[]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[#-[]")),null===e&&(/^[\]-~]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[\\]-~]")),null===e&&(e=O())))),e}function X(){var e,t,r;return r=s,92===n.charCodeAt(s)?(e="\\",s++):(e=null,0===o&&u('"\\\\"')),null!==e?(/^[\0-\t]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[\\0-\\t]")),null===t&&(/^[\x0B-\f]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[\\x0B-\\f]")),null===t&&(/^[\x0E-]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[\\x0E-]")))),null!==t?e=[e,t]:(e=null,s=r)):(e=null,s=r),e}function J(){var e,t,r,i,l,a;return l=s,a=s,null!==(e=Z())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=null!==(r=ne())?r:"")&&null!==(i=oe())?e=[e,t,r,i]:(e=null,s=a)):(e=null,s=a),null!==e&&(e=function(e){try{jn.uri=new Hn(jn.scheme,jn.user,jn.host,jn.port),delete jn.scheme,delete jn.user,delete jn.host,delete jn.host_type,delete jn.port}catch(e){jn=-1}}()),null===e&&(s=l),e}function Q(){var e,t,i,l,a,c,h,d;return h=s,d=s,null!==(e=Z())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(i=null!==(i=ne())?i:"")&&null!==(l=oe())&&null!==(a=ge())&&null!==(c=null!==(c=ke())?c:"")?e=[e,t,i,l,a,c]:(e=null,s=d)):(e=null,s=d),null!==e&&(e=function(e){try{jn.uri=new Hn(jn.scheme,jn.user,jn.host,jn.port,jn.uri_params,jn.uri_headers),delete jn.scheme,delete jn.user,delete jn.host,delete jn.host_type,delete jn.port,delete jn.uri_params,"SIP_URI"===r&&(jn=jn.uri)}catch(e){jn=-1}}()),null===e&&(s=h),e}function Z(){var e;return null===(e=ee())&&(e=te()),e}function ee(){var e,t,r;return t=s,"sips"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"sips"')),null!==e&&(r=e,e=void(jn.scheme=r.toLowerCase())),null===e&&(s=t),e}function te(){var e,t,r;return t=s,"sip"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"sip"')),null!==e&&(r=e,e=void(jn.scheme=r.toLowerCase())),null===e&&(s=t),e}function ne(){var e,t,r,i,l,a,c;return i=s,l=s,null!==(e=re())?(a=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=se())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?(64===n.charCodeAt(s)?(r="@",s++):(r=null,0===o&&u('"@"')),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l)):(e=null,s=l),null!==e&&(c=i,e=void(jn.user=decodeURIComponent(n.substring(s-1,c)))),null===e&&(s=i),e}function re(){var e,t;if(null===(t=b())&&null===(t=E())&&(t=ie()),null!==t)for(e=[];null!==t;)e.push(t),null===(t=b())&&null===(t=E())&&(t=ie());else e=null;return e}function ie(){var e;return 38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","')),null===e&&(59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"'))))))))),e}function se(){var e,t,r,i;for(r=s,e=[],null===(t=b())&&null===(t=E())&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')))))));null!==t;)e.push(t),null===(t=b())&&null===(t=E())&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')),null===t&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')))))));return null!==e&&(i=r,e=void(jn.password=n.substring(s,i))),null===e&&(s=r),e}function oe(){var e,t,r,i,l;return i=s,null!==(e=le())?(l=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=ve())?t=[t,r]:(t=null,s=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),e}function le(){var e,t,r;return t=s,null===(e=ae())&&null===(e=pe())&&(e=he()),null!==e&&(r=t,jn.host=n.substring(s,r).toLowerCase(),e=jn.host),null===e&&(s=t),e}function ae(){var e,t,r,i,l,a,c;for(i=s,l=s,e=[],a=s,null!==(t=ue())?(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r?t=[t,r]:(t=null,s=a)):(t=null,s=a);null!==t;)e.push(t),a=s,null!==(t=ue())?(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r?t=[t,r]:(t=null,s=a)):(t=null,s=a);return null!==e&&null!==(t=ce())?(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==(r=null!==r?r:"")?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(c=i,jn.host_type="domain",e=n.substring(s,c)),null===e&&(s=i),e}function ue(){var e,t,r,i;if(i=s,null!==(e=y())){for(t=[],null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==r;)t.push(r),null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e}function ce(){var e,t,r,i;if(i=s,null!==(e=d())){for(t=[],null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==r;)t.push(r),null===(r=y())&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(95===n.charCodeAt(s)?(r="_",s++):(r=null,0===o&&u('"_"'))));null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e}function he(){var e,t,r,i,l,a;return i=s,l=s,91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null!==e&&null!==(t=de())?(93===n.charCodeAt(s)?(r="]",s++):(r=null,0===o&&u('"]"')),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=i,jn.host_type="IPv6",e=n.substring(s,a)),null===e&&(s=i),e}function de(){var e,t,r,i,l,a,c,h,d,f,_,p,m,v,g,y,T;return v=s,g=s,null!==(e=fe())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?(58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?(58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?(58===n.charCodeAt(s)?(h=":",s++):(h=null,0===o&&u('":"')),null!==h&&null!==(d=fe())?(58===n.charCodeAt(s)?(f=":",s++):(f=null,0===o&&u('":"')),null!==f&&null!==(_=fe())?(58===n.charCodeAt(s)?(p=":",s++):(p=null,0===o&&u('":"')),null!==p&&null!==(m=_e())?e=[e,t,r,i,l,a,c,h,d,f,_,p,m]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?(58===n.charCodeAt(s)?(d=":",s++):(d=null,0===o&&u('":"')),null!==d&&null!==(f=fe())?(58===n.charCodeAt(s)?(_=":",s++):(_=null,0===o&&u('":"')),null!==_&&null!==(p=_e())?e=[e,t,r,i,l,a,c,h,d,f,_,p]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?(58===n.charCodeAt(s)?(d=":",s++):(d=null,0===o&&u('":"')),null!==d&&null!==(f=_e())?e=[e,t,r,i,l,a,c,h,d,f]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=_e())?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=_e())?e=[e,t,r,i,l,a]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?(58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=_e())?e=[e,t,r,i]:(e=null,s=g)):(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=_e())?e=[e,t]:(e=null,s=g),null===e&&(g=s,"::"===n.substr(s,2)?(e="::",s+=2):(e=null,0===o&&u('"::"')),null!==e&&null!==(t=fe())?e=[e,t]:(e=null,s=g),null===e&&(g=s,null!==(e=fe())?("::"===n.substr(s,2)?(t="::",s+=2):(t=null,0===o&&u('"::"')),null!==t&&null!==(r=fe())?(58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?(58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?(58===n.charCodeAt(s)?(h=":",s++):(h=null,0===o&&u('":"')),null!==h&&null!==(d=fe())?(58===n.charCodeAt(s)?(f=":",s++):(f=null,0===o&&u('":"')),null!==f&&null!==(_=_e())?e=[e,t,r,i,l,a,c,h,d,f,_]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?("::"===n.substr(s,2)?(r="::",s+=2):(r=null,0===o&&u('"::"')),null!==r&&null!==(i=fe())?(58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?(58===n.charCodeAt(s)?(d=":",s++):(d=null,0===o&&u('":"')),null!==d&&null!==(f=_e())?e=[e,t,r,i,l,a,c,h,d,f]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?("::"===n.substr(s,2)?(i="::",s+=2):(i=null,0===o&&u('"::"')),null!==i&&null!==(l=fe())?(58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?(58===n.charCodeAt(s)?(h=":",s++):(h=null,0===o&&u('":"')),null!==h&&null!==(d=_e())?e=[e,t,r,i,l,a,c,h,d]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?("::"===n.substr(s,2)?(l="::",s+=2):(l=null,0===o&&u('"::"')),null!==l&&null!==(a=fe())?(58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=_e())?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?(y=s,58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?l=[l,a]:(l=null,s=y),null!==(l=null!==l?l:"")?("::"===n.substr(s,2)?(a="::",s+=2):(a=null,0===o&&u('"::"')),null!==a&&null!==(c=_e())?e=[e,t,r,i,l,a,c]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?(y=s,58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?l=[l,a]:(l=null,s=y),null!==(l=null!==l?l:"")?(y=s,58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?a=[a,c]:(a=null,s=y),null!==(a=null!==a?a:"")?("::"===n.substr(s,2)?(c="::",s+=2):(c=null,0===o&&u('"::"')),null!==c&&null!==(h=fe())?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g),null===e&&(g=s,null!==(e=fe())?(y=s,58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?t=[t,r]:(t=null,s=y),null!==(t=null!==t?t:"")?(y=s,58===n.charCodeAt(s)?(r=":",s++):(r=null,0===o&&u('":"')),null!==r&&null!==(i=fe())?r=[r,i]:(r=null,s=y),null!==(r=null!==r?r:"")?(y=s,58===n.charCodeAt(s)?(i=":",s++):(i=null,0===o&&u('":"')),null!==i&&null!==(l=fe())?i=[i,l]:(i=null,s=y),null!==(i=null!==i?i:"")?(y=s,58===n.charCodeAt(s)?(l=":",s++):(l=null,0===o&&u('":"')),null!==l&&null!==(a=fe())?l=[l,a]:(l=null,s=y),null!==(l=null!==l?l:"")?(y=s,58===n.charCodeAt(s)?(a=":",s++):(a=null,0===o&&u('":"')),null!==a&&null!==(c=fe())?a=[a,c]:(a=null,s=y),null!==(a=null!==a?a:"")?(y=s,58===n.charCodeAt(s)?(c=":",s++):(c=null,0===o&&u('":"')),null!==c&&null!==(h=fe())?c=[c,h]:(c=null,s=y),null!==(c=null!==c?c:"")?("::"===n.substr(s,2)?(h="::",s+=2):(h=null,0===o&&u('"::"')),null!==h?e=[e,t,r,i,l,a,c,h]:(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g)):(e=null,s=g))))))))))))))),null!==e&&(T=v,jn.host_type="IPv6",e=n.substring(s,T)),null===e&&(s=v),e}function fe(){var e,t,n,r,i;return i=s,null!==(e=f())&&null!==(t=null!==(t=f())?t:"")&&null!==(n=null!==(n=f())?n:"")&&null!==(r=null!==(r=f())?r:"")?e=[e,t,n,r]:(e=null,s=i),e}function _e(){var e,t,r,i;return i=s,null!==(e=fe())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t&&null!==(r=fe())?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),null===e&&(e=pe()),e}function pe(){var e,t,r,i,l,a,c,h,d,f;return h=s,d=s,null!==(e=me())?(46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null!==t&&null!==(r=me())?(46===n.charCodeAt(s)?(i=".",s++):(i=null,0===o&&u('"."')),null!==i&&null!==(l=me())?(46===n.charCodeAt(s)?(a=".",s++):(a=null,0===o&&u('"."')),null!==a&&null!==(c=me())?e=[e,t,r,i,l,a,c]:(e=null,s=d)):(e=null,s=d)):(e=null,s=d)):(e=null,s=d),null!==e&&(f=h,jn.host_type="IPv4",e=n.substring(s,f)),null===e&&(s=h),e}function me(){var e,t,r,i;return i=s,"25"===n.substr(s,2)?(e="25",s+=2):(e=null,0===o&&u('"25"')),null!==e?(/^[0-5]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[0-5]")),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null===e&&(i=s,50===n.charCodeAt(s)?(e="2",s++):(e=null,0===o&&u('"2"')),null!==e?(/^[0-4]/.test(n.charAt(s))?(t=n.charAt(s),s++):(t=null,0===o&&u("[0-4]")),null!==t&&null!==(r=h())?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),null===e&&(i=s,49===n.charCodeAt(s)?(e="1",s++):(e=null,0===o&&u('"1"')),null!==e&&null!==(t=h())&&null!==(r=h())?e=[e,t,r]:(e=null,s=i),null===e&&(i=s,/^[1-9]/.test(n.charAt(s))?(e=n.charAt(s),s++):(e=null,0===o&&u("[1-9]")),null!==e&&null!==(t=h())?e=[e,t]:(e=null,s=i),null===e&&(e=h())))),e}function ve(){var e,t,n,r,i,o,l,a;return o=s,l=s,null!==(e=null!==(e=h())?e:"")&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")?e=[e,t,n,r,i]:(e=null,s=l),null!==e&&(a=e,a=parseInt(a.join("")),jn.port=a,e=a),null===e&&(s=o),e}function ge(){var e,t,r,i;for(e=[],i=s,59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null!==t&&null!==(r=ye())?t=[t,r]:(t=null,s=i);null!==t;)e.push(t),i=s,59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null!==t&&null!==(r=ye())?t=[t,r]:(t=null,s=i);return e}function ye(){var e;return null===(e=Te())&&null===(e=be())&&null===(e=Se())&&null===(e=Ee())&&null===(e=Ce())&&null===(e=Ae())&&(e=we()),e}function Te(){var e,t,r,i,l;return r=s,i=s,"transport="===n.substr(s,10).toLowerCase()?(e=n.substr(s,10),s+=10):(e=null,0===o&&u('"transport="')),null!==e?("udp"===n.substr(s,3).toLowerCase()?(t=n.substr(s,3),s+=3):(t=null,0===o&&u('"udp"')),null===t&&("tcp"===n.substr(s,3).toLowerCase()?(t=n.substr(s,3),s+=3):(t=null,0===o&&u('"tcp"')),null===t&&("sctp"===n.substr(s,4).toLowerCase()?(t=n.substr(s,4),s+=4):(t=null,0===o&&u('"sctp"')),null===t&&("tls"===n.substr(s,3).toLowerCase()?(t=n.substr(s,3),s+=3):(t=null,0===o&&u('"tls"')),null===t&&(t=k())))),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.transport=l.toLowerCase())),null===e&&(s=r),e}function be(){var e,t,r,i,l;return r=s,i=s,"user="===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"user="')),null!==e?("phone"===n.substr(s,5).toLowerCase()?(t=n.substr(s,5),s+=5):(t=null,0===o&&u('"phone"')),null===t&&("ip"===n.substr(s,2).toLowerCase()?(t=n.substr(s,2),s+=2):(t=null,0===o&&u('"ip"')),null===t&&(t=k())),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.user=l.toLowerCase())),null===e&&(s=r),e}function Se(){var e,t,r,i,l;return r=s,i=s,"method="===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"method="')),null!==e&&null!==(t=ct())?e=[e,t]:(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.method=l)),null===e&&(s=r),e}function Ee(){var e,t,r,i,l;return r=s,i=s,"ttl="===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"ttl="')),null!==e&&null!==(t=An())?e=[e,t]:(e=null,s=i),null!==e&&(l=e[1],jn.params||(jn.params={}),e=void(jn.params.ttl=l)),null===e&&(s=r),e}function Ce(){var e,t,r,i,l;return r=s,i=s,"maddr="===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"maddr="')),null!==e&&null!==(t=le())?e=[e,t]:(e=null,s=i),null!==e&&(l=e[1],jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.maddr=l)),null===e&&(s=r),e}function Ae(){var e,t,r,i,l,a;return i=s,l=s,"lr"===n.substr(s,2).toLowerCase()?(e=n.substr(s,2),s+=2):(e=null,0===o&&u('"lr"')),null!==e?(a=s,61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=k())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l),null!==e&&(jn.uri_params||(jn.uri_params={}),e=void(jn.uri_params.lr=void 0)),null===e&&(s=i),e}function we(){var e,t,r,i,l,a,c,h;return i=s,l=s,null!==(e=Re())?(a=s,61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=Ie())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l),null!==e&&(c=e[0],h=e[1],jn.uri_params||(jn.uri_params={}),h=void 0===h?void 0:h[1],e=void(jn.uri_params[c.toLowerCase()]=h)),null===e&&(s=i),e}function Re(){var e,t,n;if(n=s,null!==(t=Oe()))for(e=[];null!==t;)e.push(t),t=Oe();else e=null;return null!==e&&(e=e.join("")),null===e&&(s=n),e}function Ie(){var e,t,n;if(n=s,null!==(t=Oe()))for(e=[];null!==t;)e.push(t),t=Oe();else e=null;return null!==e&&(e=e.join("")),null===e&&(s=n),e}function Oe(){var e;return null===(e=Ne())&&null===(e=b())&&(e=E()),e}function Ne(){var e;return 91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null===e&&(93===n.charCodeAt(s)?(e="]",s++):(e=null,0===o&&u('"]"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')))))))),e}function ke(){var e,t,r,i,l,a,c;if(a=s,63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null!==e)if(null!==(t=Pe())){for(r=[],c=s,38===n.charCodeAt(s)?(i="&",s++):(i=null,0===o&&u('"&"')),null!==i&&null!==(l=Pe())?i=[i,l]:(i=null,s=c);null!==i;)r.push(i),c=s,38===n.charCodeAt(s)?(i="&",s++):(i=null,0===o&&u('"&"')),null!==i&&null!==(l=Pe())?i=[i,l]:(i=null,s=c);null!==r?e=[e,t,r]:(e=null,s=a)}else e=null,s=a;else e=null,s=a;return e}function Pe(){var e,t,r,i,l,a,c;return i=s,l=s,null!==(e=xe())?(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null!==t&&null!==(r=Ue())?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[0],c=e[2],a=a.join("").toLowerCase(),c=c.join(""),jn.uri_headers||(jn.uri_headers={}),e=void(jn.uri_headers[a]?jn.uri_headers[a].push(c):jn.uri_headers[a]=[c])),null===e&&(s=i),e}function xe(){var e,t;if(null===(t=De())&&null===(t=b())&&(t=E()),null!==t)for(e=[];null!==t;)e.push(t),null===(t=De())&&null===(t=b())&&(t=E());else e=null;return e}function Ue(){var e,t;for(e=[],null===(t=De())&&null===(t=b())&&(t=E());null!==t;)e.push(t),null===(t=De())&&null===(t=b())&&(t=E());return e}function De(){var e;return 91===n.charCodeAt(s)?(e="[",s++):(e=null,0===o&&u('"["')),null===e&&(93===n.charCodeAt(s)?(e="]",s++):(e=null,0===o&&u('"]"')),null===e&&(47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')))))))),e}function Me(){var e,t,n,r,i,o;return o=s,null!==(e=ct())&&null!==(t=v())&&null!==(n=qe())&&null!==(r=v())&&null!==(i=et())?e=[e,t,n,r,i]:(e=null,s=o),e}function qe(){var e;return null===(e=Q())&&(e=Le()),e}function Le(){var e,t,r,i;return i=s,null!==(e=$e())?(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null!==t?(null===(r=He())&&(r=Be()),null!==r?e=[e,t,r]:(e=null,s=i)):(e=null,s=i)):(e=null,s=i),e}function He(){var e,t,r,i,l;return i=s,null===(e=Fe())&&(e=je()),null!==e?(l=s,63===n.charCodeAt(s)?(t="?",s++):(t=null,0===o&&u('"?"')),null!==t&&null!==(r=Ze())?t=[t,r]:(t=null,s=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),e}function Fe(){var e,t,r,i;return i=s,"//"===n.substr(s,2)?(e="//",s+=2):(e=null,0===o&&u('"//"')),null!==e&&null!==(t=Xe())&&null!==(r=null!==(r=je())?r:"")?e=[e,t,r]:(e=null,s=i),e}function je(){var e,t,r;return r=s,47===n.charCodeAt(s)?(e="/",s++):(e=null,0===o&&u('"/"')),null!==e&&null!==(t=We())?e=[e,t]:(e=null,s=r),e}function Be(){var e,t,n,r;if(r=s,null!==(e=Ve())){for(t=[],n=Ge();null!==n;)t.push(n),n=Ge();null!==t?e=[e,t]:(e=null,s=r)}else e=null,s=r;return e}function Ge(){var e;return null===(e=T())&&null===(e=b())&&(e=E()),e}function Ve(){var e;return null===(e=b())&&null===(e=E())&&(59===n.charCodeAt(s)?(e=";",s++):(e=null,0===o&&u('";"')),null===e&&(63===n.charCodeAt(s)?(e="?",s++):(e=null,0===o&&u('"?"')),null===e&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","'))))))))))),e}function We(){var e,t,r,i,l,a;if(l=s,null!==(e=Ye())){for(t=[],a=s,47===n.charCodeAt(s)?(r="/",s++):(r=null,0===o&&u('"/"')),null!==r&&null!==(i=Ye())?r=[r,i]:(r=null,s=a);null!==r;)t.push(r),a=s,47===n.charCodeAt(s)?(r="/",s++):(r=null,0===o&&u('"/"')),null!==r&&null!==(i=Ye())?r=[r,i]:(r=null,s=a);null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return e}function Ye(){var e,t,r,i,l,a;for(l=s,e=[],t=ze();null!==t;)e.push(t),t=ze();if(null!==e){for(t=[],a=s,59===n.charCodeAt(s)?(r=";",s++):(r=null,0===o&&u('";"')),null!==r&&null!==(i=Ke())?r=[r,i]:(r=null,s=a);null!==r;)t.push(r),a=s,59===n.charCodeAt(s)?(r=";",s++):(r=null,0===o&&u('";"')),null!==r&&null!==(i=Ke())?r=[r,i]:(r=null,s=a);null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return e}function Ke(){var e,t;for(e=[],t=ze();null!==t;)e.push(t),t=ze();return e}function ze(){var e;return null===(e=b())&&null===(e=E())&&(58===n.charCodeAt(s)?(e=":",s++):(e=null,0===o&&u('":"')),null===e&&(64===n.charCodeAt(s)?(e="@",s++):(e=null,0===o&&u('"@"')),null===e&&(38===n.charCodeAt(s)?(e="&",s++):(e=null,0===o&&u('"&"')),null===e&&(61===n.charCodeAt(s)?(e="=",s++):(e=null,0===o&&u('"="')),null===e&&(43===n.charCodeAt(s)?(e="+",s++):(e=null,0===o&&u('"+"')),null===e&&(36===n.charCodeAt(s)?(e="$",s++):(e=null,0===o&&u('"$"')),null===e&&(44===n.charCodeAt(s)?(e=",",s++):(e=null,0===o&&u('","'))))))))),e}function $e(){var e,t,r,i,l,a;if(i=s,l=s,null!==(e=d())){for(t=[],null===(r=d())&&null===(r=h())&&(43===n.charCodeAt(s)?(r="+",s++):(r=null,0===o&&u('"+"')),null===r&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')))));null!==r;)t.push(r),null===(r=d())&&null===(r=h())&&(43===n.charCodeAt(s)?(r="+",s++):(r=null,0===o&&u('"+"')),null===r&&(45===n.charCodeAt(s)?(r="-",s++):(r=null,0===o&&u('"-"')),null===r&&(46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')))));null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return null!==e&&(a=i,e=void(jn.scheme=n.substring(s,a))),null===e&&(s=i),e}function Xe(){var e;return null===(e=Je())&&(e=Qe()),e}function Je(){var e,t,r,i;return r=s,i=s,null!==(e=ne())?(64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null!==t?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==(e=null!==e?e:"")&&null!==(t=oe())?e=[e,t]:(e=null,s=r),e=null!==e?e:""}function Qe(){var e,t;if(null===(t=b())&&null===(t=E())&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')),null===t&&(59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null===t&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"')))))))))),null!==t)for(e=[];null!==t;)e.push(t),null===(t=b())&&null===(t=E())&&(36===n.charCodeAt(s)?(t="$",s++):(t=null,0===o&&u('"$"')),null===t&&(44===n.charCodeAt(s)?(t=",",s++):(t=null,0===o&&u('","')),null===t&&(59===n.charCodeAt(s)?(t=";",s++):(t=null,0===o&&u('";"')),null===t&&(58===n.charCodeAt(s)?(t=":",s++):(t=null,0===o&&u('":"')),null===t&&(64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null===t&&(38===n.charCodeAt(s)?(t="&",s++):(t=null,0===o&&u('"&"')),null===t&&(61===n.charCodeAt(s)?(t="=",s++):(t=null,0===o&&u('"="')),null===t&&(43===n.charCodeAt(s)?(t="+",s++):(t=null,0===o&&u('"+"'))))))))));else e=null;return e}function Ze(){var e,t;for(e=[],t=Ge();null!==t;)e.push(t),t=Ge();return e}function et(){var e,t,r,i,l,a,c,d,f;if(c=s,d=s,"sip"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"SIP"')),null!==e)if(47===n.charCodeAt(s)?(t="/",s++):(t=null,0===o&&u('"/"')),null!==t){if(null!==(i=h()))for(r=[];null!==i;)r.push(i),i=h();else r=null;if(null!==r)if(46===n.charCodeAt(s)?(i=".",s++):(i=null,0===o&&u('"."')),null!==i){if(null!==(a=h()))for(l=[];null!==a;)l.push(a),a=h();else l=null;null!==l?e=[e,t,r,i,l]:(e=null,s=d)}else e=null,s=d;else e=null,s=d}else e=null,s=d;else e=null,s=d;return null!==e&&(f=c,e=void(jn.sip_version=n.substring(s,f))),null===e&&(s=c),e}function tt(){var e;return"INVITE"===n.substr(s,6)?(e="INVITE",s+=6):(e=null,0===o&&u('"INVITE"')),e}function nt(){var e;return"ACK"===n.substr(s,3)?(e="ACK",s+=3):(e=null,0===o&&u('"ACK"')),e}function rt(){var e;return"OPTIONS"===n.substr(s,7)?(e="OPTIONS",s+=7):(e=null,0===o&&u('"OPTIONS"')),e}function it(){var e;return"BYE"===n.substr(s,3)?(e="BYE",s+=3):(e=null,0===o&&u('"BYE"')),e}function st(){var e;return"CANCEL"===n.substr(s,6)?(e="CANCEL",s+=6):(e=null,0===o&&u('"CANCEL"')),e}function ot(){var e;return"REGISTER"===n.substr(s,8)?(e="REGISTER",s+=8):(e=null,0===o&&u('"REGISTER"')),e}function lt(){var e;return"SUBSCRIBE"===n.substr(s,9)?(e="SUBSCRIBE",s+=9):(e=null,0===o&&u('"SUBSCRIBE"')),e}function at(){var e;return"NOTIFY"===n.substr(s,6)?(e="NOTIFY",s+=6):(e=null,0===o&&u('"NOTIFY"')),e}function ut(){var e;return"REFER"===n.substr(s,5)?(e="REFER",s+=5):(e=null,0===o&&u('"REFER"')),e}function ct(){var e,t,r;return t=s,null===(e=tt())&&null===(e=nt())&&null===(e=rt())&&null===(e=it())&&null===(e=st())&&null===(e=ot())&&null===(e=lt())&&null===(e=at())&&null===(e=ut())&&(e=k()),null!==e&&(r=t,jn.method=n.substring(s,r),e=jn.method),null===e&&(s=t),e}function ht(){var e,t,n,r,i,o;return o=s,null!==(e=et())&&null!==(t=v())&&null!==(n=dt())&&null!==(r=v())&&null!==(i=_t())?e=[e,t,n,r,i]:(e=null,s=o),e}function dt(){var e,t,n;return t=s,null!==(e=ft())&&(n=e,e=void(jn.status_code=parseInt(n.join("")))),null===e&&(s=t),e}function ft(){var e,t,n,r;return r=s,null!==(e=h())&&null!==(t=h())&&null!==(n=h())?e=[e,t,n]:(e=null,s=r),e}function _t(){var e,t,r,i;for(r=s,e=[],null===(t=T())&&null===(t=b())&&null===(t=E())&&null===(t=O())&&null===(t=N())&&null===(t=v())&&(t=g());null!==t;)e.push(t),null===(t=T())&&null===(t=b())&&null===(t=E())&&null===(t=O())&&null===(t=N())&&null===(t=v())&&(t=g());return null!==e&&(i=r,e=void(jn.reason_phrase=n.substring(s,i))),null===e&&(s=r),e}function pt(){var e,t,n,r,i,o,l;if(i=s,o=s,null===(e=J())&&(e=mt()),null!==e){for(t=[],l=s,null!==(n=B())&&null!==(r=gt())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=B())&&null!==(r=gt())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;return null!==e&&(e=function(e){var t;jn.multi_header||(jn.multi_header=[]);try{t=new Fn(jn.uri,jn.display_name,jn.params),delete jn.uri,delete jn.display_name,delete jn.params}catch(e){t=null}jn.multi_header.push({possition:s,offset:e,parsed:t})}(i)),null===e&&(s=i),e}function mt(){var e,t,n,r,i;return i=s,null!==(e=null!==(e=vt())?e:"")&&null!==(t=F())&&null!==(n=Q())&&null!==(r=H())?e=[e,t,n,r]:(e=null,s=i),e}function vt(){var e,t,n,r,i,o,l,a;if(i=s,o=s,null!==(e=k())){for(t=[],l=s,null!==(n=C())&&null!==(r=k())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=C())&&null!==(r=k())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;return null===e&&(e=z()),null!==e&&(a=e,e=void(jn.display_name="string"==typeof a?a:a[1].reduce(function(e,t){return e+t[0]+t[1]},a[0]))),null===e&&(s=i),e}function gt(){var e;return null===(e=yt())&&null===(e=Tt())&&(e=Et()),e}function yt(){var e,t,r,i,l,a;return i=s,l=s,"q"===n.substr(s,1).toLowerCase()?(e=n.substr(s,1),s++):(e=null,0===o&&u('"q"')),null!==e&&null!==(t=M())&&null!==(r=St())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],jn.params||(jn.params={}),e=void(jn.params.q=a)),null===e&&(s=i),e}function Tt(){var e,t,r,i,l,a;return i=s,l=s,"expires"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"expires"')),null!==e&&null!==(t=M())&&null!==(r=bt())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],jn.params||(jn.params={}),e=void(jn.params.expires=a)),null===e&&(s=i),e}function bt(){var e,t,n;if(n=s,null!==(t=h()))for(e=[];null!==t;)e.push(t),t=h();else e=null;return null!==e&&(e=parseInt(e.join(""))),null===e&&(s=n),e}function St(){var e,t,r,i,l,a,c,d,f;return a=s,c=s,48===n.charCodeAt(s)?(e="0",s++):(e=null,0===o&&u('"0"')),null!==e?(d=s,46===n.charCodeAt(s)?(t=".",s++):(t=null,0===o&&u('"."')),null!==t&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")&&null!==(l=null!==(l=h())?l:"")?t=[t,r,i,l]:(t=null,s=d),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=c)):(e=null,s=c),null!==e&&(f=a,e=parseFloat(n.substring(s,f))),null===e&&(s=a),e}function Et(){var e,t,n,r,i,o,l,a;return r=s,i=s,null!==(e=k())?(o=s,null!==(t=M())&&null!==(n=Ct())?t=[t,n]:(t=null,s=o),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),null!==e&&(l=e[0],a=e[1],jn.params||(jn.params={}),a=void 0===a?void 0:a[1],e=void(jn.params[l.toLowerCase()]=a)),null===e&&(s=r),e}function Ct(){var e;return null===(e=k())&&null===(e=le())&&(e=K()),e}function At(){var e;return"render"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"render"')),null===e&&("session"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"session"')),null===e&&("icon"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"icon"')),null===e&&("alert"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"alert"')),null===e&&(e=k())))),e}function wt(){var e;return null===(e=Rt())&&(e=Et()),e}function Rt(){var e,t,r,i;return i=s,"handling"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"handling"')),null!==e&&null!==(t=M())?("optional"===n.substr(s,8).toLowerCase()?(r=n.substr(s,8),s+=8):(r=null,0===o&&u('"optional"')),null===r&&("required"===n.substr(s,8).toLowerCase()?(r=n.substr(s,8),s+=8):(r=null,0===o&&u('"required"')),null===r&&(r=k())),null!==r?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),e}function It(){var e,t,n,r,i,o,l,a;if(l=s,null!==(e=Ot()))if(null!==(t=D()))if(null!==(n=Ut())){for(r=[],a=s,null!==(i=B())&&null!==(o=Dt())?i=[i,o]:(i=null,s=a);null!==i;)r.push(i),a=s,null!==(i=B())&&null!==(o=Dt())?i=[i,o]:(i=null,s=a);null!==r?e=[e,t,n,r]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;else e=null,s=l;return e}function Ot(){var e;return null===(e=Nt())&&(e=kt()),e}function Nt(){var e;return"text"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"text"')),null===e&&("image"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"image"')),null===e&&("audio"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"audio"')),null===e&&("video"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"video"')),null===e&&("application"===n.substr(s,11).toLowerCase()?(e=n.substr(s,11),s+=11):(e=null,0===o&&u('"application"')),null===e&&(e=Pt()))))),e}function kt(){var e;return"message"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"message"')),null===e&&("multipart"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"multipart"')),null===e&&(e=Pt())),e}function Pt(){var e;return null===(e=k())&&(e=xt()),e}function xt(){var e,t,r;return r=s,"x-"===n.substr(s,2).toLowerCase()?(e=n.substr(s,2),s+=2):(e=null,0===o&&u('"x-"')),null!==e&&null!==(t=k())?e=[e,t]:(e=null,s=r),e}function Ut(){var e;return null===(e=Pt())&&(e=k()),e}function Dt(){var e,t,n,r;return r=s,null!==(e=k())&&null!==(t=M())&&null!==(n=Mt())?e=[e,t,n]:(e=null,s=r),e}function Mt(){var e;return null===(e=k())&&(e=K()),e}function qt(){var e,t,n,r;if(n=s,null!==(t=h()))for(e=[];null!==t;)e.push(t),t=h();else e=null;return null!==e&&(r=e,e=void(jn.value=parseInt(r.join("")))),null===e&&(s=n),e}function Lt(){var e,t,r,i,l,a;if(l=s,null!==(e=P())){for(t=[],a=s,46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r&&null!==(i=P())?r=[r,i]:(r=null,s=a);null!==r;)t.push(r),a=s,46===n.charCodeAt(s)?(r=".",s++):(r=null,0===o&&u('"."')),null!==r&&null!==(i=P())?r=[r,i]:(r=null,s=a);null!==t?e=[e,t]:(e=null,s=l)}else e=null,s=l;return e}function Ht(){var e;return null===(e=Ft())&&(e=Et()),e}function Ft(){var e,t,r,i,l,a;return i=s,l=s,"tag"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"tag"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.tag=a)),null===e&&(s=i),e}function jt(){var e,t,r,i,l,a,c,h;if(c=s,"digest"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"Digest"')),null!==e)if(null!==(t=C()))if(null!==(r=Vt())){for(i=[],h=s,null!==(l=j())&&null!==(a=Vt())?l=[l,a]:(l=null,s=h);null!==l;)i.push(l),h=s,null!==(l=j())&&null!==(a=Vt())?l=[l,a]:(l=null,s=h);null!==i?e=[e,t,r,i]:(e=null,s=c)}else e=null,s=c;else e=null,s=c;else e=null,s=c;return null===e&&(e=Bt()),e}function Bt(){var e,t,n,r,i,o,l,a;if(l=s,null!==(e=k()))if(null!==(t=C()))if(null!==(n=Gt())){for(r=[],a=s,null!==(i=j())&&null!==(o=Gt())?i=[i,o]:(i=null,s=a);null!==i;)r.push(i),a=s,null!==(i=j())&&null!==(o=Gt())?i=[i,o]:(i=null,s=a);null!==r?e=[e,t,n,r]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;else e=null,s=l;return e}function Gt(){var e,t,n,r;return r=s,null!==(e=k())&&null!==(t=M())?(null===(n=k())&&(n=K()),null!==n?e=[e,t,n]:(e=null,s=r)):(e=null,s=r),e}function Vt(){var e;return null===(e=Wt())&&null===(e=Kt())&&null===(e=$t())&&null===(e=Jt())&&null===(e=Qt())&&null===(e=Zt())&&null===(e=en())&&(e=Gt()),e}function Wt(){var e,t,r,i;return i=s,"realm"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"realm"')),null!==e&&null!==(t=M())&&null!==(r=Yt())?e=[e,t,r]:(e=null,s=i),e}function Yt(){var e,t,n;return t=s,null!==(e=z())&&(n=e,e=void(jn.realm=n)),null===e&&(s=t),e}function Kt(){var e,t,r,i,l,a,c,h,d;if(h=s,"domain"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"domain"')),null!==e)if(null!==(t=M()))if(null!==(r=V()))if(null!==(i=zt())){if(l=[],d=s,null!==(c=v()))for(a=[];null!==c;)a.push(c),c=v();else a=null;for(null!==a&&null!==(c=zt())?a=[a,c]:(a=null,s=d);null!==a;){if(l.push(a),d=s,null!==(c=v()))for(a=[];null!==c;)a.push(c),c=v();else a=null;null!==a&&null!==(c=zt())?a=[a,c]:(a=null,s=d)}null!==l&&null!==(a=W())?e=[e,t,r,i,l,a]:(e=null,s=h)}else e=null,s=h;else e=null,s=h;else e=null,s=h;else e=null,s=h;return e}function zt(){var e;return null===(e=Le())&&(e=je()),e}function $t(){var e,t,r,i;return i=s,"nonce"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"nonce"')),null!==e&&null!==(t=M())&&null!==(r=Xt())?e=[e,t,r]:(e=null,s=i),e}function Xt(){var e,t,n;return t=s,null!==(e=z())&&(n=e,e=void(jn.nonce=n)),null===e&&(s=t),e}function Jt(){var e,t,r,i,l,a;return i=s,l=s,"opaque"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"opaque"')),null!==e&&null!==(t=M())&&null!==(r=z())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.opaque=a)),null===e&&(s=i),e}function Qt(){var e,t,r,i,l;return i=s,"stale"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"stale"')),null!==e&&null!==(t=M())?(l=s,"true"===n.substr(s,4).toLowerCase()?(r=n.substr(s,4),s+=4):(r=null,0===o&&u('"true"')),null!==r&&(r=void(jn.stale=!0)),null===r&&(s=l),null===r&&(l=s,"false"===n.substr(s,5).toLowerCase()?(r=n.substr(s,5),s+=5):(r=null,0===o&&u('"false"')),null!==r&&(r=void(jn.stale=!1)),null===r&&(s=l)),null!==r?e=[e,t,r]:(e=null,s=i)):(e=null,s=i),e}function Zt(){var e,t,r,i,l,a;return i=s,l=s,"algorithm"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"algorithm"')),null!==e&&null!==(t=M())?("md5"===n.substr(s,3).toLowerCase()?(r=n.substr(s,3),s+=3):(r=null,0===o&&u('"MD5"')),null===r&&("md5-sess"===n.substr(s,8).toLowerCase()?(r=n.substr(s,8),s+=8):(r=null,0===o&&u('"MD5-sess"')),null===r&&(r=k())),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[2],e=void(jn.algorithm=a.toUpperCase())),null===e&&(s=i),e}function en(){var e,t,r,i,l,a,c,h,d,f;if(h=s,"qop"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"qop"')),null!==e)if(null!==(t=M()))if(null!==(r=V())){if(d=s,null!==(i=tn())){for(l=[],f=s,44===n.charCodeAt(s)?(a=",",s++):(a=null,0===o&&u('","')),null!==a&&null!==(c=tn())?a=[a,c]:(a=null,s=f);null!==a;)l.push(a),f=s,44===n.charCodeAt(s)?(a=",",s++):(a=null,0===o&&u('","')),null!==a&&null!==(c=tn())?a=[a,c]:(a=null,s=f);null!==l?i=[i,l]:(i=null,s=d)}else i=null,s=d;null!==i&&null!==(l=W())?e=[e,t,r,i,l]:(e=null,s=h)}else e=null,s=h;else e=null,s=h;else e=null,s=h;return e}function tn(){var e,t,r;return t=s,"auth-int"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"auth-int"')),null===e&&("auth"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"auth"')),null===e&&(e=k())),null!==e&&(r=e,jn.qop||(jn.qop=[]),e=void jn.qop.push(r.toLowerCase())),null===e&&(s=t),e}function nn(){var e,t,n,r,i,o,l;if(i=s,o=s,null!==(e=mt())){for(t=[],l=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=l);null!==n;)t.push(n),l=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=l);null!==t?e=[e,t]:(e=null,s=o)}else e=null,s=o;return null!==e&&(e=function(e){var t;jn.multi_header||(jn.multi_header=[]);try{t=new Fn(jn.uri,jn.display_name,jn.params),delete jn.uri,delete jn.display_name,delete jn.params}catch(e){t=null}jn.multi_header.push({possition:s,offset:e,parsed:t})}(i)),null===e&&(s=i),e}function rn(){var e;return null===(e=sn())&&(e=Et()),e}function sn(){var e,t,r,i,l,a,c;if(l=s,a=s,"cause"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"cause"')),null!==e)if(null!==(t=M())){if(null!==(i=h()))for(r=[];null!==i;)r.push(i),i=h();else r=null;null!==r?e=[e,t,r]:(e=null,s=a)}else e=null,s=a;else e=null,s=a;return null!==e&&(c=e[2],e=void(jn.cause=parseInt(c.join("")))),null===e&&(s=l),e}function on(){var e,t,n,r,i,o;if(i=s,null!==(e=mt())){for(t=[],o=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=o);null!==n;)t.push(n),o=s,null!==(n=B())&&null!==(r=Et())?n=[n,r]:(n=null,s=o);null!==t?e=[e,t]:(e=null,s=i)}else e=null,s=i;return e}function ln(){var e,t,r;return t=s,"active"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"active"')),null===e&&("pending"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"pending"')),null===e&&("terminated"===n.substr(s,10).toLowerCase()?(e=n.substr(s,10),s+=10):(e=null,0===o&&u('"terminated"')),null===e&&(e=k()))),null!==e&&(r=t,e=void(jn.state=n.substring(s,r))),null===e&&(s=t),e}function an(){var e,t,r,i,l,a,c,h;return i=s,l=s,"reason"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"reason"')),null!==e&&null!==(t=M())&&null!==(r=un())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=void(void 0!==(a=e[2])&&(jn.reason=a))),null===e&&(s=i),null===e&&(i=s,l=s,"expires"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"expires"')),null!==e&&null!==(t=M())&&null!==(r=bt())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=void(void 0!==(h=e[2])&&(jn.expires=h))),null===e&&(s=i),null===e&&(i=s,l=s,"retry_after"===n.substr(s,11).toLowerCase()?(e=n.substr(s,11),s+=11):(e=null,0===o&&u('"retry_after"')),null!==e&&null!==(t=M())&&null!==(r=bt())?e=[e,t,r]:(e=null,s=l),null!==e&&(e=void(void 0!==(c=e[2])&&(jn.retry_after=c))),null===e&&(s=i),null===e&&(e=Et()))),e}function un(){var e;return"deactivated"===n.substr(s,11).toLowerCase()?(e=n.substr(s,11),s+=11):(e=null,0===o&&u('"deactivated"')),null===e&&("probation"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"probation"')),null===e&&("rejected"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"rejected"')),null===e&&("timeout"===n.substr(s,7).toLowerCase()?(e=n.substr(s,7),s+=7):(e=null,0===o&&u('"timeout"')),null===e&&("giveup"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"giveup"')),null===e&&("noresource"===n.substr(s,10).toLowerCase()?(e=n.substr(s,10),s+=10):(e=null,0===o&&u('"noresource"')),null===e&&("invariant"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"invariant"')),null===e&&(e=k()))))))),e}function cn(){var e;return null===(e=Ft())&&(e=Et()),e}function hn(){var e,t,n,r,i,o,l,a;if(l=s,null!==(e=yn()))if(null!==(t=C()))if(null!==(n=Sn())){for(r=[],a=s,null!==(i=B())&&null!==(o=dn())?i=[i,o]:(i=null,s=a);null!==i;)r.push(i),a=s,null!==(i=B())&&null!==(o=dn())?i=[i,o]:(i=null,s=a);null!==r?e=[e,t,n,r]:(e=null,s=l)}else e=null,s=l;else e=null,s=l;else e=null,s=l;return e}function dn(){var e;return null===(e=fn())&&null===(e=_n())&&null===(e=pn())&&null===(e=mn())&&null===(e=vn())&&(e=Et()),e}function fn(){var e,t,r,i,l,a;return i=s,l=s,"ttl"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"ttl"')),null!==e&&null!==(t=M())&&null!==(r=An())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.ttl=a)),null===e&&(s=i),e}function _n(){var e,t,r,i,l,a;return i=s,l=s,"maddr"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"maddr"')),null!==e&&null!==(t=M())&&null!==(r=le())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.maddr=a)),null===e&&(s=i),e}function pn(){var e,t,r,i,l,a;return i=s,l=s,"received"===n.substr(s,8).toLowerCase()?(e=n.substr(s,8),s+=8):(e=null,0===o&&u('"received"')),null!==e&&null!==(t=M())?(null===(r=pe())&&(r=de()),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[2],e=void(jn.received=a)),null===e&&(s=i),e}function mn(){var e,t,r,i,l,a;return i=s,l=s,"branch"===n.substr(s,6).toLowerCase()?(e=n.substr(s,6),s+=6):(e=null,0===o&&u('"branch"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.branch=a)),null===e&&(s=i),e}function vn(){var e,t,r,i,l;return i=s,"rport"===n.substr(s,5).toLowerCase()?(e=n.substr(s,5),s+=5):(e=null,0===o&&u('"rport"')),null!==e?(l=s,null!==(t=M())&&null!==(r=gn())?t=[t,r]:(t=null,s=l),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=i)):(e=null,s=i),e}function gn(){var e,t,n,r,i,o,l,a;return o=s,l=s,null!==(e=null!==(e=h())?e:"")&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")?e=[e,t,n,r,i]:(e=null,s=l),null!==e&&(a=e,e=void(jn.rport=parseInt(a.join("")))),null===e&&(s=o),e}function yn(){var e,t,n,r,i,o;return o=s,null!==(e=Tn())&&null!==(t=D())&&null!==(n=k())&&null!==(r=D())&&null!==(i=bn())?e=[e,t,n,r,i]:(e=null,s=o),e}function Tn(){var e,t,r;return t=s,"sip"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"SIP"')),null===e&&(e=k()),null!==e&&(r=e,e=void(jn.protocol=r)),null===e&&(s=t),e}function bn(){var e,t,r;return t=s,"udp"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"UDP"')),null===e&&("tcp"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"TCP"')),null===e&&("tls"===n.substr(s,3).toLowerCase()?(e=n.substr(s,3),s+=3):(e=null,0===o&&u('"TLS"')),null===e&&("sctp"===n.substr(s,4).toLowerCase()?(e=n.substr(s,4),s+=4):(e=null,0===o&&u('"SCTP"')),null===e&&(e=k())))),null!==e&&(r=e,e=void(jn.transport=r)),null===e&&(s=t),e}function Sn(){var e,t,n,r,i;return r=s,null!==(e=En())?(i=s,null!==(t=G())&&null!==(n=Cn())?t=[t,n]:(t=null,s=i),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=r)):(e=null,s=r),e}function En(){var e,t,r;return t=s,null===(e=pe())&&null===(e=he())&&(e=ae()),null!==e&&(r=t,e=void(jn.host=n.substring(s,r))),null===e&&(s=t),e}function Cn(){var e,t,n,r,i,o,l,a;return o=s,l=s,null!==(e=null!==(e=h())?e:"")&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")&&null!==(r=null!==(r=h())?r:"")&&null!==(i=null!==(i=h())?i:"")?e=[e,t,n,r,i]:(e=null,s=l),null!==e&&(a=e,e=void(jn.port=parseInt(a.join("")))),null===e&&(s=o),e}function An(){var e,t,n,r,i;return r=s,i=s,null!==(e=h())&&null!==(t=null!==(t=h())?t:"")&&null!==(n=null!==(n=h())?n:"")?e=[e,t,n]:(e=null,s=i),null!==e&&(e=parseInt(e.join(""))),null===e&&(s=r),e}function wn(){var e,t,n;return t=s,null!==(e=bt())&&(n=e,e=void(jn.expires=n)),null===e&&(s=t),e}function Rn(){var e;return null===(e=In())&&(e=Et()),e}function In(){var e,t,r,i,l,a;return i=s,l=s,"refresher"===n.substr(s,9).toLowerCase()?(e=n.substr(s,9),s+=9):(e=null,0===o&&u('"refresher"')),null!==e&&null!==(t=M())?("uac"===n.substr(s,3).toLowerCase()?(r=n.substr(s,3),s+=3):(r=null,0===o&&u('"uac"')),null===r&&("uas"===n.substr(s,3).toLowerCase()?(r=n.substr(s,3),s+=3):(r=null,0===o&&u('"uas"'))),null!==r?e=[e,t,r]:(e=null,s=l)):(e=null,s=l),null!==e&&(a=e[2],e=void(jn.refresher=a.toLowerCase())),null===e&&(s=i),e}function On(){var e,t;for(e=[],null===(t=I())&&null===(t=N())&&(t=C());null!==t;)e.push(t),null===(t=I())&&null===(t=N())&&(t=C());return e}function Nn(){var e,t,r,i,l,a,c,h,d,f,_,p;return f=s,_=s,null!==(e=Pn())?(45===n.charCodeAt(s)?(t="-",s++):(t=null,0===o&&u('"-"')),null!==t&&null!==(r=kn())?(45===n.charCodeAt(s)?(i="-",s++):(i=null,0===o&&u('"-"')),null!==i&&null!==(l=kn())?(45===n.charCodeAt(s)?(a="-",s++):(a=null,0===o&&u('"-"')),null!==a&&null!==(c=kn())?(45===n.charCodeAt(s)?(h="-",s++):(h=null,0===o&&u('"-"')),null!==h&&null!==(d=xn())?e=[e,t,r,i,l,a,c,h,d]:(e=null,s=_)):(e=null,s=_)):(e=null,s=_)):(e=null,s=_)):(e=null,s=_),null!==e&&(p=f,e[0],e=void(jn=n.substring(s+5,p))),null===e&&(s=f),e}function kn(){var e,t,n,r,i;return i=s,null!==(e=f())&&null!==(t=f())&&null!==(n=f())&&null!==(r=f())?e=[e,t,n,r]:(e=null,s=i),e}function Pn(){var e,t,n;return n=s,null!==(e=kn())&&null!==(t=kn())?e=[e,t]:(e=null,s=n),e}function xn(){var e,t,n,r;return r=s,null!==(e=kn())&&null!==(t=kn())&&null!==(n=kn())?e=[e,t,n]:(e=null,s=r),e}function Un(){var e,t,r,i,l,a,c;return i=s,l=s,null!==(e=x())?(a=s,64===n.charCodeAt(s)?(t="@",s++):(t=null,0===o&&u('"@"')),null!==t&&null!==(r=x())?t=[t,r]:(t=null,s=a),null!==(t=null!==t?t:"")?e=[e,t]:(e=null,s=l)):(e=null,s=l),null!==e&&(c=i,e=void(jn.call_id=n.substring(s,c))),null===e&&(s=i),e}function Dn(){var e;return null===(e=Mn())&&null===(e=qn())&&null===(e=Ln())&&(e=Et()),e}function Mn(){var e,t,r,i,l,a;return i=s,l=s,"to-tag"===n.substr(s,6)?(e="to-tag",s+=6):(e=null,0===o&&u('"to-tag"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.to_tag=a)),null===e&&(s=i),e}function qn(){var e,t,r,i,l,a;return i=s,l=s,"from-tag"===n.substr(s,8)?(e="from-tag",s+=8):(e=null,0===o&&u('"from-tag"')),null!==e&&null!==(t=M())&&null!==(r=k())?e=[e,t,r]:(e=null,s=l),null!==e&&(a=e[2],e=void(jn.from_tag=a)),null===e&&(s=i),e}function Ln(){var e,t;return t=s,"early-only"===n.substr(s,10)?(e="early-only",s+=10):(e=null,0===o&&u('"early-only"')),null!==e&&(e=void(jn.early_only=!0)),null===e&&(s=t),e}var Hn=e("./URI"),Fn=e("./NameAddrHeader"),jn={};if(null===i[r]()||s!==n.length){var Bn=Math.max(s,l),Gn=Bn2&&void 0!==arguments[2]?arguments[2]:{},i=e;if(void 0===e||void 0===t)throw new TypeError("Not enough arguments");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(i));var s=d.cloneArray(r.extraHeaders),o=d.cloneObject(r.eventHandlers),l=r.contentType||"text/plain",a={};for(var u in r.fromUserName&&(a.from_uri=new p("sip",r.fromUserName,this._ua.configuration.uri.host),s.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()))),r.fromDisplayName&&(a.from_display_name=r.fromDisplayName),o)Object.prototype.hasOwnProperty.call(o,u)&&this.on(u,o[u]);s.push("Content-Type: ".concat(l)),this._request=new h.OutgoingRequest(c.MESSAGE,e,this._ua,a,s),t&&(this._request.body=t);var _=new f(this._ua,this._request,{onRequestTimeout:function(){n._onRequestTimeout()},onTransportError:function(){n._onTransportError()},onReceiveResponse:function(e){n._receiveResponse(e)}});this._newMessage("local",this._request),_.send()}},{key:"init_incoming",value:function(e){this._request=e,this._newMessage("remote",e),this._is_replied||(this._is_replied=!0,e.reply(200)),this._close()}},{key:"accept",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=d.cloneArray(e.extraHeaders),n=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"accept" not supported for outgoing Message');if(this._is_replied)throw new Error("incoming Message already replied");this._is_replied=!0,this._request.reply(200,null,t,n)}},{key:"reject",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.status_code||480,n=e.reason_phrase,r=d.cloneArray(e.extraHeaders),i=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"reject" not supported for outgoing Message');if(this._is_replied)throw new Error("incoming Message already replied");if(t<300||t>=700)throw new TypeError("Invalid status_code: ".concat(t));this._is_replied=!0,this._request.reply(t,n,r,i)}},{key:"_receiveResponse",value:function(e){if(!this._closed)switch(!0){case/^1[0-9]{2}$/.test(e.status_code):break;case/^2[0-9]{2}$/.test(e.status_code):this._succeeded("remote",e);break;default:var t=d.sipErrorCause(e.status_code);this._failed("remote",e,t)}}},{key:"_onRequestTimeout",value:function(){this._closed||this._failed("system",null,c.causes.REQUEST_TIMEOUT)}},{key:"_onTransportError",value:function(){this._closed||this._failed("system",null,c.causes.CONNECTION_ERROR)}},{key:"_close",value:function(){this._closed=!0,this._ua.destroyMessage(this)}},{key:"_newMessage",value:function(e,t){"remote"===e?(this._direction="incoming",this._local_identity=t.to,this._remote_identity=t.from):"local"===e&&(this._direction="outgoing",this._local_identity=t.from,this._remote_identity=t.to),this._ua.newMessage(this,{originator:e,message:this,request:t})}},{key:"_failed",value:function(e,t,n){m.debug("MESSAGE failed"),this._close(),m.debug('emit "failed"'),this.emit("failed",{originator:e,response:t||null,cause:n})}},{key:"_succeeded",value:function(e,t){m.debug("MESSAGE succeeded"),this._close(),m.debug('emit "succeeded"'),this.emit("succeeded",{originator:e,response:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./URI":29,"./Utils":30,events:33}],11:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n"),this._parameters)Object.prototype.hasOwnProperty.call(this._parameters,t)&&(e+=";".concat(t),null!==this._parameters[t]&&(e+="=".concat(this._parameters[t])));return e}}])&&r(t.prototype,n),o&&r(t,o),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Grammar":7,"./URI":29}],12:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n"),i._headers.push(i._contact)),o&&i._headers.push("Allow-Events: ".concat(o)),i._target=t.from.uri.user,t.to_tag=d.newTag();var m=new f(l(i),t,"UAS");if(m.error)throw _.warn(m.error),new Error("SUBSCRIBE missed Contact");return i._dialog=m,i._expires>0&&i._setExpiresTimer(),i}return t=c,r=[{key:"C",get:function(){return p}}],(n=[{key:"C",get:function(){return p}},{key:"receiveRequest",value:function(e){if(e.method===h.SUBSCRIBE){var t=e.getHeader("expires");null==t&&(t="900",_.debug("Missed expires header. Set by default ".concat(t))),this._expires=parseInt(t),e.reply(200,null,["Expires: ".concat(this._expires),"".concat(this._contact)]);var n=e.body,r=e.getHeader("content-type"),i=0===this._expires;i||this._setExpiresTimer(),_.debug('emit "subscribe"'),this.emit("subscribe",i,e,n,r),i&&this._dialogTerminated(p.RECEIVE_UNSUBSCRIBE)}else e.reply(405)}},{key:"start",value:function(){_.debug("start()"),this.receiveRequest(this._initial_subscribe)}},{key:"setActiveState",value:function(){_.debug("setActiveState()"),this._state===p.STATE_PENDING&&(this._state=p.STATE_ACTIVE)}},{key:"notify",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(_.debug("notify()"),this._dialog){var n=this._stateNumberToString(this._state);if(this._state!==p.STATE_TERMINATED){var r=Math.floor((this._expires_timestamp-(new Date).getTime())/1e3);r<0&&(r=0),n+=";expires=".concat(r)}else this._terminated_reason&&(n+=";reason=".concat(this._terminated_reason)),null!==this._terminated_retry_after&&(n+=";retry-after=".concat(this._terminated_retry_after));var i=this._headers.slice();i.push("Subscription-State: ".concat(n)),t&&i.push("Content-Type: ".concat(this._content_type)),this._dialog.sendRequest(h.NOTIFY,{body:t,extraHeaders:i,eventHandlers:{onRequestTimeout:function(){e._dialogTerminated(p.NOTIFY_RESPONSE_TIMEOUT)},onTransportError:function(){e._dialogTerminated(p.NOTIFY_TRANSPORT_ERROR)},onErrorResponse:function(t){401===t.status_code||407===t.status_code?e._dialogTerminated(p.NOTIFY_FAILED_AUTHENTICATION):e._dialogTerminated(p.NOTIFY_NON_OK_RESPONSE)},onDialogError:function(){e._dialogTerminated(p.NOTIFY_NON_OK_RESPONSE)}}})}else _.warn("final notify has sent")}},{key:"terminate",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;_.debug("terminate()"),this._state=p.STATE_TERMINATED,this._terminated_reason=t,this._terminated_retry_after=n,this.notify(e),this._dialogTerminated(p.SEND_FINAL_NOTIFY)}},{key:"state",get:function(){return this._state}},{key:"id",get:function(){return this._dialog?this._dialog.id:null}},{key:"_dialogTerminated",value:function(e){if(this._dialog){this._state=p.STATE_TERMINATED,clearTimeout(this._expires_timer),this._dialog&&(this._dialog.terminate(),this._dialog=null);var t=e===p.SUBSCRIPTION_EXPIRED;_.debug('emit "terminated" code='.concat(e,", send final notify=").concat(t)),this.emit("terminated",e,t)}}},{key:"_setExpiresTimer",value:function(){var e=this;this._expires_timestamp=(new Date).getTime()+1e3*this._expires,clearTimeout(this._expires_timer),this._expires_timer=setTimeout(function(){e._dialog&&(e._terminated_reason="timeout",e.notify(),e._dialogTerminated(p.SUBSCRIPTION_EXPIRED))},1e3*this._expires)}},{key:"_stateNumberToString",value:function(e){switch(e){case p.STATE_PENDING:return"pending";case p.STATE_ACTIVE:return"active";case p.STATE_TERMINATED:return"terminated";default:throw new TypeError("wrong state value")}}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),c}()},{"./Constants":2,"./Dialog":3,"./Logger":9,"./Utils":30,events:33}],13:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{},i=e;if(void 0===e)throw new TypeError("A target is required for OPTIONS");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(i));var s=d.cloneArray(r.extraHeaders),o=d.cloneObject(r.eventHandlers),l=r.contentType||"application/sdp";for(var a in o)Object.prototype.hasOwnProperty.call(o,a)&&this.on(a,o[a]);s.push("Content-Type: ".concat(l)),this._request=new h.OutgoingRequest(c.OPTIONS,e,this._ua,null,s),t&&(this._request.body=t);var u=new f(this._ua,this._request,{onRequestTimeout:function(){n._onRequestTimeout()},onTransportError:function(){n._onTransportError()},onReceiveResponse:function(e){n._receiveResponse(e)}});this._newOptions("local",this._request),u.send()}},{key:"init_incoming",value:function(e){this._request=e,this._newOptions("remote",e),this._is_replied||(this._is_replied=!0,e.reply(200)),this._close()}},{key:"accept",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=d.cloneArray(e.extraHeaders),n=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"accept" not supported for outgoing Options');if(this._is_replied)throw new Error("incoming Options already replied");this._is_replied=!0,this._request.reply(200,null,t,n)}},{key:"reject",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.status_code||480,n=e.reason_phrase,r=d.cloneArray(e.extraHeaders),i=e.body;if("incoming"!==this._direction)throw new _.NotSupportedError('"reject" not supported for outgoing Options');if(this._is_replied)throw new Error("incoming Options already replied");if(t<300||t>=700)throw new TypeError("Invalid status_code: ".concat(t));this._is_replied=!0,this._request.reply(t,n,r,i)}},{key:"_receiveResponse",value:function(e){if(!this._closed)switch(!0){case/^1[0-9]{2}$/.test(e.status_code):break;case/^2[0-9]{2}$/.test(e.status_code):this._succeeded("remote",e);break;default:var t=d.sipErrorCause(e.status_code);this._failed("remote",e,t)}}},{key:"_onRequestTimeout",value:function(){this._closed||this._failed("system",null,c.causes.REQUEST_TIMEOUT)}},{key:"_onTransportError",value:function(){this._closed||this._failed("system",null,c.causes.CONNECTION_ERROR)}},{key:"_close",value:function(){this._closed=!0,this._ua.destroyMessage(this)}},{key:"_newOptions",value:function(e,t){"remote"===e?(this._direction="incoming",this._local_identity=t.to,this._remote_identity=t.from):"local"===e&&(this._direction="outgoing",this._local_identity=t.from,this._remote_identity=t.to),this._ua.newOptions(this,{originator:e,message:this,request:t})}},{key:"_failed",value:function(e,t,n){p.debug("OPTIONS failed"),this._close(),p.debug('emit "failed"'),this.emit("failed",{originator:e,response:t||null,cause:n})}},{key:"_succeeded",value:function(e,t){p.debug("OPTIONS succeeded"),this._close(),p.debug('emit "succeeded"'),this.emit("succeeded",{originator:e,response:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,events:33}],14:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,s=function(){};return{s:s,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;w.debug("connect()");var r=e,i=m.cloneObject(t.eventHandlers),s=m.cloneArray(t.extraHeaders),o=m.cloneObject(t.mediaConstraints,{audio:!0,video:!0}),l=t.mediaStream||null,a=m.cloneObject(t.pcConfig,{iceServers:[]}),u=t.rtcConstraints||null,c=t.rtcOfferConstraints||null;if(this._rtcOfferConstraints=c,this._rtcAnswerConstraints=t.rtcAnswerConstraints||null,this._data=t.data||this._data,void 0===e)throw new TypeError("Not enough arguments");if(this._status!==R.STATUS_NULL)throw new _.InvalidStateError(this._status);if(!window.RTCPeerConnection)throw new _.NotSupportedError("WebRTC not supported");if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(r));for(var h in this._sessionTimers.enabled&&m.isDecimal(t.sessionTimersExpires)&&(t.sessionTimersExpires>=f.MIN_SESSION_EXPIRES?this._sessionTimers.defaultExpires=t.sessionTimersExpires:this._sessionTimers.defaultExpires=f.SESSION_EXPIRES),i)Object.prototype.hasOwnProperty.call(i,h)&&this.on(h,i[h]);this._from_tag=m.newTag();var d=t.anonymous||!1,p={from_tag:this._from_tag};this._contact=this._ua.contact.toString({anonymous:d,outbound:!0}),d?(p.from_display_name="Anonymous",p.from_uri=new A("sip","anonymous","anonymous.invalid"),s.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString())),s.push("Privacy: id")):t.fromUserName&&(p.from_uri=new A("sip",t.fromUserName,this._ua.configuration.uri.host),s.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()))),t.fromDisplayName&&(p.from_display_name=t.fromDisplayName),s.push("Contact: ".concat(this._contact)),s.push("Content-Type: application/sdp"),this._sessionTimers.enabled&&s.push("Session-Expires: ".concat(this._sessionTimers.defaultExpires).concat(this._ua.configuration.session_timers_force_refresher?";refresher=uac":"")),this._request=new g.InitialOutgoingInviteRequest(e,this._ua,p,s),this._id=this._request.call_id+this._from_tag,this._createRTCConnection(a,u),this._direction="outgoing",this._local_identity=this._request.from,this._remote_identity=this._request.to,n&&n(this),this._newRTCSession("local",this._request),this._sendInitialRequest(o,c,l)}},{key:"init_incoming",value:function(e,t){var n,r=this;w.debug("init_incoming()");var i=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0;if(e.body&&"application/sdp"!==i)e.reply(415);else if(this._status=R.STATUS_INVITE_RECEIVED,this._from_tag=e.from_tag,this._id=e.call_id+this._from_tag,this._request=e,this._contact=this._ua.contact.toString(),e.hasHeader("expires")&&(n=1e3*e.getHeader("expires")),e.to_tag=m.newTag(),this._createDialog(e,"UAS",!0)){if(e.body?this._late_sdp=!1:this._late_sdp=!0,this._status=R.STATUS_WAITING_FOR_ANSWER,this._timers.userNoAnswerTimer=setTimeout(function(){e.reply(408),r._failed("local",null,f.causes.NO_ANSWER)},this._ua.configuration.no_answer_timeout),n&&(this._timers.expiresTimer=setTimeout(function(){r._status===R.STATUS_WAITING_FOR_ANSWER&&(e.reply(487),r._failed("system",null,f.causes.EXPIRES))},n)),this._direction="incoming",this._local_identity=e.to,this._remote_identity=e.from,t&&t(this),this._newRTCSession("remote",e),this._status!==R.STATUS_TERMINATED){var s=["Contact: ".concat(this._contact)],o=this._ua.modes.ringing_header_mode;void 0!==o&&(Array.isArray(o)?s=s.concat(o):s.push(o)),e.reply(180,null,s),this._progress("local",null)}}else e.reply(500,"Missing Contact header field")}},{key:"answer",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("answer()");var n=this._request,r=m.cloneArray(t.extraHeaders),s=m.cloneObject(t.mediaConstraints),o=t.mediaStream||null,l=m.cloneObject(t.pcConfig,{iceServers:[]}),a=t.rtcConstraints||null,u=t.rtcAnswerConstraints||null,c=m.cloneObject(t.rtcOfferConstraints),h=!1,d=!1,p=!1,v=!1;if(this._rtcAnswerConstraints=u,this._rtcOfferConstraints=t.rtcOfferConstraints||null,this._data=t.data||this._data,"incoming"!==this._direction)throw new _.NotSupportedError('"answer" not supported for outgoing RTCSession');if(this._status!==R.STATUS_WAITING_FOR_ANSWER)throw new _.InvalidStateError(this._status);if(this._sessionTimers.enabled&&m.isDecimal(t.sessionTimersExpires)&&(t.sessionTimersExpires>=f.MIN_SESSION_EXPIRES?this._sessionTimers.defaultExpires=t.sessionTimersExpires:this._sessionTimers.defaultExpires=f.SESSION_EXPIRES),this._status=R.STATUS_ANSWERED,this._createDialog(n,"UAS")){clearTimeout(this._timers.userNoAnswerTimer),r.unshift("Contact: ".concat(this._contact));var g=n.parseSDP();Array.isArray(g.media)||(g.media=[g.media]);var y,T=i(g.media);try{for(T.s();!(y=T.n()).done;){var b=y.value;"audio"===b.type&&(h=!0,b.direction&&"sendrecv"!==b.direction||(p=!0)),"video"===b.type&&(d=!0,b.direction&&"sendrecv"!==b.direction||(v=!0))}}catch(e){T.e(e)}finally{T.f()}if(o&&!1===s.audio){var S,E=i(o.getAudioTracks());try{for(E.s();!(S=E.n()).done;){var C=S.value;o.removeTrack(C)}}catch(e){E.e(e)}finally{E.f()}}if(o&&!1===s.video){var A,I=i(o.getVideoTracks());try{for(I.s();!(A=I.n()).done;){var O=A.value;o.removeTrack(O)}}catch(e){I.e(e)}finally{I.f()}}o||void 0!==s.audio||(s.audio=p),o||void 0!==s.video||(s.video=v),o||h||c.offerToReceiveAudio||(s.audio=!1),o||d||c.offerToReceiveVideo||(s.video=!1),this._createRTCConnection(l,a),Promise.resolve().then(function(){return o||(s.audio||s.video?(e._localMediaStreamLocallyGenerated=!0,navigator.mediaDevices.getUserMedia(s).catch(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");throw n.reply(480),e._failed("local",null,f.causes.USER_DENIED_MEDIA_ACCESS),w.warn('emit "getusermediafailed" [error:%o]',t),e.emit("getusermediafailed",t),new Error("getUserMedia() failed")})):void 0)}).then(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");e._localMediaStream=t,t&&t.getTracks().forEach(function(n){e._connection.addTrack(n,t)})}).then(function(){if(!e._late_sdp){var t={originator:"remote",type:"offer",sdp:n.body};w.debug('emit "sdp"'),e.emit("sdp",t);var r=new RTCSessionDescription({type:"offer",sdp:t.sdp});return e._connectionPromiseQueue=e._connectionPromiseQueue.then(function(){return e._connection.setRemoteDescription(r)}).catch(function(t){throw n.reply(488),e._failed("system",null,f.causes.WEBRTC_ERROR),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',t),e.emit("peerconnection:setremotedescriptionfailed",t),new Error("peerconnection.setRemoteDescription() failed")}),e._connectionPromiseQueue}}).then(function(){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");return e._connecting(n),e._late_sdp?e._createLocalDescription("offer",e._rtcOfferConstraints).catch(function(){throw n.reply(500),new Error("_createLocalDescription() failed")}):e._createLocalDescription("answer",u).catch(function(){throw n.reply(500),new Error("_createLocalDescription() failed")})}).then(function(t){if(e._status===R.STATUS_TERMINATED)throw new Error("terminated");e._handleSessionTimersInIncomingRequest(n,r),n.reply(200,null,r,t,function(){e._status=R.STATUS_WAITING_FOR_ACK,e._setInvite2xxTimer(n,t),e._setACKTimer(),e._accepted("local")},function(){e._failed("system",null,f.causes.CONNECTION_ERROR)})}).catch(function(t){e._status!==R.STATUS_TERMINATED&&w.warn(t)})}else n.reply(500,"Error creating dialog")}},{key:"terminate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("terminate()");var n,r=t.cause||f.causes.BYE,i=m.cloneArray(t.extraHeaders),s=t.body,o=t.status_code,l=t.reason_phrase;if(this._status===R.STATUS_TERMINATED)throw new _.InvalidStateError(this._status);switch(this._status){case R.STATUS_NULL:case R.STATUS_INVITE_SENT:case R.STATUS_1XX_RECEIVED:if(w.debug("canceling session"),o&&(o<200||o>=700))throw new TypeError("Invalid status_code: ".concat(o));o&&(l=l||f.REASON_PHRASE[o]||"",n="SIP ;cause=".concat(o,' ;text="').concat(l,'"')),this._status===R.STATUS_NULL||this._status===R.STATUS_INVITE_SENT?(this._is_canceled=!0,this._cancel_reason=n):this._status===R.STATUS_1XX_RECEIVED&&this._request.cancel(n),this._status=R.STATUS_CANCELED,this._failed("local",null,f.causes.CANCELED);break;case R.STATUS_WAITING_FOR_ANSWER:case R.STATUS_ANSWERED:if(w.debug("rejecting session"),(o=o||480)<300||o>=700)throw new TypeError("Invalid status_code: ".concat(o));this._request.reply(o,l,i,s),this._failed("local",null,f.causes.REJECTED);break;case R.STATUS_WAITING_FOR_ACK:case R.STATUS_CONFIRMED:if(w.debug("terminating session"),l=t.reason_phrase||f.REASON_PHRASE[o]||"",o&&(o<200||o>=700))throw new TypeError("Invalid status_code: ".concat(o));if(o&&i.push("Reason: SIP ;cause=".concat(o,'; text="').concat(l,'"')),this._status===R.STATUS_WAITING_FOR_ACK&&"incoming"===this._direction&&this._request.server_transaction.state!==p.C.STATUS_TERMINATED){var a=this._dialog;this.receiveRequest=function(t){t.method===f.ACK&&(e.sendRequest(f.BYE,{extraHeaders:i,body:s}),a.terminate())},this._request.server_transaction.on("stateChanged",function(){e._request.server_transaction.state===p.C.STATUS_TERMINATED&&(e.sendRequest(f.BYE,{extraHeaders:i,body:s}),a.terminate())}),this._ended("local",null,r),this._dialog=a,this._ua.newDialog(a)}else this.sendRequest(f.BYE,{extraHeaders:i,body:s}),this._ended("local",null,r)}}},{key:"sendDTMF",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};w.debug("sendDTMF() | tones: %s",e);var n=0,r=t.duration||null,i=t.interToneGap||null,s=t.transportType||f.DTMF_TRANSPORT.INFO;if(void 0===e)throw new TypeError("Not enough arguments");if(this._status!==R.STATUS_CONFIRMED&&this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_1XX_RECEIVED)throw new _.InvalidStateError(this._status);if(s!==f.DTMF_TRANSPORT.INFO&&s!==f.DTMF_TRANSPORT.RFC2833)throw new TypeError("invalid transportType: ".concat(s));if("number"==typeof e&&(e=e.toString()),!e||"string"!=typeof e||!e.match(/^[0-9A-DR#*,]+$/i))throw new TypeError("Invalid tones: ".concat(e));if(r&&!m.isDecimal(r))throw new TypeError("Invalid tone duration: ".concat(r));if(r?rb.C.MAX_DURATION?(w.debug('"duration" value is greater than the maximum allowed, setting it to '.concat(b.C.MAX_DURATION," milliseconds")),r=b.C.MAX_DURATION):r=Math.abs(r):r=b.C.DEFAULT_DURATION,t.duration=r,i&&!m.isDecimal(i))throw new TypeError("Invalid interToneGap: ".concat(i));if(i?i=this._tones.length)return void(this._tones=null);var l=this._tones[n];n+=1;if(","===l)o=2e3;else{var a=new b(this);t.eventHandlers={onFailed:function(){s._tones=null}},a.send(l,t),o=r+i}setTimeout(e.bind(this),o)}.call(this));else{var o=this._getDTMFRTPSender();o&&(e=o.toneBuffer+e,o.insertDTMF(e,r,i))}}},{key:"sendInfo",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(w.debug("sendInfo()"),this._status!==R.STATUS_CONFIRMED&&this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_1XX_RECEIVED)throw new _.InvalidStateError(this._status);new S(this).send(e,t,n)}},{key:"mute",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{audio:!0,video:!1};w.debug("mute()");var t=!1,n=!1;!1===this._audioMuted&&e.audio&&(t=!0,this._audioMuted=!0,this._toggleMuteAudio(!0)),!1===this._videoMuted&&e.video&&(n=!0,this._videoMuted=!0,this._toggleMuteVideo(!0)),!0!==t&&!0!==n||this._onmute({audio:t,video:n})}},{key:"unmute",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{audio:!0,video:!0};w.debug("unmute()");var t=!1,n=!1;!0===this._audioMuted&&e.audio&&(t=!0,this._audioMuted=!1,!1===this._localHold&&this._toggleMuteAudio(!1)),!0===this._videoMuted&&e.video&&(n=!0,this._videoMuted=!1,!1===this._localHold&&this._toggleMuteVideo(!1)),!0!==t&&!0!==n||this._onunmute({audio:t,video:n})}},{key:"hold",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(w.debug("hold()"),this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!0===this._localHold)return!1;if(!this._isReadyToReOffer())return!1;this._localHold=!0,this._onhold("local");var r={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Hold Failed"})}};return t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:r,extraHeaders:t.extraHeaders}),!0}},{key:"unhold",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(w.debug("unhold()"),this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!1===this._localHold)return!1;if(!this._isReadyToReOffer())return!1;this._localHold=!1,this._onunhold("local");var r={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Unhold Failed"})}};return t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:r,extraHeaders:t.extraHeaders}),!0}},{key:"renegotiate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;w.debug("renegotiate()");var r=t.rtcOfferConstraints||null;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!this._isReadyToReOffer())return!1;var i={succeeded:function(){n&&n()},failed:function(){e.terminate({cause:f.causes.WEBRTC_ERROR,status_code:500,reason_phrase:"Media Renegotiation Failed"})}};return this._setLocalMediaStatus(),t.useUpdate?this._sendUpdate({sdpOffer:!0,eventHandlers:i,rtcOfferConstraints:r,extraHeaders:t.extraHeaders}):this._sendReinvite({eventHandlers:i,rtcOfferConstraints:r,extraHeaders:t.extraHeaders}),!0}},{key:"refer",value:function(e,t){var n=this;w.debug("refer()");var r=e;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;if(!(e=this._ua.normalizeTarget(e)))throw new TypeError("Invalid target: ".concat(r));var i=new C(this);i.sendRefer(e,t);var s=i.id;return this._referSubscribers[s]=i,i.on("requestFailed",function(){delete n._referSubscribers[s]}),i.on("accepted",function(){delete n._referSubscribers[s]}),i.on("failed",function(){delete n._referSubscribers[s]}),i}},{key:"sendRequest",value:function(e,t){return w.debug("sendRequest()"),this._dialog.sendRequest(e,t)}},{key:"receiveRequest",value:function(e){var t=this;if(w.debug("receiveRequest()"),e.method===f.CANCEL)this._status!==R.STATUS_WAITING_FOR_ANSWER&&this._status!==R.STATUS_ANSWERED||(this._status=R.STATUS_CANCELED,this._request.reply(487),this._failed("remote",e,f.causes.CANCELED));else switch(e.method){case f.ACK:if(this._status!==R.STATUS_WAITING_FOR_ACK)return;if(this._status=R.STATUS_CONFIRMED,clearTimeout(this._timers.ackTimer),clearTimeout(this._timers.invite2xxTimer),this._late_sdp){if(!e.body){this.terminate({cause:f.causes.MISSING_SDP,status_code:400});break}var n={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",n);var r=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(r)}).then(function(){t._is_confirmed||t._confirmed("remote",e)}).catch(function(e){t.terminate({cause:f.causes.BAD_MEDIA_DESCRIPTION,status_code:488}),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}else this._is_confirmed||this._confirmed("remote",e);break;case f.BYE:this._status===R.STATUS_CONFIRMED||this._status===R.STATUS_WAITING_FOR_ACK?(e.reply(200),this._ended("remote",e,f.causes.BYE)):this._status===R.STATUS_INVITE_RECEIVED||this._status===R.STATUS_WAITING_FOR_ANSWER?(e.reply(200),this._request.reply(487,"BYE Received"),this._ended("remote",e,f.causes.BYE)):e.reply(403,"Wrong Status");break;case f.INVITE:this._status===R.STATUS_CONFIRMED?e.hasHeader("replaces")?this._receiveReplaces(e):this._receiveReinvite(e):e.reply(403,"Wrong Status");break;case f.INFO:if(this._status===R.STATUS_1XX_RECEIVED||this._status===R.STATUS_WAITING_FOR_ANSWER||this._status===R.STATUS_ANSWERED||this._status===R.STATUS_WAITING_FOR_ACK||this._status===R.STATUS_CONFIRMED){var i=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0;i&&i.match(/^application\/dtmf-relay/i)?new b(this).init_incoming(e):void 0!==i?new S(this).init_incoming(e):e.reply(415)}else e.reply(403,"Wrong Status");break;case f.UPDATE:this._status===R.STATUS_CONFIRMED?this._receiveUpdate(e):e.reply(403,"Wrong Status");break;case f.REFER:this._status===R.STATUS_CONFIRMED?this._receiveRefer(e):e.reply(403,"Wrong Status");break;case f.NOTIFY:var s={event:e.event,request:e,taken:!1};if(this.emit("sipEvent",s),s.taken){e.reply(200);break}this._status===R.STATUS_CONFIRMED?this._receiveNotify(e):e.reply(403,"Wrong Status");break;default:e.reply(501)}}},{key:"onTransportError",value:function(){w.warn("onTransportError()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:500,reason_phrase:f.causes.CONNECTION_ERROR,cause:f.causes.CONNECTION_ERROR})}},{key:"onRequestTimeout",value:function(){w.warn("onRequestTimeout()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:408,reason_phrase:f.causes.REQUEST_TIMEOUT,cause:f.causes.REQUEST_TIMEOUT})}},{key:"onDialogError",value:function(){w.warn("onDialogError()"),this._status!==R.STATUS_TERMINATED&&this.terminate({status_code:500,reason_phrase:f.causes.DIALOG_ERROR,cause:f.causes.DIALOG_ERROR})}},{key:"newDTMF",value:function(e){w.debug("newDTMF()"),this.emit("newDTMF",e)}},{key:"newInfo",value:function(e){w.debug("newInfo()"),this.emit("newInfo",e)}},{key:"_isReadyToReOffer",value:function(){return this._rtcReady?this._dialog?!0!==this._dialog.uac_pending_reply&&!0!==this._dialog.uas_pending_reply||(w.debug("_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress"),!1):(w.debug("_isReadyToReOffer() | session not established yet"),!1):(w.debug("_isReadyToReOffer() | internal WebRTC status not ready"),!1)}},{key:"_close",value:function(){if(w.debug("close()"),this._localMediaStream&&this._localMediaStreamLocallyGenerated&&(w.debug("close() | closing local MediaStream"),m.closeMediaStream(this._localMediaStream)),this._status!==R.STATUS_TERMINATED){if(this._status=R.STATUS_TERMINATED,this._connection)try{this._connection.close()}catch(e){w.warn("close() | error closing the RTCPeerConnection: %o",e)}for(var e in this._timers)Object.prototype.hasOwnProperty.call(this._timers,e)&&clearTimeout(this._timers[e]);for(var t in clearTimeout(this._sessionTimers.timer),this._dialog&&(this._dialog.terminate(),delete this._dialog),this._earlyDialogs)Object.prototype.hasOwnProperty.call(this._earlyDialogs,t)&&(this._earlyDialogs[t].terminate(),delete this._earlyDialogs[t]);for(var n in this._referSubscribers)Object.prototype.hasOwnProperty.call(this._referSubscribers,n)&&delete this._referSubscribers[n];this._ua.destroyRTCSession(this)}}},{key:"_setInvite2xxTimer",value:function(e,t){var n=v.T1;this._timers.invite2xxTimer=setTimeout(function r(){this._status===R.STATUS_WAITING_FOR_ACK&&(e.reply(200,null,["Contact: ".concat(this._contact)],t),nv.T2&&(n=v.T2),this._timers.invite2xxTimer=setTimeout(r.bind(this),n))}.bind(this),n)}},{key:"_setACKTimer",value:function(){var e=this;this._timers.ackTimer=setTimeout(function(){e._status===R.STATUS_WAITING_FOR_ACK&&(w.debug("no ACK received, terminating the session"),clearTimeout(e._timers.invite2xxTimer),e.sendRequest(f.BYE),e._ended("remote",null,f.causes.NO_ACK))},v.TIMER_H)}},{key:"_createRTCConnection",value:function(e,t){var n=this;this._connection=CitrixVdi.createPeerConnection(e,t),this._connection.addEventListener("iceconnectionstatechange",function(){var e=n._connection.iceConnectionState;if("failed"===e&&n.terminate({cause:f.causes.RTP_TIMEOUT,status_code:408,reason_phrase:f.causes.RTP_TIMEOUT}),void 0!==n._ua.modes.chrome_rtp_timeout_fix&&navigator.webkitGetUserMedia&&"disconnected"===e){var t=n._ua.modes.chrome_rtp_timeout_fix;w.debug("AC: Chrome RTP timeout fix: iceConnectionState==disconnected: check that this will continue for ".concat(t," seconds..."));!function e(){"disconnected"===n._connection.iceConnectionState?t-- >0?setTimeout(function(){return e()},1e3):(w.debug("AC: Chrome RTP timeout fix: Hangup call"),n.terminate({cause:f.causes.RTP_TIMEOUT,status_code:408,reason_phrase:f.causes.RTP_TIMEOUT})):w.debug("AC: Chrome RTP timeout fix: iceConnectionState=".concat(n._connection.iceConnectionState))}()}}),w.debug('emit "peerconnection"'),this.emit("peerconnection",{peerconnection:this._connection})}},{key:"_createLocalDescription",value:function(e,t){var n=this;if(w.debug("createLocalDescription()"),"offer"!==e&&"answer"!==e)throw new Error('createLocalDescription() | invalid type "'.concat(e,'"'));var r=this._connection;return this._rtcReady=!1,Promise.resolve().then(function(){return"offer"===e?CitrixVdi.createOffer(r,t).catch(function(e){return w.warn('emit "peerconnection:createofferfailed" [error:%o]',e),n.emit("peerconnection:createofferfailed",e),Promise.reject(e)}):CitrixVdi.createAnswer(r,t).catch(function(e){return w.warn('emit "peerconnection:createanswerfailed" [error:%o]',e),n.emit("peerconnection:createanswerfailed",e),Promise.reject(e)})}).then(function(e){return r.setLocalDescription(e).catch(function(e){return n._rtcReady=!0,w.warn('emit "peerconnection:setlocaldescriptionfailed" [error:%o]',e),n.emit("peerconnection:setlocaldescriptionfailed",e),Promise.reject(e)})}).then(function(){var i=t&&t.iceRestart;if("complete"===r.iceGatheringState&&!i||"gathering"===r.iceGatheringState&&n._iceReady){n._rtcReady=!0;var s={originator:"local",type:e,sdp:r.localDescription.sdp};return w.debug('emit "sdp"'),n.emit("sdp",s),Promise.resolve(s.sdp)}return new Promise(function(t){var i,s,o=!1;n._iceReady=!1;var l=function(){r.removeEventListener("icecandidate",i),r.removeEventListener("icegatheringstatechange",s),o=!0,n._rtcReady=!0,n._iceReady=!0;var l={originator:"local",type:e,sdp:r.localDescription.sdp};w.debug('emit "sdp"'),n.emit("sdp",l),t(l.sdp)};r.addEventListener("icecandidate",i=function(e){var t=e.candidate;t?n.emit("icecandidate",{candidate:t,ready:l}):o||l()}),r.addEventListener("icegatheringstatechange",s=function(){"complete"!==r.iceGatheringState||o||l()}),void 0!==n._ua.modes.ice_timeout_fix&&setTimeout(function(){o||(w.debug("AC: ICE gathering timeout fix"),l())},n._ua.modes.ice_timeout_fix)})})}},{key:"_createDialog",value:function(e,t,n){var r="UAS"===t?e.to_tag:e.from_tag,i="UAS"===t?e.from_tag:e.to_tag,s=e.call_id+r+i,o=this._earlyDialogs[s];if(n)return!!o||((o=new y(this,e,t,y.C.STATUS_EARLY)).error?(w.debug(o.error),this._failed("remote",e,f.causes.INTERNAL_ERROR),!1):(this._earlyDialogs[s]=o,!0));if(this._from_tag=e.from_tag,this._to_tag=e.to_tag,o)return o.update(e,t),this._dialog=o,delete this._earlyDialogs[s],!0;var l=new y(this,e,t);return l.error?(w.debug(l.error),this._failed("remote",e,f.causes.INTERNAL_ERROR),!1):(this._dialog=l,!0)}},{key:"_receiveReinvite",value:function(e){var t=this;w.debug("receiveReinvite()");var n=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,r={request:e,callback:void 0,reject:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i=!0;var n=t.status_code||403,r=t.reason_phrase||"",s=m.cloneArray(t.extraHeaders);if(this._status!==R.STATUS_CONFIRMED)return!1;if(n<300||n>=700)throw new TypeError("Invalid status_code: ".concat(n));e.reply(n,r,s)}.bind(this)},i=!1;if(this.emit("reinvite",r),!i){if(this._late_sdp=!1,!e.body)return this._late_sdp=!0,this._remoteHold&&(this._remoteHold=!1,this._onunhold("remote")),void(this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._createLocalDescription("offer",t._rtcOfferConstraints)}).then(function(e){s.call(t,e)}).catch(function(){e.reply(500)}));if("application/sdp"!==n)return w.debug("invalid Content-Type"),void e.reply(415);this._processInDialogSdpOffer(e).then(function(e){t._status!==R.STATUS_TERMINATED&&s.call(t,e)}).catch(function(e){w.warn(e)})}function s(t){var n=this,i=["Contact: ".concat(this._contact)];this._handleSessionTimersInIncomingRequest(e,i),this._late_sdp&&(t=this._mangleOffer(t)),e.reply(200,null,i,t,function(){n._status=R.STATUS_WAITING_FOR_ACK,n._setInvite2xxTimer(e,t),n._setACKTimer()}),"function"==typeof r.callback&&r.callback()}}},{key:"_receiveUpdate",value:function(e){var t=this;w.debug("receiveUpdate()");var n=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,r={request:e,callback:void 0,reject:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i=!0;var n=t.status_code||403,r=t.reason_phrase||"",s=m.cloneArray(t.extraHeaders);if(this._status!==R.STATUS_CONFIRMED)return!1;if(n<300||n>=700)throw new TypeError("Invalid status_code: ".concat(n));e.reply(n,r,s)}.bind(this)},i=!1;if(this.emit("update",r),!i)if(e.body){if("application/sdp"!==n)return w.debug("invalid Content-Type"),void e.reply(415);this._processInDialogSdpOffer(e).then(function(e){t._status!==R.STATUS_TERMINATED&&s.call(t,e)}).catch(function(e){w.warn(e)})}else s.call(this,null);function s(t){var n=["Contact: ".concat(this._contact)];this._handleSessionTimersInIncomingRequest(e,n),e.reply(200,null,n,t),"function"==typeof r.callback&&r.callback()}}},{key:"_processInDialogSdpOffer",value:function(e){var t=this;w.debug("_processInDialogSdpOffer()");var n,r=e.parseSDP(),s=!1,o=i(r.media);try{for(o.s();!(n=o.n()).done;){var l=n.value;if(-1!==I.indexOf(l.type)){var a=l.direction||r.direction||"sendrecv";if("sendonly"!==a&&"inactive"!==a){s=!1;break}s=!0}}}catch(e){o.e(e)}finally{o.f()}var u={originator:"remote",type:"offer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",u);var c=new RTCSessionDescription({type:"offer",sdp:u.sdp});return this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");return t._connection.setRemoteDescription(c).catch(function(n){throw e.reply(488),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',n),t.emit("peerconnection:setremotedescriptionfailed",n),n})}).then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");!0===t._remoteHold&&!1===s?(t._remoteHold=!1,t._onunhold("remote")):!1===t._remoteHold&&!0===s&&(t._remoteHold=!0,t._onhold("remote"))}).then(function(){if(t._status===R.STATUS_TERMINATED)throw new Error("terminated");return t._createLocalDescription("answer",t._rtcAnswerConstraints).catch(function(t){throw e.reply(500),w.warn('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]',t),t})}).catch(function(e){w.warn("_processInDialogSdpOffer() failed [error: %o]",e)}),this._connectionPromiseQueue}},{key:"_receiveRefer",value:function(e){var t=this;if(w.debug("receiveRefer()"),!e.refer_to)return w.debug("no Refer-To header field present in REFER"),void e.reply(400);if(e.refer_to.uri.scheme!==f.SIP)return w.debug("Refer-To header field points to a non-SIP URI scheme"),void e.reply(416);e.reply(202);var n=new E(this,e.cseq);w.debug('emit "refer"'),this.emit("refer",{request:e,accept:function(r,i){(function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t="function"==typeof t?t:null,this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;var i=new u(this._ua);if(i.on("progress",function(e){var t=e.response;n.notify(t.status_code,t.reason_phrase)}),i.on("accepted",function(e){var t=e.response;n.notify(t.status_code,t.reason_phrase)}),i.on("_failed",function(e){var t=e.message,r=e.cause;t?n.notify(t.status_code,t.reason_phrase):n.notify(487,r)}),e.refer_to.uri.hasHeader("replaces")){var s=decodeURIComponent(e.refer_to.uri.getHeader("replaces"));r.extraHeaders=m.cloneArray(r.extraHeaders),r.extraHeaders.push("Replaces: ".concat(s))}i.connect(e.refer_to.uri.toAor(),r,t)}).call(t,r,i)},reject:function(){(function(){n.notify(603)}).call(t)}})}},{key:"_receiveNotify",value:function(e){switch(w.debug("receiveNotify()"),e.event||e.reply(400),e.event.event){case"refer":var t,n;if(e.event.params&&e.event.params.id)t=e.event.params.id,n=this._referSubscribers[t];else{if(1!==Object.keys(this._referSubscribers).length)return void e.reply(400,"Missing event id parameter");n=this._referSubscribers[Object.keys(this._referSubscribers)[0]]}if(!n)return void e.reply(481,"Subscription does not exist");n.receiveNotify(e),e.reply(200);break;default:e.reply(489)}}},{key:"_receiveReplaces",value:function(e){var t=this;w.debug("receiveReplaces()"),this.emit("replaces",{request:e,accept:function(n){(function(t){var n=this;if(this._status!==R.STATUS_WAITING_FOR_ACK&&this._status!==R.STATUS_CONFIRMED)return!1;var r=new u(this._ua);r.on("confirmed",function(){n.terminate()}),r.init_incoming(e,t)}).call(t,n)},reject:function(){(function(){w.debug("Replaced INVITE rejected by the user"),e.reply(486)}).call(t)}})}},{key:"_sendInitialRequest",value:function(e,t,n){var r=this,i=new T(this._ua,this._request,{onRequestTimeout:function(){r.onRequestTimeout()},onTransportError:function(){r.onTransportError()},onAuthenticated:function(e){r._request=e},onReceiveResponse:function(e){r._receiveInviteResponse(e)}});Promise.resolve().then(function(){return n||(e.audio||e.video?(r._localMediaStreamLocallyGenerated=!0,navigator.mediaDevices.getUserMedia(e).catch(function(e){if(r._status===R.STATUS_TERMINATED)throw new Error("terminated");throw r._failed("local",null,f.causes.USER_DENIED_MEDIA_ACCESS),w.warn('emit "getusermediafailed" [error:%o]',e),r.emit("getusermediafailed",e),e})):void 0)}).then(function(e){if(r._status===R.STATUS_TERMINATED)throw new Error("terminated");return r._localMediaStream=e,e&&e.getTracks().forEach(function(t){r._connection.addTrack(t,e)}),r._connecting(r._request),r._createLocalDescription("offer",t).catch(function(e){throw r._failed("local",null,f.causes.WEBRTC_ERROR),e})}).then(function(e){if(r._is_canceled||r._status===R.STATUS_TERMINATED)throw new Error("terminated");r._request.body=e,r._status=R.STATUS_INVITE_SENT,w.debug('emit "sending" [request:%o]',r._request),r.emit("sending",{request:r._request}),i.send()}).catch(function(e){r._status!==R.STATUS_TERMINATED&&w.warn(e)})}},{key:"_getDTMFRTPSender",value:function(){var e=this._connection.getSenders().find(function(e){return e.track&&"audio"===e.track.kind});if(e&&e.dtmf)return e.dtmf;w.warn("sendDTMF() | no local audio track to send DTMF with")}},{key:"_receiveInviteResponse",value:function(e){var t=this;if(w.debug("receiveInviteResponse()"),this._dialog&&e.status_code>=200&&e.status_code<=299){if(this._dialog.id.call_id===e.call_id&&this._dialog.id.local_tag===e.from_tag&&this._dialog.id.remote_tag===e.to_tag)return void this.sendRequest(f.ACK);var n=new y(this,e,"UAC");return void 0!==n.error?void w.debug(n.error):(this.sendRequest(f.ACK),void this.sendRequest(f.BYE))}if(this._is_canceled)e.status_code>=100&&e.status_code<200?this._request.cancel(this._cancel_reason):e.status_code>=200&&e.status_code<299&&this._acceptAndTerminate(e);else if(this._status===R.STATUS_INVITE_SENT||this._status===R.STATUS_1XX_RECEIVED)switch(!0){case/^100$/.test(e.status_code):this._status=R.STATUS_1XX_RECEIVED;break;case/^1[0-9]{2}$/.test(e.status_code):if(!e.to_tag){w.debug("1xx response received without to tag");break}if(e.hasHeader("contact")&&!this._createDialog(e,"UAC",!0))break;if(this._status=R.STATUS_1XX_RECEIVED,!e.body){this._progress("remote",e);break}var r={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",r);var i=new RTCSessionDescription({type:"answer",sdp:r.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){return t._progress("remote",e)}).catch(function(e){w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)});break;case/^2[0-9]{2}$/.test(e.status_code):if(this._status=R.STATUS_CONFIRMED,!e.body){this._acceptAndTerminate(e,400,f.causes.MISSING_SDP),this._failed("remote",e,f.causes.BAD_MEDIA_DESCRIPTION);break}if(!this._createDialog(e,"UAC"))break;var s={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",s);var o=new RTCSessionDescription({type:"answer",sdp:s.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){if("stable"===t._connection.signalingState)return CitrixVdi.createOffer(t._connection,t._rtcOfferConstraints).then(function(e){return t._connection.setLocalDescription(e)}).catch(function(n){t._acceptAndTerminate(e,500,n.toString()),t._failed("local",e,f.causes.WEBRTC_ERROR)})}).then(function(){t._connection.setRemoteDescription(o).then(function(){t._handleSessionTimersInIncomingResponse(e),t._accepted("remote",e),t.sendRequest(f.ACK),t._confirmed("local",null)}).catch(function(n){t._acceptAndTerminate(e,488,"Not Acceptable Here"),t._failed("remote",e,f.causes.BAD_MEDIA_DESCRIPTION),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',n),t.emit("peerconnection:setremotedescriptionfailed",n)})});break;default:var l=m.sipErrorCause(e.status_code);this._failed("remote",e,l)}}},{key:"_sendReinvite",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("sendReinvite()");var n=m.cloneArray(t.extraHeaders),r=m.cloneObject(t.eventHandlers),i=t.rtcOfferConstraints||this._rtcOfferConstraints||null,s=!1;function o(e){r.failed&&r.failed(e)}n.push("Contact: ".concat(this._contact)),n.push("Content-Type: application/sdp"),this._sessionTimers.running&&n.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(this._sessionTimers.refresher?"uac":"uas")),this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return e._createLocalDescription("offer",i)}).then(function(t){var i={originator:"local",type:"offer",sdp:t=e._mangleOffer(t)};w.debug('emit "sdp"'),e.emit("sdp",i),e.sendRequest(f.INVITE,{extraHeaders:n,body:t,eventHandlers:{onSuccessResponse:function(t){(function(e){var t=this;if(this._status===R.STATUS_TERMINATED)return;if(this.sendRequest(f.ACK),s)return;if(this._handleSessionTimersInIncomingResponse(e),!e.body)return void o.call(this);if(!e.hasHeader("Content-Type")||"application/sdp"!==e.getHeader("Content-Type").toLowerCase())return void o.call(this);var n={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",n);var i=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){r.succeeded&&r.succeeded(e)}).catch(function(e){o.call(t),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}).call(e,t),s=!0},onErrorResponse:function(t){o.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}).catch(function(){o()})}},{key:"_sendUpdate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};w.debug("sendUpdate()");var n=m.cloneArray(t.extraHeaders),r=m.cloneObject(t.eventHandlers),i=t.rtcOfferConstraints||this._rtcOfferConstraints||null,s=t.sdpOffer||!1,o=!1;function l(e){var t=this;if(this._status!==R.STATUS_TERMINATED&&!o)if(this._handleSessionTimersInIncomingResponse(e),s){if(!e.body)return void a.call(this);if(!e.hasHeader("Content-Type")||"application/sdp"!==e.getHeader("Content-Type").toLowerCase())return void a.call(this);var n={originator:"remote",type:"answer",sdp:e.body};w.debug('emit "sdp"'),this.emit("sdp",n);var i=new RTCSessionDescription({type:"answer",sdp:n.sdp});this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return t._connection.setRemoteDescription(i)}).then(function(){r.succeeded&&r.succeeded(e)}).catch(function(e){a.call(t),w.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]',e),t.emit("peerconnection:setremotedescriptionfailed",e)})}else r.succeeded&&r.succeeded(e)}function a(e){r.failed&&r.failed(e)}n.push("Contact: ".concat(this._contact)),this._sessionTimers.running&&n.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(this._sessionTimers.refresher?"uac":"uas")),s?(n.push("Content-Type: application/sdp"),this._connectionPromiseQueue=this._connectionPromiseQueue.then(function(){return e._createLocalDescription("offer",i)}).then(function(t){var r={originator:"local",type:"offer",sdp:t=e._mangleOffer(t)};w.debug('emit "sdp"'),e.emit("sdp",r),e.sendRequest(f.UPDATE,{extraHeaders:n,body:t,eventHandlers:{onSuccessResponse:function(t){l.call(e,t),o=!0},onErrorResponse:function(t){a.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}).catch(function(){a.call(e)})):this.sendRequest(f.UPDATE,{extraHeaders:n,eventHandlers:{onSuccessResponse:function(t){l.call(e,t)},onErrorResponse:function(t){a.call(e,t)},onTransportError:function(){e.onTransportError()},onRequestTimeout:function(){e.onRequestTimeout()},onDialogError:function(){e.onDialogError()}}})}},{key:"_acceptAndTerminate",value:function(e,t,n){w.debug("acceptAndTerminate()");var r=[];t&&(n=n||f.REASON_PHRASE[t]||"",r.push("Reason: SIP ;cause=".concat(t,'; text="').concat(n,'"'))),(this._dialog||this._createDialog(e,"UAC"))&&(this.sendRequest(f.ACK),this.sendRequest(f.BYE,{extraHeaders:r})),this._status=R.STATUS_TERMINATED}},{key:"_mangleOffer",value:function(e){if(!this._localHold&&!this._remoteHold)return e;if(e=h.parse(e),this._localHold&&!this._remoteHold){w.debug("mangleOffer() | me on hold, mangling offer");var t,n=i(e.media);try{for(n.s();!(t=n.n()).done;){var r=t.value;-1!==I.indexOf(r.type)&&(r.direction?"sendrecv"===r.direction?r.direction="sendonly":"recvonly"===r.direction&&(r.direction="inactive"):r.direction="sendonly")}}catch(e){n.e(e)}finally{n.f()}}else if(this._localHold&&this._remoteHold){w.debug("mangleOffer() | both on hold, mangling offer");var s,o=i(e.media);try{for(o.s();!(s=o.n()).done;){var l=s.value;-1!==I.indexOf(l.type)&&(l.direction="inactive")}}catch(e){o.e(e)}finally{o.f()}}else if(this._remoteHold){w.debug("mangleOffer() | remote on hold, mangling offer");var a,u=i(e.media);try{for(u.s();!(a=u.n()).done;){var c=a.value;-1!==I.indexOf(c.type)&&(c.direction?"sendrecv"===c.direction?c.direction="recvonly":"recvonly"===c.direction&&(c.direction="inactive"):c.direction="recvonly")}}catch(e){u.e(e)}finally{u.f()}}return h.write(e)}},{key:"_setLocalMediaStatus",value:function(){var e=!0,t=!0;(this._localHold||this._remoteHold)&&(e=!1,t=!1),this._audioMuted&&(e=!1),this._videoMuted&&(t=!1),this._toggleMuteAudio(!e),this._toggleMuteVideo(!t)}},{key:"_handleSessionTimersInIncomingRequest",value:function(e,t){var n;this._sessionTimers.enabled&&(e.session_expires&&e.session_expires>=f.MIN_SESSION_EXPIRES?(this._sessionTimers.currentExpires=e.session_expires,n=e.session_expires_refresher||"uas"):(this._sessionTimers.currentExpires=this._sessionTimers.defaultExpires,n="uas"),t.push("Session-Expires: ".concat(this._sessionTimers.currentExpires,";refresher=").concat(n)),this._sessionTimers.refresher="uas"===n,this._runSessionTimer())}},{key:"_handleSessionTimersInIncomingResponse",value:function(e){var t;this._sessionTimers.enabled&&(e.session_expires&&e.session_expires>=f.MIN_SESSION_EXPIRES?(this._sessionTimers.currentExpires=e.session_expires,t=e.session_expires_refresher||"uac"):(this._sessionTimers.currentExpires=this._sessionTimers.defaultExpires,t="uac"),this._sessionTimers.refresher="uac"===t,this._runSessionTimer())}},{key:"_runSessionTimer",value:function(){var e=this,t=this._sessionTimers.currentExpires;this._sessionTimers.running=!0,clearTimeout(this._sessionTimers.timer),this._sessionTimers.refresher?this._sessionTimers.timer=setTimeout(function(){e._status!==R.STATUS_TERMINATED&&e._isReadyToReOffer()&&(w.debug("runSessionTimer() | sending session refresh request"),e._sessionTimers.refreshMethod===f.UPDATE?e._sendUpdate():e._sendReinvite())},500*t):this._sessionTimers.timer=setTimeout(function(){e._status!==R.STATUS_TERMINATED&&(w.warn("runSessionTimer() | timer expired, terminating the session"),e.terminate({cause:f.causes.REQUEST_TIMEOUT,status_code:408,reason_phrase:"Session Timer Expired"}))},1100*t)}},{key:"_toggleMuteAudio",value:function(e){var t,n=i(this._connection.getSenders().filter(function(e){return e.track&&"audio"===e.track.kind}));try{for(n.s();!(t=n.n()).done;){t.value.track.enabled=!e}}catch(e){n.e(e)}finally{n.f()}}},{key:"_toggleMuteVideo",value:function(e){var t,n=i(this._connection.getSenders().filter(function(e){return e.track&&"video"===e.track.kind}));try{for(n.s();!(t=n.n()).done;){t.value.track.enabled=!e}}catch(e){n.e(e)}finally{n.f()}}},{key:"_newRTCSession",value:function(e,t){w.debug("newRTCSession()"),this._ua.newRTCSession(this,{originator:e,session:this,request:t})}},{key:"_connecting",value:function(e){w.debug("session connecting"),w.debug('emit "connecting"'),this.emit("connecting",{request:e})}},{key:"_progress",value:function(e,t){w.debug("session progress"),w.debug('emit "progress"'),this.emit("progress",{originator:e,response:t||null})}},{key:"_accepted",value:function(e,t){w.debug("session accepted"),this._start_time=new Date,w.debug('emit "accepted"'),this.emit("accepted",{originator:e,response:t||null})}},{key:"_confirmed",value:function(e,t){w.debug("session confirmed"),this._is_confirmed=!0,w.debug('emit "confirmed"'),this.emit("confirmed",{originator:e,ack:t||null})}},{key:"_ended",value:function(e,t,n){w.debug("session ended"),this._end_time=new Date,this._close(),w.debug('emit "ended"'),this.emit("ended",{originator:e,message:t||null,cause:n})}},{key:"_failed",value:function(e,t,n){w.debug("session failed"),w.debug('emit "_failed"'),this.emit("_failed",{originator:e,message:t||null,cause:n}),this._close(),w.debug('emit "failed"'),this.emit("failed",{originator:e,message:t||null,cause:n})}},{key:"_onhold",value:function(e){w.debug("session onhold"),this._setLocalMediaStatus(),w.debug('emit "hold"'),this.emit("hold",{originator:e})}},{key:"_onunhold",value:function(e){w.debug("session onunhold"),this._setLocalMediaStatus(),w.debug('emit "unhold"'),this.emit("unhold",{originator:e})}},{key:"_onmute",value:function(e){var t=e.audio,n=e.video;w.debug("session onmute"),this._setLocalMediaStatus(),w.debug('emit "muted"'),this.emit("muted",{audio:t,video:n})}},{key:"_onunmute",value:function(e){var t=e.audio,n=e.video;w.debug("session onunmute"),this._setLocalMediaStatus(),w.debug('emit "unmuted"'),this.emit("unmuted",{audio:t,video:n})}}])&&o(t.prototype,n),r&&o(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Dialog":3,"./Exceptions":6,"./Logger":9,"./RTCSession/DTMF":16,"./RTCSession/Info":17,"./RTCSession/ReferNotifier":18,"./RTCSession/ReferSubscriber":19,"./RequestSender":21,"./SIPMessage":22,"./Timers":25,"./Transactions":26,"./URI":29,"./Utils":30,events:33,"sdp-transform":39}],16:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};if(void 0===e)throw new TypeError("Not enough arguments");if(this._direction="outgoing",this._session.status!==this._session.C.STATUS_CONFIRMED&&this._session.status!==this._session.C.STATUS_WAITING_FOR_ACK)throw new h.InvalidStateError(this._session.status);var r=d.cloneArray(n.extraHeaders);if(this.eventHandlers=d.cloneObject(n.eventHandlers),"string"==typeof e)e=e.toUpperCase();else{if("number"!=typeof e)throw new TypeError("Invalid tone: ".concat(e));e=e.toString()}if(!e.match(/^[0-9A-DR#*]$/))throw new TypeError("Invalid tone: ".concat(e));this._tone=e,this._duration=n.duration,r.push("Content-Type: application/dtmf-relay");var i="Signal=".concat(this._tone,"\r\n");i+="Duration=".concat(this._duration),this._session.newDTMF({originator:"local",dtmf:this,request:this._request}),this._session.sendRequest(c.INFO,{extraHeaders:r,eventHandlers:{onSuccessResponse:function(e){t.emit("succeeded",{originator:"remote",response:e})},onErrorResponse:function(e){t.eventHandlers.onFailed&&t.eventHandlers.onFailed(),t.emit("failed",{originator:"remote",response:e})},onRequestTimeout:function(){t._session.onRequestTimeout()},onTransportError:function(){t._session.onTransportError()},onDialogError:function(){t._session.onDialogError()}},body:i})}},{key:"init_incoming",value:function(e){var t=/^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/,n=/^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;if(this._direction="incoming",this._request=e,e.reply(200),e.body){var r=e.body.split("\n");r.length>=1&&t.test(r[0])&&(this._tone=r[0].replace(t,"$2")),r.length>=2&&n.test(r[1])&&(this._duration=parseInt(r[1].replace(n,"$2"),10))}this._duration||(this._duration=_.DEFAULT_DURATION),this._tone?this._session.newDTMF({originator:"remote",dtmf:this,request:e}):f.debug("invalid INFO DTMF received, discarded")}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}(),t.exports.C=_},{"../Constants":2,"../Exceptions":6,"../Logger":9,"../Utils":30,events:33}],17:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{};if(this._direction="outgoing",t&&void 0===e)throw new TypeError("Not enough arguments");if(this._session.status!==this._session.C.STATUS_CONFIRMED&&this._session.status!==this._session.C.STATUS_WAITING_FOR_ACK)throw new c.InvalidStateError(this._session.status);this._contentType=e,this._body=t;var i=h.cloneArray(r.extraHeaders);e&&i.push("Content-Type: ".concat(e)),this._session.newInfo({originator:"local",info:this,request:this.request}),this._session.sendRequest(u.INFO,{extraHeaders:i,eventHandlers:{onSuccessResponse:function(e){n.emit("succeeded",{originator:"remote",response:e})},onErrorResponse:function(e){n.emit("failed",{originator:"remote",response:e})},onTransportError:function(){n._session.onTransportError()},onRequestTimeout:function(){n._session.onRequestTimeout()},onDialogError:function(){n._session.onDialogError()}},body:t})}},{key:"init_incoming",value:function(e){this._direction="incoming",this.request=e,e.reply(200),this._contentType=e.hasHeader("Content-Type")?e.getHeader("Content-Type").toLowerCase():void 0,this._body=e.body,this._session.newInfo({originator:"remote",info:this,request:e})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),d}()},{"../Constants":2,"../Exceptions":6,"../Utils":30,events:33}],18:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=200?"terminated;reason=noresource":"active;expires=".concat(this._expires);try{this._session.sendRequest(s.NOTIFY,{extraHeaders:["Event: ".concat(l.event_type,";id=").concat(this._id),"Subscription-State: ".concat(n),"Content-Type: ".concat(l.body_type)],body:"SIP/2.0 ".concat(e," ").concat(t),eventHandlers:{onErrorResponse:function(){this._active=!1}}})}catch(e){o.debug("send NOTIFY exception [ignored]")}}}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"../Constants":2,"../Logger":9}],19:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};f.debug("sendRefer()");var r=d.cloneArray(n.extraHeaders),i=d.cloneObject(n.eventHandlers);for(var s in i)Object.prototype.hasOwnProperty.call(i,s)&&this.on(s,i[s]);var o=null;n.replaces&&(o=n.replaces._request.call_id,o+=";to-tag=".concat(n.replaces._to_tag),o+=";from-tag=".concat(n.replaces._from_tag),o=encodeURIComponent(o));var l="Refer-To: <".concat(e).concat(o?"?Replaces=".concat(o):"",">");if(r.push(l),!r.some(function(e){return e.toLowerCase().startsWith("referred-by:")})){var a="Referred-By: <".concat(this._session._ua._configuration.uri._scheme,":").concat(this._session._ua._configuration.uri._user,"@").concat(this._session._ua._configuration.uri._host,">");r.push(a)}r.push("Contact: ".concat(this._session.contact));var u=this._session.sendRequest(c.REFER,{extraHeaders:r,eventHandlers:{onSuccessResponse:function(e){t._requestSucceeded(e)},onErrorResponse:function(e){t._requestFailed(e,c.causes.REJECTED)},onTransportError:function(){t._requestFailed(null,c.causes.CONNECTION_ERROR)},onRequestTimeout:function(){t._requestFailed(null,c.causes.REQUEST_TIMEOUT)},onDialogError:function(){t._requestFailed(null,c.causes.DIALOG_ERROR)}}});this._id=u.cseq}},{key:"receiveNotify",value:function(e){if(f.debug("receiveNotify()"),e.body){var t=h.parse(e.body.trim().split("\r\n",1)[0],"Status_Line");if(-1!==t)switch(!0){case/^100$/.test(t.status_code):this.emit("trying",{request:e,status_line:t});break;case/^1[0-9]{2}$/.test(t.status_code):this.emit("progress",{request:e,status_line:t});break;case/^2[0-9]{2}$/.test(t.status_code):this.emit("accepted",{request:e,status_line:t});break;default:this.emit("failed",{request:e,status_line:t})}else f.debug('receiveNotify() | error parsing NOTIFY body: "'.concat(e.body,'"'))}}},{key:"_requestSucceeded",value:function(e){f.debug("REFER succeeded"),f.debug('emit "requestSucceeded"'),this.emit("requestSucceeded",{response:e})}},{key:"_requestFailed",value:function(e,t){f.debug("REFER failed"),f.debug('emit "requestFailed"'),this.emit("requestFailed",{response:e||null,cause:t})}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"../Constants":2,"../Grammar":7,"../Logger":9,"../Utils":30,events:33}],20:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n"'),this._contact+=";reg-id=".concat(this._reg_id),this._contact+=";+sip.instance=".concat(this._sipInstance),this._auth=null}var t,n,i;return t=e,(n=[{key:"registered",get:function(){return this._registered}},{key:"setExtraHeaders",value:function(e){Array.isArray(e)||(e=[]),this._extraHeaders=e.slice()}},{key:"setExtraContactParams",value:function(e){for(var t in e instanceof Object||(e={}),this._extraContactParams="",e)if(Object.prototype.hasOwnProperty.call(e,t)){var n=e[t];this._extraContactParams+=";".concat(t),n&&(this._extraContactParams+="=".concat(n))}}},{key:"register",value:function(){var e=this;if(this._registering)u.debug("Register request in progress...");else{var t=this._extraHeaders.slice();t.push("Contact: ".concat(this._contact,";expires=").concat(this._expires).concat(this._extraContactParams)),t.push("Expires: ".concat(this._expires)),this._auth&&t.push(this._auth);var n=new l.OutgoingRequest(o.REGISTER,this._registrar,this._ua,{to_uri:this._to_uri,call_id:this._call_id,cseq:this._cseq+=1},t),r=new a(this._ua,n,{onRequestTimeout:function(){e._registrationFailure(null,o.causes.REQUEST_TIMEOUT)},onTransportError:function(){e._registrationFailure(null,o.causes.CONNECTION_ERROR)},onAuthenticated:function(t){var n,r;(e._cseq+=1,e._ua.modes.cache_register_auth_mode)&&((r=t.getHeader(n="Authorization"))?e._auth="".concat(n,": ").concat(r):(r=t.getHeader(n="Proxy-Authorization"))&&(e._auth="".concat(n,": ").concat(r)))},onReceiveResponse:function(t){if(t.cseq===e._cseq)switch(null!==e._registrationTimer&&(clearTimeout(e._registrationTimer),e._registrationTimer=null),!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):if(e._registering=!1,!t.hasHeader("Contact")){u.debug("no Contact header in response to REGISTER, response ignored");break}var n=t.headers.Contact.reduce(function(e,t){return e.concat(t.parsed)},[]),r=n.find(function(t){return e._sipInstance===t.getParam("+sip.instance")&&e._reg_id===parseInt(t.getParam("reg-id"))});if(r||(r=n.find(function(t){return t.uri.user===e._ua.contact.uri.user})),!r){u.debug("no Contact header pointing to us, response ignored");break}var i=r.getParam("expires");!i&&t.hasHeader("expires")&&(i=t.getHeader("expires")),i||(i=e._expires),(i=Number(i))<10&&(i=10);var l=i>=140?1e3*i/2+Math.floor(1e3*(i/2-70)*Math.random()):1e3*i-5e3;e._registrationTimer=setTimeout(function(){e._registrationTimer=null,0===e._ua.listeners("registrationExpiring").length?e.register():e._ua.emit("registrationExpiring")},l),r.hasParam("temp-gruu")&&(e._ua.contact.temp_gruu=r.getParam("temp-gruu").replace(/"/g,"")),r.hasParam("pub-gruu")&&(e._ua.contact.pub_gruu=r.getParam("pub-gruu").replace(/"/g,"")),e._registered||(e._registered=!0,e._ua.registered({response:t}));break;case/^423$/.test(t.status_code):t.hasHeader("min-expires")?(e._expires=Number(t.getHeader("min-expires")),e._expires<10&&(e._expires=10),e.register()):(u.debug("423 response received for REGISTER without Min-Expires"),e._registrationFailure(t,o.causes.SIP_FAILURE_CODE));break;default:var a=s.sipErrorCause(t.status_code);e._registrationFailure(t,a)}}});this._registering=!0,r.send()}}},{key:"unregister",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(this._registered){this._registered=!1,null!==this._registrationTimer&&(clearTimeout(this._registrationTimer),this._registrationTimer=null);var n=this._extraHeaders.slice();t.all?n.push("Contact: *".concat(this._extraContactParams)):n.push("Contact: ".concat(this._contact,";expires=0").concat(this._extraContactParams)),n.push("Expires: 0"),this._auth&&n.push(this._auth);var r=new l.OutgoingRequest(o.REGISTER,this._registrar,this._ua,{to_uri:this._to_uri,call_id:this._call_id,cseq:this._cseq+=1},n);new a(this._ua,r,{onRequestTimeout:function(){e._unregistered(null,o.causes.REQUEST_TIMEOUT)},onTransportError:function(){e._unregistered(null,o.causes.CONNECTION_ERROR)},onAuthenticated:function(){e._cseq+=1},onReceiveResponse:function(t){switch(!0){case/^1[0-9]{2}$/.test(t.status_code):break;case/^2[0-9]{2}$/.test(t.status_code):e._unregistered(t);break;default:var n=s.sipErrorCause(t.status_code);e._unregistered(t,n)}}}).send(),this._auth=null}else u.debug("already unregistered")}},{key:"close",value:function(){this._registered&&this.unregister()}},{key:"onTransportClosed",value:function(){this._registering=!1,null!==this._registrationTimer&&(clearTimeout(this._registrationTimer),this._registrationTimer=null),this._registered&&(this._registered=!1,this._ua.unregistered({}))}},{key:"_registrationFailure",value:function(e,t){this._registering=!1,this._ua.registrationFailed({response:e||null,cause:t}),this._registered&&(this._registered=!1,this._ua.unregistered({response:e||null,cause:t}))}},{key:"_unregistered",value:function(e,t){this._registering=!1,this._registered=!1,this._ua.unregistered({response:e||null,cause:t||null})}}])&&r(t.prototype,n),i&&r(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30}],21:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,o=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return o=e.done,e},e:function(e){l=!0,s=e},f:function(){try{o||null==n.return||n.return()}finally{if(l)throw s}}}}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n")),this.setHeader("via",""),this.setHeader("max-forwards",p.MAX_FORWARDS);var l=i.to_uri||n,a=i.to_tag?{tag:i.to_tag}:null,u=void 0!==i.to_display_name?i.to_display_name:null;this.to=new v(l,u,a),this.setHeader("to",this.to.toString());var h,d=i.from_uri||r.configuration.uri,f={tag:i.from_tag||m.newTag()};h=void 0!==i.from_display_name?i.from_display_name:r.configuration.display_name?r.configuration.display_name:null,this.from=new v(d,h,f),this.setHeader("from",this.from.toString());var _=i.call_id||r.configuration.jssip_id+m.createRandomToken(15);this.call_id=_,this.setHeader("call-id",_);var g=i.cseq||Math.floor(1e4*Math.random());this.cseq=g,this.setHeader("cseq","".concat(g," ").concat(t))}return d(e,[{key:"setHeader",value:function(e,t){for(var n=new RegExp("^\\s*".concat(e,"\\s*:"),"i"),r=0;r1&&void 0!==arguments[1]?arguments[1]:0;if(e=m.headerize(e),this.headers[e]){if(!(t>=this.headers[e].length)){var n=this.headers[e][t],r=n.raw;if(n.parsed)return n.parsed;var i=g.parse(r,e.replace(/-/g,"_"));return-1===i?(this.headers[e].splice(t,1),void y.debug('error parsing "'.concat(e,'" header field with value "').concat(r,'"'))):(n.parsed=i,i)}y.debug('not so many "'.concat(e,'" headers present'))}else y.debug('header "'.concat(e,'" not present'))}},{key:"s",value:function(e,t){return this.parseHeader(e,t)}},{key:"setHeader",value:function(e,t){var n={raw:t};this.headers[m.headerize(e)]=[n]}},{key:"parseSDP",value:function(e){return!e&&this.sdp?this.sdp:(this.sdp=f.parse(this.body||""),this.sdp)}},{key:"toString",value:function(){return this.data}}]),e}(),E=function(e){i(n,S);var t=o(n);function n(e){var r;return c(this,n),(r=t.call(this)).ua=e,r.headers={},r.ruri=null,r.transport=null,r.server_transaction=null,r}return d(n,[{key:"reply",value:function(e,t,n,r,i,s){var o=[],l=this.getHeader("To");if(t=t||null,!(e=e||null)||e<100||e>699)throw new TypeError("Invalid status_code: ".concat(e));if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: ".concat(t));t=t||p.REASON_PHRASE[e]||"",n=m.cloneArray(n),this.ua.configuration.extra_headers&&(n=n.concat(this.ua.configuration.extra_headers));var u="SIP/2.0 ".concat(e," ").concat(t,"\r\n");if(this.method===p.INVITE&&e>100&&e<=200){var c,h=a(this.getHeaders("record-route"));try{for(h.s();!(c=h.n()).done;){var d=c.value;u+="Record-Route: ".concat(d,"\r\n")}}catch(e){h.e(e)}finally{h.f()}}var f,_=a(this.getHeaders("via"));try{for(_.s();!(f=_.n()).done;){var v=f.value;u+="Via: ".concat(v,"\r\n")}}catch(e){_.e(e)}finally{_.f()}!this.to_tag&&e>100?l+=";tag=".concat(m.newTag()):this.to_tag&&!this.s("to").hasParam("tag")&&(l+=";tag=".concat(this.to_tag)),u+="To: ".concat(l,"\r\n"),u+="From: ".concat(this.getHeader("From"),"\r\n"),u+="Call-ID: ".concat(this.call_id,"\r\n"),u+="CSeq: ".concat(this.cseq," ").concat(this.method,"\r\n");var g,y=a(n);try{for(y.s();!(g=y.n()).done;){var T=g.value;u+="".concat(T.trim(),"\r\n")}}catch(e){y.e(e)}finally{y.f()}switch(this.method){case p.INVITE:this.ua.configuration.session_timers&&o.push("timer"),(this.ua.contact.pub_gruu||this.ua.contact.temp_gruu)&&o.push("gruu"),o.push("ice","replaces");break;case p.UPDATE:this.ua.configuration.session_timers&&o.push("timer"),r&&o.push("ice"),o.push("replaces")}if(o.push("outbound"),this.method===p.OPTIONS?(u+="Allow: ".concat(p.ALLOWED_METHODS,"\r\n"),u+="Accept: ".concat(p.ACCEPTED_BODY_TYPES,"\r\n")):405===e?u+="Allow: ".concat(p.ALLOWED_METHODS,"\r\n"):415===e&&(u+="Accept: ".concat(p.ACCEPTED_BODY_TYPES,"\r\n")),u+="Supported: ".concat(o,"\r\n"),r){var b=m.str_utf8_length(r);u+="Content-Type: application/sdp\r\n",u+="Content-Length: ".concat(b,"\r\n\r\n"),u+=r}else u+="Content-Length: ".concat(0,"\r\n\r\n");this.server_transaction.receiveResponse(e,u,i,s)}},{key:"reply_sl",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=this.getHeaders("via");if(!e||e<100||e>699)throw new TypeError("Invalid status_code: ".concat(e));if(t&&"string"!=typeof t&&!(t instanceof String))throw new TypeError("Invalid reason_phrase: ".concat(t));t=t||p.REASON_PHRASE[e]||"";var r,i="SIP/2.0 ".concat(e," ").concat(t,"\r\n"),s=a(n);try{for(s.s();!(r=s.n()).done;){var o=r.value;i+="Via: ".concat(o,"\r\n")}}catch(e){s.e(e)}finally{s.f()}var l=this.getHeader("To");if(!this.to_tag&&e>100?l+=";tag=".concat(m.newTag()):this.to_tag&&!this.s("to").hasParam("tag")&&(l+=";tag=".concat(this.to_tag)),i+="To: ".concat(l,"\r\n"),i+="From: ".concat(this.getHeader("From"),"\r\n"),i+="Call-ID: ".concat(this.call_id,"\r\n"),i+="CSeq: ".concat(this.cseq," ").concat(this.method,"\r\n"),this.ua.configuration.extra_headers){var u,c=a(this.ua.configuration.extra_headers);try{for(c.s();!(u=c.n()).done;){var h=u.value;i+="".concat(h.trim(),"\r\n")}}catch(e){c.e(e)}finally{c.f()}}i+="Content-Length: ".concat(0,"\r\n\r\n"),this.transport.send(i)}}]),n}(),C=function(e){i(n,S);var t=o(n);function n(){var e;return c(this,n),(e=t.call(this)).headers={},e.status_code=null,e.reason_phrase=null,e}return d(n)}();t.exports={OutgoingRequest:T,InitialOutgoingInviteRequest:b,IncomingRequest:E,IncomingResponse:C}},{"./Constants":2,"./Grammar":7,"./Logger":9,"./NameAddrHeader":11,"./Utils":30,"sdp-transform":39}],23:[function(e,t,n){"use strict";var r=e("./Logger"),i=e("./Utils"),s=e("./Grammar"),o=new r("Socket");n.isSocket=function(e){if(Array.isArray(e))return!1;if(void 0===e)return o.warn("undefined JsSIP.Socket instance"),!1;try{if(!i.isString(e.url))throw o.warn("missing or invalid JsSIP.Socket url property"),new Error("Missing or invalid JsSIP.Socket url property");if(!i.isString(e.via_transport))throw o.warn("missing or invalid JsSIP.Socket via_transport property"),new Error("Missing or invalid JsSIP.Socket via_transport property");if(-1===s.parse(e.sip_uri,"SIP_URI"))throw o.warn("missing or invalid JsSIP.Socket sip_uri property"),new Error("missing or invalid JsSIP.Socket sip_uri property")}catch(e){return!1}try{["connect","disconnect","send"].forEach(function(t){if(!i.isFunction(e[t]))throw o.warn("missing or invalid JsSIP.Socket method: ".concat(t)),new Error("Missing or invalid JsSIP.Socket method: ".concat(t))})}catch(e){return!1}return!0}},{"./Grammar":7,"./Logger":9,"./Utils":30}],24:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return s(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n2e3&&(g.debug("update sending re-SUBSCRIBE time"),this._scheduleSubscribe(l))}o!==y.STATE_PENDING&&s===y.STATE_PENDING?(g.debug('emit "pending"'),this.emit("pending")):o!==y.STATE_ACTIVE&&s===y.STATE_ACTIVE&&(g.debug('emit "active"'),this.emit("active"));var u=e.body,c=s===y.STATE_TERMINATED;if(u){var h=e.getHeader("content-type");g.debug('emit "notify"'),this.emit("notify",c,e,u,h)}if(c){var f=i.reason,_=void 0;i.params&&void 0!==i.params["retry-after"]&&(_=parseInt(i.params["retry-after"])),this._dialogTerminated(y.RECEIVE_FINAL_NOTIFY,f,_)}}},{key:"subscribe",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;g.debug("subscribe()"),this._state===y.STATE_INIT?this._sendInitialSubscribe(e,this._headers):this._sendSubsequentSubscribe(e,this._headers)}},{key:"terminate",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(g.debug("terminate()"),!this._terminated){this._terminated=!0;var n=this._headers.map(function(e){return e.startsWith("Expires")?"Expires: 0":e});this._state===y.STATE_INIT?this._sendInitialSubscribe(t,n):this._sendSubsequentSubscribe(t,n);this._unsubscribe_timeout_timer=setTimeout(function(){e._dialogTerminated(y.UNSUBSCRIBE_TIMEOUT)},3e4)}}},{key:"state",get:function(){return this._state}},{key:"id",get:function(){return this._dialog?this._dialog.id:null}},{key:"_sendInitialSubscribe",value:function(e,t){var n=this;if(e){if(!this._content_type)throw new TypeError("content_type is undefined");(t=t.slice()).push("Content-Type: ".concat(this._content_type))}this._state=y.STATE_NOTIFY_WAIT;var r=new p.OutgoingRequest(d.SUBSCRIBE,this._ua.normalizeTarget(this._target),this._ua,this._params,t,e);new m(this._ua,r,{onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},onReceiveResponse:function(e){n._receiveSubscribeResponse(e)}}).send()}},{key:"_receiveSubscribeResponse",value:function(e){if(e.status_code>=200&&e.status_code<300){if(null===this._dialog){var t=new v(this,e,"UAC");if(t.error)return g.warn(t.error),void this._dialogTerminated(y.SUBSCRIBE_BAD_OK_RESPONSE);this._dialog=t,g.debug('emit "accepted"'),this.emit("accepted");var n,r=i(this._queue);try{for(r.s();!(n=r.n()).done;){var s=n.value;g.debug("dequeue subscribe"),this._sendSubsequentSubscribe(s.body,s.headers)}}catch(e){r.e(e)}finally{r.f()}}var o=e.getHeader("expires");0===o||o||(g.warn("response without Expires header"),o="900");var l=parseInt(o);l>0&&this._scheduleSubscribe(l)}else 401===e.status_code||407===e.status_code?this._dialogTerminated(y.SUBSCRIBE_FAILED_AUTHENTICATION):e.status_code>=300&&this._dialogTerminated(y.SUBSCRIBE_NON_OK_RESPONSE)}},{key:"_sendSubsequentSubscribe",value:function(e,t){var n=this;if(this._state!==y.STATE_TERMINATED){if(!this._dialog)return g.debug("enqueue subscribe"),void this._queue.push({body:e,headers:t.slice()});if(e){if(!this._content_type)throw new TypeError("content_type is undefined");(t=t.slice()).push("Content-Type: ".concat(this._content_type))}this._dialog.sendRequest(d.SUBSCRIBE,{body:e,extraHeaders:t,eventHandlers:{onRequestTimeout:function(){n.onRequestTimeout()},onTransportError:function(){n.onTransportError()},onSuccessResponse:function(e){n._receiveSubscribeResponse(e)},onErrorResponse:function(e){n._receiveSubscribeResponse(e)},onDialogError:function(e){n._receiveSubscribeResponse(e)}}})}}},{key:"_dialogTerminated",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:void 0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0;this._state!==y.STATE_TERMINATED&&(this._state=y.STATE_TERMINATED,clearTimeout(this._expires_timer),clearTimeout(this._unsubscribe_timeout_timer),this._dialog&&(this._dialog.terminate(),this._dialog=null),g.debug('emit "terminated" code='.concat(e)),this.emit("terminated",e,t,n))}},{key:"_scheduleSubscribe",value:function(e){var t=this,n=e>=140?1e3*e/2+Math.floor(1e3*(e/2-70)*Math.random()):1e3*e-5e3;this._expires_timestamp=(new Date).getTime()+1e3*e,g.debug("next SUBSCRIBE will be sent in ".concat(Math.floor(n/1e3)," sec")),clearTimeout(this._expires_timer),this._expires_timer=setTimeout(function(){t._expires_timer=null,t._sendSubsequentSubscribe(null,t._headers)},n)}},{key:"_stateStringToNumber",value:function(e){switch(e){case"pending":return y.STATE_PENDING;case"active":return y.STATE_ACTIVE;case"terminated":return y.STATE_TERMINATED;case"init":return y.STATE_INIT;case"notify_wait":return y.STATE_NOTIFY_WAIT;default:throw new TypeError("wrong state value")}}}])&&o(t.prototype,n),r&&o(t,r),Object.defineProperty(t,"prototype",{writable:!1}),u}()},{"./Constants":2,"./Dialog":3,"./Grammar":7,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,events:33}],25:[function(e,t,n){"use strict";var r=500;t.exports={T1:r,T2:4e3,T4:5e3,TIMER_B:32e3,TIMER_D:0,TIMER_F:32e3,TIMER_H:32e3,TIMER_I:0,TIMER_J:0,TIMER_K:0,TIMER_L:32e3,TIMER_M:32e3,PROVISIONAL_RESPONSE_INTERVAL:6e4}},{}],26:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){for(var n=0;n=100&&n<=199)switch(this.state){case S.STATUS_CALLING:this.stateChanged(S.STATUS_PROCEEDING),this.eventHandlers.onReceiveResponse(e);break;case S.STATUS_PROCEEDING:this.eventHandlers.onReceiveResponse(e)}else if(n>=200&&n<=299)switch(this.state){case S.STATUS_CALLING:case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_ACCEPTED),this.M=setTimeout(function(){t.timer_M()},m.TIMER_M),this.eventHandlers.onReceiveResponse(e);break;case S.STATUS_ACCEPTED:this.eventHandlers.onReceiveResponse(e)}else if(n>=300&&n<=699)switch(this.state){case S.STATUS_CALLING:case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_COMPLETED),this.sendACK(e),this.eventHandlers.onReceiveResponse(e);break;case S.STATUS_COMPLETED:this.sendACK(e)}}}]),n}(),A=function(e){l(n,d);var t=u(n);function n(e,r,s,o){var l;i(this,n),(l=t.call(this)).id="z9hG4bK".concat(Math.floor(1e7*Math.random())),l.transport=r,l.request=s,l.eventHandlers=o;var a="SIP/2.0/".concat(r.via_transport);return a+=" ".concat(e.configuration.via_host,";branch=").concat(l.id),l.request.setHeader("via",a),l}return o(n,[{key:"C",get:function(){return S}},{key:"send",value:function(){this.transport.send(this.request)||this.onTransportError()}},{key:"onTransportError",value:function(){y.debug("transport error occurred for transaction ".concat(this.id)),this.eventHandlers.onTransportError()}}]),n}(),w=function(e){l(n,d);var t=u(n);function n(e,r,s){var o;return i(this,n),(o=t.call(this)).type=S.NON_INVITE_SERVER,o.id=s.via_branch,o.ua=e,o.transport=r,o.request=s,o.last_response="",s.server_transaction=c(o),o.state=S.STATUS_TRYING,e.newTransaction(c(o)),o}return o(n,[{key:"C",get:function(){return S}},{key:"stateChanged",value:function(e){this.state=e,this.emit("stateChanged")}},{key:"timer_J",value:function(){T.debug("Timer J expired for transaction ".concat(this.id)),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"onTransportError",value:function(){this.transportError||(this.transportError=!0,T.debug("transport error occurred, deleting transaction ".concat(this.id)),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"receiveResponse",value:function(e,t,n,r){if(100===e)switch(this.state){case S.STATUS_TRYING:this.stateChanged(S.STATUS_PROCEEDING),this.transport.send(t)||this.onTransportError();break;case S.STATUS_PROCEEDING:this.last_response=t,this.transport.send(t)?n&&n():(this.onTransportError(),r&&r())}else if(e>=200&&e<=699)switch(this.state){case S.STATUS_TRYING:case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_COMPLETED),this.last_response=t,this.timer_J(),this.transport.send(t)?n&&n():(this.onTransportError(),r&&r());break;case S.STATUS_COMPLETED:}}}]),n}(),R=function(e){l(n,d);var t=u(n);function n(e,r,s){var o;return i(this,n),(o=t.call(this)).type=S.INVITE_SERVER,o.id=s.via_branch,o.ua=e,o.transport=r,o.request=s,o.last_response="",s.server_transaction=c(o),o.state=S.STATUS_PROCEEDING,e.newTransaction(c(o)),o.resendProvisionalTimer=null,s.reply(100),o}return o(n,[{key:"C",get:function(){return S}},{key:"stateChanged",value:function(e){this.state=e,this.emit("stateChanged")}},{key:"timer_H",value:function(){b.debug("Timer H expired for transaction ".concat(this.id)),this.state===S.STATUS_COMPLETED&&b.debug("ACK not received, dialog will be terminated"),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"timer_I",value:function(){this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this)}},{key:"timer_L",value:function(){b.debug("Timer L expired for transaction ".concat(this.id)),this.state===S.STATUS_ACCEPTED&&(this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"onTransportError",value:function(){this.transportError||(this.transportError=!0,b.debug("transport error occurred, deleting transaction ".concat(this.id)),null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),clearTimeout(this.L),clearTimeout(this.H),this.stateChanged(S.STATUS_TERMINATED),this.ua.destroyTransaction(this))}},{key:"resend_provisional",value:function(){this.transport.send(this.last_response)||this.onTransportError()}},{key:"receiveResponse",value:function(e,t,n,r){var i=this;if(e>=100&&e<=199)switch(this.state){case S.STATUS_PROCEEDING:this.transport.send(t)||this.onTransportError(),this.last_response=t}if(e>100&&e<=199&&this.state===S.STATUS_PROCEEDING)null===this.resendProvisionalTimer&&(this.resendProvisionalTimer=setInterval(function(){i.resend_provisional()},m.PROVISIONAL_RESPONSE_INTERVAL));else if(e>=200&&e<=299)switch(this.state){case S.STATUS_PROCEEDING:this.stateChanged(S.STATUS_ACCEPTED),this.last_response=t,this.L=setTimeout(function(){i.timer_L()},m.TIMER_L),null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null);case S.STATUS_ACCEPTED:this.transport.send(t)?n&&n():(this.onTransportError(),r&&r())}else if(e>=300&&e<=699)switch(this.state){case S.STATUS_PROCEEDING:null!==this.resendProvisionalTimer&&(clearInterval(this.resendProvisionalTimer),this.resendProvisionalTimer=null),this.transport.send(t)?(this.stateChanged(S.STATUS_COMPLETED),this.H=setTimeout(function(){i.timer_H()},m.TIMER_H),n&&n()):(this.onTransportError(),r&&r())}}}]),n}();t.exports={C:S,NonInviteClientTransaction:E,InviteClientTransaction:C,AckClientTransaction:A,NonInviteServerTransaction:w,InviteServerTransaction:R,checkTransaction:function(e,t){var n,r=e._transactions;switch(t.method){case _.INVITE:if(n=r.ist[t.via_branch]){switch(n.state){case S.STATUS_PROCEEDING:n.transport.send(n.last_response);break;case S.STATUS_ACCEPTED:}return!0}break;case _.ACK:if(!(n=r.ist[t.via_branch]))return!1;if(n.state===S.STATUS_ACCEPTED)return!1;if(n.state===S.STATUS_COMPLETED)return n.state=S.STATUS_CONFIRMED,n.timer_I(),!0;break;case _.CANCEL:return(n=r.ist[t.via_branch])?(t.reply_sl(200),n.state!==S.STATUS_PROCEEDING):(t.reply_sl(481),!0);default:if(n=r.nist[t.via_branch]){switch(n.state){case S.STATUS_TRYING:break;case S.STATUS_PROCEEDING:case S.STATUS_COMPLETED:n.transport.send(n.last_response)}return!0}}}}},{"./Constants":2,"./Logger":9,"./SIPMessage":22,"./Timers":25,events:33}],27:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,s=function(){};return{s:s,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n2&&void 0!==arguments[2]?arguments[2]:c.recovery_options;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),u.debug("new()"),this._ua=t,this.status=c.STATUS_DISCONNECTED,this.socket=null,this.sockets=[],this.recovery_options=r,this.recover_attempts=0,this.recovery_timer=null,this.close_requested=!1;try{this.textDecoder=new TextDecoder("utf8")}catch(e){u.warn("cannot use TextDecoder: ".concat(e))}if(void 0===n)throw new TypeError("Invalid argument. undefined 'sockets' argument");n instanceof Array||(n=[n]),n.forEach(function(e){if(!l.isSocket(e.socket))throw new TypeError("Invalid argument. invalid 'JsSIP.Socket' instance");if(e.weight&&!Number(e.weight))throw new TypeError("Invalid argument. 'weight' attribute is not a number");this.sockets.push({socket:e.socket,weight:e.weight||0,status:c.SOCKET_STATUS_READY})},this),this._getSocket()}var t,n,i;return t=e,(n=[{key:"via_transport",get:function(){return this.socket.via_transport}},{key:"url",get:function(){return this.socket.url}},{key:"sip_uri",get:function(){return this.socket.sip_uri}},{key:"connect",value:function(){u.debug("connect()"),this.isConnected()?u.debug("Transport is already connected"):this.isConnecting()?u.debug("Transport is connecting"):(this.close_requested=!1,this.status=c.STATUS_CONNECTING,this.onconnecting({socket:this.socket,attempts:this.recover_attempts}),this.close_requested||(this.socket.onconnect=this._onConnect.bind(this),this.socket.ondisconnect=this._onDisconnect.bind(this),this.socket.ondata=this._onData.bind(this),this.socket.connect()))}},{key:"disconnect",value:function(){u.debug("close()"),this.close_requested=!0,this.recover_attempts=0,this.status=c.STATUS_DISCONNECTED,null!==this.recovery_timer&&(clearTimeout(this.recovery_timer),this.recovery_timer=null),this.socket.onconnect=function(){},this.socket.ondisconnect=function(){},this.socket.ondata=function(){},this.socket.disconnect(),this.ondisconnect({socket:this.socket,error:!1})}},{key:"send",value:function(e){if(u.debug("send()"),!this.isConnected())return u.warn("unable to send message, transport is not connected"),!1;var t=e.toString();return u.debug("sending message:\n\n".concat(t,"\n")),this.socket.send(t)}},{key:"isConnected",value:function(){return this.status===c.STATUS_CONNECTED}},{key:"isConnecting",value:function(){return this.status===c.STATUS_CONNECTING}},{key:"_get_number_of_sbc",value:function(){return this.sockets.length}},{key:"_switch_sbc",value:function(){var e=this.ondisconnect;this.ondisconnect=function(){},this.disconnect(),this.ondisconnect=e,this.close_requested=!1,this.sockets.forEach(function(e){this.socket===e.socket&&(e.status=c.SOCKET_STATUS_ERROR)},this),this._getSocket(),this.connect()}},{key:"_register_redirect",value:function(e){var t,n=null,i=r(this.sockets);try{for(i.s();!(t=i.n()).done;){var s=t.value;if(s.socket.url===e){n=s.socket;break}}}catch(e){i.e(e)}finally{i.f()}if(null===n&&!e.includes(":",6)){e+=":443";var o,l=r(this.sockets);try{for(l.s();!(o=l.n()).done;){var a=o.value;if(a.socket.url===e){n=a.socket;break}}}catch(e){l.e(e)}finally{l.f()}}if(null===n)return!1;var u=this.ondisconnect;return this.ondisconnect=function(){},this.disconnect(),this.ondisconnect=u,this.socket=n,this.connect(),!0}},{key:"_reconnect",value:function(){var e=this;this.recover_attempts+=1;var t=Math.floor(Math.random()*Math.pow(2,this.recover_attempts)+1);tthis.recovery_options.max_interval&&(t=this.recovery_options.max_interval),u.debug("reconnection attempt: ".concat(this.recover_attempts,". next connection attempt in ").concat(t," seconds")),this.recovery_timer=setTimeout(function(){e.close_requested||e.isConnected()||e.isConnecting()||(e._getSocket(),e.connect())},1e3*t)}},{key:"_getSocket",value:function(){var e=[];if(this.sockets.forEach(function(t){t.status!==c.SOCKET_STATUS_ERROR&&(0===e.length?e.push(t):t.weight>e[0].weight?e=[t]:t.weight===e[0].weight&&e.push(t))}),0===e.length)return this.sockets.forEach(function(e){e.status=c.SOCKET_STATUS_READY}),void this._getSocket();var t=Math.floor(Math.random()*e.length);this.socket=e[t].socket}},{key:"_onConnect",value:function(){this.recover_attempts=0,this._ha_connect_time=void 0,this.status=c.STATUS_CONNECTED,null!==this.recovery_timer&&(clearTimeout(this.recovery_timer),this.recovery_timer=null),this.onconnect({socket:this})}},{key:"_onDisconnect",value:function(e,t,n){var r=this.status;if(this.status=c.STATUS_DISCONNECTED,this.ondisconnect({socket:this.socket,error:e,code:t,reason:n}),!this.close_requested){if(void 0!==this._ua.modes.sbc_ha_pairs_mode){if(r===c.STATUS_CONNECTED)return u.debug("AC: SBC HA pairs mode: Reconnect to the same SBC ".concat(this._ua.modes.sbc_ha_pairs_mode," seconds left")),this._ha_connect_time=(new Date).getTime()+1e3*this._ua.modes.sbc_ha_pairs_mode,void this._connect2();if(void 0!==this._ha_connect_time){var i=this._ha_connect_time-(new Date).getTime();if(i>0)return u.debug("AC: SBC HA pairs mode: Repeat ".concat(i/1e3," seconds left")),void this._connect2();u.debug("AC: SBC HA pairs mode: Failed"),this._ha_connect_time=void 0}}this.sockets.forEach(function(e){this.socket===e.socket&&(e.status=c.SOCKET_STATUS_ERROR)},this),this._reconnect()}}},{key:"_connect2",value:function(){var e=this,t=0;if(this._ha_last_connect){var n=(new Date).getTime()-this._ha_last_connect;t=n>500?0:500-n}this.recovery_timer=setTimeout(function(){e.close_requested||e.isConnected()||e.isConnecting()||(e._ha_last_connect=(new Date).getTime(),e.connect())},t)}},{key:"_onData",value:function(e){if("\r\n"!==e){if("string"!=typeof e){try{e=this.textDecoder?this.textDecoder.decode(e):String.fromCharCode.apply(null,new Uint8Array(e))}catch(e){return void u.debug("received binary message failed to be converted into string, message discarded")}u.debug("received binary message:\n\n".concat(e,"\n"))}else u.debug("received text message:\n\n".concat(e,"\n"));this.ondata({transport:this,message:e})}else u.debug("received message with CRLF Keep Alive response")}}])&&s(t.prototype,n),i&&s(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Logger":9,"./Socket":23}],28:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{},t=e.anonymous||null,n=e.outbound||null,r="<";return r+=t?this.temp_gruu||"sip:anonymous@anonymous.invalid;transport=ws":this.pub_gruu||this.uri.toString(),!n||(t?this.temp_gruu:this.pub_gruu)||(r+=";ob"),r+=">"}};var r=["authorization_user","password","realm","ha1","authorization_jwt","display_name","register"];for(var i in this._configuration)Object.prototype.hasOwnProperty.call(this._configuration,i)&&(-1!==r.indexOf(i)?Object.defineProperty(this._configuration,i,{writable:!0,configurable:!1}):Object.defineProperty(this._configuration,i,{writable:!1,configurable:!1}));for(var s in R.debug("configuration parameters after validation:"),this._configuration)if(Object.prototype.hasOwnProperty.call(w.settings,s))switch(s){case"uri":case"registrar_server":R.debug("- ".concat(s,": ").concat(this._configuration[s]));break;case"password":case"ha1":case"authorization_jwt":R.debug("- ".concat(s,": NOT SHOWN"));break;default:R.debug("- ".concat(s,": ").concat(JSON.stringify(this._configuration[s])))}}}])&&i(t.prototype,n),r&&i(t,r),Object.defineProperty(t,"prototype",{writable:!1}),c}()},{"./Config":1,"./Constants":2,"./Exceptions":6,"./Logger":9,"./Message":10,"./Notifier":12,"./Options":13,"./Parser":14,"./RTCSession":15,"./Registrator":20,"./SIPMessage":22,"./Subscriber":24,"./Transactions":26,"./Transport":27,"./URI":29,"./Utils":30,"./sanityCheck":32,events:33}],29:[function(e,t,n){"use strict";function r(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,s=function(){};return{s:s,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n4&&void 0!==arguments[4]?arguments[4]:{},l=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{};if(function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),!r)throw new TypeError('missing or invalid "host" parameter');for(var a in this._parameters={},this._headers={},this._scheme=t||o.SIP,this._user=n,this._host=r,this._port=i,s)Object.prototype.hasOwnProperty.call(s,a)&&this.setParam(a,s[a]);for(var u in l)Object.prototype.hasOwnProperty.call(l,u)&&this.setHeader(u,l[u])}var t,n,i;return t=e,i=[{key:"parse",value:function(e){return-1!==(e=a.parse(e,"SIP_URI"))?e:void 0}}],(n=[{key:"scheme",get:function(){return this._scheme},set:function(e){this._scheme=e.toLowerCase()}},{key:"user",get:function(){return this._user},set:function(e){this._user=e}},{key:"host",get:function(){return this._host},set:function(e){this._host=e.toLowerCase()}},{key:"port",get:function(){return this._port},set:function(e){this._port=0===e?e:parseInt(e,10)||null}},{key:"setParam",value:function(e,t){e&&(this._parameters[e.toLowerCase()]=null==t?null:t.toString())}},{key:"getParam",value:function(e){if(e)return this._parameters[e.toLowerCase()]}},{key:"hasParam",value:function(e){if(e)return!!this._parameters.hasOwnProperty(e.toLowerCase())}},{key:"deleteParam",value:function(e){if(e=e.toLowerCase(),this._parameters.hasOwnProperty(e)){var t=this._parameters[e];return delete this._parameters[e],t}}},{key:"clearParams",value:function(){this._parameters={}}},{key:"setHeader",value:function(e,t){this._headers[l.headerize(e)]=Array.isArray(t)?t:[t]}},{key:"getHeader",value:function(e){if(e)return this._headers[l.headerize(e)]}},{key:"hasHeader",value:function(e){if(e)return!!this._headers.hasOwnProperty(l.headerize(e))}},{key:"deleteHeader",value:function(e){if(e=l.headerize(e),this._headers.hasOwnProperty(e)){var t=this._headers[e];return delete this._headers[e],t}}},{key:"clearHeaders",value:function(){this._headers={}}},{key:"clone",value:function(){return new e(this._scheme,this._user,this._host,this._port,JSON.parse(JSON.stringify(this._parameters)),JSON.parse(JSON.stringify(this._headers)))}},{key:"toString",value:function(){var e=[],t="".concat(this._scheme,":");for(var n in this._user&&(t+="".concat(l.escapeUser(this._user),"@")),t+=this._host,(this._port||0===this._port)&&(t+=":".concat(this._port)),this._parameters)Object.prototype.hasOwnProperty.call(this._parameters,n)&&(t+=";".concat(n),null!==this._parameters[n]&&(t+="=".concat(this._parameters[n])));for(var i in this._headers)if(Object.prototype.hasOwnProperty.call(this._headers,i)){var s,o=r(this._headers[i]);try{for(o.s();!(s=o.n()).done;){var a=s.value;e.push("".concat(i,"=").concat(a))}}catch(e){o.e(e)}finally{o.f()}}return e.length>0&&(t+="?".concat(e.join("&"))),t}},{key:"toAor",value:function(e){var t="".concat(this._scheme,":");return this._user&&(t+="".concat(l.escapeUser(this._user),"@")),t+=this._host,e&&(this._port||0===this._port)&&(t+=":".concat(this._port)),t}}])&&s(t.prototype,n),i&&s(t,i),Object.defineProperty(t,"prototype",{writable:!1}),e}()},{"./Constants":2,"./Grammar":7,"./Utils":30}],30:[function(e,t,n){"use strict";function r(e){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return s(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:32,r="";for(t=0;t>>32-t}function n(e,t){var n=2147483648&e,r=2147483648&t,i=1073741824&e,s=1073741824&t,o=(1073741823&e)+(1073741823&t);return i&s?2147483648^o^n^r:i|s?1073741824&o?3221225472^o^n^r:1073741824^o^n^r:o^n^r}function r(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return e&t|~e&n}(r,i,s),o),a)),n(t(e,l),r)}function i(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return e&n|t&~n}(r,i,s),o),a)),n(t(e,l),r)}function s(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return e^t^n}(r,i,s),o),a)),n(t(e,l),r)}function o(e,r,i,s,o,l,a){return e=n(e,n(n(function(e,t,n){return t^(e|~n)}(r,i,s),o),a)),n(t(e,l),r)}function l(e){var t,n="",r="";for(t=0;t<=3;t++)n+=(r="0".concat((e>>>8*t&255).toString(16))).substr(r.length-2,2);return n}var a,u,c,h,d,f,_,p,m,v;for(a=function(e){for(var t,n=e.length,r=n+8,i=16*((r-r%64)/64+1),s=new Array(i-1),o=0,l=0;l>>29,s}(e=function(e){for(var t="",n=0;n127&&r<2048?(t+=String.fromCharCode(r>>6|192),t+=String.fromCharCode(63&r|128)):(t+=String.fromCharCode(r>>12|224),t+=String.fromCharCode(r>>6&63|128),t+=String.fromCharCode(63&r|128))}return t}(e)),_=1732584193,p=4023233417,m=2562383102,v=271733878,u=0;u1&&void 0!==arguments[1]?arguments[1]:{};return e&&Object.assign({},e)||t}},{"./Constants":2,"./Grammar":7,"./URI":29}],31:[function(e,t,n){"use strict";function r(e,t){for(var n=0;n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,l=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){a=!0,o=e},f:function(){try{l||null==n.return||n.return()}finally{if(a)throw o}}}}function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1)return d.debug("more than one Via header field present in the response, dropping the response"),!1},function(){var e=h.str_utf8_length(s.body),t=s.getHeader("content-length");if(e0&&l.length>s){l.warned=!0;var a=new Error("Possible EventEmitter memory leak detected. "+l.length+' "'+String(t)+'" listeners added. Use emitter.setMaxListeners() to increase limit.');a.name="MaxListenersExceededWarning",a.emitter=e,a.type=t,a.count=l.length,"object"==typeof console&&console.warn&&console.warn("%s: %s",a.name,a.message)}}else l=o[t]=n,++e._eventsCount;return e}function d(){if(!this.fired)switch(this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length){case 0:return this.listener.call(this.target);case 1:return this.listener.call(this.target,arguments[0]);case 2:return this.listener.call(this.target,arguments[0],arguments[1]);case 3:return this.listener.call(this.target,arguments[0],arguments[1],arguments[2]);default:for(var e=new Array(arguments.length),t=0;t1&&(t=arguments[1]),t instanceof Error)throw t;var a=new Error('Unhandled "error" event. ('+t+")");throw a.context=t,a}if(!(n=o[e]))return!1;var u="function"==typeof n;switch(r=arguments.length){case 1:!function(e,t,n){if(t)e.call(n);else for(var r=e.length,i=m(e,r),s=0;s=0;o--)if(n[o]===t||n[o].listener===t){l=n[o].listener,s=o;break}if(s<0)return this;0===s?n.shift():function(e,t){for(var n=t,r=n+1,i=e.length;r=0;s--)this.removeListener(e,t[s]);return this},o.prototype.listeners=function(e){return _(this,e,!0)},o.prototype.rawListeners=function(e){return _(this,e,!1)},o.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):p.call(e,t)},o.prototype.listenerCount=p,o.prototype.eventNames=function(){return this._eventsCount>0?Reflect.ownKeys(this._events):[]}},{}],34:[function(e,t,n){(function(r){(function(){n.formatArgs=function(e){if(e[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+e[0]+(this.useColors?"%c ":" ")+"+"+t.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;e.splice(1,0,n,"color: inherit");let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,e=>{"%%"!==e&&(r++,"%c"===e&&(i=r))}),e.splice(i,0,n)},n.save=function(e){try{e?n.storage.setItem("debug",e):n.storage.removeItem("debug")}catch(e){}},n.load=function(){let e;try{e=n.storage.getItem("debug")}catch(e){}!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG);return e},n.useColors=function(){if("undefined"!=typeof window&&window.process&&("renderer"===window.process.type||window.process.__nwjs))return!0;if("undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;return"undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},n.storage=function(){try{return localStorage}catch(e){}}(),n.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),n.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],n.log=console.debug||console.log||(()=>{}),t.exports=e("./common")(n);const{formatters:i}=t.exports;i.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}}).call(this)}).call(this,e("_process"))},{"./common":35,_process:37}],35:[function(e,t,n){t.exports=function(t){function n(e){let t,i,s,o=null;function l(...e){if(!l.enabled)return;const r=l,i=Number(new Date),s=i-(t||i);r.diff=s,r.prev=t,r.curr=i,t=i,e[0]=n.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let o=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(t,i)=>{if("%%"===t)return"%";o++;const s=n.formatters[i];if("function"==typeof s){const n=e[o];t=s.call(r,n),e.splice(o,1),o--}return t}),n.formatArgs.call(r,e),(r.log||n.log).apply(r,e)}return l.namespace=e,l.useColors=n.useColors(),l.color=n.selectColor(e),l.extend=r,l.destroy=n.destroy,Object.defineProperty(l,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==o?o:(i!==n.namespaces&&(i=n.namespaces,s=n.enabled(e)),s),set:e=>{o=e}}),"function"==typeof n.init&&n.init(l),l}function r(e,t){const r=n(this.namespace+(void 0===t?":":t)+e);return r.log=this.log,r}function i(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return n.debug=n,n.default=n,n.coerce=function(e){return e instanceof Error?e.stack||e.message:e},n.disable=function(){const e=[...n.names.map(i),...n.skips.map(i).map(e=>"-"+e)].join(",");return n.enable(""),e},n.enable=function(e){let t;n.save(e),n.namespaces=e,n.names=[],n.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),i=r.length;for(t=0;t{n[e]=t[e]}),n.names=[],n.skips=[],n.formatters={},n.selectColor=function(e){let t=0;for(let n=0;n=1.5*n;return Math.round(e/n)+" "+r+(i?"s":"")}t.exports=function(e,t){t=t||{};var n=typeof e;if("string"===n&&e.length>0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var n=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return n*a;case"weeks":case"week":case"w":return n*l;case"days":case"day":case"d":return n*o;case"hours":case"hour":case"hrs":case"hr":case"h":return n*s;case"minutes":case"minute":case"mins":case"min":case"m":return n*i;case"seconds":case"second":case"secs":case"sec":case"s":return n*r;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}(e);if("number"===n&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=o)return u(e,t,o,"day");if(t>=s)return u(e,t,s,"hour");if(t>=i)return u(e,t,i,"minute");if(t>=r)return u(e,t,r,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=o)return Math.round(e/o)+"d";if(t>=s)return Math.round(e/s)+"h";if(t>=i)return Math.round(e/i)+"m";if(t>=r)return Math.round(e/r)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],37:[function(e,t,n){var r,i,s=t.exports={};function o(){throw new Error("setTimeout has not been defined")}function l(){throw new Error("clearTimeout has not been defined")}function a(e){if(r===setTimeout)return setTimeout(e,0);if((r===o||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch(t){try{return r.call(null,e,0)}catch(t){return r.call(this,e,0)}}}!function(){try{r="function"==typeof setTimeout?setTimeout:o}catch(e){r=o}try{i="function"==typeof clearTimeout?clearTimeout:l}catch(e){i=l}}();var u,c=[],h=!1,d=-1;function f(){h&&u&&(h=!1,u.length?c=u.concat(c):d=-1,c.length&&_())}function _(){if(!h){var e=a(f);h=!0;for(var t=c.length;t;){for(u=c,c=[];++d1)for(var n=1;n1&&(e[n[0]]=void 0),e};n.parseParams=function(e){return e.split(/;\s?/).reduce(l,{})},n.parseFmtpConfig=n.parseParams,n.parsePayloads=function(e){return e.toString().split(" ").map(Number)},n.parseRemoteCandidates=function(e){for(var t=[],n=e.split(" ").map(r),i=0;i=r)return e;var i=n[t];switch(t+=1,e){case"%%":return"%";case"%s":return String(i);case"%d":return Number(i);case"%v":return""}})}.apply(null,r)},o=["v","o","s","i","u","e","p","c","b","t","r","z","a"],l=["i","c","b","a"];t.exports=function(e,t){t=t||{},null==e.version&&(e.version=0),null==e.name&&(e.name=" "),e.media.forEach(function(e){null==e.payloads&&(e.payloads="")});var n=t.outerOrder||o,i=t.innerOrder||l,a=[];return n.forEach(function(t){r[t].forEach(function(n){n.name in e&&null!=e[n.name]?a.push(s(t,n,e)):n.push in e&&null!=e[n.push]&&e[n.push].forEach(function(e){a.push(s(t,n,e))})})}),e.media.forEach(function(e){a.push(s("m",r.m[0],e)),i.forEach(function(t){r[t].forEach(function(n){n.name in e&&null!=e[n.name]?a.push(s(t,n,e)):n.push in e&&null!=e[n.push]&&e[n.push].forEach(function(e){a.push(s(t,n,e))})})})}),a.join("\r\n")+"\r\n"}},{"./grammar":38}],42:[function(e,t,n){t.exports={name:"jssip",title:"JsSIP",description:"the Javascript SIP library",version:"3.10.0",homepage:"https://jssip.net",contributors:["José Luis Millán (https://github.com/jmillan)","Iñaki Baz Castillo (https://inakibaz.me)"],types:"lib/JsSIP.d.ts",main:"lib-es5/JsSIP.js",keywords:["sip","websocket","webrtc","node","browser","library"],license:"MIT",repository:{type:"git",url:"https://github.com/versatica/JsSIP.git"},bugs:{url:"https://github.com/versatica/JsSIP/issues"},dependencies:{"@types/events":"^3.0.0","@types/debug":"^4.1.7",debug:"^4.3.1",events:"^3.3.0","sdp-transform":"^2.14.1"},devDependencies:{"@babel/core":"^7.19.6","@babel/preset-env":"^7.19.4","ansi-colors":"^3.2.4",browserify:"^16.5.1",eslint:"^5.16.0","fancy-log":"^1.3.3",gulp:"^4.0.2","gulp-babel":"^8.0.0","gulp-eslint":"^5.0.0","gulp-expect-file":"^1.0.2","gulp-header":"^2.0.9","gulp-nodeunit-runner":"^0.2.2","gulp-plumber":"^1.2.1","gulp-rename":"^1.4.0","gulp-uglify-es":"^1.0.4",pegjs:"^0.7.0","vinyl-buffer":"^1.0.1","vinyl-source-stream":"^2.0.0"},scripts:{lint:"node npm-scripts.js lint",test:"node npm-scripts.js test",prepublish:"node npm-scripts.js prepublish",release:"node npm-scripts.js release"}}},{}]},{},[8])(8)}); + +"use strict"; +/* + * AudioCodes WebRTC API v1.19.0 + * © 2023 AudioCodes Ltd. All rights reserved. + * + */class AudioCodesUA{constructor(){return this._isInitialized=!1,this.serverConfig={},this.account={user:null,userAuth:null,displayName:null,password:null,registerExpires:600,useSessionTimer:!1},this.constraints={audio:!0,video:!0},this.chromiumBased=[{n:"Edge",s:"edg/"},{n:"Opera",s:"opr/"},{n:"Samsung",s:"samsungbrowser/"},{n:"Yandex",s:"yabrowser/"}],this.modes={video_call_audio_answer_firefox_fix:!0,video_call_audio_answer_safari_fix:!0,ice_timeout_fix:2e3,chrome_rtp_timeout_fix:13,sbc_ha_pairs_mode:void 0,ringing_header_mode:void 0,sbc_switch_register5xx_mode:!0,cache_register_auth_mode:!0,check_remote_sdp_mode:!0},this.credentials=[],this.listeners={},this.registerExtraHeaders=null,this.jssipUA=null,this.browser="",this.browserVersion=0,this.browserName="",this.os="other",this.reconnectMin=2,this.reconnectMax=30,this.u17=void 0,this.activeCalls=0,this.wsPingStarted=!1,this.wsSocket=null,this.wsOnMessage=null,this.wsPingMs=0,this.wsOrigPingMs=0,this.wsThrottlingPingMs=0,this.wsVisibility=!1,this.wsCall=!1,this.wsLog=0,this.wsPongTimeout=!0,this.wsIsThrottling=!1,this.wsPingJob=null,this.wsPingTime=null,this.wsNextPingTime=null,this.wsPongReceived=!1,this.wsPongSupported=null,this.wsPongTimeoutTime=null,this.wsPongDelays=null,this.wsPongDelaysIx=0,this.wsPongReport=0,this.wsPongReportCounter=0,this.wsPongDist=!1,this.wsIsPingDebugLog=!1,this.dtmfUseWebRTC=!0,this.dtmfDuration=250,this.dtmfInterToneGap=250,this.enableAddVideo=!1,this.oauthToken=null,this.oauthTokenUseInInvite=!0,this.networkPriority=void 0,AudioCodesUA.ac_log=console.log,AudioCodesUA.js_log=null,void 0===AudioCodesUA.instance&&(AudioCodesUA.instance=this),this._detectBrowser(),this._detectOS(),this.webrtcapi=AudioCodesWebRTCWrapper,this.replacedCall=null,this.codecFilter=null,this.AUDIO=Symbol("audio"),this.VIDEO=Symbol("video"),this.RECVONLY_VIDEO=Symbol("recvonly_video"),AudioCodesUA.instance}version(){return"1.19.0"}getBrowserName(){return this.browserName}getBrowser(){return this.browser}getBrowserVersion(){return this.browserVersion}getOS(){return this.os}getWR(){return this.webrtcapi}checkAvailableDevices(){return this.getWR().checkAvailableDevices()}getServerAddress(){if(null===this.wsSocket)return null;let e=this.wsSocket.url;return e.endsWith("/")&&(e=e.slice(0,-1)),e}setOAuthToken(e,i=!0){this.oauthToken=e,this.oauthTokenUseInInvite=i,this.setRegisterExtraHeaders(this.registerExtraHeaders)}setUserAgent(e){this.u17=e}setConstraints(e,i,s){let t=this.browser,o=this.browser+"|"+this.os;if(null===e||e===t||e===o){if(AudioCodesUA.ac_log(`AC: setConstraints ${e} ${i} ${JSON.stringify(s)}`),"audio"!==i&&"video"!==i)throw new TypeError(`Wrong type: ${i}`);this.constraints[i]=s}else AudioCodesUA.ac_log(`AC: setConstraints ${e} - ignored, no current browser`)}setConstraint(e,i,s){if(null!==s&&void 0!==s?AudioCodesUA.ac_log(`AC: setConstraint ${e} ${i}=${JSON.stringify(s)}`):AudioCodesUA.ac_log(`AC: setConstraint remove ${e} ${i}`),"audio"!==e&&"video"!==e)throw new TypeError(`Wrong type: ${e}`);null!==s&&void 0!==s?(!0===this.constraints[e]&&(this.constraints[e]={}),this.constraints[e][i]=s):!0!==this.constraints[e]&&!1!==this.constraints[e]&&(delete this.constraints[e][i],0===Object.keys(this.constraints[e]).length&&(this.constraints[e]=!0))}setBrowsersConstraints(e){let i=this.browser,s=this.browser+"|"+this.os;for(let t in e){if(t!==i&&t!==s)continue;let o=e[t];void 0!==o.audio&&this.setConstraints(t,"audio",o.audio),void 0!==o.video&&this.setConstraints(t,"video",o.video)}}setCodecFilter(e){e&&(AudioCodesUA.ac_log(`AC: setCodecFilter ${JSON.stringify(e)}`),this.codecFilter=this._cf_unpack(e))}setServerConfig(e,i,s=[]){this.serverConfig={addresses:e,domain:i,iceServers:this._convertIceList(s)},AudioCodesUA.ac_log(`AC: setServerConfig() ${JSON.stringify(this.serverConfig)}`)}setReconnectIntervals(e,i){AudioCodesUA.ac_log(`AC: setReconnectIntervals min=${e} max=${i}`),this.reconnectMin=e,this.reconnectMax=i}setAccount(e,i,s,t){void 0!==i&&null!==i&&0!==i.length||(i=void 0),void 0!==t&&null!==t&&0!==t.length||(t=e);let o=this.account;o.user=e,o.displayName=i,o.password=s,o.authUser=t}setRegisterExpires(e){AudioCodesUA.ac_log(`AC: setRegisterExpires=${e}`),this.account.registerExpires=e}setUseSessionTimer(e){AudioCodesUA.ac_log(`AC: setUseSessionTimer=${e}`),this.account.useSessionTimer=e}setDtmfOptions(e,i=null,s=null){AudioCodesUA.ac_log(`AC: setDtmfOptions useWebRTC=${e} duration=${i} interToneGap=${s}`),this.dtmfUseWebRTC=e,null!==i&&(this.dtmfDuration=i),null!==s&&(this.dtmfInterToneGap=s)}setEnableAddVideo(e){AudioCodesUA.ac_log(`AC: setEnableAddVideo=${e}`),this.enableAddVideo=e}getEnableAddVideo(){return this.enableAddVideo}getAccount(){return this.account}setListeners(e){AudioCodesUA.ac_log("AC: setListeners()");for(let i of["loginStateChanged","outgoingCallProgress","callTerminated","callConfirmed","callShowStreams","incomingCall","callHoldStateChanged"])if(!(i in e))throw new Error(`${i} listener is missed`);this.listeners=e}static getSessionStatusName(e){switch(e){case 0:return"NULL (0)";case 1:return"INVITE_SENT (1)";case 2:return"1XX_RECEIVED (2)";case 3:return"INVITE_RECEIVED (3)";case 4:return"WAITING_FOR_ANSWER (4)";case 5:return"ANSWERED (5)";case 6:return"WAITING_FOR_ACK (6)";case 7:return"CANCELED (7)";case 8:return"TERMINATED (8)";case 9:return"CONFIRMED (9)";default:return"Unknown ("+e+")"}}setAcLogger(e){AudioCodesUA.ac_log=e}setJsSipLogger(e){AudioCodesUA.js_log=e}isInitialized(){return this._isInitialized}setModes(e={}){AudioCodesUA.ac_log(`AC: setModes() ${JSON.stringify(e)}`),Object.assign(this.modes,e),this._normalizeModes()}_normalizeModes(){function e(e,i){return"number"==typeof e&&e<=i?void 0:e}let i=this.modes;i.sbc_ha_pairs_mode=e(i.sbc_ha_pairs_mode,0),i.chrome_rtp_timeout_fix=e(i.chrome_rtp_timeout_fix,0)}init(e=!0){if(AudioCodesUA.ac_log(`AC: init() autoLogin=${e}`),this._isInitialized)return;this._isInitialized=!0,JsSIP.debug.enable("JsSIP:*"),JsSIP.debug.formatArgs=function(){AudioCodesUA.js_log&&(this.log=AudioCodesUA.js_log)};let i=[];for(let e of this.serverConfig.addresses)e instanceof Array?i.push({socket:new JsSIP.WebSocketInterface(e[0]),weight:e[1]}):i.push(new JsSIP.WebSocketInterface(e));let s={sockets:i,uri:"sip:"+this.account.user+"@"+this.serverConfig.domain,contact_uri:"sip:"+this.account.user+"@"+this._randomToken(12)+".invalid;transport=ws",authorization_user:this.account.authUser,password:this.account.password,register:e,session_timers:this.account.useSessionTimer,register_expires:this.account.registerExpires,user_agent:this.u17,connection_recovery_min_interval:this.reconnectMin,connection_recovery_max_interval:this.reconnectMax};this.account.displayName&&this.account.displayName.length>0&&(s.display_name=this.account.displayName),this.jssipUA=new JsSIP.UA(s),this.setRegisterExtraHeaders(this.registerExtraHeaders),this._setUACallbacks(),AudioCodesUA.ac_log(`AC: applied SDK modes: ${JSON.stringify(this.modes,(e,i)=>void 0===i?"":i)}`),this.jssipUA.modes=this.modes;for(let e of this.credentials)this.jssipUA.addCredential(e);this.credentials=[],this.jssipUA.start()}deinit(){this._isInitialized=!1,this.jssipUA&&this.jssipUA.stop()}setRegisterExtraHeaders(e){if(this.registerExtraHeaders=e,this.jssipUA){let i=null!==e?e:[];null!==this.oauthToken&&(i=i.slice()).push(`Authorization: Bearer ${this.oauthToken}`),this.jssipUA.registrator().setExtraHeaders(i)}}getRegisterExtraHeaders(){return this.registerExtraHeaders}login(){AudioCodesUA.ac_log("AC: login()"),this.jssipUA.register()}logout(){AudioCodesUA.ac_log("AC: logout()"),this.jssipUA.isRegistered()&&this.jssipUA.unregister()}switchSBC(e=!0){return AudioCodesUA.ac_log("AC: switchSBC()"),this.jssipUA.switchSBC(e)}getNumberOfSBC(){return this.jssipUA.getNumberOfSBC()}setWebSocketKeepAlive(e,i=!0,s=!0,t=0,o=!1){if(AudioCodesUA.ac_log(`AC: setWebSocketKeepAlive pingInterval=${e} pongTimeout=${i}`+` timerThrottlingBestEffort=${JSON.stringify(s)} pongReport=${t} pongDist=${o}`),"number"!=typeof e||"boolean"!=typeof i)throw new TypeError("setWebSocketKeepAlive: wrong type of first or second argument");let n;this.wsPingMs=this.wsOrigPingMs=1e3*e,this.wsPongTimeout=i,this.wsPongReport=t,this.wsPongDist=o,this.wsPongReportCounter=0,this.wsIsThrottling=!1;let r=(n=!0===s?{log:0,chrome:{interval:1,visibility:!0,call:!0,log:1}}:!1===s?{log:0}:s)[this.browser];this.wsThrottlingPingMs=r&&void 0!==r.interval?1e3*r.interval:0,this.wsVisibility=!(!r||void 0===r.visibility)&&r.visibility,this.wsCall=!(!r||void 0===r.call)&&r.call,this.wsLog=r&&void 0!==r.log?r.log:n.log,this.wsPongDelays=new Array(this.wsPongReport>0?this.wsPongReport:50),this.wsPongDelaysIx=0,0!==this.wsOrigPingMs&&0!==this.wsThrottlingPingMs&&this.wsVisibility&&document.addEventListener("visibilitychange",this._onVisibilityChange.bind(this))}_pingLog(){return` (ping=${this.wsPingMs/1e3} sec)`}_visibilityLog(e){let i="AC: keep-alive: Page is "+(document.hidden?"hidden":"visible");document.hidden&&(this.wsCall&&(i+=", "+(0===this.activeCalls?"no active call":"active call")),i+=" and "+(this.wsIsThrottling?"was":"was not")+" trottling"),e&&(i+=this._pingLog()),AudioCodesUA.ac_log(i)}_activeCallsLog(e){let i=`AC: keep-alive: ${0===this.activeCalls?"Call ended":"Call started"}`;0===this.activeCalls&&(this.wsVisibility&&(i+=", page is "+(document.hidden?"hidden":"visible")),i+=" and "+(this.wsIsThrottling?"was":"was not")+" trottling"),e&&(i+=this._pingLog()),AudioCodesUA.ac_log(i)}_onActiveCallsChange(e){if(this.activeCalls+=e,this.wsCall&&0!==this.wsPingMs&&0!==this.wsThrottlingPingMs)if(this.activeCalls<0&&AudioCodesUA.ac_log("Warning: keep-alive: activeCalls < 0"),0===this.activeCalls){if((!this.wsVisibility||document.hidden)&&this.wsIsThrottling&&this.wsPingMs=2&&this._activeCallsLog(!1)}else if(1===this.activeCalls&&e>0){if(this.wsPingMs>this.wsOrigPingMs)return this.wsPingMs=this.wsOrigPingMs,void this._activeCallsLog(!0);this.wsLog>=2&&this._activeCallsLog(!1)}}_onVisibilityChange(){if(this.wsVisibility&&0!==this.wsPingMs&&0!==this.wsThrottlingPingMs)if(document.hidden){if(this.wsCall&&0===this.activeCalls&&this.wsIsThrottling&&this.wsPingMs=2&&this._visibilityLog(!1)}else{if(this.wsPingMs>this.wsOrigPingMs)return this.wsPingMs=this.wsOrigPingMs,void this._visibilityLog(!0);this.wsLog>=2&&this._visibilityLog(!1)}}_onMessageHook(e){"\r\n"===e.data?this._onPong():this.wsOnMessage(e)}_onPong(){if(!this.wsPingStarted)return;let e;this.wsPongReceived=!0,null===this.wsPongSupported&&(AudioCodesUA.ac_log("AC: keep-alive: Server supports CRLF pong"),this.wsPongSupported=!0),null!==this.wsPongTimeoutTime?(e=Date.now()-this.wsPongTimeoutTime,this.wsPongTimeoutTime=null,AudioCodesUA.ac_log(`AC: keep-alive: Received pong that exceeded the timeout, delay=${e}`)):e=Date.now()-this.wsPingTime;let i=this.wsPingMs-e;i<0&&(AudioCodesUA.ac_log(`AC: nextPing calculated to ${i}ms, so resetting to 0ms.`),i=0),null!==this.wsPingJob&&clearTimeout(this.wsPingJob),this.wsPingJob=setTimeout(this._sendPing.bind(this),i),this.wsPongDelays[this.wsPongDelaysIx]=e,this.wsPongDelaysIx=this.wsPongDelaysIx+1,this.wsPongDelaysIx===this.wsPongDelays.length&&(this.wsPongDelaysIx=0),this.wsPongReport>0&&this.wsPongReportCounter++}_onPongTimeout(e){if(AudioCodesUA.ac_log(`AC: keep-alive: Pong timeout (not received within ${e/1e3} seconds)`),AudioCodesUA.ac_log(`AC: keep-alive: Previous pongs statistics: ${this._createPongReport(!0)}`),this.wsPongTimeout){AudioCodesUA.ac_log("AC: keep-alive: Close websocket connection"),this._stopWsKeepAlive();let e=this.wsSocket;e.onopen=void 0,e.onerror=void 0,e.onclose=void 0,e.onmessage=void 0,setTimeout(()=>{try{e.close()}catch(e){AudioCodesUA.ac_log("AC: Close websocket error",e)}},0),this.wsWebSocketInterface._ws=null,this.wsWebSocketInterface._onClose.call(this.wsWebSocketInterface,{wasClean:!1,code:1001,reason:"Going Away"})}else AudioCodesUA.ac_log("AC: keep-alive: Warning: websocket is not closed, because pongTimeout=false")}_sendPing(){try{let e=Date.now();if(null!==this.wsPingTime){let i=e-this.wsNextPingTime;this.wsLog>=3&&AudioCodesUA.ac_log(`AC: keep-alive: timer deviation (ms): ${i}`);let s=this.wsPingMs;if(Math.abs(i)>=1e4&&((this.wsLog>0||!this.wsIsThrottling)&&(AudioCodesUA.ac_log(`AC: keep-alive detected timer throttling: ${Math.round(i/1e3)} seconds ${i>0?"later":"earlier"}`),0===this.wsLog&&AudioCodesUA.ac_log("AC: keep-alive: The next timer throttling will not be shown in the logs, because log==0")),this.wsIsThrottling=!0,this.wsPingMs0&&this.wsPongReportCounter>=this.wsPongReport&&(this.wsPongReportCounter=0,AudioCodesUA.ac_log(`AC: keep-alive: Pong statistics: ${this._createPongReport(this.wsPongDist)}`))}catch(e){AudioCodesUA.ac_log("AC: keep-alive: send ping error",e)}}_startWsKeepAlive(){let e=this.jssipUA._transport;this.wsWebSocketInterface=e.socket,this.wsSocket=this.wsWebSocketInterface._ws,0!==this.wsPingMs&&(this.wsOnMessage=this.wsSocket.onmessage,this.wsSocket.onmessage=this._onMessageHook.bind(this),this._stopWsKeepAlive(),this.wsPingTime=null,this.wsPingStarted=!0,this.wsPongSupported=null,this.wsPingJob=setTimeout(this._sendPing.bind(this),this.wsPingMs))}_stopWsKeepAlive(){this.wsPingStarted=!1,null!==this.wsPingJob&&(clearTimeout(this.wsPingJob),this.wsPingJob=null)}_createPongReport(e){let i,s="",t=!1,o=1e6,n=0;e&&(i=new Array(this.wsPingMs/1e3*4).fill(0));let r=0;for(let s=0;sn&&(n=a),e)){let e=Math.floor(a/250);e>=i.length&&(e=i.length-1,t=!0),i[e]++}}if(e){s="\r\npongs distribution (1/4 second step): ";for(let e=0;e{AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "connected"'),this._startWsKeepAlive(),this.listeners.loginStateChanged(!1,"connected",null)}),this.jssipUA.on("disconnected",()=>{this._stopWsKeepAlive(),AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "disconnected"'),this.listeners.loginStateChanged(!1,"disconnected",null)}),this.jssipUA.on("registered",e=>{AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=true "login"'),this.listeners.loginStateChanged(!0,"login",e.response)}),this.jssipUA.on("unregistered",e=>{AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "logout"'),this.listeners.loginStateChanged(!1,"logout",e.response)}),this.jssipUA.on("registrationFailed",e=>{let i=e.response?e.response.status_code:0;if(i>=300&&i<400){let i=e.response.parseHeader("contact");if(i){let e=i.uri,s="wss://"+e.host;if(e.port&&443!==e.port&&(s+=":"+e.port.toString()),AudioCodesUA.ac_log(`AC: registerRedirect("${s}")`),this.jssipUA.registerRedirect(s))return}else AudioCodesUA.ac_log('AC: 3xx response without "Contact" is ignored')}else if(i>=500&&i<600&&AudioCodesUA.instance.modes.sbc_switch_register5xx_mode&&AudioCodesUA.instance.switchSBC(!1))return;AudioCodesUA.ac_log('AC>>: loginStateChanged: isLogin=false "login failed"'),this.listeners.loginStateChanged(!1,"login failed",e.response?e.response:null)}),this.listeners.incomingMessage&&this.jssipUA.on("newMessage",e=>{"remote"===e.originator&&(AudioCodesUA.ac_log("AC>>: incomingMessage",e),this.listeners.incomingMessage(null,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request))}),this.listeners.incomingNotify&&this.jssipUA.on("sipEvent",e=>{AudioCodesUA.ac_log("AC>>: incoming out of dialog NOTIFY",e),this.listeners.incomingNotify(null,e.event?e.event.event:null,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request)||e.request.reply(481)}),this.listeners.incomingSubscribe&&this.jssipUA.on("newSubscribe",e=>{let i=e.request,s=i.parseHeader("event"),t=i.getHeaders("accept");AudioCodesUA.ac_log("AC>>: incomingSubscribe",i,s.event,t);let o=this.listeners.incomingSubscribe(i,s.event,t);o>0&&i.reply(o)}),this.jssipUA.on("newRTCSession",function(e){AudioCodesUA.ac_log(`AC: event ${"remote"===e.originator?"incoming":"outgoing"} "newRTCSession"`,e);let i,s=new AudioCodesSession(e.session);if(s.js_session.on("sipEvent",function(e){if(!AudioCodesUA.instance.listeners.incomingNotify)return;let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: incoming NOTIFY",i,e),e.taken=AudioCodesUA.instance.listeners.incomingNotify(i,e.event?e.event.event:null,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request)}),s.js_session.on("newInfo",function(e){if(!AudioCodesUA.instance.listeners.incomingInfo)return;if("local"===e.originator)return;let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: incoming INFO",i,e),AudioCodesUA.instance.listeners.incomingInfo(i,AudioCodesUA.instance._get_from(e.request),AudioCodesUA.instance._get_content_type(e.request),e.request.body,e.request)}),s.js_session.on("replaces",function(e){AudioCodesUA.instance.replacedCall=this.data.ac_session,AudioCodesUA.ac_log("AC>>: incoming INVITE with Replaces. This call will be replaced:",this.data.ac_session),e.accept()}),s.js_session.on("sdp",function(e){AudioCodesUA.instance._sdp_checking(this,e)}),s.js_session.on("connecting",function(e){AudioCodesUA.ac_log("AC>>: connecting");let i=AudioCodesUA.instance.codecFilter;i&&(AudioCodesUA.instance._cf_filter("audio",this.data.ac_session,i.audio),AudioCodesUA.instance._cf_filter("video",this.data.ac_session,i.video))}),s.js_session.on("reinvite",function(e){if(!AudioCodesUA.instance.listeners.callIncomingReinvite)return;let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: callIncomingReinvite start"),AudioCodesUA.instance.listeners.callIncomingReinvite(i,!0,e.request),e.callback=function(){AudioCodesUA.ac_log("AC>>: callIncomingIncomingReinvite end"),AudioCodesUA.instance.listeners.callIncomingReinvite(i,!1,null)}}),s.js_session.on("hold",function(e){let i=this.data.ac_session,s="remote"===e.originator;AudioCodesUA.ac_log(`AC>>: callHoldStateChanged isHold=true isRemote=${s} session:`,i),AudioCodesUA.instance.listeners.callHoldStateChanged(i,!0,s)}),s.js_session.on("unhold",function(e){let i=this.data.ac_session,s="remote"===e.originator;AudioCodesUA.ac_log(`AC>>: callHoldStateChanged isHold=false isRemote=${s} session:`,i),AudioCodesUA.instance.listeners.callHoldStateChanged(i,!1,s)}),s.js_session.on("progress",function(e){if("remote"===e.originator){let i=this.data.ac_session;AudioCodesUA.ac_log("AC>>: outgoingCallProgress",i),AudioCodesUA.instance.listeners.outgoingCallProgress(i,e.response)}}),s.js_session.on("failed",function(e){let i=this.data.ac_session,s=null;if("Redirected"===e.cause&&e.message&&e.message.headers){let i=e.message.parseHeader("Contact");i&&(s=i.uri.toString())}AudioCodesUA.ac_log("AC>>: callTerminated (failed)",i,e.cause,s),AudioCodesUA.instance.listeners.callTerminated(i,e.message,e.cause,s)}),s.js_session.on("accepted",function(e){let i=this.data.ac_session;i.data._accepted=!0,"remote"===e.originator&&(i.data._ok_response=e.response)}),"remote"===e.originator&&null!==AudioCodesUA.instance.replacedCall&&s.js_session.removeAllListeners("confirmed"),s.js_session.on("confirmed",function(){let e,i=this.data.ac_session,t=null;"_ok_response"in i.data?(t=i.data._ok_response,delete i.data._ok_response,e="ACK sent"):e="ACK received",s.data._video_call_audio_answer_firefox&&(s.data._video_call_audio_answer_firefox=!1,AudioCodesUA.ac_log("AC: [video call/audio answer] Firefox workaround. Send re-INVITE"),s.sendReInvite({showStreams:!0})),AudioCodesUA.ac_log("AC>>: callConfirmed",i,e),AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance,1),AudioCodesUA.instance.listeners.callConfirmed(i,t,e)}),s.js_session.on("ended",function(e){let i=this.data.ac_session;i.data._screenSharing&&i._onEndedScreenSharing.call(i,"call terminated"),AudioCodesUA.ac_log("AC>>: callTerminated (ended)",i,e.cause),AudioCodesUA.instance._onActiveCallsChange.call(AudioCodesUA.instance,-1),AudioCodesUA.instance.listeners.callTerminated(i,e.message,e.cause)}),s.js_session.on("refer",function(e){if(AudioCodesUA.instance.listeners.transfereeCreatedCall){let i,s=this.data.ac_session;if(i=!AudioCodesUA.instance.listeners.transfereeRefer||AudioCodesUA.instance.listeners.transfereeRefer(s,e.request)){let i;AudioCodesUA.ac_log("AC>>: incoming REFER accepted"),i=s.isScreenSharing()?s.doesScreenSharingReplaceCamera():s.hasSendVideo();let t=AudioCodesUA.instance._callOptions(i,!0);e.accept(e=>{e.data._created_by_refer=s},t)}else AudioCodesUA.ac_log("AC>>: incoming REFER rejected"),e.reject()}else AudioCodesUA.ac_log("AC>>: incoming REFER rejected, because transfereeCreatedCall is not set"),e.reject()}),s._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo),s.js_session.connection?(AudioCodesUA.instance._set_connection_listener(s),AudioCodesUA.ac_log('AC: connection exists, set "track" listener')):(AudioCodesUA.ac_log("AC: peer connection does not exist, wait creation"),s.js_session.on("peerconnection",()=>{AudioCodesUA.instance._set_connection_listener(s),AudioCodesUA.ac_log('AC: [event connection] connection created, set "track" listener')})),i="remote"===e.originator?e.request.from:e.request.to,s.data._user=i.uri.user,s.data._host=i.uri.host,s.data._display_name=i.display_name,s.data._create_time=new Date,"remote"===e.originator){let i,t,o,n=null;if(null!==AudioCodesUA.instance.replacedCall&&(n=AudioCodesUA.instance.replacedCall,AudioCodesUA.instance.replacedCall=null),e.request.body){o=!0;let s=new AudioCodesSDP(e.request.body);[i,t]=s.getMediaDirection("video",!0)}else o=!1,s.data._incoming_invite_without_sdp=!0,i=t=!0,AudioCodesUA.ac_log("AC: warning incoming INVITE without SDP");s._setVideoState(i,t),AudioCodesUA.ac_log(`AC>>: incomingCall ${s.hasVideo()?"video":"audio"} from "${s.data._display_name}" ${s.data._user}`,s,n),AudioCodesUA.instance.listeners.incomingCall(s,e.request,n,o)}else s.js_session.data._created_by_refer?(AudioCodesUA.ac_log("AC>>: outgoing call created by REFER"),s.data._created_by_refer=s.js_session.data._created_by_refer,AudioCodesUA.instance.listeners.transfereeCreatedCall(s)):AudioCodesUA.ac_log("AC>>: outgoing call created by phone.call()")})}_get_from(e){return{user:e.from.uri.user,host:e.from.uri.host,displayName:e.from.display_name?e.from.display_name:null}}_get_content_type(e){let i=e.headers["Content-Type"];return i&&i.length>0?i[0].parsed:null}_set_connection_listener(e){AudioCodesUA.instance.getWR().connection.addEventListener(e.js_session.connection,"track",i=>{if(AudioCodesUA.ac_log(`AC>>: "track" event kind= ${i.track.kind}`,i),i.streams.length>0){let s=i.streams[0];AudioCodesUA.ac_log(`AC: set call remote stream id=${s.id}`,e),e.data._remoteMediaStream=s}else AudioCodesUA.ac_log('AC: Warning "track" event without stream');if("video"===i.track.kind){if(!e.hasEnabledReceiveVideo()){e.data._video_call_audio_answer_safari&&(i.track.onmute=(()=>{AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Fired video track "mute" event. Call callShowStream'),i.track.onmute=null;let s=e.getRTCLocalStream(),t=e.getRTCRemoteStream();AudioCodesUA.ac_log("AC>>: callShowStreams",e,s,t),AudioCodesUA.instance.listeners.callShowStreams(e,s,t)}),AudioCodesUA.ac_log('AC: [video call/audio answer] Safari fix. Set video track "mute" event listener'),e.data._video_call_audio_answer_safari=!1),AudioCodesUA.ac_log('AC>>: event "track" video and !hasEnabledReceiveVideo therefore change transceiver direction.',e);let s=AudioCodesUA.instance.getWR().connection.getTransceiver(e.js_session.connection,"video");if(null!==s){let i=e.hasEnabledSendVideo()?"sendonly":"inactive";AudioCodesUA.instance.getWR().transceiver.setDirection(s,i)}}return void(AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",e,AudioCodesUA.instance.codecFilter.video))}let s=e.getRTCLocalStream(),t=e.getRTCRemoteStream();AudioCodesUA.ac_log("AC>>: callShowStreams",e,s,t),AudioCodesUA.instance.listeners.callShowStreams(e,s,t)})}_check_remote_sdp(e,i){try{i.codec_map||(i.codec_map={});let s=e.getMedia("audio");AudioCodesUA.instance._check_remote_m(s,i.codec_map);let t=e.getMedia("video");t&&AudioCodesUA.instance._check_remote_m(t,i.codec_map)}catch(e){AudioCodesUA.ac_log("AC:SDP exception",e)}}_check_remote_m(e,i){let s={};function t(e,i){let s=i.indexOf(" ",e);return-1===s?["?","?"]:[i.substring(e,s),i.substring(s+1).toLowerCase()]}for(let i of e)if(i.startsWith("a=rtpmap:")){let[e,o]=t(9,i);s[e]||(s[e]={}),s[e].rtpmap=o}else if(i.startsWith("a=fmtp:")){let[e,o]=t(7,i);s[e]||(s[e]={}),s[e].fmtp=o}for(let e of Object.keys(s))if(i[e])s[e].rtpmap===i[e].rtpmap?s[e].fmtp!==i[e].fmtp&&AudioCodesUA.ac_log(`AC:SDP [The same payload type and codec name, different fmtp] pt=${e} rtpmap=${s[e].rtpmap} fmtp=${s[e].fmtp}, previously was fmtp=${i[e].fmtp}`):(parseInt(e)>=64||s[e].rtpmap&&i[e].rtpmap)&&AudioCodesUA.ac_log(`AC:SDP [The same payload type, different codec names] pt=${e} rtpmap=${s[e].rtpmap}, previously was rtpmap=${i[e].rtpmap}`);else{let t,o=s[e];for(let[e,s]of Object.entries(i))if(o.rtpmap===s.rtpmap&&o.fmtp===s.fmtp){t=e;break}if(t){let s=i[t];o.fmtp||s.fmtp?AudioCodesUA.ac_log(`AC:SDP [The same codec name used with different payload types] pt=${e} rtpmap=${o.rtpmap} fmtp=${o.fmtp}, previously was pt=${t} rtpmap=${s.rtpmap} fmtp=${s.fmtp}`):AudioCodesUA.ac_log(`AC:SDP [The same codec name used with different payload types] pt=${e} rtpmap=${o.rtpmap}, previously was pt=${t} rtpmap=${s.rtpmap}`)}else i[e]=o}}_sdp_checking(e,i){let s,t,o,n=i.originator+" "+i.type,r=e.data.ac_session;try{s=new AudioCodesSDP(i.sdp),[t,o]=s.getMediaDirection("video","remote"===i.originator)}catch(i){return void AudioCodesUA.ac_log("AC: cannot parse SDP",i)}let a=r.data._initial;switch("answer"===i.type&&(r.data._initial=!1),AudioCodesUA.ac_log(`AC: Event "sdp" ${a?"initial":""} ${n} Session state:${AudioCodesUA.getSessionStatusName(e._status)}`),n){case"remote offer":AudioCodesUA.instance.modes.check_remote_sdp_mode&&AudioCodesUA.instance._check_remote_sdp(s,e.data);break;case"remote answer":if(AudioCodesUA.instance.modes.check_remote_sdp_mode&&AudioCodesUA.instance._check_remote_sdp(s,e.data),r.isLocalHold()||r.isRemoteHold())break;r._setVideoState(t,o);break;case"local offer":AudioCodesUA.instance.networkPriority&&AudioCodesUA.instance._set_senders_dscp(e);break;case"local answer":if(r.isLocalHold()||r.isRemoteHold())break;AudioCodesUA.instance.networkPriority&&AudioCodesUA.instance._set_senders_dscp(e),r._setVideoState(t,o)}}_set_senders_dscp(e){if("chrome"!==AudioCodesUA.instance.browser)return;AudioCodesUA.ac_log("AC: _set_senders_dscp()");let i=AudioCodesUA.instance.networkPriority;AudioCodesUA.instance._set_dscp(e,"audio",i),AudioCodesUA.instance._set_dscp(e,"video",i)}_set_dscp(e,i,s){let t=e.connection,o=AudioCodesUA.instance.getWR().connection.getTransceiver(t,i);return o||"video"!==i?Promise.resolve().then(()=>{let e=o.sender.getParameters();if(!e)throw new Error("sender getParameters() returns undefined");let t=e.encodings;if(!t)throw new Error("parameters encodings is undefined");if(0===t.length)throw new Error("parameters encodings is empty array");let n=t[0].networkPriority;if(!n)throw new Error("parameters encodings networkPriority is undefined");return n===s||(t[0].networkPriority=s,o.sender.setParameters(e).then(()=>(AudioCodesUA.ac_log(`AC: DSCP: ${i} "${s}"`),!0)))}).catch(e=>(AudioCodesUA.ac_log(`AC: DSCP: ${i} error: ${e}`),!1)):Promise.resolve(!1)}_cf_unpack(e){function i(e,i){let s,t=i.indexOf("/"),o=i.indexOf("#");s=-1!==t?t:-1!==o?o:void 0;let n={mimeType:(e+"/"+i.substring(0,s)).toLowerCase()};return-1!==t&&(s=-1!==o?o:void 0,n.clockRate=parseInt(i.substring(t+1,s))),-1!==o&&(n.sdpFmtpLine=i.substring(o+1)),n}if(!e)return null;let s={};for(let t in e){s[t]={};for(let o in e[t])s[t][o]=e[t][o].map(e=>i(t,e))}return s}_cf_pack(e){return e.map(e=>(function(e){let i=e.mimeType.substring(6).toLowerCase();return e.clockRate&&(i+="/"+e.clockRate),e.sdpFmtpLine&&(i+="#"+e.sdpFmtpLine),i})(e))}_cf_str(e){return JSON.stringify(AudioCodesUA.instance._cf_pack(e))}_cf_match(e,i){let s=e.mimeType.toLowerCase();for(let t of i)if(t.mimeType===s){if(t.clockRate&&t.clockRate!==e.clockRate)continue;if(t.sdpFmtpLine&&t.sdpFmtpLine!==e.sdpFmtpLine)continue;return!0}return!1}_cf_find(e,i){let s=[];for(let t of i){let i=t.mimeType.toLowerCase();if(e.mimeType===i){if(e.clockRate&&e.clockRate!==t.clockRate)continue;if(e.sdpFmtpLine&&e.sdpFmtpLine!==t.sdpFmtpLine)continue;s.push(t)}}return s}_cf_filter(e,i,s){if(s&&!i.data[`_used_${e}_codec_filter`])try{let t=i.getRTCPeerConnection(),o=AudioCodesUA.instance.getWR().connection.getTransceiver(t,e);if(!o)return void("audio"===e&&AudioCodesUA.ac_log("AC: codec-filter: cannot get audio transceiver"));if(i.data[`_used_${e}_codec_filter`]=!0,!RTCRtpSender.getCapabilities||!RTCRtpReceiver.getCapabilities||!o.setCodecPreferences)return void AudioCodesUA.ac_log("AC: codec-filter is not supported.");let n=RTCRtpSender.getCapabilities(e).codecs,r=RTCRtpReceiver.getCapabilities(e).codecs,a=[];for(let e of r){-1===n.findIndex(i=>e.mimeType===i.mimeType&&e.clockRate===i.clockRate&&e.sdpFmtpLine===i.sdpFmtpLine)&&a.push(e)}let d=n.concat(a);if(AudioCodesUA.ac_log(`AC: ${e} codec-filter original: ${AudioCodesUA.instance._cf_str(d)}\n(receiver: ${a.length})`),s.remove&&s.remove.length>0){let i=d.length;(d=d.filter(e=>!AudioCodesUA.instance._cf_match(e,s.remove))).length0){let i=[];for(let e of s.priority){let s=AudioCodesUA.instance._cf_find(e,d);0!==s.length&&(i=i.concat(s),d=d.filter(e=>!s.includes(e)))}d=i.concat(d),AudioCodesUA.ac_log(`AC: ${e} codec-filter changed priority: ${AudioCodesUA.instance._cf_str(d)}`)}return void o.setCodecPreferences(d)}catch(e){return void AudioCodesUA.ac_log("AC: codec filter exception",e)}}_convertIceList(e){let i=[];for(let s of e)"string"==typeof s&&(s={urls:"stun:"+s}),i.push(s);return i}_randomToken(e){let i="";for(let s=0;s{let n={contentType:s,eventHandlers:{succeeded:e=>t(e),failed:e=>o(e)}};this.jssipUA.sendMessage(e,i,n)})}isScreenSharingSupported(){return AudioCodesUA.instance.getWR().hasDisplayMedia()}openScreenSharing(){return this.isScreenSharingSupported()?(AudioCodesUA.ac_log("AC: openScreenSharing()"),AudioCodesUA.instance.getWR().getDisplayMedia().then(e=>e).catch(e=>{throw AudioCodesUA.ac_log("AC: openScreenSharing() error",e),e})):(AudioCodesUA.ac_log("AC: openScreenSharing: screen sharing is not supported in the browser"),Promise.reject("Screen sharing is not supported"))}closeScreenSharing(e){if(AudioCodesUA.ac_log("AC: closeScreenSharing()"),e){let i=e.getVideoTracks();if(0==i.length)return;let s=i[0];"live"===s.readyState&&(s.stop(),s.dispatchEvent(new Event("ended")))}}setNetworkPriority(e){if(AudioCodesUA.ac_log(`AC: setNetworkPriority ${e}`),void 0!==e&&"high"!==e&&"medium"!==e&&"low"!==e&&"very-low"!==e)throw new TypeError(`setNetworkPriority: illegal value: ${e}`);this.networkPriority=e}subscribe(...e){return this.jssipUA.subscribe(...e)}notify(...e){return this.jssipUA.notify(...e)}addCredential(e){if(!e.realm||!e.password||!e.username)throw new TypeError("wrong credential structure");this.credentials.push(e)}}class AudioCodesSession{constructor(e){this.js_session=e,this.data={_user:null,_display_name:null,_create_time:null,_initial:!0,_remoteMediaStream:null,_wasUsedSendVideo:!1,_screenSharing:null,_video:{send:!1,receive:!1,enabledSend:!1,enabledReceive:!1}},e.data.ac_session=this}getRTCPeerConnection(){return this.js_session.connection}getRTCLocalStream(){return this.js_session._localMediaStream}getRTCRemoteStream(){return this.data._remoteMediaStream}isEstablished(){return this.js_session.isEstablished()}isTerminated(){return this.js_session.isEnded()}isOutgoing(){return"outgoing"===this.js_session.direction}isAudioMuted(){return this.js_session.isMuted().audio}isVideoMuted(){return this.js_session.isMuted().video}wasAccepted(){return!0===this.data._accepted}getReplacesHeader(){if(!this.js_session.isEstablished()||!this.js_session._dialog)return AudioCodesUA.ac_log("getReplacesHeader(): call is not established"),null;let e=this.js_session._dialog.id;return`${e.call_id};to-tag=${e.remote_tag};from-tag=${e.local_tag}`}muteAudio(e){AudioCodesUA.ac_log(`AC: muteAudio() arg=${e} `),e?this.js_session.mute({audio:!0,video:!1}):this.js_session.unmute({audio:!0,video:!1})}muteVideo(e){AudioCodesUA.ac_log(`AC: muteVideo() arg=${e} `),e?this.js_session.mute({audio:!1,video:!0}):this.js_session.unmute({audio:!1,video:!0})}sendDTMF(e){let i=AudioCodesUA.instance.dtmfUseWebRTC;if(i&&"safari"===AudioCodesUA.instance.browser){void 0===AudioCodesUA.instance.getWR().connection.getDTMFSender(this.js_session.connection)&&(i=!1)}AudioCodesUA.ac_log(`AC: sendDTMF() tone=${e} ${i?"[RFC2833]":"[INFO]"}`);let s={duration:AudioCodesUA.instance.dtmfDuration,interToneGap:AudioCodesUA.instance.dtmfInterToneGap,transportType:i?"RFC2833":"INFO"};this.js_session.sendDTMF(e,s)}sendInfo(e,i,s=null){AudioCodesUA.ac_log("AC: sendInfo()",e,i,s);let t=null!==s?{extraHeaders:s}:void 0;this.js_session.sendInfo(i,e,t)}duration(){let e=this.js_session.start_time;if(!e)return 0;let i=this.js_session.end_time;return i||(i=new Date),Math.floor((i.getTime()-e.getTime())/1e3)}hasSendVideo(){return this.data._video.send}hasReceiveVideo(){return this.data._video.receive}hasVideo(){return this.hasSendVideo()&&this.hasReceiveVideo()}getVideoState(){return this.hasSendVideo()&&this.hasReceiveVideo()?"sendrecv":this.hasSendVideo()?"sendonly":this.hasReceiveVideo()?"recvonly":"inactive"}_setVideoState(e,i){AudioCodesUA.ac_log(`AC: _setVideoState(send=${e}, receive=${i})`),this.data._video.send=e,this.data._video.receive=i}hasEnabledSendVideo(){return this.data._video.enabledSend}hasEnabledReceiveVideo(){return this.data._video.enabledReceive}getEnabledVideoState(){return this.hasEnabledSendVideo()&&this.hasEnabledReceiveVideo()?"sendrecv":this.hasEnabledSendVideo()?"sendonly":this.hasEnabledReceiveVideo()?"recvonly":"inactive"}_setEnabledSendVideo(e){AudioCodesUA.ac_log(`AC: _setEnabledSendVideo(${e})`),this.data._video.enabledSend=e}_setEnabledReceiveVideo(e){AudioCodesUA.ac_log(`AC: _setEnabledReceiveVideo(${e})`),this.data._video.enabledReceive=e}answer(e,i=null,s=null){if(this.data._answer_called)return void AudioCodesUA.ac_log("AC: answer() is already called. [Ignored]");if(this.data._answer_called=!0,!1===e?e=AudioCodesUA.instance.AUDIO:!0===e&&(e=AudioCodesUA.instance.VIDEO),"symbol"!=typeof e||![AudioCodesUA.instance.AUDIO,AudioCodesUA.instance.RECVONLY_VIDEO,AudioCodesUA.instance.VIDEO].includes(e))throw new TypeError(`Illegal videoOption=${e.toString()}`);if(AudioCodesUA.ac_log(`AC: ${e.description} answer`),this.hasVideo()||e!==AudioCodesUA.instance.RECVONLY_VIDEO&&e!==AudioCodesUA.instance.VIDEO||(AudioCodesUA.ac_log('AC: incoming INVITE without video, so answer can be only "audio"'),e=AudioCodesUA.instance.AUDIO),this.hasVideo()&&e===AudioCodesUA.instance.AUDIO){let e=AudioCodesUA.instance,i=e.browser,s=e.modes,t=e.browserVersion;"firefox"===i&&s.video_call_audio_answer_firefox_fix?this.data._video_call_audio_answer_firefox=!0:"safari"===i&&(!0===s.video_call_audio_answer_safari_fix&&t<14||"force"===s.video_call_audio_answer_safari_fix)&&(this.data._video_call_audio_answer_safari=!0)}switch(e){case AudioCodesUA.instance.AUDIO:this._setEnabledSendVideo(!1),this.data._incoming_invite_without_sdp?this._setEnabledReceiveVideo(AudioCodesUA.instance.enableAddVideo):this._setEnabledReceiveVideo(!this.hasVideo()&&AudioCodesUA.instance.enableAddVideo),this._setVideoState(!1,!1);break;case AudioCodesUA.instance.VIDEO:this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(!0),this._setVideoState(!0,!0);break;case AudioCodesUA.instance.RECVONLY_VIDEO:this._setEnabledSendVideo(!1),this._setEnabledReceiveVideo(!0),this._setVideoState(!1,!0)}let t=AudioCodesUA.instance._callOptions(e===AudioCodesUA.instance.VIDEO,!1,i,s);Promise.resolve().then(()=>t.mediaStream?t.mediaStream:AudioCodesUA.instance.getWR().getUserMedia(t.mediaConstraints)).then(e=>{t.mediaStream=e,this.js_session._localMediaStreamLocallyGenerated=!0,AudioCodesUA.ac_log("AC: answer options:",t),this.js_session.answer(t)}).catch(e=>{AudioCodesUA.ac_log("AC: getUserMedia failure",e),this.reject(488)})}reject(e=486,i=null){AudioCodesUA.ac_log("AC: reject()");try{let s={status_code:e};i&&(s.extraHeaders=i),this.js_session.terminate(s)}catch(e){AudioCodesUA.ac_log("AC: call reject error:",e)}}terminate(){AudioCodesUA.ac_log("AC: terminate()");try{this.js_session.terminate()}catch(e){AudioCodesUA.ac_log("AC: call terminate error:",e)}}redirect(e,i=302,s=null){AudioCodesUA.ac_log(`AC: redirect() callTo=${e}`);try{let t={status_code:i,extraHeaders:["Contact: "+AudioCodesUA.instance.jssipUA.normalizeTarget(e)]};s&&t.extraHeaders.push(...s),this.js_session.terminate(t)}catch(e){AudioCodesUA.ac_log("AC: call redirect error:",e)}}isLocalHold(){return this.js_session.isOnHold().local}isRemoteHold(){return this.js_session.isOnHold().remote}isReadyToReOffer(){return this.js_session._isReadyToReOffer()}hold(e){return AudioCodesUA.ac_log(`AC: hold(${e})`),new Promise((i,s)=>{(e?this.js_session.hold:this.js_session.unhold).call(this.js_session,{},()=>{AudioCodesUA.ac_log("AC: hold()/unhold() is completed"),i()})||(AudioCodesUA.ac_log("AC: hold()/unhold() failed"),s())})}enableReceiveVideo(e){this._setEnabledReceiveVideo(e);let i=this.getRTCPeerConnection(),s=AudioCodesUA.instance.getWR().connection.getTransceiver(i,"video");if(null!==s){let e=this.getEnabledVideoState();AudioCodesUA.instance.getWR().transceiver.setDirection(s,e)}return AudioCodesUA.ac_log(`AC: enableReceiveVideo(${e}) ${null!==s?"":"No video transceiver"}`),null!==s}startSendingVideo(e={}){let i=e&&!1!==e.enabledReceiveVideo;return this.hasEnabledSendVideo()?(AudioCodesUA.ac_log("AC: startSendingVideo(). Already started"),Promise.reject("video already started")):(AudioCodesUA.ac_log("AC: startSendingVideo()"),AudioCodesUA.instance.getWR().getUserMedia({video:AudioCodesUA.instance.constraints.video}).catch(e=>{throw AudioCodesUA.ac_log("AC: startSendingVideo() getUserMedia failure",e),e}).then(e=>{let s=e.getVideoTracks()[0];this.getRTCLocalStream().addTrack(s),this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(i);let t=this.data._wasUsedSendVideo;return AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(),this.getRTCLocalStream(),s,this.hasEnabledReceiveVideo(),t).then(()=>{!t&&AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",this,AudioCodesUA.instance.codecFilter.video)}).catch(e=>{throw AudioCodesUA.ac_log("AC: startSendingVideo(). Adding video error",e),e})}).then(()=>this._renegotiate(e)))}stopSendingVideo(e={}){return this.hasEnabledSendVideo()?(AudioCodesUA.ac_log("AC: stopSendingVideo()"),AudioCodesUA.instance.getWR().connection.removeVideo(this.getRTCPeerConnection(),this.getRTCLocalStream()).catch(e=>{throw AudioCodesUA.ac_log("AC: stopSendingVideo(). Remove video error",e),e}).then(()=>(this._setEnabledSendVideo(!1),this.data._wasUsedSendVideo=!0,this._renegotiate(e)))):(AudioCodesUA.ac_log("AC: stopSendingVideo(). Already stopped"),Promise.reject("video already stopped"))}_doRenegotiate(e){return this.js_session.isEnded()?Promise.reject("call is ended"):new Promise(i=>{if(!this.js_session.renegotiate(e,()=>i(!0)))return i(!1)})}_renegotiate(e,i=30,s=500){return AudioCodesUA.ac_log(`AC: _renegotiate() attemptsLeft=${i}`),this._doRenegotiate(e).then(t=>{if(t)return AudioCodesUA.ac_log("AC: Renegotiation success"),!0;if(i<=1)throw new Error("Too many attempts");return new Promise(e=>setTimeout(e,s)).then(()=>this._renegotiate(e,i-1,s))}).catch(e=>{throw AudioCodesUA.ac_log("AC: Renegotiation failed",e),e})}sendReInvite(e={}){return AudioCodesUA.ac_log("AC: sendReInvite()"),this._renegotiate(e).then(()=>{if(e.showStreams){let e=this.getRTCLocalStream(),i=this.getRTCRemoteStream();AudioCodesUA.ac_log("AC>>: [after send re-INVITE] callShowStreams",this,e,i),AudioCodesUA.instance.listeners.callShowStreams(this,e,i)}})}startScreenSharing(e,i={localScreenSharing:!0,enabledReceiveVideo:!0,separateVideo:!1}){if(AudioCodesUA.ac_log("AC: startScreenSharing"),!e)return Promise.reject("missed stream argument");if(this.data._screenSharing)return Promise.reject("the call is already using screen-sharing");let s=i&&!1!==i.enabledReceiveVideo,t=e.getVideoTracks()[0],o=void 0;i.localScreenSharing&&(o=this._onEndedScreenSharingTrack.bind(this),t.addEventListener("ended",o)),this.data._screenSharing={stream:e,onended:o,hadSendVideo:this.hasSendVideo()};let n=this.data._wasUsedSendVideo;return this._setEnabledSendVideo(!0),this._setEnabledReceiveVideo(s),AudioCodesUA.instance.getWR().connection.addVideo(this.getRTCPeerConnection(),this.getRTCLocalStream(),t,this.hasEnabledReceiveVideo(),n).then(()=>{!n&&AudioCodesUA.instance.codecFilter&&AudioCodesUA.instance._cf_filter("video",this,AudioCodesUA.instance.codecFilter.video)}).catch(e=>{throw AudioCodesUA.ac_log("AC: startScreenSharing() error",e),this.data._screenSharing=null,e}).then(()=>{return this._renegotiate({extraHeaders:["X-Screen-Sharing: on"]})})}stopScreenSharing(){return AudioCodesUA.ac_log("AC: stopScreenSharing"),this.data._screenSharing?this._onEndedScreenSharing("called stopScreenSharing()"):Promise.reject("the call does not use screen-sharing")}isScreenSharing(){return!!this.data._screenSharing}doesScreenSharingReplaceCamera(){let e=this.data._screenSharing;return e&&e.hadSendVideo}_onEndedScreenSharingTrack(){return this._onEndedScreenSharing("track ended")}_onEndedScreenSharing(e){let i=this.data._screenSharing;this.data._screenSharing=null;let s=i.stream,t=i.onended;if(s&&t){s.getVideoTracks()[0].removeEventListener("ended",t)}return Promise.resolve().then(()=>{if(!this.isTerminated()){let e=this.getRTCPeerConnection(),s=this.getRTCLocalStream(),t={extraHeaders:["X-Screen-Sharing: off"]};return i.hadSendVideo?(AudioCodesUA.ac_log("AC: screen sharing stopped - restore previously sending video track"),AudioCodesUA.instance.getWR().connection.replaceSenderTrack(e,"video",s),this._renegotiate(t)):(AudioCodesUA.ac_log("AC: screen sharing stopped - stop send video"),this.stopSendingVideo(t))}}).then(()=>{AudioCodesUA.instance.listeners.callScreenSharingEnded&&(AudioCodesUA.ac_log(`AC>>: callScreenSharingEnded "${e}"`,this,s),AudioCodesUA.instance.listeners.callScreenSharingEnded(this,s))})}setRemoteHoldState(){this.js_session._remoteHold=!0}sendRefer(e,i=null){if(!AudioCodesUA.instance.listeners.transferorNotification)throw new Error("transferorNotification listener is missed");let s=this,t={eventHandlers:{requestSucceeded(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [REFER accepted]"),AudioCodesUA.instance.listeners.transferorNotification(s,0)},requestFailed(){AudioCodesUA.ac_log("AC>>: transferorNotification failed [REFER failed]"),AudioCodesUA.instance.listeners.transferorNotification(s,-1)},trying(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [NOTIFY 1xx]"),AudioCodesUA.instance.listeners.transferorNotification(s,0)},progress(){AudioCodesUA.ac_log("AC>>: transferorNotification progress [NOTIFY 1xx]"),AudioCodesUA.instance.listeners.transferorNotification(s,0)},accepted(){AudioCodesUA.ac_log("AC>>: transferorNotification success [NOTIFY 2xx]"),AudioCodesUA.instance.listeners.transferorNotification(s,1)},failed(){AudioCodesUA.ac_log("AC>>: transferorNotification failed [NOTIFY >= 300]"),AudioCodesUA.instance.listeners.transferorNotification(s,-1)}}};null!==i&&(t.replaces=i.js_session),this.js_session.refer(e,t)}}class AudioCodesSDP{constructor(e){this.start=[],this.media=[];let i=e.split("\n").map(e=>e.trim()).filter(e=>e.length>0),s=this.start;for(let e of i)e.startsWith("m=")&&(s=[],this.media.push(s)),s.push(e)}getMedia(e){for(let i of this.media)if(i.length>0&&i[0].startsWith("m="+e))return i;return null}checkSendRecv(e){switch(e){case"a=sendrecv":return"sendrecv";case"a=sendonly":return"sendonly";case"a=recvonly":return"recvonly";case"a=inactive":return"inactive";default:return null}}getMediaDirectionValue(e){let i,s=this.getMedia(e);if(null===s)return null;let t="sendrecv";for(let e of this.start)if(null!==(i=this.checkSendRecv(e))){t=i;break}for(let e of s)if(null!==(i=this.checkSendRecv(e))){t=i;break}return t}getMediaDirection(e,i){let s=this.getMediaDirectionValue(e);switch(s){case"sendrecv":return[!0,!0,s];case"sendonly":return i?[!1,!0,s]:[!0,!1,s];case"recvonly":return i?[!0,!1,s]:[!1,!0,s];case null:case"inactive":return[!1,!1,s]}}toString(){let e=this.start;for(let i of this.media)e=e.concat(i);return e.join("\r\n")+"\r\n"}}let AudioCodesWebRTCWrapper={getUserMedia:e=>(AudioCodesUA.ac_log(`[webrtc] getUserMedia constraints=${JSON.stringify(e)}`),navigator.mediaDevices.getUserMedia(e)),hasDisplayMedia:()=>navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia,getDisplayMedia:()=>(AudioCodesUA.ac_log("[webrtc] getDisplayMedia"),navigator.mediaDevices.getDisplayMedia({video:!0})),mediaDevices:{enumerateDevices:()=>navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices?navigator.mediaDevices.enumerateDevices():Promise.reject("WebRTC is not supported"),addDeviceChangeListener(e){navigator.mediaDevices&&navigator.mediaDevices.addEventListener("devicechange",e)},removeDeviceChangeListener(e){navigator.mediaDevices&&navigator.mediaDevices.removeEventListener("devicechange",e)}},checkAvailableDevices(){if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia)return Promise.reject("WebRTC is not supported");let e=!1,i=!1,s=!1;return navigator.mediaDevices.enumerateDevices().then(t=>(t.forEach(function(t){switch(t.kind){case"videoinput":e=!0;break;case"audioinput":i=!0;break;case"audiooutput":s=!0}}),void 0===navigator.webkitGetUserMedia&&(s=!0),s?i?Promise.resolve(e):Promise.reject("Missing a microphone! Please connect one and reload"):Promise.reject("Missing a speaker! Please connect one and reload")))},transceiver:{setDirection(e,i){let s="";null!==e.sender.track?s=e.sender.track.kind:null!==e.receiver.track&&(s=e.receiver.track.kind),AudioCodesUA.ac_log(`[webrtc] set ${s} transceiver direction=${i}`),e.direction=i}},stream:{getInfo(e){function i(e){return e.length>0?e[0].enabled.toString():"-"}return null===e?Promise.resolve("stream is null"):Promise.resolve(`audio: ${i(e.getAudioTracks())} video: ${i(e.getVideoTracks())}`)}},connection:{getTransceiversInfo(e){function i(e){return null===e?"none":`d=${e.direction} c=${e.currentDirection}`}let s=e.getTransceivers(),t=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"audio"),o=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");return Promise.resolve(`(${s.length}) audio ${i(t)} video ${i(o)}`)},getTransceiver(e,i){for(let s of e.getTransceivers()){if(null!==s.sender&&null!==s.sender.track&&s.sender.track.kind===i)return s;if(null!==s.receiver&&null!==s.receiver.track&&s.receiver.track.kind===i)return s}return null},addEventListener:(e,i,s)=>(AudioCodesUA.ac_log(`[webrtc] Connection addEventListener ${i}`),"track"!==i?Promise.reject(`Wrong event name: ${i}`):(e.addEventListener(i,s),Promise.resolve())),getDTMFSender(e){let i=e.getSenders().find(e=>e.track&&"audio"===e.track.kind);if(i&&i.dtmf)return i.dtmf},addVideo(e,i,s,t,o){AudioCodesUA.ac_log("[webrtc] Connection addVideo");let n=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");if(null!==n){let e=t?"sendrecv":"sendonly";AudioCodesUA.instance.getWR().transceiver.setDirection(n,e)}return null===n||null===n.sender.track&&!o?(AudioCodesUA.ac_log("[webrtc] addVideo (connection addTrack)"),e.addTrack(s,i),Promise.resolve(!0)):(AudioCodesUA.ac_log("[webrtc] addVideo (video transceiver sender replaceTrack)"),n.sender.replaceTrack(s).then(()=>!1))},removeVideo(e,i){AudioCodesUA.ac_log("[webrtc] Connection removeVideo");let s=AudioCodesUA.instance.getWR().connection.getTransceiver(e,"video");if(null===s)return Promise.reject("no video transceiver found");if(e.removeTrack(s.sender),i)for(let e of i.getVideoTracks())i.removeTrack(e),e.stop();return Promise.resolve()},replaceSenderTrack(e,i,s){AudioCodesUA.ac_log(`[webrtc] ReplaceSenderTrack ${i}`);let t=null;for(let s of e.getSenders())if(null!==s.track&&s.track.kind===i){t=s;break}if(null===t)return Promise.reject(`No ${i} sender`);let o="audio"===i?s.getAudioTracks():s.getVideoTracks();return 0===o.length?Promise.reject(`No ${i} track`):t.replaceTrack(o[0])},getStats(e,i){let s="";return e.getStats(null).then(e=>(e.forEach(e=>{if(i.includes(e.type)){s+=" {";let i=!0;for(let t of Object.keys(e))i?i=!1:s+=",",s+=t+"="+e[t];s+="} \r\n"}}),s))}}}; diff --git a/js/jssip.js b/js/jssip.js new file mode 100644 index 0000000..6412405 --- /dev/null +++ b/js/jssip.js @@ -0,0 +1,25822 @@ +/* + * JsSIP v3.10.0 + * the Javascript SIP library + * Copyright: 2012-2023 + * Homepage: https://jssip.net + * License: MIT + */ + +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.JsSIP = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +var Utils = require('./Utils'); +var JsSIP_C = require('./Constants'); +var Grammar = require('./Grammar'); +var URI = require('./URI'); +var Socket = require('./Socket'); +var Exceptions = require('./Exceptions'); + +// Default settings. +exports.settings = { + // SIP authentication. + authorization_user: null, + password: null, + realm: null, + ha1: null, + authorization_jwt: null, + // SIP account. + display_name: null, + uri: null, + contact_uri: null, + // SIP instance id (GRUU). + instance_id: null, + // Preloaded SIP Route header field. + use_preloaded_route: false, + // Session parameters. + session_timers: true, + session_timers_refresh_method: JsSIP_C.UPDATE, + session_timers_force_refresher: false, + no_answer_timeout: 60, + // Registration parameters. + register: true, + register_expires: 600, + registrar_server: null, + // Connection options. + sockets: null, + connection_recovery_max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL, + connection_recovery_min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL, + // Global extra headers, to be added to every request and response + extra_headers: null, + /* + * Host address. + * Value to be set in Via sent_by and host part of Contact FQDN. + */ + via_host: "".concat(Utils.createRandomToken(12), ".invalid") +}; + +// Configuration checks. +var checks = { + mandatory: { + sockets: function sockets(_sockets2) { + /* Allow defining sockets parameter as: + * Socket: socket + * Array of Socket: [socket1, socket2] + * Array of Objects: [{socket: socket1, weight:1}, {socket: Socket2, weight:0}] + * Array of Objects and Socket: [{socket: socket1}, socket2] + */ + var _sockets = []; + if (Socket.isSocket(_sockets2)) { + _sockets.push({ + socket: _sockets2 + }); + } else if (Array.isArray(_sockets2) && _sockets2.length) { + var _iterator = _createForOfIteratorHelper(_sockets2), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var socket = _step.value; + if (Object.prototype.hasOwnProperty.call(socket, 'socket') && Socket.isSocket(socket.socket)) { + _sockets.push(socket); + } else if (Socket.isSocket(socket)) { + _sockets.push({ + socket: socket + }); + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } else { + return; + } + return _sockets; + }, + uri: function uri(_uri) { + if (!/^sip:/i.test(_uri)) { + _uri = "".concat(JsSIP_C.SIP, ":").concat(_uri); + } + var parsed = URI.parse(_uri); + if (!parsed) { + return; + } else if (!parsed.user) { + return; + } else { + return parsed; + } + } + }, + optional: { + authorization_user: function authorization_user(_authorization_user) { + if (Grammar.parse("\"".concat(_authorization_user, "\""), 'quoted_string') === -1) { + return; + } else { + return _authorization_user; + } + }, + authorization_jwt: function authorization_jwt(_authorization_jwt) { + if (typeof _authorization_jwt === 'string') { + return _authorization_jwt; + } + }, + user_agent: function user_agent(_user_agent) { + if (typeof _user_agent === 'string') { + return _user_agent; + } + }, + connection_recovery_max_interval: function connection_recovery_max_interval(_connection_recovery_max_interval) { + if (Utils.isDecimal(_connection_recovery_max_interval)) { + var value = Number(_connection_recovery_max_interval); + if (value > 0) { + return value; + } + } + }, + connection_recovery_min_interval: function connection_recovery_min_interval(_connection_recovery_min_interval) { + if (Utils.isDecimal(_connection_recovery_min_interval)) { + var value = Number(_connection_recovery_min_interval); + if (value > 0) { + return value; + } + } + }, + contact_uri: function contact_uri(_contact_uri) { + if (typeof _contact_uri === 'string') { + var uri = Grammar.parse(_contact_uri, 'SIP_URI'); + if (uri !== -1) { + return uri; + } + } + }, + display_name: function display_name(_display_name) { + return _display_name; + }, + instance_id: function instance_id(_instance_id) { + if (/^uuid:/i.test(_instance_id)) { + _instance_id = _instance_id.substr(5); + } + if (Grammar.parse(_instance_id, 'uuid') === -1) { + return; + } else { + return _instance_id; + } + }, + no_answer_timeout: function no_answer_timeout(_no_answer_timeout) { + if (Utils.isDecimal(_no_answer_timeout)) { + var value = Number(_no_answer_timeout); + if (value > 0) { + return value; + } + } + }, + session_timers: function session_timers(_session_timers) { + if (typeof _session_timers === 'boolean') { + return _session_timers; + } + }, + session_timers_refresh_method: function session_timers_refresh_method(method) { + if (typeof method === 'string') { + method = method.toUpperCase(); + if (method === JsSIP_C.INVITE || method === JsSIP_C.UPDATE) { + return method; + } + } + }, + session_timers_force_refresher: function session_timers_force_refresher(_session_timers_force_refresher) { + if (typeof _session_timers_force_refresher === 'boolean') { + return _session_timers_force_refresher; + } + }, + password: function password(_password) { + return String(_password); + }, + realm: function realm(_realm) { + return String(_realm); + }, + ha1: function ha1(_ha) { + return String(_ha); + }, + register: function register(_register) { + if (typeof _register === 'boolean') { + return _register; + } + }, + register_expires: function register_expires(_register_expires) { + if (Utils.isDecimal(_register_expires)) { + var value = Number(_register_expires); + if (value > 0) { + return value; + } + } + }, + registrar_server: function registrar_server(_registrar_server) { + if (!/^sip:/i.test(_registrar_server)) { + _registrar_server = "".concat(JsSIP_C.SIP, ":").concat(_registrar_server); + } + var parsed = URI.parse(_registrar_server); + if (!parsed) { + return; + } else if (parsed.user) { + return; + } else { + return parsed; + } + }, + use_preloaded_route: function use_preloaded_route(_use_preloaded_route) { + if (typeof _use_preloaded_route === 'boolean') { + return _use_preloaded_route; + } + }, + extra_headers: function extra_headers(_extra_headers) { + var _extraHeaders = []; + if (Array.isArray(_extra_headers) && _extra_headers.length) { + var _iterator2 = _createForOfIteratorHelper(_extra_headers), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var header = _step2.value; + if (typeof header === 'string') { + _extraHeaders.push(header); + } + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + } else { + return; + } + return _extraHeaders; + } + } +}; +exports.load = function (dst, src) { + // Check Mandatory parameters. + for (var parameter in checks.mandatory) { + if (!src.hasOwnProperty(parameter)) { + throw new Exceptions.ConfigurationError(parameter); + } else { + var value = src[parameter]; + var checked_value = checks.mandatory[parameter](value); + if (checked_value !== undefined) { + dst[parameter] = checked_value; + } else { + throw new Exceptions.ConfigurationError(parameter, value); + } + } + } + + // Check Optional parameters. + for (var _parameter in checks.optional) { + if (src.hasOwnProperty(_parameter)) { + var _value = src[_parameter]; + + /* If the parameter value is null, empty string, undefined, empty array + * or it's a number with NaN value, then apply its default value. + */ + if (Utils.isEmpty(_value)) { + continue; + } + var _checked_value = checks.optional[_parameter](_value); + if (_checked_value !== undefined) { + dst[_parameter] = _checked_value; + } else { + throw new Exceptions.ConfigurationError(_parameter, _value); + } + } + } +}; +},{"./Constants":2,"./Exceptions":6,"./Grammar":7,"./Socket":23,"./URI":29,"./Utils":30}],2:[function(require,module,exports){ +"use strict"; + +var pkg = require('../package.json'); +module.exports = { + USER_AGENT: "".concat(pkg.title, " ").concat(pkg.version), + // SIP scheme. + SIP: 'sip', + SIPS: 'sips', + // End and Failure causes. + causes: { + // Generic error causes. + CONNECTION_ERROR: 'Connection Error', + REQUEST_TIMEOUT: 'Request Timeout', + SIP_FAILURE_CODE: 'SIP Failure Code', + INTERNAL_ERROR: 'Internal Error', + // SIP error causes. + BUSY: 'Busy', + REJECTED: 'Rejected', + REDIRECTED: 'Redirected', + UNAVAILABLE: 'Unavailable', + NOT_FOUND: 'Not Found', + ADDRESS_INCOMPLETE: 'Address Incomplete', + INCOMPATIBLE_SDP: 'Incompatible SDP', + MISSING_SDP: 'Missing SDP', + AUTHENTICATION_ERROR: 'Authentication Error', + // Session error causes. + BYE: 'Terminated', + WEBRTC_ERROR: 'WebRTC Error', + CANCELED: 'Canceled', + NO_ANSWER: 'No Answer', + EXPIRES: 'Expires', + NO_ACK: 'No ACK', + DIALOG_ERROR: 'Dialog Error', + USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access', + BAD_MEDIA_DESCRIPTION: 'Bad Media Description', + RTP_TIMEOUT: 'RTP Timeout' + }, + SIP_ERROR_CAUSES: { + REDIRECTED: [300, 301, 302, 305, 380], + BUSY: [486, 600], + REJECTED: [403, 603], + NOT_FOUND: [404, 604], + UNAVAILABLE: [480, 410, 408, 430], + ADDRESS_INCOMPLETE: [484, 424], + INCOMPATIBLE_SDP: [488, 606], + AUTHENTICATION_ERROR: [401, 407] + }, + // SIP Methods. + ACK: 'ACK', + BYE: 'BYE', + CANCEL: 'CANCEL', + INFO: 'INFO', + INVITE: 'INVITE', + MESSAGE: 'MESSAGE', + NOTIFY: 'NOTIFY', + OPTIONS: 'OPTIONS', + REGISTER: 'REGISTER', + REFER: 'REFER', + UPDATE: 'UPDATE', + SUBSCRIBE: 'SUBSCRIBE', + // DTMF transport methods. + DTMF_TRANSPORT: { + INFO: 'INFO', + RFC2833: 'RFC2833' + }, + /* SIP Response Reasons + * DOC: https://www.iana.org/assignments/sip-parameters + * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7 + */ + REASON_PHRASE: { + 100: 'Trying', + 180: 'Ringing', + 181: 'Call Is Being Forwarded', + 182: 'Queued', + 183: 'Session Progress', + 199: 'Early Dialog Terminated', + // draft-ietf-sipcore-199 + 200: 'OK', + 202: 'Accepted', + // RFC 3265 + 204: 'No Notification', + // RFC 5839 + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Moved Temporarily', + 305: 'Use Proxy', + 380: 'Alternative Service', + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 410: 'Gone', + 412: 'Conditional Request Failed', + // RFC 3903 + 413: 'Request Entity Too Large', + 414: 'Request-URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Unsupported URI Scheme', + 417: 'Unknown Resource-Priority', + // RFC 4412 + 420: 'Bad Extension', + 421: 'Extension Required', + 422: 'Session Interval Too Small', + // RFC 4028 + 423: 'Interval Too Brief', + 424: 'Bad Location Information', + // RFC 6442 + 428: 'Use Identity Header', + // RFC 4474 + 429: 'Provide Referrer Identity', + // RFC 3892 + 430: 'Flow Failed', + // RFC 5626 + 433: 'Anonymity Disallowed', + // RFC 5079 + 436: 'Bad Identity-Info', + // RFC 4474 + 437: 'Unsupported Certificate', + // RFC 4744 + 438: 'Invalid Identity Header', + // RFC 4744 + 439: 'First Hop Lacks Outbound Support', + // RFC 5626 + 440: 'Max-Breadth Exceeded', + // RFC 5393 + 469: 'Bad Info Package', + // draft-ietf-sipcore-info-events + 470: 'Consent Needed', + // RFC 5360 + 478: 'Unresolvable Destination', + // Custom code copied from Kamailio. + 480: 'Temporarily Unavailable', + 481: 'Call/Transaction Does Not Exist', + 482: 'Loop Detected', + 483: 'Too Many Hops', + 484: 'Address Incomplete', + 485: 'Ambiguous', + 486: 'Busy Here', + 487: 'Request Terminated', + 488: 'Not Acceptable Here', + 489: 'Bad Event', + // RFC 3265 + 491: 'Request Pending', + 493: 'Undecipherable', + 494: 'Security Agreement Required', + // RFC 3329 + 500: 'JsSIP Internal Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Server Time-out', + 505: 'Version Not Supported', + 513: 'Message Too Large', + 580: 'Precondition Failure', + // RFC 3312 + 600: 'Busy Everywhere', + 603: 'Decline', + 604: 'Does Not Exist Anywhere', + 606: 'Not Acceptable' + }, + ALLOWED_METHODS: 'INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO,NOTIFY,SUBSCRIBE', + ACCEPTED_BODY_TYPES: 'application/sdp, application/dtmf-relay', + MAX_FORWARDS: 69, + SESSION_EXPIRES: 90, + MIN_SESSION_EXPIRES: 60, + CONNECTION_RECOVERY_MAX_INTERVAL: 30, + CONNECTION_RECOVERY_MIN_INTERVAL: 2 +}; +},{"../package.json":42}],3:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var Logger = require('./Logger'); +var SIPMessage = require('./SIPMessage'); +var JsSIP_C = require('./Constants'); +var Transactions = require('./Transactions'); +var Dialog_RequestSender = require('./Dialog/RequestSender'); +var Utils = require('./Utils'); +var logger = new Logger('Dialog'); +var C = { + // Dialog states. + STATUS_EARLY: 1, + STATUS_CONFIRMED: 2, + STATUS_TERMINATED: 3 +}; + +// RFC 3261 12.1. +module.exports = /*#__PURE__*/function () { + function Dialog(owner, message, type) { + var state = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : C.STATUS_CONFIRMED; + _classCallCheck(this, Dialog); + this._owner = owner; + this._ua = owner._ua; + this._uac_pending_reply = false; + this._uas_pending_reply = false; + if (!message.hasHeader('contact')) { + return { + error: 'unable to create a Dialog without Contact header field' + }; + } + if (message instanceof SIPMessage.IncomingResponse) { + state = message.status_code < 200 ? C.STATUS_EARLY : C.STATUS_CONFIRMED; + } + var contact = message.parseHeader('contact'); + + // RFC 3261 12.1.1. + if (type === 'UAS') { + this._id = { + call_id: message.call_id, + local_tag: message.to_tag, + remote_tag: message.from_tag, + toString: function toString() { + return this.call_id + this.local_tag + this.remote_tag; + } + }; + this._state = state; + this._remote_seqnum = message.cseq; + this._local_uri = message.parseHeader('to').uri; + this._remote_uri = message.parseHeader('from').uri; + this._remote_target = contact.uri; + this._route_set = message.getHeaders('record-route'); + this._ack_seqnum = this._remote_seqnum; + } + // RFC 3261 12.1.2. + else if (type === 'UAC') { + this._id = { + call_id: message.call_id, + local_tag: message.from_tag, + remote_tag: message.to_tag, + toString: function toString() { + return this.call_id + this.local_tag + this.remote_tag; + } + }; + this._state = state; + this._local_seqnum = message.cseq; + this._local_uri = message.parseHeader('from').uri; + this._remote_uri = message.parseHeader('to').uri; + this._remote_target = contact.uri; + this._route_set = message.getHeaders('record-route').reverse(); + this._ack_seqnum = null; + } + this._ua.newDialog(this); + logger.debug("new ".concat(type, " dialog created with status ").concat(this._state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED')); + } + _createClass(Dialog, [{ + key: "id", + get: function get() { + return this._id; + } + }, { + key: "local_seqnum", + get: function get() { + return this._local_seqnum; + }, + set: function set(num) { + this._local_seqnum = num; + } + }, { + key: "owner", + get: function get() { + return this._owner; + } + }, { + key: "uac_pending_reply", + get: function get() { + return this._uac_pending_reply; + }, + set: function set(pending) { + this._uac_pending_reply = pending; + } + }, { + key: "uas_pending_reply", + get: function get() { + return this._uas_pending_reply; + } + }, { + key: "isTerminated", + value: function isTerminated() { + return this._status === C.STATUS_TERMINATED; + } + }, { + key: "update", + value: function update(message, type) { + this._state = C.STATUS_CONFIRMED; + logger.debug("dialog ".concat(this._id.toString(), " changed to CONFIRMED state")); + if (type === 'UAC') { + // RFC 3261 13.2.2.4. + this._route_set = message.getHeaders('record-route').reverse(); + } + } + }, { + key: "terminate", + value: function terminate() { + logger.debug("dialog ".concat(this._id.toString(), " deleted")); + this._ua.destroyDialog(this); + this._state = C.STATUS_TERMINATED; + } + }, { + key: "sendRequest", + value: function sendRequest(method) { + var _this = this; + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var eventHandlers = Utils.cloneObject(options.eventHandlers); + var body = options.body || null; + var request = this._createRequest(method, extraHeaders, body); + + // Increase the local CSeq on authentication. + eventHandlers.onAuthenticated = function () { + _this._local_seqnum += 1; + }; + var request_sender = new Dialog_RequestSender(this, request, eventHandlers); + request_sender.send(); + + // Return the instance of OutgoingRequest. + return request; + } + }, { + key: "receiveRequest", + value: function receiveRequest(request) { + // Check in-dialog request. + if (!this._checkInDialogRequest(request)) { + return; + } + + // ACK received. Cleanup this._ack_seqnum. + if (request.method === JsSIP_C.ACK && this._ack_seqnum !== null) { + this._ack_seqnum = null; + } + // INVITE received. Set this._ack_seqnum. + else if (request.method === JsSIP_C.INVITE) { + this._ack_seqnum = request.cseq; + } + this._owner.receiveRequest(request); + } + + // RFC 3261 12.2.1.1. + }, { + key: "_createRequest", + value: function _createRequest(method, extraHeaders, body) { + extraHeaders = Utils.cloneArray(extraHeaders); + if (!this._local_seqnum) { + this._local_seqnum = Math.floor(Math.random() * 10000); + } + var cseq = method === JsSIP_C.CANCEL || method === JsSIP_C.ACK ? this._local_seqnum : this._local_seqnum += 1; + var request = new SIPMessage.OutgoingRequest(method, this._remote_target, this._ua, { + 'cseq': cseq, + 'call_id': this._id.call_id, + 'from_uri': this._local_uri, + 'from_tag': this._id.local_tag, + 'to_uri': this._remote_uri, + 'to_tag': this._id.remote_tag, + 'route_set': this._route_set + }, extraHeaders, body); + return request; + } + + // RFC 3261 12.2.2. + }, { + key: "_checkInDialogRequest", + value: function _checkInDialogRequest(request) { + var _this2 = this; + if (!this._remote_seqnum) { + this._remote_seqnum = request.cseq; + } else if (request.cseq < this._remote_seqnum) { + if (request.method === JsSIP_C.ACK) { + // We are not expecting any ACK with lower seqnum than the current one. + // Or this is not the ACK we are waiting for. + if (this._ack_seqnum === null || request.cseq !== this._ack_seqnum) { + return false; + } + } else { + request.reply(500); + return false; + } + } else if (request.cseq > this._remote_seqnum) { + this._remote_seqnum = request.cseq; + } + + // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-. + if (request.method === JsSIP_C.INVITE || request.method === JsSIP_C.UPDATE && request.body) { + if (this._uac_pending_reply === true) { + request.reply(491); + } else if (this._uas_pending_reply === true) { + var retryAfter = (Math.random() * 10 | 0) + 1; + request.reply(500, null, ["Retry-After:".concat(retryAfter)]); + return false; + } else { + this._uas_pending_reply = true; + var stateChanged = function stateChanged() { + if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED || request.server_transaction.state === Transactions.C.STATUS_COMPLETED || request.server_transaction.state === Transactions.C.STATUS_TERMINATED) { + request.server_transaction.removeListener('stateChanged', stateChanged); + _this2._uas_pending_reply = false; + } + }; + request.server_transaction.on('stateChanged', stateChanged); + } + + // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted. + if (request.hasHeader('contact')) { + request.server_transaction.on('stateChanged', function () { + if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED) { + _this2._remote_target = request.parseHeader('contact').uri; + } + }); + } + } else if (request.method === JsSIP_C.NOTIFY) { + // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted. + if (request.hasHeader('contact')) { + request.server_transaction.on('stateChanged', function () { + if (request.server_transaction.state === Transactions.C.STATUS_COMPLETED) { + _this2._remote_target = request.parseHeader('contact').uri; + } + }); + } + } + return true; + } + }], [{ + key: "C", + get: + // Expose C object. + function get() { + return C; + } + }]); + return Dialog; +}(); +},{"./Constants":2,"./Dialog/RequestSender":4,"./Logger":9,"./SIPMessage":22,"./Transactions":26,"./Utils":30}],4:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var JsSIP_C = require('../Constants'); +var Transactions = require('../Transactions'); +var RequestSender = require('../RequestSender'); + +// Default event handlers. +var EventHandlers = { + onRequestTimeout: function onRequestTimeout() {}, + onTransportError: function onTransportError() {}, + onSuccessResponse: function onSuccessResponse() {}, + onErrorResponse: function onErrorResponse() {}, + onAuthenticated: function onAuthenticated() {}, + onDialogError: function onDialogError() {} +}; +module.exports = /*#__PURE__*/function () { + function DialogRequestSender(dialog, request, eventHandlers) { + _classCallCheck(this, DialogRequestSender); + this._dialog = dialog; + this._ua = dialog._ua; + this._request = request; + this._eventHandlers = eventHandlers; + + // RFC3261 14.1 Modifying an Existing Session. UAC Behavior. + this._reattempt = false; + this._reattemptTimer = null; + + // Define the undefined handlers. + for (var handler in EventHandlers) { + if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) { + if (!this._eventHandlers[handler]) { + this._eventHandlers[handler] = EventHandlers[handler]; + } + } + } + } + _createClass(DialogRequestSender, [{ + key: "request", + get: function get() { + return this._request; + } + }, { + key: "send", + value: function send() { + var _this = this; + var request_sender = new RequestSender(this._ua, this._request, { + onRequestTimeout: function onRequestTimeout() { + _this._eventHandlers.onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this._eventHandlers.onTransportError(); + }, + onAuthenticated: function onAuthenticated(request) { + _this._eventHandlers.onAuthenticated(request); + }, + onReceiveResponse: function onReceiveResponse(response) { + _this._receiveResponse(response); + } + }); + request_sender.send(); + + // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR-. + if ((this._request.method === JsSIP_C.INVITE || this._request.method === JsSIP_C.UPDATE && this._request.body) && request_sender.clientTransaction.state !== Transactions.C.STATUS_TERMINATED) { + this._dialog.uac_pending_reply = true; + var stateChanged = function stateChanged() { + if (request_sender.clientTransaction.state === Transactions.C.STATUS_ACCEPTED || request_sender.clientTransaction.state === Transactions.C.STATUS_COMPLETED || request_sender.clientTransaction.state === Transactions.C.STATUS_TERMINATED) { + request_sender.clientTransaction.removeListener('stateChanged', stateChanged); + _this._dialog.uac_pending_reply = false; + } + }; + request_sender.clientTransaction.on('stateChanged', stateChanged); + } + } + }, { + key: "_receiveResponse", + value: function _receiveResponse(response) { + var _this2 = this; + // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog. + if (response.status_code === 408 || response.status_code === 481) { + this._eventHandlers.onDialogError(response); + } else if (response.method === JsSIP_C.INVITE && response.status_code === 491) { + if (this._reattempt) { + if (response.status_code >= 200 && response.status_code < 300) { + this._eventHandlers.onSuccessResponse(response); + } else if (response.status_code >= 300) { + this._eventHandlers.onErrorResponse(response); + } + } else { + this._request.cseq = this._dialog.local_seqnum += 1; + this._reattemptTimer = setTimeout(function () { + if (!_this2._dialog.isTerminated()) { + _this2._reattempt = true; + _this2.send(); + } + }, 1000); + } + } else if (response.status_code >= 200 && response.status_code < 300) { + this._eventHandlers.onSuccessResponse(response); + } else if (response.status_code >= 300) { + this._eventHandlers.onErrorResponse(response); + } + } + }]); + return DialogRequestSender; +}(); +},{"../Constants":2,"../RequestSender":21,"../Transactions":26}],5:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var Logger = require('./Logger'); +var Utils = require('./Utils'); +var logger = new Logger('DigestAuthentication'); +module.exports = /*#__PURE__*/function () { + function DigestAuthentication(credentials) { + _classCallCheck(this, DigestAuthentication); + this._credentials = credentials; + this._cnonce = null; + this._nc = 0; + this._ncHex = '00000000'; + this._algorithm = null; + this._realm = null; + this._nonce = null; + this._opaque = null; + this._stale = null; + this._qop = null; + this._method = null; + this._uri = null; + this._ha1 = null; + this._response = null; + } + _createClass(DigestAuthentication, [{ + key: "get", + value: function get(parameter) { + switch (parameter) { + case 'realm': + return this._realm; + case 'ha1': + return this._ha1; + default: + logger.warn('get() | cannot get "%s" parameter', parameter); + return undefined; + } + } + + /** + * Performs Digest authentication given a SIP request and the challenge + * received in a response to that request. + * Returns true if auth was successfully generated, false otherwise. + */ + }, { + key: "authenticate", + value: function authenticate(_ref, challenge) { + var method = _ref.method, + ruri = _ref.ruri, + body = _ref.body; + var cnonce = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + this._algorithm = challenge.algorithm; + this._realm = challenge.realm; + this._nonce = challenge.nonce; + this._opaque = challenge.opaque; + this._stale = challenge.stale; + if (this._algorithm) { + if (this._algorithm !== 'MD5') { + logger.warn('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted'); + return false; + } + } else { + this._algorithm = 'MD5'; + } + if (!this._nonce) { + logger.warn('authenticate() | challenge without Digest nonce, authentication aborted'); + return false; + } + if (!this._realm) { + logger.warn('authenticate() | challenge without Digest realm, authentication aborted'); + return false; + } + + // If no plain SIP password is provided. + if (!this._credentials.password) { + // If ha1 is not provided we cannot authenticate. + if (!this._credentials.ha1) { + logger.warn('authenticate() | no plain SIP password nor ha1 provided, authentication aborted'); + return false; + } + + // If the realm does not match the stored realm we cannot authenticate. + if (this._credentials.realm !== this._realm) { + logger.warn('authenticate() | no plain SIP password, and stored `realm` does not match the given `realm`, cannot authenticate [stored:"%s", given:"%s"]', this._credentials.realm, this._realm); + return false; + } + } + + // 'qop' can contain a list of values (Array). Let's choose just one. + if (challenge.qop) { + if (challenge.qop.indexOf('auth-int') > -1) { + this._qop = 'auth-int'; + } else if (challenge.qop.indexOf('auth') > -1) { + this._qop = 'auth'; + } else { + // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here. + logger.warn('authenticate() | challenge without Digest qop different than "auth" or "auth-int", authentication aborted'); + return false; + } + } else { + this._qop = null; + } + + // Fill other attributes. + + this._method = method; + this._uri = ruri; + this._cnonce = cnonce || Utils.createRandomToken(12); + this._nc += 1; + var hex = Number(this._nc).toString(16); + this._ncHex = '00000000'.substr(0, 8 - hex.length) + hex; + + // Nc-value = 8LHEX. Max value = 'FFFFFFFF'. + if (this._nc === 4294967296) { + this._nc = 1; + this._ncHex = '00000001'; + } + + // Calculate the Digest "response" value. + + // If we have plain SIP password then regenerate ha1. + if (this._credentials.password) { + // HA1 = MD5(A1) = MD5(username:realm:password). + this._ha1 = Utils.calculateMD5("".concat(this._credentials.username, ":").concat(this._realm, ":").concat(this._credentials.password)); + } + // Otherwise reuse the stored ha1. + else { + this._ha1 = this._credentials.ha1; + } + var a2; + var ha2; + if (this._qop === 'auth') { + // HA2 = MD5(A2) = MD5(method:digestURI). + a2 = "".concat(this._method, ":").concat(this._uri); + ha2 = Utils.calculateMD5(a2); + logger.debug('authenticate() | using qop=auth [a2:"%s"]', a2); + + // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2). + this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth:").concat(ha2)); + } else if (this._qop === 'auth-int') { + // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody)). + a2 = "".concat(this._method, ":").concat(this._uri, ":").concat(Utils.calculateMD5(body ? body : '')); + ha2 = Utils.calculateMD5(a2); + logger.debug('authenticate() | using qop=auth-int [a2:"%s"]', a2); + + // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2). + this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth-int:").concat(ha2)); + } else if (this._qop === null) { + // HA2 = MD5(A2) = MD5(method:digestURI). + a2 = "".concat(this._method, ":").concat(this._uri); + ha2 = Utils.calculateMD5(a2); + logger.debug('authenticate() | using qop=null [a2:"%s"]', a2); + + // Response = MD5(HA1:nonce:HA2). + this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(ha2)); + } + logger.debug('authenticate() | response generated'); + return true; + } + + /** + * Return the Proxy-Authorization or WWW-Authorization header value. + */ + }, { + key: "toString", + value: function toString() { + var auth_params = []; + if (!this._response) { + throw new Error('response field does not exist, cannot generate Authorization header'); + } + auth_params.push("algorithm=".concat(this._algorithm)); + auth_params.push("username=\"".concat(this._credentials.username, "\"")); + auth_params.push("realm=\"".concat(this._realm, "\"")); + auth_params.push("nonce=\"".concat(this._nonce, "\"")); + auth_params.push("uri=\"".concat(this._uri, "\"")); + auth_params.push("response=\"".concat(this._response, "\"")); + if (this._opaque) { + auth_params.push("opaque=\"".concat(this._opaque, "\"")); + } + if (this._qop) { + auth_params.push("qop=".concat(this._qop)); + auth_params.push("cnonce=\"".concat(this._cnonce, "\"")); + auth_params.push("nc=".concat(this._ncHex)); + } + return "Digest ".concat(auth_params.join(', ')); + } + }]); + return DigestAuthentication; +}(); +},{"./Logger":9,"./Utils":30}],6:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); } +function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct.bind(); } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var ConfigurationError = /*#__PURE__*/function (_Error) { + _inherits(ConfigurationError, _Error); + var _super = _createSuper(ConfigurationError); + function ConfigurationError(parameter, value) { + var _this; + _classCallCheck(this, ConfigurationError); + _this = _super.call(this); + _this.code = 1; + _this.name = 'CONFIGURATION_ERROR'; + _this.parameter = parameter; + _this.value = value; + _this.message = !_this.value ? "Missing parameter: ".concat(_this.parameter) : "Invalid value ".concat(JSON.stringify(_this.value), " for parameter \"").concat(_this.parameter, "\""); + return _this; + } + return _createClass(ConfigurationError); +}( /*#__PURE__*/_wrapNativeSuper(Error)); +var InvalidStateError = /*#__PURE__*/function (_Error2) { + _inherits(InvalidStateError, _Error2); + var _super2 = _createSuper(InvalidStateError); + function InvalidStateError(status) { + var _this2; + _classCallCheck(this, InvalidStateError); + _this2 = _super2.call(this); + _this2.code = 2; + _this2.name = 'INVALID_STATE_ERROR'; + _this2.status = status; + _this2.message = "Invalid status: ".concat(status); + return _this2; + } + return _createClass(InvalidStateError); +}( /*#__PURE__*/_wrapNativeSuper(Error)); +var NotSupportedError = /*#__PURE__*/function (_Error3) { + _inherits(NotSupportedError, _Error3); + var _super3 = _createSuper(NotSupportedError); + function NotSupportedError(message) { + var _this3; + _classCallCheck(this, NotSupportedError); + _this3 = _super3.call(this); + _this3.code = 3; + _this3.name = 'NOT_SUPPORTED_ERROR'; + _this3.message = message; + return _this3; + } + return _createClass(NotSupportedError); +}( /*#__PURE__*/_wrapNativeSuper(Error)); +var NotReadyError = /*#__PURE__*/function (_Error4) { + _inherits(NotReadyError, _Error4); + var _super4 = _createSuper(NotReadyError); + function NotReadyError(message) { + var _this4; + _classCallCheck(this, NotReadyError); + _this4 = _super4.call(this); + _this4.code = 4; + _this4.name = 'NOT_READY_ERROR'; + _this4.message = message; + return _this4; + } + return _createClass(NotReadyError); +}( /*#__PURE__*/_wrapNativeSuper(Error)); +module.exports = { + ConfigurationError: ConfigurationError, + InvalidStateError: InvalidStateError, + NotSupportedError: NotSupportedError, + NotReadyError: NotReadyError +}; +},{}],7:[function(require,module,exports){ +"use strict"; + +module.exports = function () { + /* + * Generated by PEG.js 0.7.0. + * + * http://pegjs.majda.cz/ + */ + function quote(s) { + /* + * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a + * string literal except for the closing quote character, backslash, + * carriage return, line separator, paragraph separator, and line feed. + * Any character may appear in the form of an escape sequence. + * + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used + * because JSHint does not like the first and IE the second. + */ + return '"' + s.replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; + } + var result = { + /* + * Parses the input with a generated parser. If the parsing is successfull, + * returns a value explicitly or implicitly specified by the grammar from + * which the parser was generated (see |PEG.buildParser|). If the parsing is + * unsuccessful, throws |PEG.parser.SyntaxError| describing the error. + */ + parse: function parse(input, startRule) { + var parseFunctions = { + "CRLF": parse_CRLF, + "DIGIT": parse_DIGIT, + "ALPHA": parse_ALPHA, + "HEXDIG": parse_HEXDIG, + "WSP": parse_WSP, + "OCTET": parse_OCTET, + "DQUOTE": parse_DQUOTE, + "SP": parse_SP, + "HTAB": parse_HTAB, + "alphanum": parse_alphanum, + "reserved": parse_reserved, + "unreserved": parse_unreserved, + "mark": parse_mark, + "escaped": parse_escaped, + "LWS": parse_LWS, + "SWS": parse_SWS, + "HCOLON": parse_HCOLON, + "TEXT_UTF8_TRIM": parse_TEXT_UTF8_TRIM, + "TEXT_UTF8char": parse_TEXT_UTF8char, + "UTF8_NONASCII": parse_UTF8_NONASCII, + "UTF8_CONT": parse_UTF8_CONT, + "LHEX": parse_LHEX, + "token": parse_token, + "token_nodot": parse_token_nodot, + "separators": parse_separators, + "word": parse_word, + "STAR": parse_STAR, + "SLASH": parse_SLASH, + "EQUAL": parse_EQUAL, + "LPAREN": parse_LPAREN, + "RPAREN": parse_RPAREN, + "RAQUOT": parse_RAQUOT, + "LAQUOT": parse_LAQUOT, + "COMMA": parse_COMMA, + "SEMI": parse_SEMI, + "COLON": parse_COLON, + "LDQUOT": parse_LDQUOT, + "RDQUOT": parse_RDQUOT, + "comment": parse_comment, + "ctext": parse_ctext, + "quoted_string": parse_quoted_string, + "quoted_string_clean": parse_quoted_string_clean, + "qdtext": parse_qdtext, + "quoted_pair": parse_quoted_pair, + "SIP_URI_noparams": parse_SIP_URI_noparams, + "SIP_URI": parse_SIP_URI, + "uri_scheme": parse_uri_scheme, + "uri_scheme_sips": parse_uri_scheme_sips, + "uri_scheme_sip": parse_uri_scheme_sip, + "userinfo": parse_userinfo, + "user": parse_user, + "user_unreserved": parse_user_unreserved, + "password": parse_password, + "hostport": parse_hostport, + "host": parse_host, + "hostname": parse_hostname, + "domainlabel": parse_domainlabel, + "toplabel": parse_toplabel, + "IPv6reference": parse_IPv6reference, + "IPv6address": parse_IPv6address, + "h16": parse_h16, + "ls32": parse_ls32, + "IPv4address": parse_IPv4address, + "dec_octet": parse_dec_octet, + "port": parse_port, + "uri_parameters": parse_uri_parameters, + "uri_parameter": parse_uri_parameter, + "transport_param": parse_transport_param, + "user_param": parse_user_param, + "method_param": parse_method_param, + "ttl_param": parse_ttl_param, + "maddr_param": parse_maddr_param, + "lr_param": parse_lr_param, + "other_param": parse_other_param, + "pname": parse_pname, + "pvalue": parse_pvalue, + "paramchar": parse_paramchar, + "param_unreserved": parse_param_unreserved, + "headers": parse_headers, + "header": parse_header, + "hname": parse_hname, + "hvalue": parse_hvalue, + "hnv_unreserved": parse_hnv_unreserved, + "Request_Response": parse_Request_Response, + "Request_Line": parse_Request_Line, + "Request_URI": parse_Request_URI, + "absoluteURI": parse_absoluteURI, + "hier_part": parse_hier_part, + "net_path": parse_net_path, + "abs_path": parse_abs_path, + "opaque_part": parse_opaque_part, + "uric": parse_uric, + "uric_no_slash": parse_uric_no_slash, + "path_segments": parse_path_segments, + "segment": parse_segment, + "param": parse_param, + "pchar": parse_pchar, + "scheme": parse_scheme, + "authority": parse_authority, + "srvr": parse_srvr, + "reg_name": parse_reg_name, + "query": parse_query, + "SIP_Version": parse_SIP_Version, + "INVITEm": parse_INVITEm, + "ACKm": parse_ACKm, + "OPTIONSm": parse_OPTIONSm, + "BYEm": parse_BYEm, + "CANCELm": parse_CANCELm, + "REGISTERm": parse_REGISTERm, + "SUBSCRIBEm": parse_SUBSCRIBEm, + "NOTIFYm": parse_NOTIFYm, + "REFERm": parse_REFERm, + "Method": parse_Method, + "Status_Line": parse_Status_Line, + "Status_Code": parse_Status_Code, + "extension_code": parse_extension_code, + "Reason_Phrase": parse_Reason_Phrase, + "Allow_Events": parse_Allow_Events, + "Call_ID": parse_Call_ID, + "Contact": parse_Contact, + "contact_param": parse_contact_param, + "name_addr": parse_name_addr, + "display_name": parse_display_name, + "contact_params": parse_contact_params, + "c_p_q": parse_c_p_q, + "c_p_expires": parse_c_p_expires, + "delta_seconds": parse_delta_seconds, + "qvalue": parse_qvalue, + "generic_param": parse_generic_param, + "gen_value": parse_gen_value, + "Content_Disposition": parse_Content_Disposition, + "disp_type": parse_disp_type, + "disp_param": parse_disp_param, + "handling_param": parse_handling_param, + "Content_Encoding": parse_Content_Encoding, + "Content_Length": parse_Content_Length, + "Content_Type": parse_Content_Type, + "media_type": parse_media_type, + "m_type": parse_m_type, + "discrete_type": parse_discrete_type, + "composite_type": parse_composite_type, + "extension_token": parse_extension_token, + "x_token": parse_x_token, + "m_subtype": parse_m_subtype, + "m_parameter": parse_m_parameter, + "m_value": parse_m_value, + "CSeq": parse_CSeq, + "CSeq_value": parse_CSeq_value, + "Expires": parse_Expires, + "Event": parse_Event, + "event_type": parse_event_type, + "From": parse_From, + "from_param": parse_from_param, + "tag_param": parse_tag_param, + "Max_Forwards": parse_Max_Forwards, + "Min_Expires": parse_Min_Expires, + "Name_Addr_Header": parse_Name_Addr_Header, + "Proxy_Authenticate": parse_Proxy_Authenticate, + "challenge": parse_challenge, + "other_challenge": parse_other_challenge, + "auth_param": parse_auth_param, + "digest_cln": parse_digest_cln, + "realm": parse_realm, + "realm_value": parse_realm_value, + "domain": parse_domain, + "URI": parse_URI, + "nonce": parse_nonce, + "nonce_value": parse_nonce_value, + "opaque": parse_opaque, + "stale": parse_stale, + "algorithm": parse_algorithm, + "qop_options": parse_qop_options, + "qop_value": parse_qop_value, + "Proxy_Require": parse_Proxy_Require, + "Record_Route": parse_Record_Route, + "rec_route": parse_rec_route, + "Reason": parse_Reason, + "reason_param": parse_reason_param, + "reason_cause": parse_reason_cause, + "Require": parse_Require, + "Route": parse_Route, + "route_param": parse_route_param, + "Subscription_State": parse_Subscription_State, + "substate_value": parse_substate_value, + "subexp_params": parse_subexp_params, + "event_reason_value": parse_event_reason_value, + "Subject": parse_Subject, + "Supported": parse_Supported, + "To": parse_To, + "to_param": parse_to_param, + "Via": parse_Via, + "via_param": parse_via_param, + "via_params": parse_via_params, + "via_ttl": parse_via_ttl, + "via_maddr": parse_via_maddr, + "via_received": parse_via_received, + "via_branch": parse_via_branch, + "response_port": parse_response_port, + "rport": parse_rport, + "sent_protocol": parse_sent_protocol, + "protocol_name": parse_protocol_name, + "transport": parse_transport, + "sent_by": parse_sent_by, + "via_host": parse_via_host, + "via_port": parse_via_port, + "ttl": parse_ttl, + "WWW_Authenticate": parse_WWW_Authenticate, + "Session_Expires": parse_Session_Expires, + "s_e_expires": parse_s_e_expires, + "s_e_params": parse_s_e_params, + "s_e_refresher": parse_s_e_refresher, + "extension_header": parse_extension_header, + "header_value": parse_header_value, + "message_body": parse_message_body, + "uuid_URI": parse_uuid_URI, + "uuid": parse_uuid, + "hex4": parse_hex4, + "hex8": parse_hex8, + "hex12": parse_hex12, + "Refer_To": parse_Refer_To, + "Replaces": parse_Replaces, + "call_id": parse_call_id, + "replaces_param": parse_replaces_param, + "to_tag": parse_to_tag, + "from_tag": parse_from_tag, + "early_flag": parse_early_flag + }; + if (startRule !== undefined) { + if (parseFunctions[startRule] === undefined) { + throw new Error("Invalid rule name: " + quote(startRule) + "."); + } + } else { + startRule = "CRLF"; + } + var pos = 0; + var reportFailures = 0; + var rightmostFailuresPos = 0; + var rightmostFailuresExpected = []; + function padLeft(input, padding, length) { + var result = input; + var padLength = length - input.length; + for (var i = 0; i < padLength; i++) { + result = padding + result; + } + return result; + } + function escape(ch) { + var charCode = ch.charCodeAt(0); + var escapeChar; + var length; + if (charCode <= 0xFF) { + escapeChar = 'x'; + length = 2; + } else { + escapeChar = 'u'; + length = 4; + } + return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length); + } + function matchFailed(failure) { + if (pos < rightmostFailuresPos) { + return; + } + if (pos > rightmostFailuresPos) { + rightmostFailuresPos = pos; + rightmostFailuresExpected = []; + } + rightmostFailuresExpected.push(failure); + } + function parse_CRLF() { + var result0; + if (input.substr(pos, 2) === "\r\n") { + result0 = "\r\n"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\r\\n\""); + } + } + return result0; + } + function parse_DIGIT() { + var result0; + if (/^[0-9]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[0-9]"); + } + } + return result0; + } + function parse_ALPHA() { + var result0; + if (/^[a-zA-Z]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[a-zA-Z]"); + } + } + return result0; + } + function parse_HEXDIG() { + var result0; + if (/^[0-9a-fA-F]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[0-9a-fA-F]"); + } + } + return result0; + } + function parse_WSP() { + var result0; + result0 = parse_SP(); + if (result0 === null) { + result0 = parse_HTAB(); + } + return result0; + } + function parse_OCTET() { + var result0; + if (/^[\0-\xFF]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[\\0-\\xFF]"); + } + } + return result0; + } + function parse_DQUOTE() { + var result0; + if (/^["]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[\"]"); + } + } + return result0; + } + function parse_SP() { + var result0; + if (input.charCodeAt(pos) === 32) { + result0 = " "; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\" \""); + } + } + return result0; + } + function parse_HTAB() { + var result0; + if (input.charCodeAt(pos) === 9) { + result0 = "\t"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\t\""); + } + } + return result0; + } + function parse_alphanum() { + var result0; + if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[a-zA-Z0-9]"); + } + } + return result0; + } + function parse_reserved() { + var result0; + if (input.charCodeAt(pos) === 59) { + result0 = ";"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 47) { + result0 = "/"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 63) { + result0 = "?"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 58) { + result0 = ":"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 64) { + result0 = "@"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 38) { + result0 = "&"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 61) { + result0 = "="; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 43) { + result0 = "+"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 36) { + result0 = "$"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 44) { + result0 = ","; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + } + } + } + } + } + } + } + } + } + return result0; + } + function parse_unreserved() { + var result0; + result0 = parse_alphanum(); + if (result0 === null) { + result0 = parse_mark(); + } + return result0; + } + function parse_mark() { + var result0; + if (input.charCodeAt(pos) === 45) { + result0 = "-"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 95) { + result0 = "_"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 46) { + result0 = "."; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 33) { + result0 = "!"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 126) { + result0 = "~"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 42) { + result0 = "*"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 39) { + result0 = "'"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 40) { + result0 = "("; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"(\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 41) { + result0 = ")"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + } + } + } + } + } + } + } + } + return result0; + } + function parse_escaped() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 37) { + result0 = "%"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"%\""); + } + } + if (result0 !== null) { + result1 = parse_HEXDIG(); + if (result1 !== null) { + result2 = parse_HEXDIG(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, escaped) { + return escaped.join(''); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_LWS() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + pos2 = pos; + result0 = []; + result1 = parse_WSP(); + while (result1 !== null) { + result0.push(result1); + result1 = parse_WSP(); + } + if (result0 !== null) { + result1 = parse_CRLF(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos2; + } + } else { + result0 = null; + pos = pos2; + } + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result2 = parse_WSP(); + if (result2 !== null) { + result1 = []; + while (result2 !== null) { + result1.push(result2); + result2 = parse_WSP(); + } + } else { + result1 = null; + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return " "; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_SWS() { + var result0; + result0 = parse_LWS(); + result0 = result0 !== null ? result0 : ""; + return result0; + } + function parse_HCOLON() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = []; + result1 = parse_SP(); + if (result1 === null) { + result1 = parse_HTAB(); + } + while (result1 !== null) { + result0.push(result1); + result1 = parse_SP(); + if (result1 === null) { + result1 = parse_HTAB(); + } + } + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return ':'; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_TEXT_UTF8_TRIM() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result1 = parse_TEXT_UTF8char(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_TEXT_UTF8char(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = []; + result3 = parse_LWS(); + while (result3 !== null) { + result2.push(result3); + result3 = parse_LWS(); + } + if (result2 !== null) { + result3 = parse_TEXT_UTF8char(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = []; + result3 = parse_LWS(); + while (result3 !== null) { + result2.push(result3); + result3 = parse_LWS(); + } + if (result2 !== null) { + result3 = parse_TEXT_UTF8char(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_TEXT_UTF8char() { + var result0; + if (/^[!-~]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[!-~]"); + } + } + if (result0 === null) { + result0 = parse_UTF8_NONASCII(); + } + return result0; + } + function parse_UTF8_NONASCII() { + var result0; + if (/^[\x80-\uFFFF]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[\\x80-\\uFFFF]"); + } + } + return result0; + } + function parse_UTF8_CONT() { + var result0; + if (/^[\x80-\xBF]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[\\x80-\\xBF]"); + } + } + return result0; + } + function parse_LHEX() { + var result0; + result0 = parse_DIGIT(); + if (result0 === null) { + if (/^[a-f]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[a-f]"); + } + } + } + return result0; + } + function parse_token() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_alphanum(); + if (result1 === null) { + if (input.charCodeAt(pos) === 45) { + result1 = "-"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 33) { + result1 = "!"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 37) { + result1 = "%"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"%\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 42) { + result1 = "*"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 95) { + result1 = "_"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 96) { + result1 = "`"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"`\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 39) { + result1 = "'"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 126) { + result1 = "~"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + } + } + } + } + } + } + } + } + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_alphanum(); + if (result1 === null) { + if (input.charCodeAt(pos) === 45) { + result1 = "-"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 33) { + result1 = "!"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 37) { + result1 = "%"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"%\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 42) { + result1 = "*"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 95) { + result1 = "_"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 96) { + result1 = "`"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"`\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 39) { + result1 = "'"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 126) { + result1 = "~"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + } + } + } + } + } + } + } + } + } + } + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset) { + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_token_nodot() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_alphanum(); + if (result1 === null) { + if (input.charCodeAt(pos) === 45) { + result1 = "-"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 33) { + result1 = "!"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 37) { + result1 = "%"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"%\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 42) { + result1 = "*"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 95) { + result1 = "_"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 96) { + result1 = "`"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"`\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 39) { + result1 = "'"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 126) { + result1 = "~"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + } + } + } + } + } + } + } + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_alphanum(); + if (result1 === null) { + if (input.charCodeAt(pos) === 45) { + result1 = "-"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 33) { + result1 = "!"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 37) { + result1 = "%"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"%\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 42) { + result1 = "*"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 95) { + result1 = "_"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 96) { + result1 = "`"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"`\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 39) { + result1 = "'"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 126) { + result1 = "~"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + } + } + } + } + } + } + } + } + } + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset) { + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_separators() { + var result0; + if (input.charCodeAt(pos) === 40) { + result0 = "("; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"(\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 41) { + result0 = ")"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 60) { + result0 = "<"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"<\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 62) { + result0 = ">"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\">\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 64) { + result0 = "@"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 44) { + result0 = ","; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 59) { + result0 = ";"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 58) { + result0 = ":"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 92) { + result0 = "\\"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result0 === null) { + result0 = parse_DQUOTE(); + if (result0 === null) { + if (input.charCodeAt(pos) === 47) { + result0 = "/"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 91) { + result0 = "["; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 93) { + result0 = "]"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 63) { + result0 = "?"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 61) { + result0 = "="; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 123) { + result0 = "{"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"{\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 125) { + result0 = "}"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"}\""); + } + } + if (result0 === null) { + result0 = parse_SP(); + if (result0 === null) { + result0 = parse_HTAB(); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + return result0; + } + function parse_word() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_alphanum(); + if (result1 === null) { + if (input.charCodeAt(pos) === 45) { + result1 = "-"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 33) { + result1 = "!"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 37) { + result1 = "%"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"%\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 42) { + result1 = "*"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 95) { + result1 = "_"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 96) { + result1 = "`"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"`\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 39) { + result1 = "'"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 126) { + result1 = "~"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 40) { + result1 = "("; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"(\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 41) { + result1 = ")"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 60) { + result1 = "<"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"<\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 62) { + result1 = ">"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\">\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 92) { + result1 = "\\"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result1 === null) { + result1 = parse_DQUOTE(); + if (result1 === null) { + if (input.charCodeAt(pos) === 47) { + result1 = "/"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 91) { + result1 = "["; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 93) { + result1 = "]"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 63) { + result1 = "?"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 123) { + result1 = "{"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"{\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 125) { + result1 = "}"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"}\""); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_alphanum(); + if (result1 === null) { + if (input.charCodeAt(pos) === 45) { + result1 = "-"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 33) { + result1 = "!"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 37) { + result1 = "%"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"%\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 42) { + result1 = "*"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 95) { + result1 = "_"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 96) { + result1 = "`"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"`\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 39) { + result1 = "'"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"'\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 126) { + result1 = "~"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"~\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 40) { + result1 = "("; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"(\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 41) { + result1 = ")"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 60) { + result1 = "<"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"<\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 62) { + result1 = ">"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\">\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 92) { + result1 = "\\"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result1 === null) { + result1 = parse_DQUOTE(); + if (result1 === null) { + if (input.charCodeAt(pos) === 47) { + result1 = "/"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 91) { + result1 = "["; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 93) { + result1 = "]"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 63) { + result1 = "?"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 123) { + result1 = "{"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"{\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 125) { + result1 = "}"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"}\""); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset) { + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_STAR() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 42) { + result1 = "*"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"*\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return "*"; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_SLASH() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 47) { + result1 = "/"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return "/"; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_EQUAL() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return "="; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_LPAREN() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 40) { + result1 = "("; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"(\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return "("; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_RPAREN() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 41) { + result1 = ")"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\")\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return ")"; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_RAQUOT() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 62) { + result0 = ">"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\">\""); + } + } + if (result0 !== null) { + result1 = parse_SWS(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return ">"; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_LAQUOT() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 60) { + result1 = "<"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"<\""); + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return "<"; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_COMMA() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 44) { + result1 = ","; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return ","; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_SEMI() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 59) { + result1 = ";"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return ";"; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_COLON() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_SWS(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return ":"; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_LDQUOT() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + result1 = parse_DQUOTE(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return "\""; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_RDQUOT() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_DQUOTE(); + if (result0 !== null) { + result1 = parse_SWS(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return "\""; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_comment() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_LPAREN(); + if (result0 !== null) { + result1 = []; + result2 = parse_ctext(); + if (result2 === null) { + result2 = parse_quoted_pair(); + if (result2 === null) { + result2 = parse_comment(); + } + } + while (result2 !== null) { + result1.push(result2); + result2 = parse_ctext(); + if (result2 === null) { + result2 = parse_quoted_pair(); + if (result2 === null) { + result2 = parse_comment(); + } + } + } + if (result1 !== null) { + result2 = parse_RPAREN(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_ctext() { + var result0; + if (/^[!-']/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[!-']"); + } + } + if (result0 === null) { + if (/^[*-[]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[*-[]"); + } + } + if (result0 === null) { + if (/^[\]-~]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[\\]-~]"); + } + } + if (result0 === null) { + result0 = parse_UTF8_NONASCII(); + if (result0 === null) { + result0 = parse_LWS(); + } + } + } + } + return result0; + } + function parse_quoted_string() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + result1 = parse_DQUOTE(); + if (result1 !== null) { + result2 = []; + result3 = parse_qdtext(); + if (result3 === null) { + result3 = parse_quoted_pair(); + } + while (result3 !== null) { + result2.push(result3); + result3 = parse_qdtext(); + if (result3 === null) { + result3 = parse_quoted_pair(); + } + } + if (result2 !== null) { + result3 = parse_DQUOTE(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_quoted_string_clean() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_SWS(); + if (result0 !== null) { + result1 = parse_DQUOTE(); + if (result1 !== null) { + result2 = []; + result3 = parse_qdtext(); + if (result3 === null) { + result3 = parse_quoted_pair(); + } + while (result3 !== null) { + result2.push(result3); + result3 = parse_qdtext(); + if (result3 === null) { + result3 = parse_quoted_pair(); + } + } + if (result2 !== null) { + result3 = parse_DQUOTE(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + var trimmed = input.substring(pos, offset).trim(); + return trimmed.substring(1, trimmed.length - 1) // remove outer quotes + .replace(/\\([\x00-\x09\x0b-\x0c\x0e-\x7f])/g, '$1'); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_qdtext() { + var result0; + result0 = parse_LWS(); + if (result0 === null) { + if (input.charCodeAt(pos) === 33) { + result0 = "!"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"!\""); + } + } + if (result0 === null) { + if (/^[#-[]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[#-[]"); + } + } + if (result0 === null) { + if (/^[\]-~]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[\\]-~]"); + } + } + if (result0 === null) { + result0 = parse_UTF8_NONASCII(); + } + } + } + } + return result0; + } + function parse_quoted_pair() { + var result0, result1; + var pos0; + pos0 = pos; + if (input.charCodeAt(pos) === 92) { + result0 = "\\"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"\\\\\""); + } + } + if (result0 !== null) { + if (/^[\0-\t]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[\\0-\\t]"); + } + } + if (result1 === null) { + if (/^[\x0B-\f]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[\\x0B-\\f]"); + } + } + if (result1 === null) { + if (/^[\x0E-]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[\\x0E-]"); + } + } + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_SIP_URI_noparams() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_uri_scheme(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_userinfo(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result3 = parse_hostport(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + try { + data.uri = new URI(data.scheme, data.user, data.host, data.port); + delete data.scheme; + delete data.user; + delete data.host; + delete data.host_type; + delete data.port; + } catch (e) { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_SIP_URI() { + var result0, result1, result2, result3, result4, result5; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_uri_scheme(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_userinfo(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result3 = parse_hostport(); + if (result3 !== null) { + result4 = parse_uri_parameters(); + if (result4 !== null) { + result5 = parse_headers(); + result5 = result5 !== null ? result5 : ""; + if (result5 !== null) { + result0 = [result0, result1, result2, result3, result4, result5]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + var header; + try { + data.uri = new URI(data.scheme, data.user, data.host, data.port, data.uri_params, data.uri_headers); + delete data.scheme; + delete data.user; + delete data.host; + delete data.host_type; + delete data.port; + delete data.uri_params; + if (startRule === 'SIP_URI') { + data = data.uri; + } + } catch (e) { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_uri_scheme() { + var result0; + result0 = parse_uri_scheme_sips(); + if (result0 === null) { + result0 = parse_uri_scheme_sip(); + } + return result0; + } + function parse_uri_scheme_sips() { + var result0; + var pos0; + pos0 = pos; + if (input.substr(pos, 4).toLowerCase() === "sips") { + result0 = input.substr(pos, 4); + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"sips\""); + } + } + if (result0 !== null) { + result0 = function (offset, scheme) { + data.scheme = scheme.toLowerCase(); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_uri_scheme_sip() { + var result0; + var pos0; + pos0 = pos; + if (input.substr(pos, 3).toLowerCase() === "sip") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"sip\""); + } + } + if (result0 !== null) { + result0 = function (offset, scheme) { + data.scheme = scheme.toLowerCase(); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_userinfo() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_user(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_password(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + if (input.charCodeAt(pos) === 64) { + result2 = "@"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data.user = decodeURIComponent(input.substring(pos - 1, offset)); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_user() { + var result0, result1; + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + result1 = parse_user_unreserved(); + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + result1 = parse_user_unreserved(); + } + } + } + } else { + result0 = null; + } + return result0; + } + function parse_user_unreserved() { + var result0; + if (input.charCodeAt(pos) === 38) { + result0 = "&"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 61) { + result0 = "="; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 43) { + result0 = "+"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 36) { + result0 = "$"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 44) { + result0 = ","; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 59) { + result0 = ";"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 63) { + result0 = "?"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 47) { + result0 = "/"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + } + } + } + } + } + } + } + return result0; + } + function parse_password() { + var result0, result1; + var pos0; + pos0 = pos; + result0 = []; + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + if (input.charCodeAt(pos) === 38) { + result1 = "&"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 36) { + result1 = "$"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 44) { + result1 = ","; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + } + } + } + } + } + } + while (result1 !== null) { + result0.push(result1); + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + if (input.charCodeAt(pos) === 38) { + result1 = "&"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 36) { + result1 = "$"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 44) { + result1 = ","; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + } + } + } + } + } + } + } + if (result0 !== null) { + result0 = function (offset) { + data.password = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_hostport() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + result0 = parse_host(); + if (result0 !== null) { + pos1 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_port(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos1; + } + } else { + result1 = null; + pos = pos1; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_host() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_hostname(); + if (result0 === null) { + result0 = parse_IPv4address(); + if (result0 === null) { + result0 = parse_IPv6reference(); + } + } + if (result0 !== null) { + result0 = function (offset) { + data.host = input.substring(pos, offset).toLowerCase(); + return data.host; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_hostname() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = []; + pos2 = pos; + result1 = parse_domainlabel(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 46) { + result2 = "."; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + while (result1 !== null) { + result0.push(result1); + pos2 = pos; + result1 = parse_domainlabel(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 46) { + result2 = "."; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + } + if (result0 !== null) { + result1 = parse_toplabel(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 46) { + result2 = "."; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data.host_type = 'domain'; + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_domainlabel() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_alphanum(); + if (result0 !== null) { + result1 = []; + result2 = parse_alphanum(); + if (result2 === null) { + if (input.charCodeAt(pos) === 45) { + result2 = "-"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 95) { + result2 = "_"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + } + } + while (result2 !== null) { + result1.push(result2); + result2 = parse_alphanum(); + if (result2 === null) { + if (input.charCodeAt(pos) === 45) { + result2 = "-"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 95) { + result2 = "_"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + } + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_toplabel() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_ALPHA(); + if (result0 !== null) { + result1 = []; + result2 = parse_alphanum(); + if (result2 === null) { + if (input.charCodeAt(pos) === 45) { + result2 = "-"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 95) { + result2 = "_"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + } + } + while (result2 !== null) { + result1.push(result2); + result2 = parse_alphanum(); + if (result2 === null) { + if (input.charCodeAt(pos) === 45) { + result2 = "-"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 95) { + result2 = "_"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"_\""); + } + } + } + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_IPv6reference() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 91) { + result0 = "["; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result0 !== null) { + result1 = parse_IPv6address(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 93) { + result2 = "]"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data.host_type = 'IPv6'; + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_IPv6address() { + var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 58) { + result3 = ":"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result3 !== null) { + result4 = parse_h16(); + if (result4 !== null) { + if (input.charCodeAt(pos) === 58) { + result5 = ":"; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result5 !== null) { + result6 = parse_h16(); + if (result6 !== null) { + if (input.charCodeAt(pos) === 58) { + result7 = ":"; + pos++; + } else { + result7 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result7 !== null) { + result8 = parse_h16(); + if (result8 !== null) { + if (input.charCodeAt(pos) === 58) { + result9 = ":"; + pos++; + } else { + result9 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result9 !== null) { + result10 = parse_h16(); + if (result10 !== null) { + if (input.charCodeAt(pos) === 58) { + result11 = ":"; + pos++; + } else { + result11 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result11 !== null) { + result12 = parse_ls32(); + if (result12 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 2) === "::") { + result0 = "::"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result0 !== null) { + result1 = parse_h16(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + if (input.charCodeAt(pos) === 58) { + result6 = ":"; + pos++; + } else { + result6 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result6 !== null) { + result7 = parse_h16(); + if (result7 !== null) { + if (input.charCodeAt(pos) === 58) { + result8 = ":"; + pos++; + } else { + result8 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result8 !== null) { + result9 = parse_h16(); + if (result9 !== null) { + if (input.charCodeAt(pos) === 58) { + result10 = ":"; + pos++; + } else { + result10 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result10 !== null) { + result11 = parse_ls32(); + if (result11 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 2) === "::") { + result0 = "::"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result0 !== null) { + result1 = parse_h16(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + if (input.charCodeAt(pos) === 58) { + result6 = ":"; + pos++; + } else { + result6 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result6 !== null) { + result7 = parse_h16(); + if (result7 !== null) { + if (input.charCodeAt(pos) === 58) { + result8 = ":"; + pos++; + } else { + result8 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result8 !== null) { + result9 = parse_ls32(); + if (result9 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 2) === "::") { + result0 = "::"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result0 !== null) { + result1 = parse_h16(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + if (input.charCodeAt(pos) === 58) { + result6 = ":"; + pos++; + } else { + result6 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result6 !== null) { + result7 = parse_ls32(); + if (result7 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 2) === "::") { + result0 = "::"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result0 !== null) { + result1 = parse_h16(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_ls32(); + if (result5 !== null) { + result0 = [result0, result1, result2, result3, result4, result5]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 2) === "::") { + result0 = "::"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result0 !== null) { + result1 = parse_h16(); + if (result1 !== null) { + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_ls32(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 2) === "::") { + result0 = "::"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result0 !== null) { + result1 = parse_ls32(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + if (input.substr(pos, 2) === "::") { + result0 = "::"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result0 !== null) { + result1 = parse_h16(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + if (input.substr(pos, 2) === "::") { + result1 = "::"; + pos += 2; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 58) { + result3 = ":"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result3 !== null) { + result4 = parse_h16(); + if (result4 !== null) { + if (input.charCodeAt(pos) === 58) { + result5 = ":"; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result5 !== null) { + result6 = parse_h16(); + if (result6 !== null) { + if (input.charCodeAt(pos) === 58) { + result7 = ":"; + pos++; + } else { + result7 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result7 !== null) { + result8 = parse_h16(); + if (result8 !== null) { + if (input.charCodeAt(pos) === 58) { + result9 = ":"; + pos++; + } else { + result9 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result9 !== null) { + result10 = parse_ls32(); + if (result10 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + if (input.substr(pos, 2) === "::") { + result2 = "::"; + pos += 2; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + if (input.charCodeAt(pos) === 58) { + result6 = ":"; + pos++; + } else { + result6 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result6 !== null) { + result7 = parse_h16(); + if (result7 !== null) { + if (input.charCodeAt(pos) === 58) { + result8 = ":"; + pos++; + } else { + result8 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result8 !== null) { + result9 = parse_ls32(); + if (result9 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + if (input.substr(pos, 2) === "::") { + result3 = "::"; + pos += 2; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result3 !== null) { + result4 = parse_h16(); + if (result4 !== null) { + if (input.charCodeAt(pos) === 58) { + result5 = ":"; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result5 !== null) { + result6 = parse_h16(); + if (result6 !== null) { + if (input.charCodeAt(pos) === 58) { + result7 = ":"; + pos++; + } else { + result7 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result7 !== null) { + result8 = parse_ls32(); + if (result8 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result3 = ":"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result3 !== null) { + result4 = parse_h16(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos2; + } + } else { + result3 = null; + pos = pos2; + } + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + if (input.substr(pos, 2) === "::") { + result4 = "::"; + pos += 2; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + if (input.charCodeAt(pos) === 58) { + result6 = ":"; + pos++; + } else { + result6 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result6 !== null) { + result7 = parse_ls32(); + if (result7 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result3 = ":"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result3 !== null) { + result4 = parse_h16(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos2; + } + } else { + result3 = null; + pos = pos2; + } + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos2; + } + } else { + result4 = null; + pos = pos2; + } + result4 = result4 !== null ? result4 : ""; + if (result4 !== null) { + if (input.substr(pos, 2) === "::") { + result5 = "::"; + pos += 2; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result5 !== null) { + result6 = parse_ls32(); + if (result6 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result3 = ":"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result3 !== null) { + result4 = parse_h16(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos2; + } + } else { + result3 = null; + pos = pos2; + } + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos2; + } + } else { + result4 = null; + pos = pos2; + } + result4 = result4 !== null ? result4 : ""; + if (result4 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result5 = ":"; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result5 !== null) { + result6 = parse_h16(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos2; + } + } else { + result5 = null; + pos = pos2; + } + result5 = result5 !== null ? result5 : ""; + if (result5 !== null) { + if (input.substr(pos, 2) === "::") { + result6 = "::"; + pos += 2; + } else { + result6 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result6 !== null) { + result7 = parse_h16(); + if (result7 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + pos1 = pos; + result0 = parse_h16(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result2 = ":"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result2 !== null) { + result3 = parse_h16(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result3 = ":"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result3 !== null) { + result4 = parse_h16(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos2; + } + } else { + result3 = null; + pos = pos2; + } + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result4 = ":"; + pos++; + } else { + result4 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result4 !== null) { + result5 = parse_h16(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos2; + } + } else { + result4 = null; + pos = pos2; + } + result4 = result4 !== null ? result4 : ""; + if (result4 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result5 = ":"; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result5 !== null) { + result6 = parse_h16(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos2; + } + } else { + result5 = null; + pos = pos2; + } + result5 = result5 !== null ? result5 : ""; + if (result5 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 58) { + result6 = ":"; + pos++; + } else { + result6 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result6 !== null) { + result7 = parse_h16(); + if (result7 !== null) { + result6 = [result6, result7]; + } else { + result6 = null; + pos = pos2; + } + } else { + result6 = null; + pos = pos2; + } + result6 = result6 !== null ? result6 : ""; + if (result6 !== null) { + if (input.substr(pos, 2) === "::") { + result7 = "::"; + pos += 2; + } else { + result7 = null; + if (reportFailures === 0) { + matchFailed("\"::\""); + } + } + if (result7 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + if (result0 !== null) { + result0 = function (offset) { + data.host_type = 'IPv6'; + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_h16() { + var result0, result1, result2, result3; + var pos0; + pos0 = pos; + result0 = parse_HEXDIG(); + if (result0 !== null) { + result1 = parse_HEXDIG(); + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result2 = parse_HEXDIG(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result3 = parse_HEXDIG(); + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_ls32() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_h16(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_h16(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + if (result0 === null) { + result0 = parse_IPv4address(); + } + return result0; + } + function parse_IPv4address() { + var result0, result1, result2, result3, result4, result5, result6; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_dec_octet(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result1 !== null) { + result2 = parse_dec_octet(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 46) { + result3 = "."; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result3 !== null) { + result4 = parse_dec_octet(); + if (result4 !== null) { + if (input.charCodeAt(pos) === 46) { + result5 = "."; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result5 !== null) { + result6 = parse_dec_octet(); + if (result6 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data.host_type = 'IPv4'; + return input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_dec_octet() { + var result0, result1, result2; + var pos0; + pos0 = pos; + if (input.substr(pos, 2) === "25") { + result0 = "25"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"25\""); + } + } + if (result0 !== null) { + if (/^[0-5]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[0-5]"); + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.charCodeAt(pos) === 50) { + result0 = "2"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"2\""); + } + } + if (result0 !== null) { + if (/^[0-4]/.test(input.charAt(pos))) { + result1 = input.charAt(pos); + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("[0-4]"); + } + } + if (result1 !== null) { + result2 = parse_DIGIT(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (input.charCodeAt(pos) === 49) { + result0 = "1"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"1\""); + } + } + if (result0 !== null) { + result1 = parse_DIGIT(); + if (result1 !== null) { + result2 = parse_DIGIT(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + if (/^[1-9]/.test(input.charAt(pos))) { + result0 = input.charAt(pos); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("[1-9]"); + } + } + if (result0 !== null) { + result1 = parse_DIGIT(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + if (result0 === null) { + result0 = parse_DIGIT(); + } + } + } + } + return result0; + } + function parse_port() { + var result0, result1, result2, result3, result4; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_DIGIT(); + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result1 = parse_DIGIT(); + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result2 = parse_DIGIT(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result3 = parse_DIGIT(); + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + result4 = parse_DIGIT(); + result4 = result4 !== null ? result4 : ""; + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, port) { + port = parseInt(port.join('')); + data.port = port; + return port; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_uri_parameters() { + var result0, result1, result2; + var pos0; + result0 = []; + pos0 = pos; + if (input.charCodeAt(pos) === 59) { + result1 = ";"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result1 !== null) { + result2 = parse_uri_parameter(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos0; + } + } else { + result1 = null; + pos = pos0; + } + while (result1 !== null) { + result0.push(result1); + pos0 = pos; + if (input.charCodeAt(pos) === 59) { + result1 = ";"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result1 !== null) { + result2 = parse_uri_parameter(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos0; + } + } else { + result1 = null; + pos = pos0; + } + } + return result0; + } + function parse_uri_parameter() { + var result0; + result0 = parse_transport_param(); + if (result0 === null) { + result0 = parse_user_param(); + if (result0 === null) { + result0 = parse_method_param(); + if (result0 === null) { + result0 = parse_ttl_param(); + if (result0 === null) { + result0 = parse_maddr_param(); + if (result0 === null) { + result0 = parse_lr_param(); + if (result0 === null) { + result0 = parse_other_param(); + } + } + } + } + } + } + return result0; + } + function parse_transport_param() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 10).toLowerCase() === "transport=") { + result0 = input.substr(pos, 10); + pos += 10; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"transport=\""); + } + } + if (result0 !== null) { + if (input.substr(pos, 3).toLowerCase() === "udp") { + result1 = input.substr(pos, 3); + pos += 3; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"udp\""); + } + } + if (result1 === null) { + if (input.substr(pos, 3).toLowerCase() === "tcp") { + result1 = input.substr(pos, 3); + pos += 3; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"tcp\""); + } + } + if (result1 === null) { + if (input.substr(pos, 4).toLowerCase() === "sctp") { + result1 = input.substr(pos, 4); + pos += 4; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"sctp\""); + } + } + if (result1 === null) { + if (input.substr(pos, 3).toLowerCase() === "tls") { + result1 = input.substr(pos, 3); + pos += 3; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"tls\""); + } + } + if (result1 === null) { + result1 = parse_token(); + } + } + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, transport) { + if (!data.uri_params) data.uri_params = {}; + data.uri_params['transport'] = transport.toLowerCase(); + }(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_user_param() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 5).toLowerCase() === "user=") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"user=\""); + } + } + if (result0 !== null) { + if (input.substr(pos, 5).toLowerCase() === "phone") { + result1 = input.substr(pos, 5); + pos += 5; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"phone\""); + } + } + if (result1 === null) { + if (input.substr(pos, 2).toLowerCase() === "ip") { + result1 = input.substr(pos, 2); + pos += 2; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"ip\""); + } + } + if (result1 === null) { + result1 = parse_token(); + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, user) { + if (!data.uri_params) data.uri_params = {}; + data.uri_params['user'] = user.toLowerCase(); + }(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_method_param() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 7).toLowerCase() === "method=") { + result0 = input.substr(pos, 7); + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"method=\""); + } + } + if (result0 !== null) { + result1 = parse_Method(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, method) { + if (!data.uri_params) data.uri_params = {}; + data.uri_params['method'] = method; + }(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_ttl_param() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 4).toLowerCase() === "ttl=") { + result0 = input.substr(pos, 4); + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"ttl=\""); + } + } + if (result0 !== null) { + result1 = parse_ttl(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, ttl) { + if (!data.params) data.params = {}; + data.params['ttl'] = ttl; + }(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_maddr_param() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 6).toLowerCase() === "maddr=") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"maddr=\""); + } + } + if (result0 !== null) { + result1 = parse_host(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, maddr) { + if (!data.uri_params) data.uri_params = {}; + data.uri_params['maddr'] = maddr; + }(pos0, result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_lr_param() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 2).toLowerCase() === "lr") { + result0 = input.substr(pos, 2); + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"lr\""); + } + } + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 !== null) { + result2 = parse_token(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + if (!data.uri_params) data.uri_params = {}; + data.uri_params['lr'] = undefined; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_other_param() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_pname(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 !== null) { + result2 = parse_pvalue(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, param, value) { + if (!data.uri_params) data.uri_params = {}; + if (typeof value === 'undefined') { + value = undefined; + } else { + value = value[1]; + } + data.uri_params[param.toLowerCase()] = value; + }(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_pname() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_paramchar(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_paramchar(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset, pname) { + return pname.join(''); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_pvalue() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_paramchar(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_paramchar(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset, pvalue) { + return pvalue.join(''); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_paramchar() { + var result0; + result0 = parse_param_unreserved(); + if (result0 === null) { + result0 = parse_unreserved(); + if (result0 === null) { + result0 = parse_escaped(); + } + } + return result0; + } + function parse_param_unreserved() { + var result0; + if (input.charCodeAt(pos) === 91) { + result0 = "["; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 93) { + result0 = "]"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 47) { + result0 = "/"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 58) { + result0 = ":"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 38) { + result0 = "&"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 43) { + result0 = "+"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 36) { + result0 = "$"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + } + } + } + } + } + } + return result0; + } + function parse_headers() { + var result0, result1, result2, result3, result4; + var pos0, pos1; + pos0 = pos; + if (input.charCodeAt(pos) === 63) { + result0 = "?"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result0 !== null) { + result1 = parse_header(); + if (result1 !== null) { + result2 = []; + pos1 = pos; + if (input.charCodeAt(pos) === 38) { + result3 = "&"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result3 !== null) { + result4 = parse_header(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos1; + } + } else { + result3 = null; + pos = pos1; + } + while (result3 !== null) { + result2.push(result3); + pos1 = pos; + if (input.charCodeAt(pos) === 38) { + result3 = "&"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result3 !== null) { + result4 = parse_header(); + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos1; + } + } else { + result3 = null; + pos = pos1; + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_header() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_hname(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 !== null) { + result2 = parse_hvalue(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, hname, hvalue) { + hname = hname.join('').toLowerCase(); + hvalue = hvalue.join(''); + if (!data.uri_headers) data.uri_headers = {}; + if (!data.uri_headers[hname]) { + data.uri_headers[hname] = [hvalue]; + } else { + data.uri_headers[hname].push(hvalue); + } + }(pos0, result0[0], result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_hname() { + var result0, result1; + result1 = parse_hnv_unreserved(); + if (result1 === null) { + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_hnv_unreserved(); + if (result1 === null) { + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + } + } + } + } else { + result0 = null; + } + return result0; + } + function parse_hvalue() { + var result0, result1; + result0 = []; + result1 = parse_hnv_unreserved(); + if (result1 === null) { + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + } + } + while (result1 !== null) { + result0.push(result1); + result1 = parse_hnv_unreserved(); + if (result1 === null) { + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + } + } + } + return result0; + } + function parse_hnv_unreserved() { + var result0; + if (input.charCodeAt(pos) === 91) { + result0 = "["; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"[\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 93) { + result0 = "]"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"]\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 47) { + result0 = "/"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 63) { + result0 = "?"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 58) { + result0 = ":"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 43) { + result0 = "+"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 36) { + result0 = "$"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + } + } + } + } + } + } + return result0; + } + function parse_Request_Response() { + var result0; + result0 = parse_Status_Line(); + if (result0 === null) { + result0 = parse_Request_Line(); + } + return result0; + } + function parse_Request_Line() { + var result0, result1, result2, result3, result4; + var pos0; + pos0 = pos; + result0 = parse_Method(); + if (result0 !== null) { + result1 = parse_SP(); + if (result1 !== null) { + result2 = parse_Request_URI(); + if (result2 !== null) { + result3 = parse_SP(); + if (result3 !== null) { + result4 = parse_SIP_Version(); + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Request_URI() { + var result0; + result0 = parse_SIP_URI(); + if (result0 === null) { + result0 = parse_absoluteURI(); + } + return result0; + } + function parse_absoluteURI() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_scheme(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 !== null) { + result2 = parse_hier_part(); + if (result2 === null) { + result2 = parse_opaque_part(); + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_hier_part() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + result0 = parse_net_path(); + if (result0 === null) { + result0 = parse_abs_path(); + } + if (result0 !== null) { + pos1 = pos; + if (input.charCodeAt(pos) === 63) { + result1 = "?"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result1 !== null) { + result2 = parse_query(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos1; + } + } else { + result1 = null; + pos = pos1; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_net_path() { + var result0, result1, result2; + var pos0; + pos0 = pos; + if (input.substr(pos, 2) === "//") { + result0 = "//"; + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"//\""); + } + } + if (result0 !== null) { + result1 = parse_authority(); + if (result1 !== null) { + result2 = parse_abs_path(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_abs_path() { + var result0, result1; + var pos0; + pos0 = pos; + if (input.charCodeAt(pos) === 47) { + result0 = "/"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result0 !== null) { + result1 = parse_path_segments(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_opaque_part() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_uric_no_slash(); + if (result0 !== null) { + result1 = []; + result2 = parse_uric(); + while (result2 !== null) { + result1.push(result2); + result2 = parse_uric(); + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_uric() { + var result0; + result0 = parse_reserved(); + if (result0 === null) { + result0 = parse_unreserved(); + if (result0 === null) { + result0 = parse_escaped(); + } + } + return result0; + } + function parse_uric_no_slash() { + var result0; + result0 = parse_unreserved(); + if (result0 === null) { + result0 = parse_escaped(); + if (result0 === null) { + if (input.charCodeAt(pos) === 59) { + result0 = ";"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 63) { + result0 = "?"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"?\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 58) { + result0 = ":"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 64) { + result0 = "@"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 38) { + result0 = "&"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 61) { + result0 = "="; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 43) { + result0 = "+"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 36) { + result0 = "$"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 44) { + result0 = ","; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + } + } + } + } + } + } + } + } + } + } + return result0; + } + function parse_path_segments() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_segment(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + if (input.charCodeAt(pos) === 47) { + result2 = "/"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result2 !== null) { + result3 = parse_segment(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + if (input.charCodeAt(pos) === 47) { + result2 = "/"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result2 !== null) { + result3 = parse_segment(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_segment() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = []; + result1 = parse_pchar(); + while (result1 !== null) { + result0.push(result1); + result1 = parse_pchar(); + } + if (result0 !== null) { + result1 = []; + pos1 = pos; + if (input.charCodeAt(pos) === 59) { + result2 = ";"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result2 !== null) { + result3 = parse_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + if (input.charCodeAt(pos) === 59) { + result2 = ";"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result2 !== null) { + result3 = parse_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_param() { + var result0, result1; + result0 = []; + result1 = parse_pchar(); + while (result1 !== null) { + result0.push(result1); + result1 = parse_pchar(); + } + return result0; + } + function parse_pchar() { + var result0; + result0 = parse_unreserved(); + if (result0 === null) { + result0 = parse_escaped(); + if (result0 === null) { + if (input.charCodeAt(pos) === 58) { + result0 = ":"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 64) { + result0 = "@"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 38) { + result0 = "&"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 61) { + result0 = "="; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 43) { + result0 = "+"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 36) { + result0 = "$"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result0 === null) { + if (input.charCodeAt(pos) === 44) { + result0 = ","; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + } + } + } + } + } + } + } + } + return result0; + } + function parse_scheme() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_ALPHA(); + if (result0 !== null) { + result1 = []; + result2 = parse_ALPHA(); + if (result2 === null) { + result2 = parse_DIGIT(); + if (result2 === null) { + if (input.charCodeAt(pos) === 43) { + result2 = "+"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 45) { + result2 = "-"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 46) { + result2 = "."; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + } + } + } + } + while (result2 !== null) { + result1.push(result2); + result2 = parse_ALPHA(); + if (result2 === null) { + result2 = parse_DIGIT(); + if (result2 === null) { + if (input.charCodeAt(pos) === 43) { + result2 = "+"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 45) { + result2 = "-"; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result2 === null) { + if (input.charCodeAt(pos) === 46) { + result2 = "."; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + } + } + } + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data.scheme = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_authority() { + var result0; + result0 = parse_srvr(); + if (result0 === null) { + result0 = parse_reg_name(); + } + return result0; + } + function parse_srvr() { + var result0, result1; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_userinfo(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 64) { + result1 = "@"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result1 = parse_hostport(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + result0 = result0 !== null ? result0 : ""; + return result0; + } + function parse_reg_name() { + var result0, result1; + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + if (input.charCodeAt(pos) === 36) { + result1 = "$"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 44) { + result1 = ","; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 59) { + result1 = ";"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 64) { + result1 = "@"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 38) { + result1 = "&"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + } + } + } + } + } + } + } + } + } + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + if (input.charCodeAt(pos) === 36) { + result1 = "$"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"$\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 44) { + result1 = ","; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 59) { + result1 = ";"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\";\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 58) { + result1 = ":"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\":\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 64) { + result1 = "@"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 38) { + result1 = "&"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"&\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 61) { + result1 = "="; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"=\""); + } + } + if (result1 === null) { + if (input.charCodeAt(pos) === 43) { + result1 = "+"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"+\""); + } + } + } + } + } + } + } + } + } + } + } + } + } else { + result0 = null; + } + return result0; + } + function parse_query() { + var result0, result1; + result0 = []; + result1 = parse_uric(); + while (result1 !== null) { + result0.push(result1); + result1 = parse_uric(); + } + return result0; + } + function parse_SIP_Version() { + var result0, result1, result2, result3, result4, result5; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 3).toLowerCase() === "sip") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"SIP\""); + } + } + if (result0 !== null) { + if (input.charCodeAt(pos) === 47) { + result1 = "/"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"/\""); + } + } + if (result1 !== null) { + result3 = parse_DIGIT(); + if (result3 !== null) { + result2 = []; + while (result3 !== null) { + result2.push(result3); + result3 = parse_DIGIT(); + } + } else { + result2 = null; + } + if (result2 !== null) { + if (input.charCodeAt(pos) === 46) { + result3 = "."; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result3 !== null) { + result5 = parse_DIGIT(); + if (result5 !== null) { + result4 = []; + while (result5 !== null) { + result4.push(result5); + result5 = parse_DIGIT(); + } + } else { + result4 = null; + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data.sip_version = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_INVITEm() { + var result0; + if (input.substr(pos, 6) === "INVITE") { + result0 = "INVITE"; + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"INVITE\""); + } + } + return result0; + } + function parse_ACKm() { + var result0; + if (input.substr(pos, 3) === "ACK") { + result0 = "ACK"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"ACK\""); + } + } + return result0; + } + function parse_OPTIONSm() { + var result0; + if (input.substr(pos, 7) === "OPTIONS") { + result0 = "OPTIONS"; + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"OPTIONS\""); + } + } + return result0; + } + function parse_BYEm() { + var result0; + if (input.substr(pos, 3) === "BYE") { + result0 = "BYE"; + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"BYE\""); + } + } + return result0; + } + function parse_CANCELm() { + var result0; + if (input.substr(pos, 6) === "CANCEL") { + result0 = "CANCEL"; + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"CANCEL\""); + } + } + return result0; + } + function parse_REGISTERm() { + var result0; + if (input.substr(pos, 8) === "REGISTER") { + result0 = "REGISTER"; + pos += 8; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"REGISTER\""); + } + } + return result0; + } + function parse_SUBSCRIBEm() { + var result0; + if (input.substr(pos, 9) === "SUBSCRIBE") { + result0 = "SUBSCRIBE"; + pos += 9; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"SUBSCRIBE\""); + } + } + return result0; + } + function parse_NOTIFYm() { + var result0; + if (input.substr(pos, 6) === "NOTIFY") { + result0 = "NOTIFY"; + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"NOTIFY\""); + } + } + return result0; + } + function parse_REFERm() { + var result0; + if (input.substr(pos, 5) === "REFER") { + result0 = "REFER"; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"REFER\""); + } + } + return result0; + } + function parse_Method() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_INVITEm(); + if (result0 === null) { + result0 = parse_ACKm(); + if (result0 === null) { + result0 = parse_OPTIONSm(); + if (result0 === null) { + result0 = parse_BYEm(); + if (result0 === null) { + result0 = parse_CANCELm(); + if (result0 === null) { + result0 = parse_REGISTERm(); + if (result0 === null) { + result0 = parse_SUBSCRIBEm(); + if (result0 === null) { + result0 = parse_NOTIFYm(); + if (result0 === null) { + result0 = parse_REFERm(); + if (result0 === null) { + result0 = parse_token(); + } + } + } + } + } + } + } + } + } + if (result0 !== null) { + result0 = function (offset) { + data.method = input.substring(pos, offset); + return data.method; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Status_Line() { + var result0, result1, result2, result3, result4; + var pos0; + pos0 = pos; + result0 = parse_SIP_Version(); + if (result0 !== null) { + result1 = parse_SP(); + if (result1 !== null) { + result2 = parse_Status_Code(); + if (result2 !== null) { + result3 = parse_SP(); + if (result3 !== null) { + result4 = parse_Reason_Phrase(); + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Status_Code() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_extension_code(); + if (result0 !== null) { + result0 = function (offset, status_code) { + data.status_code = parseInt(status_code.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_extension_code() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_DIGIT(); + if (result0 !== null) { + result1 = parse_DIGIT(); + if (result1 !== null) { + result2 = parse_DIGIT(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Reason_Phrase() { + var result0, result1; + var pos0; + pos0 = pos; + result0 = []; + result1 = parse_reserved(); + if (result1 === null) { + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + result1 = parse_UTF8_NONASCII(); + if (result1 === null) { + result1 = parse_UTF8_CONT(); + if (result1 === null) { + result1 = parse_SP(); + if (result1 === null) { + result1 = parse_HTAB(); + } + } + } + } + } + } + while (result1 !== null) { + result0.push(result1); + result1 = parse_reserved(); + if (result1 === null) { + result1 = parse_unreserved(); + if (result1 === null) { + result1 = parse_escaped(); + if (result1 === null) { + result1 = parse_UTF8_NONASCII(); + if (result1 === null) { + result1 = parse_UTF8_CONT(); + if (result1 === null) { + result1 = parse_SP(); + if (result1 === null) { + result1 = parse_HTAB(); + } + } + } + } + } + } + } + if (result0 !== null) { + result0 = function (offset) { + data.reason_phrase = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Allow_Events() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_event_type(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_event_type(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_event_type(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Call_ID() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_word(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 64) { + result1 = "@"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result1 !== null) { + result2 = parse_word(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Contact() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + result0 = parse_STAR(); + if (result0 === null) { + pos1 = pos; + result0 = parse_contact_param(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_contact_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_contact_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } + if (result0 !== null) { + result0 = function (offset) { + var idx, length; + length = data.multi_header.length; + for (idx = 0; idx < length; idx++) { + if (data.multi_header[idx].parsed === null) { + data = null; + break; + } + } + if (data !== null) { + data = data.multi_header; + } else { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_contact_param() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_SIP_URI_noparams(); + if (result0 === null) { + result0 = parse_name_addr(); + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_contact_params(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_contact_params(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + var header; + if (!data.multi_header) data.multi_header = []; + try { + header = new NameAddrHeader(data.uri, data.display_name, data.params); + delete data.uri; + delete data.display_name; + delete data.params; + } catch (e) { + header = null; + } + data.multi_header.push({ + 'possition': pos, + 'offset': offset, + 'parsed': header + }); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_name_addr() { + var result0, result1, result2, result3; + var pos0; + pos0 = pos; + result0 = parse_display_name(); + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result1 = parse_LAQUOT(); + if (result1 !== null) { + result2 = parse_SIP_URI(); + if (result2 !== null) { + result3 = parse_RAQUOT(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_display_name() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_LWS(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_LWS(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 === null) { + result0 = parse_quoted_string_clean(); + } + if (result0 !== null) { + result0 = function (offset, display_name) { + if (typeof display_name === 'string') { + // quoted_string_clean + data.display_name = display_name; + } else { + // token ( LWS token )* + data.display_name = display_name[1].reduce(function (acc, cur) { + return acc + cur[0] + cur[1]; + }, display_name[0]); + } + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_contact_params() { + var result0; + result0 = parse_c_p_q(); + if (result0 === null) { + result0 = parse_c_p_expires(); + if (result0 === null) { + result0 = parse_generic_param(); + } + } + return result0; + } + function parse_c_p_q() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 1).toLowerCase() === "q") { + result0 = input.substr(pos, 1); + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"q\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_qvalue(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, q) { + if (!data.params) data.params = {}; + data.params['q'] = q; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_c_p_expires() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 7).toLowerCase() === "expires") { + result0 = input.substr(pos, 7); + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"expires\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_delta_seconds(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, expires) { + if (!data.params) data.params = {}; + data.params['expires'] = expires; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_delta_seconds() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_DIGIT(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_DIGIT(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset, delta_seconds) { + return parseInt(delta_seconds.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_qvalue() { + var result0, result1, result2, result3, result4; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + if (input.charCodeAt(pos) === 48) { + result0 = "0"; + pos++; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"0\""); + } + } + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 46) { + result1 = "."; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result1 !== null) { + result2 = parse_DIGIT(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result3 = parse_DIGIT(); + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + result4 = parse_DIGIT(); + result4 = result4 !== null ? result4 : ""; + if (result4 !== null) { + result1 = [result1, result2, result3, result4]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + return parseFloat(input.substring(pos, offset)); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_generic_param() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_token(); + if (result0 !== null) { + pos2 = pos; + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_gen_value(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, param, value) { + if (!data.params) data.params = {}; + if (typeof value === 'undefined') { + value = undefined; + } else { + value = value[1]; + } + data.params[param.toLowerCase()] = value; + }(pos0, result0[0], result0[1]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_gen_value() { + var result0; + result0 = parse_token(); + if (result0 === null) { + result0 = parse_host(); + if (result0 === null) { + result0 = parse_quoted_string(); + } + } + return result0; + } + function parse_Content_Disposition() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_disp_type(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_disp_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_disp_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_disp_type() { + var result0; + if (input.substr(pos, 6).toLowerCase() === "render") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"render\""); + } + } + if (result0 === null) { + if (input.substr(pos, 7).toLowerCase() === "session") { + result0 = input.substr(pos, 7); + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"session\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4).toLowerCase() === "icon") { + result0 = input.substr(pos, 4); + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"icon\""); + } + } + if (result0 === null) { + if (input.substr(pos, 5).toLowerCase() === "alert") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"alert\""); + } + } + if (result0 === null) { + result0 = parse_token(); + } + } + } + } + return result0; + } + function parse_disp_param() { + var result0; + result0 = parse_handling_param(); + if (result0 === null) { + result0 = parse_generic_param(); + } + return result0; + } + function parse_handling_param() { + var result0, result1, result2; + var pos0; + pos0 = pos; + if (input.substr(pos, 8).toLowerCase() === "handling") { + result0 = input.substr(pos, 8); + pos += 8; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"handling\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + if (input.substr(pos, 8).toLowerCase() === "optional") { + result2 = input.substr(pos, 8); + pos += 8; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"optional\""); + } + } + if (result2 === null) { + if (input.substr(pos, 8).toLowerCase() === "required") { + result2 = input.substr(pos, 8); + pos += 8; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"required\""); + } + } + if (result2 === null) { + result2 = parse_token(); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Content_Encoding() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Content_Length() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_DIGIT(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_DIGIT(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset, length) { + data = parseInt(length.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Content_Type() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_media_type(); + if (result0 !== null) { + result0 = function (offset) { + data = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_media_type() { + var result0, result1, result2, result3, result4, result5; + var pos0, pos1; + pos0 = pos; + result0 = parse_m_type(); + if (result0 !== null) { + result1 = parse_SLASH(); + if (result1 !== null) { + result2 = parse_m_subtype(); + if (result2 !== null) { + result3 = []; + pos1 = pos; + result4 = parse_SEMI(); + if (result4 !== null) { + result5 = parse_m_parameter(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + while (result4 !== null) { + result3.push(result4); + pos1 = pos; + result4 = parse_SEMI(); + if (result4 !== null) { + result5 = parse_m_parameter(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + } + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_m_type() { + var result0; + result0 = parse_discrete_type(); + if (result0 === null) { + result0 = parse_composite_type(); + } + return result0; + } + function parse_discrete_type() { + var result0; + if (input.substr(pos, 4).toLowerCase() === "text") { + result0 = input.substr(pos, 4); + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"text\""); + } + } + if (result0 === null) { + if (input.substr(pos, 5).toLowerCase() === "image") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"image\""); + } + } + if (result0 === null) { + if (input.substr(pos, 5).toLowerCase() === "audio") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"audio\""); + } + } + if (result0 === null) { + if (input.substr(pos, 5).toLowerCase() === "video") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"video\""); + } + } + if (result0 === null) { + if (input.substr(pos, 11).toLowerCase() === "application") { + result0 = input.substr(pos, 11); + pos += 11; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"application\""); + } + } + if (result0 === null) { + result0 = parse_extension_token(); + } + } + } + } + } + return result0; + } + function parse_composite_type() { + var result0; + if (input.substr(pos, 7).toLowerCase() === "message") { + result0 = input.substr(pos, 7); + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"message\""); + } + } + if (result0 === null) { + if (input.substr(pos, 9).toLowerCase() === "multipart") { + result0 = input.substr(pos, 9); + pos += 9; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"multipart\""); + } + } + if (result0 === null) { + result0 = parse_extension_token(); + } + } + return result0; + } + function parse_extension_token() { + var result0; + result0 = parse_token(); + if (result0 === null) { + result0 = parse_x_token(); + } + return result0; + } + function parse_x_token() { + var result0, result1; + var pos0; + pos0 = pos; + if (input.substr(pos, 2).toLowerCase() === "x-") { + result0 = input.substr(pos, 2); + pos += 2; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"x-\""); + } + } + if (result0 !== null) { + result1 = parse_token(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_m_subtype() { + var result0; + result0 = parse_extension_token(); + if (result0 === null) { + result0 = parse_token(); + } + return result0; + } + function parse_m_parameter() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_m_value(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_m_value() { + var result0; + result0 = parse_token(); + if (result0 === null) { + result0 = parse_quoted_string(); + } + return result0; + } + function parse_CSeq() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_CSeq_value(); + if (result0 !== null) { + result1 = parse_LWS(); + if (result1 !== null) { + result2 = parse_Method(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_CSeq_value() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_DIGIT(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_DIGIT(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset, cseq_value) { + data.value = parseInt(cseq_value.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Expires() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_delta_seconds(); + if (result0 !== null) { + result0 = function (offset, expires) { + data = expires; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Event() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_event_type(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, event_type) { + data.event = event_type.join('').toLowerCase(); + }(pos0, result0[0]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_event_type() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_token_nodot(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + if (input.charCodeAt(pos) === 46) { + result2 = "."; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result2 !== null) { + result3 = parse_token_nodot(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + if (input.charCodeAt(pos) === 46) { + result2 = "."; + pos++; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\".\""); + } + } + if (result2 !== null) { + result3 = parse_token_nodot(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_From() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_SIP_URI_noparams(); + if (result0 === null) { + result0 = parse_name_addr(); + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_from_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_from_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + var tag = data.tag; + try { + data = new NameAddrHeader(data.uri, data.display_name, data.params); + if (tag) { + data.setParam('tag', tag); + } + } catch (e) { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_from_param() { + var result0; + result0 = parse_tag_param(); + if (result0 === null) { + result0 = parse_generic_param(); + } + return result0; + } + function parse_tag_param() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 3).toLowerCase() === "tag") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"tag\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_token(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, tag) { + data.tag = tag; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Max_Forwards() { + var result0, result1; + var pos0; + pos0 = pos; + result1 = parse_DIGIT(); + if (result1 !== null) { + result0 = []; + while (result1 !== null) { + result0.push(result1); + result1 = parse_DIGIT(); + } + } else { + result0 = null; + } + if (result0 !== null) { + result0 = function (offset, forwards) { + data = parseInt(forwards.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Min_Expires() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_delta_seconds(); + if (result0 !== null) { + result0 = function (offset, min_expires) { + data = min_expires; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Name_Addr_Header() { + var result0, result1, result2, result3, result4, result5, result6; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = []; + result1 = parse_display_name(); + while (result1 !== null) { + result0.push(result1); + result1 = parse_display_name(); + } + if (result0 !== null) { + result1 = parse_LAQUOT(); + if (result1 !== null) { + result2 = parse_SIP_URI(); + if (result2 !== null) { + result3 = parse_RAQUOT(); + if (result3 !== null) { + result4 = []; + pos2 = pos; + result5 = parse_SEMI(); + if (result5 !== null) { + result6 = parse_generic_param(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos2; + } + } else { + result5 = null; + pos = pos2; + } + while (result5 !== null) { + result4.push(result5); + pos2 = pos; + result5 = parse_SEMI(); + if (result5 !== null) { + result6 = parse_generic_param(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos2; + } + } else { + result5 = null; + pos = pos2; + } + } + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + try { + data = new NameAddrHeader(data.uri, data.display_name, data.params); + } catch (e) { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Proxy_Authenticate() { + var result0; + result0 = parse_challenge(); + return result0; + } + function parse_challenge() { + var result0, result1, result2, result3, result4, result5; + var pos0, pos1; + pos0 = pos; + if (input.substr(pos, 6).toLowerCase() === "digest") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"Digest\""); + } + } + if (result0 !== null) { + result1 = parse_LWS(); + if (result1 !== null) { + result2 = parse_digest_cln(); + if (result2 !== null) { + result3 = []; + pos1 = pos; + result4 = parse_COMMA(); + if (result4 !== null) { + result5 = parse_digest_cln(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + while (result4 !== null) { + result3.push(result4); + pos1 = pos; + result4 = parse_COMMA(); + if (result4 !== null) { + result5 = parse_digest_cln(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + } + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + if (result0 === null) { + result0 = parse_other_challenge(); + } + return result0; + } + function parse_other_challenge() { + var result0, result1, result2, result3, result4, result5; + var pos0, pos1; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = parse_LWS(); + if (result1 !== null) { + result2 = parse_auth_param(); + if (result2 !== null) { + result3 = []; + pos1 = pos; + result4 = parse_COMMA(); + if (result4 !== null) { + result5 = parse_auth_param(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + while (result4 !== null) { + result3.push(result4); + pos1 = pos; + result4 = parse_COMMA(); + if (result4 !== null) { + result5 = parse_auth_param(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + } + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_auth_param() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_token(); + if (result2 === null) { + result2 = parse_quoted_string(); + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_digest_cln() { + var result0; + result0 = parse_realm(); + if (result0 === null) { + result0 = parse_domain(); + if (result0 === null) { + result0 = parse_nonce(); + if (result0 === null) { + result0 = parse_opaque(); + if (result0 === null) { + result0 = parse_stale(); + if (result0 === null) { + result0 = parse_algorithm(); + if (result0 === null) { + result0 = parse_qop_options(); + if (result0 === null) { + result0 = parse_auth_param(); + } + } + } + } + } + } + } + return result0; + } + function parse_realm() { + var result0, result1, result2; + var pos0; + pos0 = pos; + if (input.substr(pos, 5).toLowerCase() === "realm") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"realm\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_realm_value(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_realm_value() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_quoted_string_clean(); + if (result0 !== null) { + result0 = function (offset, realm) { + data.realm = realm; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_domain() { + var result0, result1, result2, result3, result4, result5, result6; + var pos0, pos1; + pos0 = pos; + if (input.substr(pos, 6).toLowerCase() === "domain") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"domain\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_LDQUOT(); + if (result2 !== null) { + result3 = parse_URI(); + if (result3 !== null) { + result4 = []; + pos1 = pos; + result6 = parse_SP(); + if (result6 !== null) { + result5 = []; + while (result6 !== null) { + result5.push(result6); + result6 = parse_SP(); + } + } else { + result5 = null; + } + if (result5 !== null) { + result6 = parse_URI(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos1; + } + } else { + result5 = null; + pos = pos1; + } + while (result5 !== null) { + result4.push(result5); + pos1 = pos; + result6 = parse_SP(); + if (result6 !== null) { + result5 = []; + while (result6 !== null) { + result5.push(result6); + result6 = parse_SP(); + } + } else { + result5 = null; + } + if (result5 !== null) { + result6 = parse_URI(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos1; + } + } else { + result5 = null; + pos = pos1; + } + } + if (result4 !== null) { + result5 = parse_RDQUOT(); + if (result5 !== null) { + result0 = [result0, result1, result2, result3, result4, result5]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_URI() { + var result0; + result0 = parse_absoluteURI(); + if (result0 === null) { + result0 = parse_abs_path(); + } + return result0; + } + function parse_nonce() { + var result0, result1, result2; + var pos0; + pos0 = pos; + if (input.substr(pos, 5).toLowerCase() === "nonce") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"nonce\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_nonce_value(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_nonce_value() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_quoted_string_clean(); + if (result0 !== null) { + result0 = function (offset, nonce) { + data.nonce = nonce; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_opaque() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 6).toLowerCase() === "opaque") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"opaque\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_quoted_string_clean(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, opaque) { + data.opaque = opaque; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_stale() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + if (input.substr(pos, 5).toLowerCase() === "stale") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"stale\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + pos1 = pos; + if (input.substr(pos, 4).toLowerCase() === "true") { + result2 = input.substr(pos, 4); + pos += 4; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"true\""); + } + } + if (result2 !== null) { + result2 = function (offset) { + data.stale = true; + }(pos1); + } + if (result2 === null) { + pos = pos1; + } + if (result2 === null) { + pos1 = pos; + if (input.substr(pos, 5).toLowerCase() === "false") { + result2 = input.substr(pos, 5); + pos += 5; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"false\""); + } + } + if (result2 !== null) { + result2 = function (offset) { + data.stale = false; + }(pos1); + } + if (result2 === null) { + pos = pos1; + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_algorithm() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 9).toLowerCase() === "algorithm") { + result0 = input.substr(pos, 9); + pos += 9; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"algorithm\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + if (input.substr(pos, 3).toLowerCase() === "md5") { + result2 = input.substr(pos, 3); + pos += 3; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"MD5\""); + } + } + if (result2 === null) { + if (input.substr(pos, 8).toLowerCase() === "md5-sess") { + result2 = input.substr(pos, 8); + pos += 8; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"MD5-sess\""); + } + } + if (result2 === null) { + result2 = parse_token(); + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, algorithm) { + data.algorithm = algorithm.toUpperCase(); + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_qop_options() { + var result0, result1, result2, result3, result4, result5, result6; + var pos0, pos1, pos2; + pos0 = pos; + if (input.substr(pos, 3).toLowerCase() === "qop") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"qop\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_LDQUOT(); + if (result2 !== null) { + pos1 = pos; + result3 = parse_qop_value(); + if (result3 !== null) { + result4 = []; + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result5 = ","; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result5 !== null) { + result6 = parse_qop_value(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos2; + } + } else { + result5 = null; + pos = pos2; + } + while (result5 !== null) { + result4.push(result5); + pos2 = pos; + if (input.charCodeAt(pos) === 44) { + result5 = ","; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\",\""); + } + } + if (result5 !== null) { + result6 = parse_qop_value(); + if (result6 !== null) { + result5 = [result5, result6]; + } else { + result5 = null; + pos = pos2; + } + } else { + result5 = null; + pos = pos2; + } + } + if (result4 !== null) { + result3 = [result3, result4]; + } else { + result3 = null; + pos = pos1; + } + } else { + result3 = null; + pos = pos1; + } + if (result3 !== null) { + result4 = parse_RDQUOT(); + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_qop_value() { + var result0; + var pos0; + pos0 = pos; + if (input.substr(pos, 8).toLowerCase() === "auth-int") { + result0 = input.substr(pos, 8); + pos += 8; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"auth-int\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4).toLowerCase() === "auth") { + result0 = input.substr(pos, 4); + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"auth\""); + } + } + if (result0 === null) { + result0 = parse_token(); + } + } + if (result0 !== null) { + result0 = function (offset, qop_value) { + data.qop || (data.qop = []); + data.qop.push(qop_value.toLowerCase()); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Proxy_Require() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Record_Route() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_rec_route(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_rec_route(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_rec_route(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + var idx, length; + length = data.multi_header.length; + for (idx = 0; idx < length; idx++) { + if (data.multi_header[idx].parsed === null) { + data = null; + break; + } + } + if (data !== null) { + data = data.multi_header; + } else { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_rec_route() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_name_addr(); + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + var header; + if (!data.multi_header) data.multi_header = []; + try { + header = new NameAddrHeader(data.uri, data.display_name, data.params); + delete data.uri; + delete data.display_name; + delete data.params; + } catch (e) { + header = null; + } + data.multi_header.push({ + 'possition': pos, + 'offset': offset, + 'parsed': header + }); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Reason() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 3).toLowerCase() === "sip") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"SIP\""); + } + } + if (result0 === null) { + result0 = parse_token(); + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_reason_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_reason_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, protocol) { + data.protocol = protocol.toLowerCase(); + if (!data.params) data.params = {}; + if (data.params.text && data.params.text[0] === '"') { + var text = data.params.text; + data.text = text.substring(1, text.length - 1); + delete data.params.text; + } + }(pos0, result0[0]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_reason_param() { + var result0; + result0 = parse_reason_cause(); + if (result0 === null) { + result0 = parse_generic_param(); + } + return result0; + } + function parse_reason_cause() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 5).toLowerCase() === "cause") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"cause\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result3 = parse_DIGIT(); + if (result3 !== null) { + result2 = []; + while (result3 !== null) { + result2.push(result3); + result3 = parse_DIGIT(); + } + } else { + result2 = null; + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, cause) { + data.cause = parseInt(cause.join('')); + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Require() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Route() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_route_param(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_route_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_route_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_route_param() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_name_addr(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Subscription_State() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_substate_value(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_subexp_params(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_subexp_params(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_substate_value() { + var result0; + var pos0; + pos0 = pos; + if (input.substr(pos, 6).toLowerCase() === "active") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"active\""); + } + } + if (result0 === null) { + if (input.substr(pos, 7).toLowerCase() === "pending") { + result0 = input.substr(pos, 7); + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"pending\""); + } + } + if (result0 === null) { + if (input.substr(pos, 10).toLowerCase() === "terminated") { + result0 = input.substr(pos, 10); + pos += 10; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"terminated\""); + } + } + if (result0 === null) { + result0 = parse_token(); + } + } + } + if (result0 !== null) { + result0 = function (offset) { + data.state = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_subexp_params() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 6).toLowerCase() === "reason") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"reason\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_event_reason_value(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, reason) { + if (typeof reason !== 'undefined') data.reason = reason; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 7).toLowerCase() === "expires") { + result0 = input.substr(pos, 7); + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"expires\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_delta_seconds(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, expires) { + if (typeof expires !== 'undefined') data.expires = expires; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 11).toLowerCase() === "retry_after") { + result0 = input.substr(pos, 11); + pos += 11; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"retry_after\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_delta_seconds(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, retry_after) { + if (typeof retry_after !== 'undefined') data.retry_after = retry_after; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + if (result0 === null) { + result0 = parse_generic_param(); + } + } + } + return result0; + } + function parse_event_reason_value() { + var result0; + if (input.substr(pos, 11).toLowerCase() === "deactivated") { + result0 = input.substr(pos, 11); + pos += 11; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"deactivated\""); + } + } + if (result0 === null) { + if (input.substr(pos, 9).toLowerCase() === "probation") { + result0 = input.substr(pos, 9); + pos += 9; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"probation\""); + } + } + if (result0 === null) { + if (input.substr(pos, 8).toLowerCase() === "rejected") { + result0 = input.substr(pos, 8); + pos += 8; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rejected\""); + } + } + if (result0 === null) { + if (input.substr(pos, 7).toLowerCase() === "timeout") { + result0 = input.substr(pos, 7); + pos += 7; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"timeout\""); + } + } + if (result0 === null) { + if (input.substr(pos, 6).toLowerCase() === "giveup") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"giveup\""); + } + } + if (result0 === null) { + if (input.substr(pos, 10).toLowerCase() === "noresource") { + result0 = input.substr(pos, 10); + pos += 10; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"noresource\""); + } + } + if (result0 === null) { + if (input.substr(pos, 9).toLowerCase() === "invariant") { + result0 = input.substr(pos, 9); + pos += 9; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"invariant\""); + } + } + if (result0 === null) { + result0 = parse_token(); + } + } + } + } + } + } + } + return result0; + } + function parse_Subject() { + var result0; + result0 = parse_TEXT_UTF8_TRIM(); + result0 = result0 !== null ? result0 : ""; + return result0; + } + function parse_Supported() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_token(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + result0 = result0 !== null ? result0 : ""; + return result0; + } + function parse_To() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_SIP_URI_noparams(); + if (result0 === null) { + result0 = parse_name_addr(); + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_to_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_to_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + var tag = data.tag; + try { + data = new NameAddrHeader(data.uri, data.display_name, data.params); + if (tag) { + data.setParam('tag', tag); + } + } catch (e) { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_to_param() { + var result0; + result0 = parse_tag_param(); + if (result0 === null) { + result0 = parse_generic_param(); + } + return result0; + } + function parse_Via() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_via_param(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_via_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_COMMA(); + if (result2 !== null) { + result3 = parse_via_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_via_param() { + var result0, result1, result2, result3, result4, result5; + var pos0, pos1; + pos0 = pos; + result0 = parse_sent_protocol(); + if (result0 !== null) { + result1 = parse_LWS(); + if (result1 !== null) { + result2 = parse_sent_by(); + if (result2 !== null) { + result3 = []; + pos1 = pos; + result4 = parse_SEMI(); + if (result4 !== null) { + result5 = parse_via_params(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + while (result4 !== null) { + result3.push(result4); + pos1 = pos; + result4 = parse_SEMI(); + if (result4 !== null) { + result5 = parse_via_params(); + if (result5 !== null) { + result4 = [result4, result5]; + } else { + result4 = null; + pos = pos1; + } + } else { + result4 = null; + pos = pos1; + } + } + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_via_params() { + var result0; + result0 = parse_via_ttl(); + if (result0 === null) { + result0 = parse_via_maddr(); + if (result0 === null) { + result0 = parse_via_received(); + if (result0 === null) { + result0 = parse_via_branch(); + if (result0 === null) { + result0 = parse_response_port(); + if (result0 === null) { + result0 = parse_generic_param(); + } + } + } + } + } + return result0; + } + function parse_via_ttl() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 3).toLowerCase() === "ttl") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"ttl\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_ttl(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, via_ttl_value) { + data.ttl = via_ttl_value; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_via_maddr() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 5).toLowerCase() === "maddr") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"maddr\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_host(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, via_maddr) { + data.maddr = via_maddr; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_via_received() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 8).toLowerCase() === "received") { + result0 = input.substr(pos, 8); + pos += 8; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"received\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_IPv4address(); + if (result2 === null) { + result2 = parse_IPv6address(); + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, via_received) { + data.received = via_received; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_via_branch() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 6).toLowerCase() === "branch") { + result0 = input.substr(pos, 6); + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"branch\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_token(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, via_branch) { + data.branch = via_branch; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_response_port() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + if (input.substr(pos, 5).toLowerCase() === "rport") { + result0 = input.substr(pos, 5); + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"rport\""); + } + } + if (result0 !== null) { + pos1 = pos; + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_rport(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos1; + } + } else { + result1 = null; + pos = pos1; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_rport() { + var result0, result1, result2, result3, result4; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_DIGIT(); + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result1 = parse_DIGIT(); + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result2 = parse_DIGIT(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result3 = parse_DIGIT(); + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + result4 = parse_DIGIT(); + result4 = result4 !== null ? result4 : ""; + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, rport) { + data.rport = parseInt(rport.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_sent_protocol() { + var result0, result1, result2, result3, result4; + var pos0; + pos0 = pos; + result0 = parse_protocol_name(); + if (result0 !== null) { + result1 = parse_SLASH(); + if (result1 !== null) { + result2 = parse_token(); + if (result2 !== null) { + result3 = parse_SLASH(); + if (result3 !== null) { + result4 = parse_transport(); + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_protocol_name() { + var result0; + var pos0; + pos0 = pos; + if (input.substr(pos, 3).toLowerCase() === "sip") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"SIP\""); + } + } + if (result0 === null) { + result0 = parse_token(); + } + if (result0 !== null) { + result0 = function (offset, via_protocol) { + data.protocol = via_protocol; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_transport() { + var result0; + var pos0; + pos0 = pos; + if (input.substr(pos, 3).toLowerCase() === "udp") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"UDP\""); + } + } + if (result0 === null) { + if (input.substr(pos, 3).toLowerCase() === "tcp") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"TCP\""); + } + } + if (result0 === null) { + if (input.substr(pos, 3).toLowerCase() === "tls") { + result0 = input.substr(pos, 3); + pos += 3; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"TLS\""); + } + } + if (result0 === null) { + if (input.substr(pos, 4).toLowerCase() === "sctp") { + result0 = input.substr(pos, 4); + pos += 4; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"SCTP\""); + } + } + if (result0 === null) { + result0 = parse_token(); + } + } + } + } + if (result0 !== null) { + result0 = function (offset, via_transport) { + data.transport = via_transport; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_sent_by() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + result0 = parse_via_host(); + if (result0 !== null) { + pos1 = pos; + result1 = parse_COLON(); + if (result1 !== null) { + result2 = parse_via_port(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos1; + } + } else { + result1 = null; + pos = pos1; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_via_host() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_IPv4address(); + if (result0 === null) { + result0 = parse_IPv6reference(); + if (result0 === null) { + result0 = parse_hostname(); + } + } + if (result0 !== null) { + result0 = function (offset) { + data.host = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_via_port() { + var result0, result1, result2, result3, result4; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_DIGIT(); + result0 = result0 !== null ? result0 : ""; + if (result0 !== null) { + result1 = parse_DIGIT(); + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result2 = parse_DIGIT(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result3 = parse_DIGIT(); + result3 = result3 !== null ? result3 : ""; + if (result3 !== null) { + result4 = parse_DIGIT(); + result4 = result4 !== null ? result4 : ""; + if (result4 !== null) { + result0 = [result0, result1, result2, result3, result4]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, via_sent_by_port) { + data.port = parseInt(via_sent_by_port.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_ttl() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_DIGIT(); + if (result0 !== null) { + result1 = parse_DIGIT(); + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result2 = parse_DIGIT(); + result2 = result2 !== null ? result2 : ""; + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, ttl) { + return parseInt(ttl.join('')); + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_WWW_Authenticate() { + var result0; + result0 = parse_challenge(); + return result0; + } + function parse_Session_Expires() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_s_e_expires(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_s_e_params(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_s_e_params(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_s_e_expires() { + var result0; + var pos0; + pos0 = pos; + result0 = parse_delta_seconds(); + if (result0 !== null) { + result0 = function (offset, expires) { + data.expires = expires; + }(pos0, result0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_s_e_params() { + var result0; + result0 = parse_s_e_refresher(); + if (result0 === null) { + result0 = parse_generic_param(); + } + return result0; + } + function parse_s_e_refresher() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 9).toLowerCase() === "refresher") { + result0 = input.substr(pos, 9); + pos += 9; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"refresher\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + if (input.substr(pos, 3).toLowerCase() === "uac") { + result2 = input.substr(pos, 3); + pos += 3; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"uac\""); + } + } + if (result2 === null) { + if (input.substr(pos, 3).toLowerCase() === "uas") { + result2 = input.substr(pos, 3); + pos += 3; + } else { + result2 = null; + if (reportFailures === 0) { + matchFailed("\"uas\""); + } + } + } + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, s_e_refresher_value) { + data.refresher = s_e_refresher_value.toLowerCase(); + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_extension_header() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_token(); + if (result0 !== null) { + result1 = parse_HCOLON(); + if (result1 !== null) { + result2 = parse_header_value(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_header_value() { + var result0, result1; + result0 = []; + result1 = parse_TEXT_UTF8char(); + if (result1 === null) { + result1 = parse_UTF8_CONT(); + if (result1 === null) { + result1 = parse_LWS(); + } + } + while (result1 !== null) { + result0.push(result1); + result1 = parse_TEXT_UTF8char(); + if (result1 === null) { + result1 = parse_UTF8_CONT(); + if (result1 === null) { + result1 = parse_LWS(); + } + } + } + return result0; + } + function parse_message_body() { + var result0, result1; + result0 = []; + result1 = parse_OCTET(); + while (result1 !== null) { + result0.push(result1); + result1 = parse_OCTET(); + } + return result0; + } + function parse_uuid_URI() { + var result0, result1; + var pos0; + pos0 = pos; + if (input.substr(pos, 5) === "uuid:") { + result0 = "uuid:"; + pos += 5; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"uuid:\""); + } + } + if (result0 !== null) { + result1 = parse_uuid(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_uuid() { + var result0, result1, result2, result3, result4, result5, result6, result7, result8; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + result0 = parse_hex8(); + if (result0 !== null) { + if (input.charCodeAt(pos) === 45) { + result1 = "-"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result1 !== null) { + result2 = parse_hex4(); + if (result2 !== null) { + if (input.charCodeAt(pos) === 45) { + result3 = "-"; + pos++; + } else { + result3 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result3 !== null) { + result4 = parse_hex4(); + if (result4 !== null) { + if (input.charCodeAt(pos) === 45) { + result5 = "-"; + pos++; + } else { + result5 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result5 !== null) { + result6 = parse_hex4(); + if (result6 !== null) { + if (input.charCodeAt(pos) === 45) { + result7 = "-"; + pos++; + } else { + result7 = null; + if (reportFailures === 0) { + matchFailed("\"-\""); + } + } + if (result7 !== null) { + result8 = parse_hex12(); + if (result8 !== null) { + result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, uuid) { + data = input.substring(pos + 5, offset); + }(pos0, result0[0]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_hex4() { + var result0, result1, result2, result3; + var pos0; + pos0 = pos; + result0 = parse_HEXDIG(); + if (result0 !== null) { + result1 = parse_HEXDIG(); + if (result1 !== null) { + result2 = parse_HEXDIG(); + if (result2 !== null) { + result3 = parse_HEXDIG(); + if (result3 !== null) { + result0 = [result0, result1, result2, result3]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_hex8() { + var result0, result1; + var pos0; + pos0 = pos; + result0 = parse_hex4(); + if (result0 !== null) { + result1 = parse_hex4(); + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_hex12() { + var result0, result1, result2; + var pos0; + pos0 = pos; + result0 = parse_hex4(); + if (result0 !== null) { + result1 = parse_hex4(); + if (result1 !== null) { + result2 = parse_hex4(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_Refer_To() { + var result0, result1, result2, result3; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_SIP_URI_noparams(); + if (result0 === null) { + result0 = parse_name_addr(); + } + if (result0 !== null) { + result1 = []; + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + while (result2 !== null) { + result1.push(result2); + pos2 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_generic_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos2; + } + } else { + result2 = null; + pos = pos2; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + try { + data = new NameAddrHeader(data.uri, data.display_name, data.params); + } catch (e) { + data = -1; + } + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_Replaces() { + var result0, result1, result2, result3; + var pos0, pos1; + pos0 = pos; + result0 = parse_call_id(); + if (result0 !== null) { + result1 = []; + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_replaces_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + while (result2 !== null) { + result1.push(result2); + pos1 = pos; + result2 = parse_SEMI(); + if (result2 !== null) { + result3 = parse_replaces_param(); + if (result3 !== null) { + result2 = [result2, result3]; + } else { + result2 = null; + pos = pos1; + } + } else { + result2 = null; + pos = pos1; + } + } + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos0; + } + } else { + result0 = null; + pos = pos0; + } + return result0; + } + function parse_call_id() { + var result0, result1, result2; + var pos0, pos1, pos2; + pos0 = pos; + pos1 = pos; + result0 = parse_word(); + if (result0 !== null) { + pos2 = pos; + if (input.charCodeAt(pos) === 64) { + result1 = "@"; + pos++; + } else { + result1 = null; + if (reportFailures === 0) { + matchFailed("\"@\""); + } + } + if (result1 !== null) { + result2 = parse_word(); + if (result2 !== null) { + result1 = [result1, result2]; + } else { + result1 = null; + pos = pos2; + } + } else { + result1 = null; + pos = pos2; + } + result1 = result1 !== null ? result1 : ""; + if (result1 !== null) { + result0 = [result0, result1]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset) { + data.call_id = input.substring(pos, offset); + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_replaces_param() { + var result0; + result0 = parse_to_tag(); + if (result0 === null) { + result0 = parse_from_tag(); + if (result0 === null) { + result0 = parse_early_flag(); + if (result0 === null) { + result0 = parse_generic_param(); + } + } + } + return result0; + } + function parse_to_tag() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 6) === "to-tag") { + result0 = "to-tag"; + pos += 6; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"to-tag\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_token(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, to_tag) { + data.to_tag = to_tag; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_from_tag() { + var result0, result1, result2; + var pos0, pos1; + pos0 = pos; + pos1 = pos; + if (input.substr(pos, 8) === "from-tag") { + result0 = "from-tag"; + pos += 8; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"from-tag\""); + } + } + if (result0 !== null) { + result1 = parse_EQUAL(); + if (result1 !== null) { + result2 = parse_token(); + if (result2 !== null) { + result0 = [result0, result1, result2]; + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + } else { + result0 = null; + pos = pos1; + } + if (result0 !== null) { + result0 = function (offset, from_tag) { + data.from_tag = from_tag; + }(pos0, result0[2]); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function parse_early_flag() { + var result0; + var pos0; + pos0 = pos; + if (input.substr(pos, 10) === "early-only") { + result0 = "early-only"; + pos += 10; + } else { + result0 = null; + if (reportFailures === 0) { + matchFailed("\"early-only\""); + } + } + if (result0 !== null) { + result0 = function (offset) { + data.early_only = true; + }(pos0); + } + if (result0 === null) { + pos = pos0; + } + return result0; + } + function cleanupExpected(expected) { + expected.sort(); + var lastExpected = null; + var cleanExpected = []; + for (var i = 0; i < expected.length; i++) { + if (expected[i] !== lastExpected) { + cleanExpected.push(expected[i]); + lastExpected = expected[i]; + } + } + return cleanExpected; + } + function computeErrorPosition() { + /* + * The first idea was to use |String.split| to break the input up to the + * error position along newlines and derive the line and column from + * there. However IE's |split| implementation is so broken that it was + * enough to prevent it. + */ + var line = 1; + var column = 1; + var seenCR = false; + for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) { + var ch = input.charAt(i); + if (ch === "\n") { + if (!seenCR) { + line++; + } + column = 1; + seenCR = false; + } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { + line++; + column = 1; + seenCR = true; + } else { + column++; + seenCR = false; + } + } + return { + line: line, + column: column + }; + } + var URI = require('./URI'); + var NameAddrHeader = require('./NameAddrHeader'); + var data = {}; + var result = parseFunctions[startRule](); + /* + * The parser is now in one of the following three states: + * + * 1. The parser successfully parsed the whole input. + * + * - |result !== null| + * - |pos === input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 2. The parser successfully parsed only a part of the input. + * + * - |result !== null| + * - |pos < input.length| + * - |rightmostFailuresExpected| may or may not contain something + * + * 3. The parser did not successfully parse any part of the input. + * + * - |result === null| + * - |pos === 0| + * - |rightmostFailuresExpected| contains at least one failure + * + * All code following this comment (including called functions) must + * handle these states. + */ + if (result === null || pos !== input.length) { + var offset = Math.max(pos, rightmostFailuresPos); + var found = offset < input.length ? input.charAt(offset) : null; + var errorPosition = computeErrorPosition(); + new this.SyntaxError(cleanupExpected(rightmostFailuresExpected), found, offset, errorPosition.line, errorPosition.column); + return -1; + } + return data; + }, + /* Returns the parser source code. */ + toSource: function toSource() { + return this._source; + } + }; + /* Thrown when a parser encounters a syntax error. */ + result.SyntaxError = function (expected, found, offset, line, column) { + function buildMessage(expected, found) { + var expectedHumanized, foundHumanized; + switch (expected.length) { + case 0: + expectedHumanized = "end of input"; + break; + case 1: + expectedHumanized = expected[0]; + break; + default: + expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + " or " + expected[expected.length - 1]; + } + foundHumanized = found ? quote(found) : "end of input"; + return "Expected " + expectedHumanized + " but " + foundHumanized + " found."; + } + this.name = "SyntaxError"; + this.expected = expected; + this.found = found; + this.message = buildMessage(expected, found); + this.offset = offset; + this.line = line; + this.column = column; + }; + result.SyntaxError.prototype = Error.prototype; + return result; +}(); +},{"./NameAddrHeader":11,"./URI":29}],8:[function(require,module,exports){ +"use strict"; + +var pkg = require('../package.json'); +var C = require('./Constants'); +var Exceptions = require('./Exceptions'); +var Utils = require('./Utils'); +var UA = require('./UA'); +var URI = require('./URI'); +var NameAddrHeader = require('./NameAddrHeader'); +var Grammar = require('./Grammar'); +var WebSocketInterface = require('./WebSocketInterface'); +var SIPMessage = require('./SIPMessage'); +var Parser = require('./Parser'); +var DigestAuthentication = require('./DigestAuthentication'); +var debug = require('debug')('JsSIP'); +debug('version %s', pkg.version); + +/** + * Expose the JsSIP module. + */ +module.exports = { + C: C, + Exceptions: Exceptions, + Utils: Utils, + UA: UA, + URI: URI, + NameAddrHeader: NameAddrHeader, + WebSocketInterface: WebSocketInterface, + Grammar: Grammar, + // Expose for dual registration. Igor + SIPMessage: SIPMessage, + Parser: Parser, + DigestAuthentication: DigestAuthentication, + // Expose the debug module. + debug: require('debug'), + get name() { + return pkg.title; + }, + get version() { + return pkg.version; + } +}; +},{"../package.json":42,"./Constants":2,"./DigestAuthentication":5,"./Exceptions":6,"./Grammar":7,"./NameAddrHeader":11,"./Parser":14,"./SIPMessage":22,"./UA":28,"./URI":29,"./Utils":30,"./WebSocketInterface":31,"debug":34}],9:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var debug = require('debug'); +var APP_NAME = 'JsSIP'; +module.exports = /*#__PURE__*/function () { + function Logger(prefix) { + _classCallCheck(this, Logger); + if (prefix) { + this._debug = debug["default"]("".concat(APP_NAME, ":").concat(prefix)); + this._warn = debug["default"]("".concat(APP_NAME, ":WARN:").concat(prefix)); + this._error = debug["default"]("".concat(APP_NAME, ":ERROR:").concat(prefix)); + } else { + this._debug = debug["default"](APP_NAME); + this._warn = debug["default"]("".concat(APP_NAME, ":WARN")); + this._error = debug["default"]("".concat(APP_NAME, ":ERROR")); + } + /* eslint-disable no-console */ + this._debug.log = console.info.bind(console); + this._warn.log = console.warn.bind(console); + this._error.log = console.error.bind(console); + /* eslint-enable no-console */ + } + _createClass(Logger, [{ + key: "debug", + get: function get() { + return this._debug; + } + }, { + key: "warn", + get: function get() { + return this._warn; + } + }, { + key: "error", + get: function get() { + return this._error; + } + }]); + return Logger; +}(); +},{"debug":34}],10:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var SIPMessage = require('./SIPMessage'); +var Utils = require('./Utils'); +var RequestSender = require('./RequestSender'); +var Exceptions = require('./Exceptions'); +var URI = require('./URI'); +var logger = new Logger('Message'); +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(Message, _EventEmitter); + var _super = _createSuper(Message); + function Message(ua) { + var _this; + _classCallCheck(this, Message); + _this = _super.call(this); + _this._ua = ua; + _this._request = null; + _this._closed = false; + _this._direction = null; + _this._local_identity = null; + _this._remote_identity = null; + + // Whether an incoming message has been replied. + _this._is_replied = false; + + // Custom message empty object for high level use. + _this._data = {}; + return _this; + } + _createClass(Message, [{ + key: "direction", + get: function get() { + return this._direction; + } + }, { + key: "local_identity", + get: function get() { + return this._local_identity; + } + }, { + key: "remote_identity", + get: function get() { + return this._remote_identity; + } + }, { + key: "send", + value: function send(target, body) { + var _this2 = this; + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + var originalTarget = target; + if (target === undefined || body === undefined) { + throw new TypeError('Not enough arguments'); + } + + // Check target validity. + target = this._ua.normalizeTarget(target); + if (!target) { + throw new TypeError("Invalid target: ".concat(originalTarget)); + } + + // Get call options. + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var eventHandlers = Utils.cloneObject(options.eventHandlers); + var contentType = options.contentType || 'text/plain'; + var requestParams = {}; + if (options.fromUserName) { + requestParams.from_uri = new URI('sip', options.fromUserName, this._ua.configuration.uri.host); + extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString())); + } + if (options.fromDisplayName) { + requestParams.from_display_name = options.fromDisplayName; + } + + // Set event handlers. + for (var event in eventHandlers) { + if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) { + this.on(event, eventHandlers[event]); + } + } + extraHeaders.push("Content-Type: ".concat(contentType)); + this._request = new SIPMessage.OutgoingRequest(JsSIP_C.MESSAGE, target, this._ua, requestParams, extraHeaders); + if (body) { + this._request.body = body; + } + var request_sender = new RequestSender(this._ua, this._request, { + onRequestTimeout: function onRequestTimeout() { + _this2._onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this2._onTransportError(); + }, + onReceiveResponse: function onReceiveResponse(response) { + _this2._receiveResponse(response); + } + }); + this._newMessage('local', this._request); + request_sender.send(); + } + }, { + key: "init_incoming", + value: function init_incoming(request) { + this._request = request; + this._newMessage('remote', request); + + // Reply with a 200 OK if the user didn't reply. + if (!this._is_replied) { + this._is_replied = true; + request.reply(200); + } + this._close(); + } + + /** + * Accept the incoming Message + * Only valid for incoming Messages + */ + }, { + key: "accept", + value: function accept() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var body = options.body; + if (this._direction !== 'incoming') { + throw new Exceptions.NotSupportedError('"accept" not supported for outgoing Message'); + } + if (this._is_replied) { + throw new Error('incoming Message already replied'); + } + this._is_replied = true; + this._request.reply(200, null, extraHeaders, body); + } + + /** + * Reject the incoming Message + * Only valid for incoming Messages + */ + }, { + key: "reject", + value: function reject() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var status_code = options.status_code || 480; + var reason_phrase = options.reason_phrase; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var body = options.body; + if (this._direction !== 'incoming') { + throw new Exceptions.NotSupportedError('"reject" not supported for outgoing Message'); + } + if (this._is_replied) { + throw new Error('incoming Message already replied'); + } + if (status_code < 300 || status_code >= 700) { + throw new TypeError("Invalid status_code: ".concat(status_code)); + } + this._is_replied = true; + this._request.reply(status_code, reason_phrase, extraHeaders, body); + } + }, { + key: "_receiveResponse", + value: function _receiveResponse(response) { + if (this._closed) { + return; + } + switch (true) { + case /^1[0-9]{2}$/.test(response.status_code): + // Ignore provisional responses. + break; + case /^2[0-9]{2}$/.test(response.status_code): + this._succeeded('remote', response); + break; + default: + { + var cause = Utils.sipErrorCause(response.status_code); + this._failed('remote', response, cause); + break; + } + } + } + }, { + key: "_onRequestTimeout", + value: function _onRequestTimeout() { + if (this._closed) { + return; + } + this._failed('system', null, JsSIP_C.causes.REQUEST_TIMEOUT); + } + }, { + key: "_onTransportError", + value: function _onTransportError() { + if (this._closed) { + return; + } + this._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR); + } + }, { + key: "_close", + value: function _close() { + this._closed = true; + this._ua.destroyMessage(this); + } + + /** + * Internal Callbacks + */ + }, { + key: "_newMessage", + value: function _newMessage(originator, request) { + if (originator === 'remote') { + this._direction = 'incoming'; + this._local_identity = request.to; + this._remote_identity = request.from; + } else if (originator === 'local') { + this._direction = 'outgoing'; + this._local_identity = request.from; + this._remote_identity = request.to; + } + this._ua.newMessage(this, { + originator: originator, + message: this, + request: request + }); + } + }, { + key: "_failed", + value: function _failed(originator, response, cause) { + logger.debug('MESSAGE failed'); + this._close(); + logger.debug('emit "failed"'); + this.emit('failed', { + originator: originator, + response: response || null, + cause: cause + }); + } + }, { + key: "_succeeded", + value: function _succeeded(originator, response) { + logger.debug('MESSAGE succeeded'); + this._close(); + logger.debug('emit "succeeded"'); + this.emit('succeeded', { + originator: originator, + response: response + }); + } + }]); + return Message; +}(EventEmitter); +},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./URI":29,"./Utils":30,"events":33}],11:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var URI = require('./URI'); +var Grammar = require('./Grammar'); +module.exports = /*#__PURE__*/function () { + function NameAddrHeader(uri, display_name, parameters) { + _classCallCheck(this, NameAddrHeader); + // Checks. + if (!uri || !(uri instanceof URI)) { + throw new TypeError('missing or invalid "uri" parameter'); + } + + // Initialize parameters. + this._uri = uri; + this._parameters = {}; + this.display_name = display_name; + for (var param in parameters) { + if (Object.prototype.hasOwnProperty.call(parameters, param)) { + this.setParam(param, parameters[param]); + } + } + } + _createClass(NameAddrHeader, [{ + key: "uri", + get: function get() { + return this._uri; + } + }, { + key: "display_name", + get: function get() { + return this._display_name; + }, + set: function set(value) { + this._display_name = value === 0 ? '0' : value; + } + }, { + key: "setParam", + value: function setParam(key, value) { + if (key) { + this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString(); + } + } + }, { + key: "getParam", + value: function getParam(key) { + if (key) { + return this._parameters[key.toLowerCase()]; + } + } + }, { + key: "hasParam", + value: function hasParam(key) { + if (key) { + return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false; + } + } + }, { + key: "deleteParam", + value: function deleteParam(parameter) { + parameter = parameter.toLowerCase(); + if (this._parameters.hasOwnProperty(parameter)) { + var value = this._parameters[parameter]; + delete this._parameters[parameter]; + return value; + } + } + }, { + key: "clearParams", + value: function clearParams() { + this._parameters = {}; + } + }, { + key: "clone", + value: function clone() { + return new NameAddrHeader(this._uri.clone(), this._display_name, JSON.parse(JSON.stringify(this._parameters))); + } + }, { + key: "_quote", + value: function _quote(str) { + return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + } + }, { + key: "toString", + value: function toString() { + var body = this._display_name ? "\"".concat(this._quote(this._display_name), "\" ") : ''; + body += "<".concat(this._uri.toString(), ">"); + for (var parameter in this._parameters) { + if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) { + body += ";".concat(parameter); + if (this._parameters[parameter] !== null) { + body += "=".concat(this._parameters[parameter]); + } + } + } + return body; + } + }], [{ + key: "parse", + value: + /** + * Parse the given string and returns a NameAddrHeader instance or undefined if + * it is an invalid NameAddrHeader. + */ + function parse(name_addr_header) { + name_addr_header = Grammar.parse(name_addr_header, 'Name_Addr_Header'); + if (name_addr_header !== -1) { + return name_addr_header; + } else { + return undefined; + } + } + }]); + return NameAddrHeader; +}(); +},{"./Grammar":7,"./URI":29}],12:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var Utils = require('./Utils'); +var Dialog = require('./Dialog'); +var logger = new Logger('Notifier'); + +/** + * Termination codes. + */ +var C = { + // Termination codes. + NOTIFY_RESPONSE_TIMEOUT: 0, + NOTIFY_TRANSPORT_ERROR: 1, + NOTIFY_NON_OK_RESPONSE: 2, + NOTIFY_FAILED_AUTHENTICATION: 3, + SEND_FINAL_NOTIFY: 4, + RECEIVE_UNSUBSCRIBE: 5, + SUBSCRIPTION_EXPIRED: 6, + // Notifer states + STATE_PENDING: 0, + STATE_ACTIVE: 1, + STATE_TERMINATED: 2 +}; + +/** + * RFC 6665 Notifier implementation. + */ +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(Notifier, _EventEmitter); + var _super = _createSuper(Notifier); + /** + * @param {UA} ua - JsSIP User Agent instance. + * @param {IncomingRequest} subscribe - Subscribe request. + * @param {string} contentType - Content-Type header value. + * @param {NotifierOptions} options - Optional parameters. + * @param {Array} extraHeaders - Additional SIP headers. + * @param {string} allowEvents - Allow-Events header value. + * @param {boolean} pending - Set initial dialog state as "pending". + */ + function Notifier(ua, subscribe, contentType, _ref) { + var _this; + var extraHeaders = _ref.extraHeaders, + allowEvents = _ref.allowEvents, + pending = _ref.pending; + _classCallCheck(this, Notifier); + logger.debug('new'); + _this = _super.call(this); + if (!subscribe) { + throw new TypeError('subscribe is undefined'); + } + if (!contentType) { + throw new TypeError('contentType is undefined'); + } + _this._ua = ua; + _this._initial_subscribe = subscribe; + _this._expires_timestamp = null; + _this._expires_timer = null; + + // Notifier state: pending, active, terminated. Not used: init, resp_wait. + _this._state = pending ? C.STATE_PENDING : C.STATE_ACTIVE; + + // Optional. Used to build terminated Subscription-State. + _this._terminated_reason = null; + _this._terminated_retry_after = null; + + // Custom session empty object for high level use. + _this.data = {}; + _this._dialog = null; + var eventName = subscribe.getHeader('event'); + _this._content_type = contentType; + _this._expires = parseInt(subscribe.getHeader('expires')); + _this._headers = Utils.cloneArray(extraHeaders); + _this._headers.push("Event: ".concat(eventName)); + + // Use contact from extraHeaders or create it. + _this._contact = _this._headers.find(function (header) { + return header.startsWith('Contact'); + }); + if (!_this._contact) { + _this._contact = "Contact: "); + _this._headers.push(_this._contact); + } + if (allowEvents) { + _this._headers.push("Allow-Events: ".concat(allowEvents)); + } + _this._target = subscribe.from.uri.user; + subscribe.to_tag = Utils.newTag(); + + // Create dialog for normal and fetch-subscribe. + var dialog = new Dialog(_assertThisInitialized(_this), subscribe, 'UAS'); + if (dialog.error) { + logger.warn(dialog.error); + throw new Error('SUBSCRIBE missed Contact'); + } + _this._dialog = dialog; + if (_this._expires > 0) { + // Set expires timer and time-stamp. + _this._setExpiresTimer(); + } + return _this; + } + + /** + * Dialog callback. + * Called also for initial subscribe. + * Supported RFC 6665 4.4.3: initial fetch subscribe (with expires: 0). + */ + _createClass(Notifier, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "receiveRequest", + value: function receiveRequest(request) { + if (request.method !== JsSIP_C.SUBSCRIBE) { + request.reply(405); + return; + } + var expiresValue = request.getHeader('expires'); + if (expiresValue === undefined || expiresValue === null) { + // Missed header Expires. RFC 6665 3.1.1. Set default expires value. + expiresValue = '900'; + logger.debug("Missed expires header. Set by default ".concat(expiresValue)); + } + this._expires = parseInt(expiresValue); + request.reply(200, null, ["Expires: ".concat(this._expires), "".concat(this._contact)]); + var body = request.body; + var content_type = request.getHeader('content-type'); + var is_unsubscribe = this._expires === 0; + if (!is_unsubscribe) { + this._setExpiresTimer(); + } + logger.debug('emit "subscribe"'); + this.emit('subscribe', is_unsubscribe, request, body, content_type); + if (is_unsubscribe) { + this._dialogTerminated(C.RECEIVE_UNSUBSCRIBE); + } + } + + /** + * User API + */ + /** + * Please call after creating the Notifier instance and setting the event handlers. + */ + }, { + key: "start", + value: function start() { + logger.debug('start()'); + this.receiveRequest(this._initial_subscribe); + } + + /** + * Switch pending dialog state to active. + */ + }, { + key: "setActiveState", + value: function setActiveState() { + logger.debug('setActiveState()'); + if (this._state === C.STATE_PENDING) { + this._state = C.STATE_ACTIVE; + } + } + + /** + * Send the initial and subsequent notify request. + * @param {string} body - notify request body. + */ + }, { + key: "notify", + value: function notify() { + var _this2 = this; + var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + logger.debug('notify()'); + + // Prevent send notify after final notify. + if (!this._dialog) { + logger.warn('final notify has sent'); + return; + } + var subs_state = this._stateNumberToString(this._state); + if (this._state !== C.STATE_TERMINATED) { + var expires = Math.floor((this._expires_timestamp - new Date().getTime()) / 1000); + if (expires < 0) { + expires = 0; + } + subs_state += ";expires=".concat(expires); + } else { + if (this._terminated_reason) { + subs_state += ";reason=".concat(this._terminated_reason); + } + if (this._terminated_retry_after !== null) { + subs_state += ";retry-after=".concat(this._terminated_retry_after); + } + } + var headers = this._headers.slice(); + headers.push("Subscription-State: ".concat(subs_state)); + if (body) { + headers.push("Content-Type: ".concat(this._content_type)); + } + this._dialog.sendRequest(JsSIP_C.NOTIFY, { + body: body, + extraHeaders: headers, + eventHandlers: { + onRequestTimeout: function onRequestTimeout() { + _this2._dialogTerminated(C.NOTIFY_RESPONSE_TIMEOUT); + }, + onTransportError: function onTransportError() { + _this2._dialogTerminated(C.NOTIFY_TRANSPORT_ERROR); + }, + onErrorResponse: function onErrorResponse(response) { + if (response.status_code === 401 || response.status_code === 407) { + _this2._dialogTerminated(C.NOTIFY_FAILED_AUTHENTICATION); + } else { + _this2._dialogTerminated(C.NOTIFY_NON_OK_RESPONSE); + } + }, + onDialogError: function onDialogError() { + _this2._dialogTerminated(C.NOTIFY_NON_OK_RESPONSE); + } + } + }); + } + + /** + * Terminate. (Send the final NOTIFY request). + * + * @param {string} body - Notify message body. + * @param {string} reason - Set Subscription-State reason parameter. + * @param {number} retryAfter - Set Subscription-State retry-after parameter. + */ + }, { + key: "terminate", + value: function terminate() { + var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var retryAfter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + logger.debug('terminate()'); + this._state = C.STATE_TERMINATED; + this._terminated_reason = reason; + this._terminated_retry_after = retryAfter; + this.notify(body); + this._dialogTerminated(C.SEND_FINAL_NOTIFY); + } + + /** + * Get dialog state. + */ + }, { + key: "state", + get: function get() { + return this._state; + } + + /** + * Get dialog id. + */ + }, { + key: "id", + get: function get() { + return this._dialog ? this._dialog.id : null; + } + + /** + * Private API + */ + }, { + key: "_dialogTerminated", + value: function _dialogTerminated(termination_code) { + if (!this._dialog) { + return; + } + this._state = C.STATE_TERMINATED; + clearTimeout(this._expires_timer); + if (this._dialog) { + this._dialog.terminate(); + this._dialog = null; + } + var send_final_notify = termination_code === C.SUBSCRIPTION_EXPIRED; + logger.debug("emit \"terminated\" code=".concat(termination_code, ", send final notify=").concat(send_final_notify)); + this.emit('terminated', termination_code, send_final_notify); + } + }, { + key: "_setExpiresTimer", + value: function _setExpiresTimer() { + var _this3 = this; + this._expires_timestamp = new Date().getTime() + this._expires * 1000; + clearTimeout(this._expires_timer); + this._expires_timer = setTimeout(function () { + if (!_this3._dialog) { + return; + } + _this3._terminated_reason = 'timeout'; + _this3.notify(); + _this3._dialogTerminated(C.SUBSCRIPTION_EXPIRED); + }, this._expires * 1000); + } + }, { + key: "_stateNumberToString", + value: function _stateNumberToString(state) { + switch (state) { + case C.STATE_PENDING: + return 'pending'; + case C.STATE_ACTIVE: + return 'active'; + case C.STATE_TERMINATED: + return 'terminated'; + default: + throw new TypeError('wrong state value'); + } + } + }], [{ + key: "C", + get: + /** + * Expose C object. + */ + function get() { + return C; + } + }]); + return Notifier; +}(EventEmitter); +},{"./Constants":2,"./Dialog":3,"./Logger":9,"./Utils":30,"events":33}],13:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var SIPMessage = require('./SIPMessage'); +var Utils = require('./Utils'); +var RequestSender = require('./RequestSender'); +var Exceptions = require('./Exceptions'); +var logger = new Logger('Options'); +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(Options, _EventEmitter); + var _super = _createSuper(Options); + function Options(ua) { + var _this; + _classCallCheck(this, Options); + _this = _super.call(this); + _this._ua = ua; + _this._request = null; + _this._closed = false; + _this._direction = null; + _this._local_identity = null; + _this._remote_identity = null; + + // Whether an incoming message has been replied. + _this._is_replied = false; + + // Custom message empty object for high level use. + _this._data = {}; + return _this; + } + _createClass(Options, [{ + key: "direction", + get: function get() { + return this._direction; + } + }, { + key: "local_identity", + get: function get() { + return this._local_identity; + } + }, { + key: "remote_identity", + get: function get() { + return this._remote_identity; + } + }, { + key: "send", + value: function send(target, body) { + var _this2 = this; + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + var originalTarget = target; + if (target === undefined) { + throw new TypeError('A target is required for OPTIONS'); + } + + // Check target validity. + target = this._ua.normalizeTarget(target); + if (!target) { + throw new TypeError("Invalid target: ".concat(originalTarget)); + } + + // Get call options. + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var eventHandlers = Utils.cloneObject(options.eventHandlers); + var contentType = options.contentType || 'application/sdp'; + + // Set event handlers. + for (var event in eventHandlers) { + if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) { + this.on(event, eventHandlers[event]); + } + } + extraHeaders.push("Content-Type: ".concat(contentType)); + this._request = new SIPMessage.OutgoingRequest(JsSIP_C.OPTIONS, target, this._ua, null, extraHeaders); + if (body) { + this._request.body = body; + } + var request_sender = new RequestSender(this._ua, this._request, { + onRequestTimeout: function onRequestTimeout() { + _this2._onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this2._onTransportError(); + }, + onReceiveResponse: function onReceiveResponse(response) { + _this2._receiveResponse(response); + } + }); + this._newOptions('local', this._request); + request_sender.send(); + } + }, { + key: "init_incoming", + value: function init_incoming(request) { + this._request = request; + this._newOptions('remote', request); + + // Reply with a 200 OK if the user didn't reply. + if (!this._is_replied) { + this._is_replied = true; + request.reply(200); + } + this._close(); + } + + /** + * Accept the incoming Options + * Only valid for incoming Options + */ + }, { + key: "accept", + value: function accept() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var body = options.body; + if (this._direction !== 'incoming') { + throw new Exceptions.NotSupportedError('"accept" not supported for outgoing Options'); + } + if (this._is_replied) { + throw new Error('incoming Options already replied'); + } + this._is_replied = true; + this._request.reply(200, null, extraHeaders, body); + } + + /** + * Reject the incoming Options + * Only valid for incoming Options + */ + }, { + key: "reject", + value: function reject() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var status_code = options.status_code || 480; + var reason_phrase = options.reason_phrase; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var body = options.body; + if (this._direction !== 'incoming') { + throw new Exceptions.NotSupportedError('"reject" not supported for outgoing Options'); + } + if (this._is_replied) { + throw new Error('incoming Options already replied'); + } + if (status_code < 300 || status_code >= 700) { + throw new TypeError("Invalid status_code: ".concat(status_code)); + } + this._is_replied = true; + this._request.reply(status_code, reason_phrase, extraHeaders, body); + } + }, { + key: "_receiveResponse", + value: function _receiveResponse(response) { + if (this._closed) { + return; + } + switch (true) { + case /^1[0-9]{2}$/.test(response.status_code): + // Ignore provisional responses. + break; + case /^2[0-9]{2}$/.test(response.status_code): + this._succeeded('remote', response); + break; + default: + { + var cause = Utils.sipErrorCause(response.status_code); + this._failed('remote', response, cause); + break; + } + } + } + }, { + key: "_onRequestTimeout", + value: function _onRequestTimeout() { + if (this._closed) { + return; + } + this._failed('system', null, JsSIP_C.causes.REQUEST_TIMEOUT); + } + }, { + key: "_onTransportError", + value: function _onTransportError() { + if (this._closed) { + return; + } + this._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR); + } + }, { + key: "_close", + value: function _close() { + this._closed = true; + this._ua.destroyMessage(this); + } + + /** + * Internal Callbacks + */ + }, { + key: "_newOptions", + value: function _newOptions(originator, request) { + if (originator === 'remote') { + this._direction = 'incoming'; + this._local_identity = request.to; + this._remote_identity = request.from; + } else if (originator === 'local') { + this._direction = 'outgoing'; + this._local_identity = request.from; + this._remote_identity = request.to; + } + this._ua.newOptions(this, { + originator: originator, + message: this, + request: request + }); + } + }, { + key: "_failed", + value: function _failed(originator, response, cause) { + logger.debug('OPTIONS failed'); + this._close(); + logger.debug('emit "failed"'); + this.emit('failed', { + originator: originator, + response: response || null, + cause: cause + }); + } + }, { + key: "_succeeded", + value: function _succeeded(originator, response) { + logger.debug('OPTIONS succeeded'); + this._close(); + logger.debug('emit "succeeded"'); + this.emit('succeeded', { + originator: originator, + response: response + }); + } + }]); + return Options; +}(EventEmitter); +},{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,"events":33}],14:[function(require,module,exports){ +"use strict"; + +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +var Logger = require('./Logger'); +var Grammar = require('./Grammar'); +var SIPMessage = require('./SIPMessage'); +var logger = new Logger('Parser'); + +/** + * Parse SIP Message + */ +exports.parseMessage = function (data, ua) { + var message; + var bodyStart; + var headerEnd = data.indexOf('\r\n'); + if (headerEnd === -1) { + logger.warn('parseMessage() | no CRLF found, not a SIP message'); + return; + } + + // Parse first line. Check if it is a Request or a Reply. + var firstLine = data.substring(0, headerEnd); + var parsed = Grammar.parse(firstLine, 'Request_Response'); + if (parsed === -1) { + logger.warn("parseMessage() | error parsing first line of SIP message: \"".concat(firstLine, "\"")); + return; + } else if (!parsed.status_code) { + message = new SIPMessage.IncomingRequest(ua); + message.method = parsed.method; + message.ruri = parsed.uri; + } else { + message = new SIPMessage.IncomingResponse(); + message.status_code = parsed.status_code; + message.reason_phrase = parsed.reason_phrase; + } + message.data = data; + var headerStart = headerEnd + 2; + + /* Loop over every line in data. Detect the end of each header and parse + * it or simply add to the headers collection. + */ + while (true) { + headerEnd = getHeader(data, headerStart); + + // The SIP message has normally finished. + if (headerEnd === -2) { + bodyStart = headerStart + 2; + break; + } + // Data.indexOf returned -1 due to a malformed message. + else if (headerEnd === -1) { + logger.warn('parseMessage() | malformed message'); + return; + } + parsed = parseHeader(message, data, headerStart, headerEnd); + if (parsed !== true) { + logger.warn('parseMessage() |', parsed.error); + return; + } + headerStart = headerEnd + 2; + } + + /* RFC3261 18.3. + * If there are additional bytes in the transport packet + * beyond the end of the body, they MUST be discarded. + */ + if (message.hasHeader('content-length')) { + var contentLength = message.getHeader('content-length'); + message.body = data.substr(bodyStart, contentLength); + } else { + message.body = data.substring(bodyStart); + } + return message; +}; + +/** + * Extract and parse every header of a SIP message. + */ +function getHeader(data, headerStart) { + // 'start' position of the header. + var start = headerStart; + // 'end' position of the header. + var end = 0; + // 'partial end' position of the header. + var partialEnd = 0; + + // End of message. + if (data.substring(start, start + 2).match(/(^\r\n)/)) { + return -2; + } + while (end === 0) { + // Partial End of Header. + partialEnd = data.indexOf('\r\n', start); + + // 'indexOf' returns -1 if the value to be found never occurs. + if (partialEnd === -1) { + return partialEnd; + } + if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) { + // Not the end of the message. Continue from the next position. + start = partialEnd + 2; + } else { + end = partialEnd; + } + } + return end; +} +function parseHeader(message, data, headerStart, headerEnd) { + var parsed; + var hcolonIndex = data.indexOf(':', headerStart); + var headerName = data.substring(headerStart, hcolonIndex).trim(); + var headerValue = data.substring(hcolonIndex + 1, headerEnd).trim(); + + // If header-field is well-known, parse it. + switch (headerName.toLowerCase()) { + case 'via': + case 'v': + message.addHeader('via', headerValue); + if (message.getHeaders('via').length === 1) { + parsed = message.parseHeader('Via'); + if (parsed) { + message.via = parsed; + message.via_branch = parsed.branch; + } + } else { + parsed = 0; + } + break; + case 'from': + case 'f': + message.setHeader('from', headerValue); + parsed = message.parseHeader('from'); + if (parsed) { + message.from = parsed; + message.from_tag = parsed.getParam('tag'); + } + break; + case 'to': + case 't': + message.setHeader('to', headerValue); + parsed = message.parseHeader('to'); + if (parsed) { + message.to = parsed; + message.to_tag = parsed.getParam('tag'); + } + break; + case 'record-route': + parsed = Grammar.parse(headerValue, 'Record_Route'); + if (parsed === -1) { + parsed = undefined; + } else { + var _iterator = _createForOfIteratorHelper(parsed), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var header = _step.value; + message.addHeader('record-route', headerValue.substring(header.possition, header.offset)); + message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed; + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } + break; + case 'call-id': + case 'i': + message.setHeader('call-id', headerValue); + parsed = message.parseHeader('call-id'); + if (parsed) { + message.call_id = headerValue; + } + break; + case 'contact': + case 'm': + parsed = Grammar.parse(headerValue, 'Contact'); + if (parsed === -1) { + parsed = undefined; + } else { + var _iterator2 = _createForOfIteratorHelper(parsed), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var _header = _step2.value; + message.addHeader('contact', headerValue.substring(_header.possition, _header.offset)); + message.headers.Contact[message.getHeaders('contact').length - 1].parsed = _header.parsed; + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + } + break; + case 'content-length': + case 'l': + message.setHeader('content-length', headerValue); + parsed = message.parseHeader('content-length'); + break; + case 'content-type': + case 'c': + message.setHeader('content-type', headerValue); + parsed = message.parseHeader('content-type'); + break; + case 'cseq': + message.setHeader('cseq', headerValue); + parsed = message.parseHeader('cseq'); + if (parsed) { + message.cseq = parsed.value; + } + if (message instanceof SIPMessage.IncomingResponse) { + message.method = parsed.method; + } + break; + case 'max-forwards': + message.setHeader('max-forwards', headerValue); + parsed = message.parseHeader('max-forwards'); + break; + case 'www-authenticate': + message.setHeader('www-authenticate', headerValue); + parsed = message.parseHeader('www-authenticate'); + break; + case 'proxy-authenticate': + message.setHeader('proxy-authenticate', headerValue); + parsed = message.parseHeader('proxy-authenticate'); + break; + case 'session-expires': + case 'x': + message.setHeader('session-expires', headerValue); + parsed = message.parseHeader('session-expires'); + if (parsed) { + message.session_expires = parsed.expires; + message.session_expires_refresher = parsed.refresher; + } + break; + case 'refer-to': + case 'r': + message.setHeader('refer-to', headerValue); + parsed = message.parseHeader('refer-to'); + if (parsed) { + message.refer_to = parsed; + } + break; + case 'replaces': + message.setHeader('replaces', headerValue); + parsed = message.parseHeader('replaces'); + if (parsed) { + message.replaces = parsed; + } + break; + case 'event': + case 'o': + message.setHeader('event', headerValue); + parsed = message.parseHeader('event'); + if (parsed) { + message.event = parsed; + } + break; + default: + // Do not parse this header. + message.addHeader(headerName, headerValue); + parsed = 0; + } + if (parsed === undefined) { + return { + error: "error parsing header \"".concat(headerName, "\"") + }; + } else { + return true; + } +} +},{"./Grammar":7,"./Logger":9,"./SIPMessage":22}],15:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e3) { throw _e3; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e4) { didErr = true; err = _e4; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +/* globals RTCPeerConnection: false, RTCSessionDescription: false */ + +var EventEmitter = require('events').EventEmitter; +var sdp_transform = require('sdp-transform'); +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var Exceptions = require('./Exceptions'); +var Transactions = require('./Transactions'); +var Utils = require('./Utils'); +var Timers = require('./Timers'); +var SIPMessage = require('./SIPMessage'); +var Dialog = require('./Dialog'); +var RequestSender = require('./RequestSender'); +var RTCSession_DTMF = require('./RTCSession/DTMF'); +var RTCSession_Info = require('./RTCSession/Info'); +var RTCSession_ReferNotifier = require('./RTCSession/ReferNotifier'); +var RTCSession_ReferSubscriber = require('./RTCSession/ReferSubscriber'); +var URI = require('./URI'); +var logger = new Logger('RTCSession'); +var C = { + // RTCSession states. + STATUS_NULL: 0, + STATUS_INVITE_SENT: 1, + STATUS_1XX_RECEIVED: 2, + STATUS_INVITE_RECEIVED: 3, + STATUS_WAITING_FOR_ANSWER: 4, + STATUS_ANSWERED: 5, + STATUS_WAITING_FOR_ACK: 6, + STATUS_CANCELED: 7, + STATUS_TERMINATED: 8, + STATUS_CONFIRMED: 9 +}; + +/** + * Local variables. + */ +var holdMediaTypes = ['audio', 'video']; +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(RTCSession, _EventEmitter); + var _super = _createSuper(RTCSession); + function RTCSession(ua) { + var _this; + _classCallCheck(this, RTCSession); + logger.debug('new'); + _this = _super.call(this); + _this._id = null; + _this._ua = ua; + _this._status = C.STATUS_NULL; + _this._dialog = null; + _this._earlyDialogs = {}; + _this._contact = null; + _this._from_tag = null; + _this._to_tag = null; + + // The RTCPeerConnection instance (public attribute). + _this._connection = null; + + // Prevent races on serial PeerConnction operations. + _this._connectionPromiseQueue = Promise.resolve(); + + // Incoming/Outgoing request being currently processed. + _this._request = null; + + // Cancel state for initial outgoing request. + _this._is_canceled = false; + _this._cancel_reason = ''; + + // RTCSession confirmation flag. + _this._is_confirmed = false; + + // Is late SDP being negotiated. + _this._late_sdp = false; + + // Default rtcOfferConstraints and rtcAnswerConstrainsts (passed in connect() or answer()). + _this._rtcOfferConstraints = null; + _this._rtcAnswerConstraints = null; + + // Local MediaStream. + _this._localMediaStream = null; + _this._localMediaStreamLocallyGenerated = false; + + // Flag to indicate PeerConnection ready for new actions. + _this._rtcReady = true; + + // Flag to indicate ICE candidate gathering is finished even if iceGatheringState is not yet 'complete'. + _this._iceReady = false; + + // SIP Timers. + _this._timers = { + ackTimer: null, + expiresTimer: null, + invite2xxTimer: null, + userNoAnswerTimer: null + }; + + // Session info. + _this._direction = null; + _this._local_identity = null; + _this._remote_identity = null; + _this._start_time = null; + _this._end_time = null; + _this._tones = null; + + // Mute/Hold state. + _this._audioMuted = false; + _this._videoMuted = false; + _this._localHold = false; + _this._remoteHold = false; + + // Session Timers (RFC 4028). + _this._sessionTimers = { + enabled: _this._ua.configuration.session_timers, + refreshMethod: _this._ua.configuration.session_timers_refresh_method, + defaultExpires: JsSIP_C.SESSION_EXPIRES, + currentExpires: null, + running: false, + refresher: false, + timer: null // A setTimeout. + }; + + // Map of ReferSubscriber instances indexed by the REFER's CSeq number. + _this._referSubscribers = {}; + + // Custom session empty object for high level use. + _this._data = {}; + return _this; + } + + /** + * User API + */ + + // Expose RTCSession constants as a property of the RTCSession instance. + _createClass(RTCSession, [{ + key: "C", + get: function get() { + return C; + } + + // Expose session failed/ended causes as a property of the RTCSession instance. + }, { + key: "causes", + get: function get() { + return JsSIP_C.causes; + } + }, { + key: "id", + get: function get() { + return this._id; + } + }, { + key: "connection", + get: function get() { + return this._connection; + } + }, { + key: "contact", + get: function get() { + return this._contact; + } + }, { + key: "direction", + get: function get() { + return this._direction; + } + }, { + key: "local_identity", + get: function get() { + return this._local_identity; + } + }, { + key: "remote_identity", + get: function get() { + return this._remote_identity; + } + }, { + key: "start_time", + get: function get() { + return this._start_time; + } + }, { + key: "end_time", + get: function get() { + return this._end_time; + } + }, { + key: "data", + get: function get() { + return this._data; + }, + set: function set(_data) { + this._data = _data; + } + }, { + key: "status", + get: function get() { + return this._status; + } + }, { + key: "isInProgress", + value: function isInProgress() { + switch (this._status) { + case C.STATUS_NULL: + case C.STATUS_INVITE_SENT: + case C.STATUS_1XX_RECEIVED: + case C.STATUS_INVITE_RECEIVED: + case C.STATUS_WAITING_FOR_ANSWER: + return true; + default: + return false; + } + } + }, { + key: "isEstablished", + value: function isEstablished() { + switch (this._status) { + case C.STATUS_ANSWERED: + case C.STATUS_WAITING_FOR_ACK: + case C.STATUS_CONFIRMED: + return true; + default: + return false; + } + } + }, { + key: "isEnded", + value: function isEnded() { + switch (this._status) { + case C.STATUS_CANCELED: + case C.STATUS_TERMINATED: + return true; + default: + return false; + } + } + }, { + key: "isMuted", + value: function isMuted() { + return { + audio: this._audioMuted, + video: this._videoMuted + }; + } + }, { + key: "isOnHold", + value: function isOnHold() { + return { + local: this._localHold, + remote: this._remoteHold + }; + } + }, { + key: "connect", + value: function connect(target) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var initCallback = arguments.length > 2 ? arguments[2] : undefined; + logger.debug('connect()'); + var originalTarget = target; + var eventHandlers = Utils.cloneObject(options.eventHandlers); + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var mediaConstraints = Utils.cloneObject(options.mediaConstraints, { + audio: true, + video: true + }); + var mediaStream = options.mediaStream || null; + var pcConfig = Utils.cloneObject(options.pcConfig, { + iceServers: [] + }); + var rtcConstraints = options.rtcConstraints || null; + var rtcOfferConstraints = options.rtcOfferConstraints || null; + this._rtcOfferConstraints = rtcOfferConstraints; + this._rtcAnswerConstraints = options.rtcAnswerConstraints || null; + this._data = options.data || this._data; + + // Check target. + if (target === undefined) { + throw new TypeError('Not enough arguments'); + } + + // Check Session Status. + if (this._status !== C.STATUS_NULL) { + throw new Exceptions.InvalidStateError(this._status); + } + + // Check WebRTC support. + if (!window.RTCPeerConnection) { + throw new Exceptions.NotSupportedError('WebRTC not supported'); + } + + // Check target validity. + target = this._ua.normalizeTarget(target); + if (!target) { + throw new TypeError("Invalid target: ".concat(originalTarget)); + } + + // Session Timers. + if (this._sessionTimers.enabled) { + if (Utils.isDecimal(options.sessionTimersExpires)) { + if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) { + this._sessionTimers.defaultExpires = options.sessionTimersExpires; + } else { + this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES; + } + } + } + + // Set event handlers. + for (var event in eventHandlers) { + if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) { + this.on(event, eventHandlers[event]); + } + } + + // Session parameter initialization. + this._from_tag = Utils.newTag(); + + // Set anonymous property. + var anonymous = options.anonymous || false; + var requestParams = { + from_tag: this._from_tag + }; + this._contact = this._ua.contact.toString({ + anonymous: anonymous, + outbound: true + }); + if (anonymous) { + requestParams.from_display_name = 'Anonymous'; + requestParams.from_uri = new URI('sip', 'anonymous', 'anonymous.invalid'); + extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString())); + extraHeaders.push('Privacy: id'); + } else if (options.fromUserName) { + requestParams.from_uri = new URI('sip', options.fromUserName, this._ua.configuration.uri.host); + extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString())); + } + if (options.fromDisplayName) { + requestParams.from_display_name = options.fromDisplayName; + } + extraHeaders.push("Contact: ".concat(this._contact)); + extraHeaders.push('Content-Type: application/sdp'); + if (this._sessionTimers.enabled) { + extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.defaultExpires).concat(this._ua.configuration.session_timers_force_refresher ? ';refresher=uac' : '')); + } + this._request = new SIPMessage.InitialOutgoingInviteRequest(target, this._ua, requestParams, extraHeaders); + this._id = this._request.call_id + this._from_tag; + + // Create a new RTCPeerConnection instance. + this._createRTCConnection(pcConfig, rtcConstraints); + + // Set internal properties. + this._direction = 'outgoing'; + this._local_identity = this._request.from; + this._remote_identity = this._request.to; + + // User explicitly provided a newRTCSession callback for this session. + if (initCallback) { + initCallback(this); + } + this._newRTCSession('local', this._request); + this._sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream); + } + }, { + key: "init_incoming", + value: function init_incoming(request, initCallback) { + var _this2 = this; + logger.debug('init_incoming()'); + var expires; + var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; + + // Check body and content type. + if (request.body && contentType !== 'application/sdp') { + request.reply(415); + return; + } + + // Session parameter initialization. + this._status = C.STATUS_INVITE_RECEIVED; + this._from_tag = request.from_tag; + this._id = request.call_id + this._from_tag; + this._request = request; + this._contact = this._ua.contact.toString(); + + // Get the Expires header value if exists. + if (request.hasHeader('expires')) { + expires = request.getHeader('expires') * 1000; + } + + /* Set the to_tag before + * replying a response code that will create a dialog. + */ + request.to_tag = Utils.newTag(); + + // An error on dialog creation will fire 'failed' event. + if (!this._createDialog(request, 'UAS', true)) { + request.reply(500, 'Missing Contact header field'); + return; + } + if (request.body) { + this._late_sdp = false; + } else { + this._late_sdp = true; + } + this._status = C.STATUS_WAITING_FOR_ANSWER; + + // Set userNoAnswerTimer. + this._timers.userNoAnswerTimer = setTimeout(function () { + request.reply(408); + _this2._failed('local', null, JsSIP_C.causes.NO_ANSWER); + }, this._ua.configuration.no_answer_timeout); + + /* Set expiresTimer + * RFC3261 13.3.1 + */ + if (expires) { + this._timers.expiresTimer = setTimeout(function () { + if (_this2._status === C.STATUS_WAITING_FOR_ANSWER) { + request.reply(487); + _this2._failed('system', null, JsSIP_C.causes.EXPIRES); + } + }, expires); + } + + // Set internal properties. + this._direction = 'incoming'; + this._local_identity = request.to; + this._remote_identity = request.from; + + // A init callback was specifically defined. + if (initCallback) { + initCallback(this); + } + + // Fire 'newRTCSession' event. + this._newRTCSession('remote', request); + + // The user may have rejected the call in the 'newRTCSession' event. + if (this._status === C.STATUS_TERMINATED) { + return; + } + + // Reply 180. + + // Igor's mode: header(s) for ringing response + var headers = ["Contact: ".concat(this._contact)]; + var h = this._ua.modes.ringing_header_mode; + if (h !== undefined) { + if (Array.isArray(h)) { + headers = headers.concat(h); + } else { + headers.push(h); + } + } + request.reply(180, null, headers); + + // Fire 'progress' event. + // TODO: Document that 'response' field in 'progress' event is null for incoming calls. + this._progress('local', null); + } + + /** + * Answer the call. + */ + }, { + key: "answer", + value: function answer() { + var _this3 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + logger.debug('answer()'); + var request = this._request; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var mediaConstraints = Utils.cloneObject(options.mediaConstraints); + var mediaStream = options.mediaStream || null; + var pcConfig = Utils.cloneObject(options.pcConfig, { + iceServers: [] + }); + var rtcConstraints = options.rtcConstraints || null; + var rtcAnswerConstraints = options.rtcAnswerConstraints || null; + var rtcOfferConstraints = Utils.cloneObject(options.rtcOfferConstraints); + var tracks; + var peerHasAudioLine = false; + var peerHasVideoLine = false; + var peerOffersFullAudio = false; + var peerOffersFullVideo = false; + this._rtcAnswerConstraints = rtcAnswerConstraints; + this._rtcOfferConstraints = options.rtcOfferConstraints || null; + this._data = options.data || this._data; + + // Check Session Direction and Status. + if (this._direction !== 'incoming') { + throw new Exceptions.NotSupportedError('"answer" not supported for outgoing RTCSession'); + } + + // Check Session status. + if (this._status !== C.STATUS_WAITING_FOR_ANSWER) { + throw new Exceptions.InvalidStateError(this._status); + } + + // Session Timers. + if (this._sessionTimers.enabled) { + if (Utils.isDecimal(options.sessionTimersExpires)) { + if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) { + this._sessionTimers.defaultExpires = options.sessionTimersExpires; + } else { + this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES; + } + } + } + this._status = C.STATUS_ANSWERED; + + // An error on dialog creation will fire 'failed' event. + if (!this._createDialog(request, 'UAS')) { + request.reply(500, 'Error creating dialog'); + return; + } + clearTimeout(this._timers.userNoAnswerTimer); + extraHeaders.unshift("Contact: ".concat(this._contact)); + + // Determine incoming media from incoming SDP offer (if any). + var sdp = request.parseSDP(); + + // Make sure sdp.media is an array, not the case if there is only one media. + if (!Array.isArray(sdp.media)) { + sdp.media = [sdp.media]; + } + + // Go through all medias in SDP to find offered capabilities to answer with. + var _iterator = _createForOfIteratorHelper(sdp.media), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var m = _step.value; + if (m.type === 'audio') { + peerHasAudioLine = true; + if (!m.direction || m.direction === 'sendrecv') { + peerOffersFullAudio = true; + } + } + if (m.type === 'video') { + peerHasVideoLine = true; + if (!m.direction || m.direction === 'sendrecv') { + peerOffersFullVideo = true; + } + } + } + + // Remove audio from mediaStream if suggested by mediaConstraints. + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + if (mediaStream && mediaConstraints.audio === false) { + tracks = mediaStream.getAudioTracks(); + var _iterator2 = _createForOfIteratorHelper(tracks), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var track = _step2.value; + mediaStream.removeTrack(track); + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + } + + // Remove video from mediaStream if suggested by mediaConstraints. + if (mediaStream && mediaConstraints.video === false) { + tracks = mediaStream.getVideoTracks(); + var _iterator3 = _createForOfIteratorHelper(tracks), + _step3; + try { + for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { + var _track = _step3.value; + mediaStream.removeTrack(_track); + } + } catch (err) { + _iterator3.e(err); + } finally { + _iterator3.f(); + } + } + + // Set audio constraints based on incoming stream if not supplied. + if (!mediaStream && mediaConstraints.audio === undefined) { + mediaConstraints.audio = peerOffersFullAudio; + } + + // Set video constraints based on incoming stream if not supplied. + if (!mediaStream && mediaConstraints.video === undefined) { + mediaConstraints.video = peerOffersFullVideo; + } + + // Don't ask for audio if the incoming offer has no audio section. + if (!mediaStream && !peerHasAudioLine && !rtcOfferConstraints.offerToReceiveAudio) { + mediaConstraints.audio = false; + } + + // Don't ask for video if the incoming offer has no video section. + if (!mediaStream && !peerHasVideoLine && !rtcOfferConstraints.offerToReceiveVideo) { + mediaConstraints.video = false; + } + + // Create a new RTCPeerConnection instance. + // TODO: This may throw an error, should react. + this._createRTCConnection(pcConfig, rtcConstraints); + Promise.resolve() + // Handle local MediaStream. + .then(function () { + // A local MediaStream is given, use it. + if (mediaStream) { + return mediaStream; + } + + // Audio and/or video requested, prompt getUserMedia. + else if (mediaConstraints.audio || mediaConstraints.video) { + _this3._localMediaStreamLocallyGenerated = true; + return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) { + if (_this3._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + request.reply(480); + _this3._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS); + logger.warn('emit "getusermediafailed" [error:%o]', error); + _this3.emit('getusermediafailed', error); + throw new Error('getUserMedia() failed'); + }); + } + }) + // Attach MediaStream to RTCPeerconnection. + .then(function (stream) { + if (_this3._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + _this3._localMediaStream = stream; + if (stream) { + stream.getTracks().forEach(function (track) { + _this3._connection.addTrack(track, stream); + }); + } + }) + // Set remote description. + .then(function () { + if (_this3._late_sdp) { + return; + } + var e = { + originator: 'remote', + type: 'offer', + sdp: request.body + }; + logger.debug('emit "sdp"'); + _this3.emit('sdp', e); + var offer = new RTCSessionDescription({ + type: 'offer', + sdp: e.sdp + }); + _this3._connectionPromiseQueue = _this3._connectionPromiseQueue.then(function () { + return _this3._connection.setRemoteDescription(offer); + })["catch"](function (error) { + request.reply(488); + _this3._failed('system', null, JsSIP_C.causes.WEBRTC_ERROR); + logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error); + _this3.emit('peerconnection:setremotedescriptionfailed', error); + throw new Error('peerconnection.setRemoteDescription() failed'); + }); + return _this3._connectionPromiseQueue; + }) + // Create local description. + .then(function () { + if (_this3._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + + // TODO: Is this event already useful? + _this3._connecting(request); + if (!_this3._late_sdp) { + return _this3._createLocalDescription('answer', rtcAnswerConstraints)["catch"](function () { + request.reply(500); + throw new Error('_createLocalDescription() failed'); + }); + } else { + return _this3._createLocalDescription('offer', _this3._rtcOfferConstraints)["catch"](function () { + request.reply(500); + throw new Error('_createLocalDescription() failed'); + }); + } + }) + // Send reply. + .then(function (desc) { + if (_this3._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + _this3._handleSessionTimersInIncomingRequest(request, extraHeaders); + request.reply(200, null, extraHeaders, desc, function () { + _this3._status = C.STATUS_WAITING_FOR_ACK; + _this3._setInvite2xxTimer(request, desc); + _this3._setACKTimer(); + _this3._accepted('local'); + }, function () { + _this3._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR); + }); + })["catch"](function (error) { + if (_this3._status === C.STATUS_TERMINATED) { + return; + } + logger.warn(error); + }); + } + + /** + * Terminate the call. + */ + }, { + key: "terminate", + value: function terminate() { + var _this4 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + logger.debug('terminate()'); + var cause = options.cause || JsSIP_C.causes.BYE; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var body = options.body; + var cancel_reason; + var status_code = options.status_code; + var reason_phrase = options.reason_phrase; + + // Check Session Status. + if (this._status === C.STATUS_TERMINATED) { + throw new Exceptions.InvalidStateError(this._status); + } + switch (this._status) { + // - UAC - + case C.STATUS_NULL: + case C.STATUS_INVITE_SENT: + case C.STATUS_1XX_RECEIVED: + logger.debug('canceling session'); + if (status_code && (status_code < 200 || status_code >= 700)) { + throw new TypeError("Invalid status_code: ".concat(status_code)); + } else if (status_code) { + reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || ''; + cancel_reason = "SIP ;cause=".concat(status_code, " ;text=\"").concat(reason_phrase, "\""); + } + + // Check Session Status. + if (this._status === C.STATUS_NULL || this._status === C.STATUS_INVITE_SENT) { + this._is_canceled = true; + this._cancel_reason = cancel_reason; + } else if (this._status === C.STATUS_1XX_RECEIVED) { + this._request.cancel(cancel_reason); + } + this._status = C.STATUS_CANCELED; + this._failed('local', null, JsSIP_C.causes.CANCELED); + break; + + // - UAS - + case C.STATUS_WAITING_FOR_ANSWER: + case C.STATUS_ANSWERED: + logger.debug('rejecting session'); + status_code = status_code || 480; + if (status_code < 300 || status_code >= 700) { + throw new TypeError("Invalid status_code: ".concat(status_code)); + } + this._request.reply(status_code, reason_phrase, extraHeaders, body); + this._failed('local', null, JsSIP_C.causes.REJECTED); + break; + case C.STATUS_WAITING_FOR_ACK: + case C.STATUS_CONFIRMED: + logger.debug('terminating session'); + reason_phrase = options.reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || ''; + if (status_code && (status_code < 200 || status_code >= 700)) { + throw new TypeError("Invalid status_code: ".concat(status_code)); + } else if (status_code) { + extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\"")); + } + + /* RFC 3261 section 15 (Terminating a session): + * + * "...the callee's UA MUST NOT send a BYE on a confirmed dialog + * until it has received an ACK for its 2xx response or until the server + * transaction times out." + */ + if (this._status === C.STATUS_WAITING_FOR_ACK && this._direction === 'incoming' && this._request.server_transaction.state !== Transactions.C.STATUS_TERMINATED) { + // Save the dialog for later restoration. + var dialog = this._dialog; + + // Send the BYE as soon as the ACK is received... + this.receiveRequest = function (_ref) { + var method = _ref.method; + if (method === JsSIP_C.ACK) { + _this4.sendRequest(JsSIP_C.BYE, { + extraHeaders: extraHeaders, + body: body + }); + dialog.terminate(); + } + }; + + // .., or when the INVITE transaction times out + this._request.server_transaction.on('stateChanged', function () { + if (_this4._request.server_transaction.state === Transactions.C.STATUS_TERMINATED) { + _this4.sendRequest(JsSIP_C.BYE, { + extraHeaders: extraHeaders, + body: body + }); + dialog.terminate(); + } + }); + this._ended('local', null, cause); + + // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-). + this._dialog = dialog; + + // Restore the dialog into 'ua' so the ACK can reach 'this' session. + this._ua.newDialog(dialog); + } else { + this.sendRequest(JsSIP_C.BYE, { + extraHeaders: extraHeaders, + body: body + }); + this._ended('local', null, cause); + } + } + } + }, { + key: "sendDTMF", + value: function sendDTMF(tones) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + logger.debug('sendDTMF() | tones: %s', tones); + var position = 0; + var duration = options.duration || null; + var interToneGap = options.interToneGap || null; + var transportType = options.transportType || JsSIP_C.DTMF_TRANSPORT.INFO; + if (tones === undefined) { + throw new TypeError('Not enough arguments'); + } + + // Check Session Status. + if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_1XX_RECEIVED) { + throw new Exceptions.InvalidStateError(this._status); + } + + // Check Transport type. + if (transportType !== JsSIP_C.DTMF_TRANSPORT.INFO && transportType !== JsSIP_C.DTMF_TRANSPORT.RFC2833) { + throw new TypeError("invalid transportType: ".concat(transportType)); + } + + // Convert to string. + if (typeof tones === 'number') { + tones = tones.toString(); + } + + // Check tones. + if (!tones || typeof tones !== 'string' || !tones.match(/^[0-9A-DR#*,]+$/i)) { + throw new TypeError("Invalid tones: ".concat(tones)); + } + + // Check duration. + if (duration && !Utils.isDecimal(duration)) { + throw new TypeError("Invalid tone duration: ".concat(duration)); + } else if (!duration) { + duration = RTCSession_DTMF.C.DEFAULT_DURATION; + } else if (duration < RTCSession_DTMF.C.MIN_DURATION) { + logger.debug("\"duration\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_DURATION, " milliseconds")); + duration = RTCSession_DTMF.C.MIN_DURATION; + } else if (duration > RTCSession_DTMF.C.MAX_DURATION) { + logger.debug("\"duration\" value is greater than the maximum allowed, setting it to ".concat(RTCSession_DTMF.C.MAX_DURATION, " milliseconds")); + duration = RTCSession_DTMF.C.MAX_DURATION; + } else { + duration = Math.abs(duration); + } + options.duration = duration; + + // Check interToneGap. + if (interToneGap && !Utils.isDecimal(interToneGap)) { + throw new TypeError("Invalid interToneGap: ".concat(interToneGap)); + } else if (!interToneGap) { + interToneGap = RTCSession_DTMF.C.DEFAULT_INTER_TONE_GAP; + } else if (interToneGap < RTCSession_DTMF.C.MIN_INTER_TONE_GAP) { + logger.debug("\"interToneGap\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_INTER_TONE_GAP, " milliseconds")); + interToneGap = RTCSession_DTMF.C.MIN_INTER_TONE_GAP; + } else { + interToneGap = Math.abs(interToneGap); + } + + // RFC2833. Let RTCDTMFSender enqueue the DTMFs. + if (transportType === JsSIP_C.DTMF_TRANSPORT.RFC2833) { + // Send DTMF in current audio RTP stream. + var sender = this._getDTMFRTPSender(); + if (sender) { + // Add remaining buffered tones. + tones = sender.toneBuffer + tones; + // Insert tones. + sender.insertDTMF(tones, duration, interToneGap); + } + return; + } + if (this._tones) { + // Tones are already queued, just add to the queue. + this._tones += tones; + return; + } + this._tones = tones; + + // Send the first tone. + _sendDTMF.call(this); + function _sendDTMF() { + var _this5 = this; + var timeout; + if (this._status === C.STATUS_TERMINATED || !this._tones || position >= this._tones.length) { + // Stop sending DTMF. + this._tones = null; + return; + } + var tone = this._tones[position]; + position += 1; + if (tone === ',') { + timeout = 2000; + } else { + // Send DTMF via SIP INFO messages. + var dtmf = new RTCSession_DTMF(this); + options.eventHandlers = { + onFailed: function onFailed() { + _this5._tones = null; + } + }; + dtmf.send(tone, options); + timeout = duration + interToneGap; + } + + // Set timeout for the next tone. + setTimeout(_sendDTMF.bind(this), timeout); + } + } + }, { + key: "sendInfo", + value: function sendInfo(contentType, body) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + logger.debug('sendInfo()'); + + // Check Session Status. + if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_1XX_RECEIVED) { + throw new Exceptions.InvalidStateError(this._status); + } + var info = new RTCSession_Info(this); + info.send(contentType, body, options); + } + + /** + * Mute + */ + }, { + key: "mute", + value: function mute() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { + audio: true, + video: false + }; + logger.debug('mute()'); + var audioMuted = false, + videoMuted = false; + if (this._audioMuted === false && options.audio) { + audioMuted = true; + this._audioMuted = true; + this._toggleMuteAudio(true); + } + if (this._videoMuted === false && options.video) { + videoMuted = true; + this._videoMuted = true; + this._toggleMuteVideo(true); + } + if (audioMuted === true || videoMuted === true) { + this._onmute({ + audio: audioMuted, + video: videoMuted + }); + } + } + + /** + * Unmute + */ + }, { + key: "unmute", + value: function unmute() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { + audio: true, + video: true + }; + logger.debug('unmute()'); + var audioUnMuted = false, + videoUnMuted = false; + if (this._audioMuted === true && options.audio) { + audioUnMuted = true; + this._audioMuted = false; + if (this._localHold === false) { + this._toggleMuteAudio(false); + } + } + if (this._videoMuted === true && options.video) { + videoUnMuted = true; + this._videoMuted = false; + if (this._localHold === false) { + this._toggleMuteVideo(false); + } + } + if (audioUnMuted === true || videoUnMuted === true) { + this._onunmute({ + audio: audioUnMuted, + video: videoUnMuted + }); + } + } + + /** + * Hold + */ + }, { + key: "hold", + value: function hold() { + var _this6 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var done = arguments.length > 1 ? arguments[1] : undefined; + logger.debug('hold()'); + if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) { + return false; + } + if (this._localHold === true) { + return false; + } + if (!this._isReadyToReOffer()) { + return false; + } + this._localHold = true; + this._onhold('local'); + var eventHandlers = { + succeeded: function succeeded() { + if (done) { + done(); + } + }, + failed: function failed() { + _this6.terminate({ + cause: JsSIP_C.causes.WEBRTC_ERROR, + status_code: 500, + reason_phrase: 'Hold Failed' + }); + } + }; + if (options.useUpdate) { + this._sendUpdate({ + sdpOffer: true, + eventHandlers: eventHandlers, + extraHeaders: options.extraHeaders + }); + } else { + this._sendReinvite({ + eventHandlers: eventHandlers, + extraHeaders: options.extraHeaders + }); + } + return true; + } + }, { + key: "unhold", + value: function unhold() { + var _this7 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var done = arguments.length > 1 ? arguments[1] : undefined; + logger.debug('unhold()'); + if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) { + return false; + } + if (this._localHold === false) { + return false; + } + if (!this._isReadyToReOffer()) { + return false; + } + this._localHold = false; + this._onunhold('local'); + var eventHandlers = { + succeeded: function succeeded() { + if (done) { + done(); + } + }, + failed: function failed() { + _this7.terminate({ + cause: JsSIP_C.causes.WEBRTC_ERROR, + status_code: 500, + reason_phrase: 'Unhold Failed' + }); + } + }; + if (options.useUpdate) { + this._sendUpdate({ + sdpOffer: true, + eventHandlers: eventHandlers, + extraHeaders: options.extraHeaders + }); + } else { + this._sendReinvite({ + eventHandlers: eventHandlers, + extraHeaders: options.extraHeaders + }); + } + return true; + } + }, { + key: "renegotiate", + value: function renegotiate() { + var _this8 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var done = arguments.length > 1 ? arguments[1] : undefined; + logger.debug('renegotiate()'); + var rtcOfferConstraints = options.rtcOfferConstraints || null; + if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) { + return false; + } + if (!this._isReadyToReOffer()) { + return false; + } + var eventHandlers = { + succeeded: function succeeded() { + if (done) { + done(); + } + }, + failed: function failed() { + _this8.terminate({ + cause: JsSIP_C.causes.WEBRTC_ERROR, + status_code: 500, + reason_phrase: 'Media Renegotiation Failed' + }); + } + }; + this._setLocalMediaStatus(); + if (options.useUpdate) { + this._sendUpdate({ + sdpOffer: true, + eventHandlers: eventHandlers, + rtcOfferConstraints: rtcOfferConstraints, + extraHeaders: options.extraHeaders + }); + } else { + this._sendReinvite({ + eventHandlers: eventHandlers, + rtcOfferConstraints: rtcOfferConstraints, + extraHeaders: options.extraHeaders + }); + } + return true; + } + + /** + * Refer + */ + }, { + key: "refer", + value: function refer(target, options) { + var _this9 = this; + logger.debug('refer()'); + var originalTarget = target; + if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) { + return false; + } + + // Check target validity. + target = this._ua.normalizeTarget(target); + if (!target) { + throw new TypeError("Invalid target: ".concat(originalTarget)); + } + var referSubscriber = new RTCSession_ReferSubscriber(this); + referSubscriber.sendRefer(target, options); + + // Store in the map. + var id = referSubscriber.id; + this._referSubscribers[id] = referSubscriber; + + // Listen for ending events so we can remove it from the map. + referSubscriber.on('requestFailed', function () { + delete _this9._referSubscribers[id]; + }); + referSubscriber.on('accepted', function () { + delete _this9._referSubscribers[id]; + }); + referSubscriber.on('failed', function () { + delete _this9._referSubscribers[id]; + }); + return referSubscriber; + } + + /** + * Send a generic in-dialog Request + */ + }, { + key: "sendRequest", + value: function sendRequest(method, options) { + logger.debug('sendRequest()'); + return this._dialog.sendRequest(method, options); + } + + /** + * In dialog Request Reception + */ + }, { + key: "receiveRequest", + value: function receiveRequest(request) { + var _this10 = this; + logger.debug('receiveRequest()'); + if (request.method === JsSIP_C.CANCEL) { + /* RFC3261 15 States that a UAS may have accepted an invitation while a CANCEL + * was in progress and that the UAC MAY continue with the session established by + * any 2xx response, or MAY terminate with BYE. JsSIP does continue with the + * established session. So the CANCEL is processed only if the session is not yet + * established. + */ + + /* + * Terminate the whole session in case the user didn't accept (or yet send the answer) + * nor reject the request opening the session. + */ + if (this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED) { + this._status = C.STATUS_CANCELED; + this._request.reply(487); + this._failed('remote', request, JsSIP_C.causes.CANCELED); + } + } else { + // Requests arriving here are in-dialog requests. + switch (request.method) { + case JsSIP_C.ACK: + if (this._status !== C.STATUS_WAITING_FOR_ACK) { + return; + } + + // Update signaling status. + this._status = C.STATUS_CONFIRMED; + clearTimeout(this._timers.ackTimer); + clearTimeout(this._timers.invite2xxTimer); + if (this._late_sdp) { + if (!request.body) { + this.terminate({ + cause: JsSIP_C.causes.MISSING_SDP, + status_code: 400 + }); + break; + } + var e = { + originator: 'remote', + type: 'answer', + sdp: request.body + }; + logger.debug('emit "sdp"'); + this.emit('sdp', e); + var answer = new RTCSessionDescription({ + type: 'answer', + sdp: e.sdp + }); + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + return _this10._connection.setRemoteDescription(answer); + }).then(function () { + if (!_this10._is_confirmed) { + _this10._confirmed('remote', request); + } + })["catch"](function (error) { + _this10.terminate({ + cause: JsSIP_C.causes.BAD_MEDIA_DESCRIPTION, + status_code: 488 + }); + logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error); + _this10.emit('peerconnection:setremotedescriptionfailed', error); + }); + } else if (!this._is_confirmed) { + this._confirmed('remote', request); + } + break; + case JsSIP_C.BYE: + if (this._status === C.STATUS_CONFIRMED || this._status === C.STATUS_WAITING_FOR_ACK) { + request.reply(200); + this._ended('remote', request, JsSIP_C.causes.BYE); + } else if (this._status === C.STATUS_INVITE_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER) { + request.reply(200); + this._request.reply(487, 'BYE Received'); + this._ended('remote', request, JsSIP_C.causes.BYE); + } else { + request.reply(403, 'Wrong Status'); + } + break; + case JsSIP_C.INVITE: + if (this._status === C.STATUS_CONFIRMED) { + if (request.hasHeader('replaces')) { + this._receiveReplaces(request); + } else { + this._receiveReinvite(request); + } + } else { + request.reply(403, 'Wrong Status'); + } + break; + case JsSIP_C.INFO: + if (this._status === C.STATUS_1XX_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED || this._status === C.STATUS_WAITING_FOR_ACK || this._status === C.STATUS_CONFIRMED) { + var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; + if (contentType && contentType.match(/^application\/dtmf-relay/i)) { + new RTCSession_DTMF(this).init_incoming(request); + } else if (contentType !== undefined) { + new RTCSession_Info(this).init_incoming(request); + } else { + request.reply(415); + } + } else { + request.reply(403, 'Wrong Status'); + } + break; + case JsSIP_C.UPDATE: + if (this._status === C.STATUS_CONFIRMED) { + this._receiveUpdate(request); + } else { + request.reply(403, 'Wrong Status'); + } + break; + case JsSIP_C.REFER: + if (this._status === C.STATUS_CONFIRMED) { + this._receiveRefer(request); + } else { + request.reply(403, 'Wrong Status'); + } + break; + case JsSIP_C.NOTIFY: + // Igor's in dialog NOTIFY extension. + { + var _e = { + event: request.event, + request: request, + taken: false + }; + this.emit('sipEvent', _e); + if (_e.taken) { + request.reply(200); + break; + } + } + // end of extension + + if (this._status === C.STATUS_CONFIRMED) { + this._receiveNotify(request); + } else { + request.reply(403, 'Wrong Status'); + } + break; + default: + request.reply(501); + } + } + } + + /** + * Session Callbacks + */ + }, { + key: "onTransportError", + value: function onTransportError() { + logger.warn('onTransportError()'); + if (this._status !== C.STATUS_TERMINATED) { + this.terminate({ + status_code: 500, + reason_phrase: JsSIP_C.causes.CONNECTION_ERROR, + cause: JsSIP_C.causes.CONNECTION_ERROR + }); + } + } + }, { + key: "onRequestTimeout", + value: function onRequestTimeout() { + logger.warn('onRequestTimeout()'); + if (this._status !== C.STATUS_TERMINATED) { + this.terminate({ + status_code: 408, + reason_phrase: JsSIP_C.causes.REQUEST_TIMEOUT, + cause: JsSIP_C.causes.REQUEST_TIMEOUT + }); + } + } + }, { + key: "onDialogError", + value: function onDialogError() { + logger.warn('onDialogError()'); + if (this._status !== C.STATUS_TERMINATED) { + this.terminate({ + status_code: 500, + reason_phrase: JsSIP_C.causes.DIALOG_ERROR, + cause: JsSIP_C.causes.DIALOG_ERROR + }); + } + } + + // Called from DTMF handler. + }, { + key: "newDTMF", + value: function newDTMF(data) { + logger.debug('newDTMF()'); + this.emit('newDTMF', data); + } + + // Called from Info handler. + }, { + key: "newInfo", + value: function newInfo(data) { + logger.debug('newInfo()'); + this.emit('newInfo', data); + } + + /** + * Check if RTCSession is ready for an outgoing re-INVITE or UPDATE with SDP. + */ + }, { + key: "_isReadyToReOffer", + value: function _isReadyToReOffer() { + if (!this._rtcReady) { + logger.debug('_isReadyToReOffer() | internal WebRTC status not ready'); + return false; + } + + // No established yet. + if (!this._dialog) { + logger.debug('_isReadyToReOffer() | session not established yet'); + return false; + } + + // Another INVITE transaction is in progress. + if (this._dialog.uac_pending_reply === true || this._dialog.uas_pending_reply === true) { + logger.debug('_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress'); + return false; + } + return true; + } + }, { + key: "_close", + value: function _close() { + logger.debug('close()'); + + // Close local MediaStream if it was not given by the user. + if (this._localMediaStream && this._localMediaStreamLocallyGenerated) { + logger.debug('close() | closing local MediaStream'); + Utils.closeMediaStream(this._localMediaStream); + } + if (this._status === C.STATUS_TERMINATED) { + return; + } + this._status = C.STATUS_TERMINATED; + + // Terminate RTC. + if (this._connection) { + try { + this._connection.close(); + } catch (error) { + logger.warn('close() | error closing the RTCPeerConnection: %o', error); + } + } + + // Terminate signaling. + + // Clear SIP timers. + for (var timer in this._timers) { + if (Object.prototype.hasOwnProperty.call(this._timers, timer)) { + clearTimeout(this._timers[timer]); + } + } + + // Clear Session Timers. + clearTimeout(this._sessionTimers.timer); + + // Terminate confirmed dialog. + if (this._dialog) { + this._dialog.terminate(); + delete this._dialog; + } + + // Terminate early dialogs. + for (var dialog in this._earlyDialogs) { + if (Object.prototype.hasOwnProperty.call(this._earlyDialogs, dialog)) { + this._earlyDialogs[dialog].terminate(); + delete this._earlyDialogs[dialog]; + } + } + + // Terminate REFER subscribers. + for (var subscriber in this._referSubscribers) { + if (Object.prototype.hasOwnProperty.call(this._referSubscribers, subscriber)) { + delete this._referSubscribers[subscriber]; + } + } + this._ua.destroyRTCSession(this); + } + + /** + * Private API. + */ + + /** + * RFC3261 13.3.1.4 + * Response retransmissions cannot be accomplished by transaction layer + * since it is destroyed when receiving the first 2xx answer + */ + }, { + key: "_setInvite2xxTimer", + value: function _setInvite2xxTimer(request, body) { + var timeout = Timers.T1; + function invite2xxRetransmission() { + if (this._status !== C.STATUS_WAITING_FOR_ACK) { + return; + } + request.reply(200, null, ["Contact: ".concat(this._contact)], body); + if (timeout < Timers.T2) { + timeout = timeout * 2; + if (timeout > Timers.T2) { + timeout = Timers.T2; + } + } + this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout); + } + this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout); + } + + /** + * RFC3261 14.2 + * If a UAS generates a 2xx response and never receives an ACK, + * it SHOULD generate a BYE to terminate the dialog. + */ + }, { + key: "_setACKTimer", + value: function _setACKTimer() { + var _this11 = this; + this._timers.ackTimer = setTimeout(function () { + if (_this11._status === C.STATUS_WAITING_FOR_ACK) { + logger.debug('no ACK received, terminating the session'); + clearTimeout(_this11._timers.invite2xxTimer); + _this11.sendRequest(JsSIP_C.BYE); + _this11._ended('remote', null, JsSIP_C.causes.NO_ACK); + } + }, Timers.TIMER_H); + } + }, { + key: "_createRTCConnection", + value: function _createRTCConnection(pcConfig, rtcConstraints) { + var _this12 = this; + this._connection = new RTCPeerConnection(pcConfig, rtcConstraints); + this._connection.addEventListener('iceconnectionstatechange', function () { + var state = _this12._connection.iceConnectionState; + + // TODO: Do more with different states. + if (state === 'failed') { + _this12.terminate({ + cause: JsSIP_C.causes.RTP_TIMEOUT, + status_code: 408, + reason_phrase: JsSIP_C.causes.RTP_TIMEOUT + }); + } + + // Igor's RTP timeout fix, see https://bugs.chromium.org/p/chromium/issues/detail?id=982793 + if (_this12._ua.modes.chrome_rtp_timeout_fix !== undefined && navigator.webkitGetUserMedia && state === 'disconnected') { + var timeout = _this12._ua.modes.chrome_rtp_timeout_fix; + logger.debug("AC: Chrome RTP timeout fix: iceConnectionState==disconnected: check that this will continue for ".concat(timeout, " seconds...")); + var checking = function checking() { + if (_this12._connection.iceConnectionState === 'disconnected') { + if (timeout-- > 0) { + setTimeout(function () { + return checking(); + }, 1000); + } else { + logger.debug('AC: Chrome RTP timeout fix: Hangup call'); + _this12.terminate({ + cause: JsSIP_C.causes.RTP_TIMEOUT, + status_code: 408, + reason_phrase: JsSIP_C.causes.RTP_TIMEOUT + }); + } + } else { + logger.debug("AC: Chrome RTP timeout fix: iceConnectionState=".concat(_this12._connection.iceConnectionState)); + } + }; + checking(); + } + // end of fix + }); + + logger.debug('emit "peerconnection"'); + this.emit('peerconnection', { + peerconnection: this._connection + }); + } + }, { + key: "_createLocalDescription", + value: function _createLocalDescription(type, constraints) { + var _this13 = this; + logger.debug('createLocalDescription()'); + if (type !== 'offer' && type !== 'answer') throw new Error("createLocalDescription() | invalid type \"".concat(type, "\"")); + var connection = this._connection; + this._rtcReady = false; + return Promise.resolve() + // Create Offer or Answer. + .then(function () { + if (type === 'offer') { + return connection.createOffer(constraints)["catch"](function (error) { + logger.warn('emit "peerconnection:createofferfailed" [error:%o]', error); + _this13.emit('peerconnection:createofferfailed', error); + return Promise.reject(error); + }); + } else { + return connection.createAnswer(constraints)["catch"](function (error) { + logger.warn('emit "peerconnection:createanswerfailed" [error:%o]', error); + _this13.emit('peerconnection:createanswerfailed', error); + return Promise.reject(error); + }); + } + }) + // Set local description. + .then(function (desc) { + return connection.setLocalDescription(desc)["catch"](function (error) { + _this13._rtcReady = true; + logger.warn('emit "peerconnection:setlocaldescriptionfailed" [error:%o]', error); + _this13.emit('peerconnection:setlocaldescriptionfailed', error); + return Promise.reject(error); + }); + }).then(function () { + // Resolve right away if 'pc.iceGatheringState' is 'complete'. + /** + * Resolve right away if: + * - 'connection.iceGatheringState' is 'complete' and no 'iceRestart' constraint is set. + * - 'connection.iceGatheringState' is 'gathering' and 'iceReady' is true. + */ + var iceRestart = constraints && constraints.iceRestart; + if (connection.iceGatheringState === 'complete' && !iceRestart || connection.iceGatheringState === 'gathering' && _this13._iceReady) { + _this13._rtcReady = true; + var e = { + originator: 'local', + type: type, + sdp: connection.localDescription.sdp + }; + logger.debug('emit "sdp"'); + _this13.emit('sdp', e); + return Promise.resolve(e.sdp); + } + + // Add 'pc.onicencandidate' event handler to resolve on last candidate. + return new Promise(function (resolve) { + var finished = false; + var iceCandidateListener; + var iceGatheringStateListener; + _this13._iceReady = false; + var ready = function ready() { + connection.removeEventListener('icecandidate', iceCandidateListener); + connection.removeEventListener('icegatheringstatechange', iceGatheringStateListener); + finished = true; + _this13._rtcReady = true; + + // connection.iceGatheringState will still indicate 'gathering' and thus be blocking. + _this13._iceReady = true; + var e = { + originator: 'local', + type: type, + sdp: connection.localDescription.sdp + }; + logger.debug('emit "sdp"'); + _this13.emit('sdp', e); + resolve(e.sdp); + }; + connection.addEventListener('icecandidate', iceCandidateListener = function iceCandidateListener(event) { + var candidate = event.candidate; + if (candidate) { + _this13.emit('icecandidate', { + candidate: candidate, + ready: ready + }); + } else if (!finished) { + ready(); + } + }); + connection.addEventListener('icegatheringstatechange', iceGatheringStateListener = function iceGatheringStateListener() { + if (connection.iceGatheringState === 'complete' && !finished) { + ready(); + } + }); + + // Igor's fix. Ice gathering timeout + if (_this13._ua.modes.ice_timeout_fix !== undefined) { + setTimeout(function () { + if (finished) return; + logger.debug('AC: ICE gathering timeout fix'); + ready(); + }, _this13._ua.modes.ice_timeout_fix); + } + // end of fix + }); + }); + } + + /** + * Dialog Management + */ + }, { + key: "_createDialog", + value: function _createDialog(message, type, early) { + var local_tag = type === 'UAS' ? message.to_tag : message.from_tag; + var remote_tag = type === 'UAS' ? message.from_tag : message.to_tag; + var id = message.call_id + local_tag + remote_tag; + var early_dialog = this._earlyDialogs[id]; + + // Early Dialog. + if (early) { + if (early_dialog) { + return true; + } else { + early_dialog = new Dialog(this, message, type, Dialog.C.STATUS_EARLY); + + // Dialog has been successfully created. + if (early_dialog.error) { + logger.debug(early_dialog.error); + this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR); + return false; + } else { + this._earlyDialogs[id] = early_dialog; + return true; + } + } + } + + // Confirmed Dialog. + else { + this._from_tag = message.from_tag; + this._to_tag = message.to_tag; + + // In case the dialog is in _early_ state, update it. + if (early_dialog) { + early_dialog.update(message, type); + this._dialog = early_dialog; + delete this._earlyDialogs[id]; + return true; + } + + // Otherwise, create a _confirmed_ dialog. + var dialog = new Dialog(this, message, type); + if (dialog.error) { + logger.debug(dialog.error); + this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR); + return false; + } else { + this._dialog = dialog; + return true; + } + } + } + + /** + * In dialog INVITE Reception + */ + }, { + key: "_receiveReinvite", + value: function _receiveReinvite(request) { + var _this14 = this; + logger.debug('receiveReinvite()'); + var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; + var data = { + request: request, + callback: undefined, + reject: reject.bind(this) + }; + var rejected = false; + function reject() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + rejected = true; + var status_code = options.status_code || 403; + var reason_phrase = options.reason_phrase || ''; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + if (this._status !== C.STATUS_CONFIRMED) { + return false; + } + if (status_code < 300 || status_code >= 700) { + throw new TypeError("Invalid status_code: ".concat(status_code)); + } + request.reply(status_code, reason_phrase, extraHeaders); + } + + // Emit 'reinvite'. + this.emit('reinvite', data); + if (rejected) { + return; + } + this._late_sdp = false; + + // Request without SDP. + if (!request.body) { + this._late_sdp = true; + if (this._remoteHold) { + this._remoteHold = false; + this._onunhold('remote'); + } + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + return _this14._createLocalDescription('offer', _this14._rtcOfferConstraints); + }).then(function (sdp) { + sendAnswer.call(_this14, sdp); + })["catch"](function () { + request.reply(500); + }); + return; + } + + // Request with SDP. + if (contentType !== 'application/sdp') { + logger.debug('invalid Content-Type'); + request.reply(415); + return; + } + this._processInDialogSdpOffer(request) + // Send answer. + .then(function (desc) { + if (_this14._status === C.STATUS_TERMINATED) { + return; + } + sendAnswer.call(_this14, desc); + })["catch"](function (error) { + logger.warn(error); + }); + function sendAnswer(desc) { + var _this15 = this; + var extraHeaders = ["Contact: ".concat(this._contact)]; + this._handleSessionTimersInIncomingRequest(request, extraHeaders); + if (this._late_sdp) { + desc = this._mangleOffer(desc); + } + request.reply(200, null, extraHeaders, desc, function () { + _this15._status = C.STATUS_WAITING_FOR_ACK; + _this15._setInvite2xxTimer(request, desc); + _this15._setACKTimer(); + }); + + // If callback is given execute it. + if (typeof data.callback === 'function') { + data.callback(); + } + } + } + + /** + * In dialog UPDATE Reception + */ + }, { + key: "_receiveUpdate", + value: function _receiveUpdate(request) { + var _this16 = this; + logger.debug('receiveUpdate()'); + var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; + var data = { + request: request, + callback: undefined, + reject: reject.bind(this) + }; + var rejected = false; + function reject() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + rejected = true; + var status_code = options.status_code || 403; + var reason_phrase = options.reason_phrase || ''; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + if (this._status !== C.STATUS_CONFIRMED) { + return false; + } + if (status_code < 300 || status_code >= 700) { + throw new TypeError("Invalid status_code: ".concat(status_code)); + } + request.reply(status_code, reason_phrase, extraHeaders); + } + + // Emit 'update'. + this.emit('update', data); + if (rejected) { + return; + } + if (!request.body) { + sendAnswer.call(this, null); + return; + } + if (contentType !== 'application/sdp') { + logger.debug('invalid Content-Type'); + request.reply(415); + return; + } + this._processInDialogSdpOffer(request) + // Send answer. + .then(function (desc) { + if (_this16._status === C.STATUS_TERMINATED) { + return; + } + sendAnswer.call(_this16, desc); + })["catch"](function (error) { + logger.warn(error); + }); + function sendAnswer(desc) { + var extraHeaders = ["Contact: ".concat(this._contact)]; + this._handleSessionTimersInIncomingRequest(request, extraHeaders); + request.reply(200, null, extraHeaders, desc); + + // If callback is given execute it. + if (typeof data.callback === 'function') { + data.callback(); + } + } + } + }, { + key: "_processInDialogSdpOffer", + value: function _processInDialogSdpOffer(request) { + var _this17 = this; + logger.debug('_processInDialogSdpOffer()'); + var sdp = request.parseSDP(); + var hold = false; + var _iterator4 = _createForOfIteratorHelper(sdp.media), + _step4; + try { + for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { + var m = _step4.value; + if (holdMediaTypes.indexOf(m.type) === -1) { + continue; + } + var direction = m.direction || sdp.direction || 'sendrecv'; + if (direction === 'sendonly' || direction === 'inactive') { + hold = true; + } + // If at least one of the streams is active don't emit 'hold'. + else { + hold = false; + break; + } + } + } catch (err) { + _iterator4.e(err); + } finally { + _iterator4.f(); + } + var e = { + originator: 'remote', + type: 'offer', + sdp: request.body + }; + logger.debug('emit "sdp"'); + this.emit('sdp', e); + var offer = new RTCSessionDescription({ + type: 'offer', + sdp: e.sdp + }); + this._connectionPromiseQueue = this._connectionPromiseQueue + // Set remote description. + .then(function () { + if (_this17._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + return _this17._connection.setRemoteDescription(offer)["catch"](function (error) { + request.reply(488); + logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error); + _this17.emit('peerconnection:setremotedescriptionfailed', error); + throw error; + }); + }).then(function () { + if (_this17._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + if (_this17._remoteHold === true && hold === false) { + _this17._remoteHold = false; + _this17._onunhold('remote'); + } else if (_this17._remoteHold === false && hold === true) { + _this17._remoteHold = true; + _this17._onhold('remote'); + } + }) + // Create local description. + .then(function () { + if (_this17._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + return _this17._createLocalDescription('answer', _this17._rtcAnswerConstraints)["catch"](function (error) { + request.reply(500); + logger.warn('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]', error); + throw error; + }); + })["catch"](function (error) { + logger.warn('_processInDialogSdpOffer() failed [error: %o]', error); + }); + return this._connectionPromiseQueue; + } + + /** + * In dialog Refer Reception + */ + }, { + key: "_receiveRefer", + value: function _receiveRefer(request) { + var _this18 = this; + logger.debug('receiveRefer()'); + if (!request.refer_to) { + logger.debug('no Refer-To header field present in REFER'); + request.reply(400); + return; + } + if (request.refer_to.uri.scheme !== JsSIP_C.SIP) { + logger.debug('Refer-To header field points to a non-SIP URI scheme'); + request.reply(416); + return; + } + + // Reply before the transaction timer expires. + request.reply(202); + var notifier = new RTCSession_ReferNotifier(this, request.cseq); + logger.debug('emit "refer"'); + + // Emit 'refer'. + this.emit('refer', { + request: request, + accept: function accept(initCallback, options) { + _accept.call(_this18, initCallback, options); + }, + reject: function reject() { + _reject.call(_this18); + } + }); + function _accept(initCallback) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + initCallback = typeof initCallback === 'function' ? initCallback : null; + if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) { + return false; + } + var session = new RTCSession(this._ua); + session.on('progress', function (_ref2) { + var response = _ref2.response; + notifier.notify(response.status_code, response.reason_phrase); + }); + session.on('accepted', function (_ref3) { + var response = _ref3.response; + notifier.notify(response.status_code, response.reason_phrase); + }); + session.on('_failed', function (_ref4) { + var message = _ref4.message, + cause = _ref4.cause; + if (message) { + notifier.notify(message.status_code, message.reason_phrase); + } else { + notifier.notify(487, cause); + } + }); + + // Consider the Replaces header present in the Refer-To URI. + if (request.refer_to.uri.hasHeader('replaces')) { + var replaces = decodeURIComponent(request.refer_to.uri.getHeader('replaces')); + options.extraHeaders = Utils.cloneArray(options.extraHeaders); + options.extraHeaders.push("Replaces: ".concat(replaces)); + } + session.connect(request.refer_to.uri.toAor(), options, initCallback); + } + function _reject() { + notifier.notify(603); + } + } + + /** + * In dialog Notify Reception + */ + }, { + key: "_receiveNotify", + value: function _receiveNotify(request) { + logger.debug('receiveNotify()'); + if (!request.event) { + request.reply(400); + } + switch (request.event.event) { + case 'refer': + { + var id; + var referSubscriber; + if (request.event.params && request.event.params.id) { + id = request.event.params.id; + referSubscriber = this._referSubscribers[id]; + } else if (Object.keys(this._referSubscribers).length === 1) { + referSubscriber = this._referSubscribers[Object.keys(this._referSubscribers)[0]]; + } else { + request.reply(400, 'Missing event id parameter'); + return; + } + if (!referSubscriber) { + request.reply(481, 'Subscription does not exist'); + return; + } + referSubscriber.receiveNotify(request); + request.reply(200); + break; + } + default: + { + request.reply(489); + } + } + } + + /** + * INVITE with Replaces Reception + */ + }, { + key: "_receiveReplaces", + value: function _receiveReplaces(request) { + var _this20 = this; + logger.debug('receiveReplaces()'); + function _accept2(initCallback) { + var _this19 = this; + if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) { + return false; + } + var session = new RTCSession(this._ua); + + // Terminate the current session when the new one is confirmed. + session.on('confirmed', function () { + _this19.terminate(); + }); + session.init_incoming(request, initCallback); + } + function _reject2() { + logger.debug('Replaced INVITE rejected by the user'); + request.reply(486); + } + + // Emit 'replace'. + this.emit('replaces', { + request: request, + accept: function accept(initCallback) { + _accept2.call(_this20, initCallback); + }, + reject: function reject() { + _reject2.call(_this20); + } + }); + } + + /** + * Initial Request Sender + */ + }, { + key: "_sendInitialRequest", + value: function _sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream) { + var _this21 = this; + var request_sender = new RequestSender(this._ua, this._request, { + onRequestTimeout: function onRequestTimeout() { + _this21.onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this21.onTransportError(); + }, + // Update the request on authentication. + onAuthenticated: function onAuthenticated(request) { + _this21._request = request; + }, + onReceiveResponse: function onReceiveResponse(response) { + _this21._receiveInviteResponse(response); + } + }); + + // This Promise is resolved within the next iteration, so the app has now + // a chance to set events such as 'peerconnection' and 'connecting'. + Promise.resolve() + // Get a stream if required. + .then(function () { + // A stream is given, let the app set events such as 'peerconnection' and 'connecting'. + if (mediaStream) { + return mediaStream; + } + // Request for user media access. + else if (mediaConstraints.audio || mediaConstraints.video) { + _this21._localMediaStreamLocallyGenerated = true; + return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) { + if (_this21._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + _this21._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS); + logger.warn('emit "getusermediafailed" [error:%o]', error); + _this21.emit('getusermediafailed', error); + throw error; + }); + } + }).then(function (stream) { + if (_this21._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + _this21._localMediaStream = stream; + if (stream) { + stream.getTracks().forEach(function (track) { + _this21._connection.addTrack(track, stream); + }); + } + + // TODO: should this be triggered here? + _this21._connecting(_this21._request); + return _this21._createLocalDescription('offer', rtcOfferConstraints)["catch"](function (error) { + _this21._failed('local', null, JsSIP_C.causes.WEBRTC_ERROR); + throw error; + }); + }).then(function (desc) { + if (_this21._is_canceled || _this21._status === C.STATUS_TERMINATED) { + throw new Error('terminated'); + } + _this21._request.body = desc; + _this21._status = C.STATUS_INVITE_SENT; + logger.debug('emit "sending" [request:%o]', _this21._request); + + // Emit 'sending' so the app can mangle the body before the request is sent. + _this21.emit('sending', { + request: _this21._request + }); + request_sender.send(); + })["catch"](function (error) { + if (_this21._status === C.STATUS_TERMINATED) { + return; + } + logger.warn(error); + }); + } + + /** + * Get DTMF RTCRtpSender. + */ + }, { + key: "_getDTMFRTPSender", + value: function _getDTMFRTPSender() { + var sender = this._connection.getSenders().find(function (rtpSender) { + return rtpSender.track && rtpSender.track.kind === 'audio'; + }); + if (!(sender && sender.dtmf)) { + logger.warn('sendDTMF() | no local audio track to send DTMF with'); + return; + } + return sender.dtmf; + } + + /** + * Reception of Response for Initial INVITE + */ + }, { + key: "_receiveInviteResponse", + value: function _receiveInviteResponse(response) { + var _this22 = this; + logger.debug('receiveInviteResponse()'); + + // Handle 2XX retransmissions and responses from forked requests. + if (this._dialog && response.status_code >= 200 && response.status_code <= 299) { + /* + * If it is a retransmission from the endpoint that established + * the dialog, send an ACK + */ + if (this._dialog.id.call_id === response.call_id && this._dialog.id.local_tag === response.from_tag && this._dialog.id.remote_tag === response.to_tag) { + this.sendRequest(JsSIP_C.ACK); + return; + } + + // If not, send an ACK and terminate. + else { + var dialog = new Dialog(this, response, 'UAC'); + if (dialog.error !== undefined) { + logger.debug(dialog.error); + return; + } + this.sendRequest(JsSIP_C.ACK); + this.sendRequest(JsSIP_C.BYE); + return; + } + } + + // Proceed to cancellation if the user requested. + if (this._is_canceled) { + if (response.status_code >= 100 && response.status_code < 200) { + this._request.cancel(this._cancel_reason); + } else if (response.status_code >= 200 && response.status_code < 299) { + this._acceptAndTerminate(response); + } + return; + } + if (this._status !== C.STATUS_INVITE_SENT && this._status !== C.STATUS_1XX_RECEIVED) { + return; + } + switch (true) { + case /^100$/.test(response.status_code): + this._status = C.STATUS_1XX_RECEIVED; + break; + case /^1[0-9]{2}$/.test(response.status_code): + { + // Do nothing with 1xx responses without To tag. + if (!response.to_tag) { + logger.debug('1xx response received without to tag'); + break; + } + + // Create Early Dialog if 1XX comes with contact. + if (response.hasHeader('contact')) { + // An error on dialog creation will fire 'failed' event. + if (!this._createDialog(response, 'UAC', true)) { + break; + } + } + this._status = C.STATUS_1XX_RECEIVED; + if (!response.body) { + this._progress('remote', response); + break; + } + var e = { + originator: 'remote', + type: 'answer', + sdp: response.body + }; + logger.debug('emit "sdp"'); + this.emit('sdp', e); + var answer = new RTCSessionDescription({ + type: 'answer', + sdp: e.sdp + }); + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + return _this22._connection.setRemoteDescription(answer); + }).then(function () { + return _this22._progress('remote', response); + })["catch"](function (error) { + logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error); + _this22.emit('peerconnection:setremotedescriptionfailed', error); + }); + break; + } + case /^2[0-9]{2}$/.test(response.status_code): + { + this._status = C.STATUS_CONFIRMED; + if (!response.body) { + this._acceptAndTerminate(response, 400, JsSIP_C.causes.MISSING_SDP); + this._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION); + break; + } + + // An error on dialog creation will fire 'failed' event. + if (!this._createDialog(response, 'UAC')) { + break; + } + var _e2 = { + originator: 'remote', + type: 'answer', + sdp: response.body + }; + logger.debug('emit "sdp"'); + this.emit('sdp', _e2); + var _answer = new RTCSessionDescription({ + type: 'answer', + sdp: _e2.sdp + }); + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + // Be ready for 200 with SDP after a 180/183 with SDP. + // We created a SDP 'answer' for it, so check the current signaling state. + if (_this22._connection.signalingState === 'stable') { + return _this22._connection.createOffer(_this22._rtcOfferConstraints).then(function (offer) { + return _this22._connection.setLocalDescription(offer); + })["catch"](function (error) { + _this22._acceptAndTerminate(response, 500, error.toString()); + _this22._failed('local', response, JsSIP_C.causes.WEBRTC_ERROR); + }); + } + }).then(function () { + _this22._connection.setRemoteDescription(_answer).then(function () { + // Handle Session Timers. + _this22._handleSessionTimersInIncomingResponse(response); + _this22._accepted('remote', response); + _this22.sendRequest(JsSIP_C.ACK); + _this22._confirmed('local', null); + })["catch"](function (error) { + _this22._acceptAndTerminate(response, 488, 'Not Acceptable Here'); + _this22._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION); + logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error); + _this22.emit('peerconnection:setremotedescriptionfailed', error); + }); + }); + break; + } + default: + { + var cause = Utils.sipErrorCause(response.status_code); + this._failed('remote', response, cause); + } + } + } + + /** + * Send Re-INVITE + */ + }, { + key: "_sendReinvite", + value: function _sendReinvite() { + var _this23 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + logger.debug('sendReinvite()'); + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var eventHandlers = Utils.cloneObject(options.eventHandlers); + var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null; + var succeeded = false; + extraHeaders.push("Contact: ".concat(this._contact)); + extraHeaders.push('Content-Type: application/sdp'); + + // Session Timers. + if (this._sessionTimers.running) { + extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas')); + } + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + return _this23._createLocalDescription('offer', rtcOfferConstraints); + }).then(function (sdp) { + sdp = _this23._mangleOffer(sdp); + var e = { + originator: 'local', + type: 'offer', + sdp: sdp + }; + logger.debug('emit "sdp"'); + _this23.emit('sdp', e); + _this23.sendRequest(JsSIP_C.INVITE, { + extraHeaders: extraHeaders, + body: sdp, + eventHandlers: { + onSuccessResponse: function onSuccessResponse(response) { + onSucceeded.call(_this23, response); + succeeded = true; + }, + onErrorResponse: function onErrorResponse(response) { + onFailed.call(_this23, response); + }, + onTransportError: function onTransportError() { + _this23.onTransportError(); // Do nothing because session ends. + }, + + onRequestTimeout: function onRequestTimeout() { + _this23.onRequestTimeout(); // Do nothing because session ends. + }, + + onDialogError: function onDialogError() { + _this23.onDialogError(); // Do nothing because session ends. + } + } + }); + })["catch"](function () { + onFailed(); + }); + function onSucceeded(response) { + var _this24 = this; + if (this._status === C.STATUS_TERMINATED) { + return; + } + this.sendRequest(JsSIP_C.ACK); + + // If it is a 2XX retransmission exit now. + if (succeeded) { + return; + } + + // Handle Session Timers. + this._handleSessionTimersInIncomingResponse(response); + + // Must have SDP answer. + if (!response.body) { + onFailed.call(this); + return; + } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') { + onFailed.call(this); + return; + } + var e = { + originator: 'remote', + type: 'answer', + sdp: response.body + }; + logger.debug('emit "sdp"'); + this.emit('sdp', e); + var answer = new RTCSessionDescription({ + type: 'answer', + sdp: e.sdp + }); + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + return _this24._connection.setRemoteDescription(answer); + }).then(function () { + if (eventHandlers.succeeded) { + eventHandlers.succeeded(response); + } + })["catch"](function (error) { + onFailed.call(_this24); + logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error); + _this24.emit('peerconnection:setremotedescriptionfailed', error); + }); + } + function onFailed(response) { + if (eventHandlers.failed) { + eventHandlers.failed(response); + } + } + } + + /** + * Send UPDATE + */ + }, { + key: "_sendUpdate", + value: function _sendUpdate() { + var _this25 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + logger.debug('sendUpdate()'); + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var eventHandlers = Utils.cloneObject(options.eventHandlers); + var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null; + var sdpOffer = options.sdpOffer || false; + var succeeded = false; + extraHeaders.push("Contact: ".concat(this._contact)); + + // Session Timers. + if (this._sessionTimers.running) { + extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas')); + } + if (sdpOffer) { + extraHeaders.push('Content-Type: application/sdp'); + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + return _this25._createLocalDescription('offer', rtcOfferConstraints); + }).then(function (sdp) { + sdp = _this25._mangleOffer(sdp); + var e = { + originator: 'local', + type: 'offer', + sdp: sdp + }; + logger.debug('emit "sdp"'); + _this25.emit('sdp', e); + _this25.sendRequest(JsSIP_C.UPDATE, { + extraHeaders: extraHeaders, + body: sdp, + eventHandlers: { + onSuccessResponse: function onSuccessResponse(response) { + onSucceeded.call(_this25, response); + succeeded = true; + }, + onErrorResponse: function onErrorResponse(response) { + onFailed.call(_this25, response); + }, + onTransportError: function onTransportError() { + _this25.onTransportError(); // Do nothing because session ends. + }, + + onRequestTimeout: function onRequestTimeout() { + _this25.onRequestTimeout(); // Do nothing because session ends. + }, + + onDialogError: function onDialogError() { + _this25.onDialogError(); // Do nothing because session ends. + } + } + }); + })["catch"](function () { + onFailed.call(_this25); + }); + } + + // No SDP. + else { + this.sendRequest(JsSIP_C.UPDATE, { + extraHeaders: extraHeaders, + eventHandlers: { + onSuccessResponse: function onSuccessResponse(response) { + onSucceeded.call(_this25, response); + }, + onErrorResponse: function onErrorResponse(response) { + onFailed.call(_this25, response); + }, + onTransportError: function onTransportError() { + _this25.onTransportError(); // Do nothing because session ends. + }, + + onRequestTimeout: function onRequestTimeout() { + _this25.onRequestTimeout(); // Do nothing because session ends. + }, + + onDialogError: function onDialogError() { + _this25.onDialogError(); // Do nothing because session ends. + } + } + }); + } + + function onSucceeded(response) { + var _this26 = this; + if (this._status === C.STATUS_TERMINATED) { + return; + } + + // If it is a 2XX retransmission exit now. + if (succeeded) { + return; + } + + // Handle Session Timers. + this._handleSessionTimersInIncomingResponse(response); + + // Must have SDP answer. + if (sdpOffer) { + if (!response.body) { + onFailed.call(this); + return; + } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') { + onFailed.call(this); + return; + } + var e = { + originator: 'remote', + type: 'answer', + sdp: response.body + }; + logger.debug('emit "sdp"'); + this.emit('sdp', e); + var answer = new RTCSessionDescription({ + type: 'answer', + sdp: e.sdp + }); + this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () { + return _this26._connection.setRemoteDescription(answer); + }).then(function () { + if (eventHandlers.succeeded) { + eventHandlers.succeeded(response); + } + })["catch"](function (error) { + onFailed.call(_this26); + logger.warn('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error); + _this26.emit('peerconnection:setremotedescriptionfailed', error); + }); + } + // No SDP answer. + else if (eventHandlers.succeeded) { + eventHandlers.succeeded(response); + } + } + function onFailed(response) { + if (eventHandlers.failed) { + eventHandlers.failed(response); + } + } + } + }, { + key: "_acceptAndTerminate", + value: function _acceptAndTerminate(response, status_code, reason_phrase) { + logger.debug('acceptAndTerminate()'); + var extraHeaders = []; + if (status_code) { + reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || ''; + extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\"")); + } + + // An error on dialog creation will fire 'failed' event. + if (this._dialog || this._createDialog(response, 'UAC')) { + this.sendRequest(JsSIP_C.ACK); + this.sendRequest(JsSIP_C.BYE, { + extraHeaders: extraHeaders + }); + } + + // Update session status. + this._status = C.STATUS_TERMINATED; + } + + /** + * Correctly set the SDP direction attributes if the call is on local hold + */ + }, { + key: "_mangleOffer", + value: function _mangleOffer(sdp) { + if (!this._localHold && !this._remoteHold) { + return sdp; + } + sdp = sdp_transform.parse(sdp); + + // Local hold. + if (this._localHold && !this._remoteHold) { + logger.debug('mangleOffer() | me on hold, mangling offer'); + var _iterator5 = _createForOfIteratorHelper(sdp.media), + _step5; + try { + for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { + var m = _step5.value; + if (holdMediaTypes.indexOf(m.type) === -1) { + continue; + } + if (!m.direction) { + m.direction = 'sendonly'; + } else if (m.direction === 'sendrecv') { + m.direction = 'sendonly'; + } else if (m.direction === 'recvonly') { + m.direction = 'inactive'; + } + } + } catch (err) { + _iterator5.e(err); + } finally { + _iterator5.f(); + } + } + // Local and remote hold. + else if (this._localHold && this._remoteHold) { + logger.debug('mangleOffer() | both on hold, mangling offer'); + var _iterator6 = _createForOfIteratorHelper(sdp.media), + _step6; + try { + for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { + var _m = _step6.value; + if (holdMediaTypes.indexOf(_m.type) === -1) { + continue; + } + _m.direction = 'inactive'; + } + } catch (err) { + _iterator6.e(err); + } finally { + _iterator6.f(); + } + } + // Remote hold. + else if (this._remoteHold) { + logger.debug('mangleOffer() | remote on hold, mangling offer'); + var _iterator7 = _createForOfIteratorHelper(sdp.media), + _step7; + try { + for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { + var _m2 = _step7.value; + if (holdMediaTypes.indexOf(_m2.type) === -1) { + continue; + } + if (!_m2.direction) { + _m2.direction = 'recvonly'; + } else if (_m2.direction === 'sendrecv') { + _m2.direction = 'recvonly'; + } else if (_m2.direction === 'recvonly') { + _m2.direction = 'inactive'; + } + } + } catch (err) { + _iterator7.e(err); + } finally { + _iterator7.f(); + } + } + return sdp_transform.write(sdp); + } + }, { + key: "_setLocalMediaStatus", + value: function _setLocalMediaStatus() { + var enableAudio = true, + enableVideo = true; + if (this._localHold || this._remoteHold) { + enableAudio = false; + enableVideo = false; + } + if (this._audioMuted) { + enableAudio = false; + } + if (this._videoMuted) { + enableVideo = false; + } + this._toggleMuteAudio(!enableAudio); + this._toggleMuteVideo(!enableVideo); + } + + /** + * Handle SessionTimers for an incoming INVITE or UPDATE. + * @param {IncomingRequest} request + * @param {Array} responseExtraHeaders Extra headers for the 200 response. + */ + }, { + key: "_handleSessionTimersInIncomingRequest", + value: function _handleSessionTimersInIncomingRequest(request, responseExtraHeaders) { + if (!this._sessionTimers.enabled) { + return; + } + var session_expires_refresher; + if (request.session_expires && request.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) { + this._sessionTimers.currentExpires = request.session_expires; + session_expires_refresher = request.session_expires_refresher || 'uas'; + } else { + this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires; + session_expires_refresher = 'uas'; + } + responseExtraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(session_expires_refresher)); + this._sessionTimers.refresher = session_expires_refresher === 'uas'; + this._runSessionTimer(); + } + + /** + * Handle SessionTimers for an incoming response to INVITE or UPDATE. + * @param {IncomingResponse} response + */ + }, { + key: "_handleSessionTimersInIncomingResponse", + value: function _handleSessionTimersInIncomingResponse(response) { + if (!this._sessionTimers.enabled) { + return; + } + var session_expires_refresher; + if (response.session_expires && response.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) { + this._sessionTimers.currentExpires = response.session_expires; + session_expires_refresher = response.session_expires_refresher || 'uac'; + } else { + this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires; + session_expires_refresher = 'uac'; + } + this._sessionTimers.refresher = session_expires_refresher === 'uac'; + this._runSessionTimer(); + } + }, { + key: "_runSessionTimer", + value: function _runSessionTimer() { + var _this27 = this; + var expires = this._sessionTimers.currentExpires; + this._sessionTimers.running = true; + clearTimeout(this._sessionTimers.timer); + + // I'm the refresher. + if (this._sessionTimers.refresher) { + this._sessionTimers.timer = setTimeout(function () { + if (_this27._status === C.STATUS_TERMINATED) { + return; + } + if (!_this27._isReadyToReOffer()) { + return; + } + logger.debug('runSessionTimer() | sending session refresh request'); + if (_this27._sessionTimers.refreshMethod === JsSIP_C.UPDATE) { + _this27._sendUpdate(); + } else { + _this27._sendReinvite(); + } + }, expires * 500); // Half the given interval (as the RFC states). + } + + // I'm not the refresher. + else { + this._sessionTimers.timer = setTimeout(function () { + if (_this27._status === C.STATUS_TERMINATED) { + return; + } + logger.warn('runSessionTimer() | timer expired, terminating the session'); + _this27.terminate({ + cause: JsSIP_C.causes.REQUEST_TIMEOUT, + status_code: 408, + reason_phrase: 'Session Timer Expired' + }); + }, expires * 1100); + } + } + }, { + key: "_toggleMuteAudio", + value: function _toggleMuteAudio(mute) { + var senders = this._connection.getSenders().filter(function (sender) { + return sender.track && sender.track.kind === 'audio'; + }); + var _iterator8 = _createForOfIteratorHelper(senders), + _step8; + try { + for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { + var sender = _step8.value; + sender.track.enabled = !mute; + } + } catch (err) { + _iterator8.e(err); + } finally { + _iterator8.f(); + } + } + }, { + key: "_toggleMuteVideo", + value: function _toggleMuteVideo(mute) { + var senders = this._connection.getSenders().filter(function (sender) { + return sender.track && sender.track.kind === 'video'; + }); + var _iterator9 = _createForOfIteratorHelper(senders), + _step9; + try { + for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) { + var sender = _step9.value; + sender.track.enabled = !mute; + } + } catch (err) { + _iterator9.e(err); + } finally { + _iterator9.f(); + } + } + }, { + key: "_newRTCSession", + value: function _newRTCSession(originator, request) { + logger.debug('newRTCSession()'); + this._ua.newRTCSession(this, { + originator: originator, + session: this, + request: request + }); + } + }, { + key: "_connecting", + value: function _connecting(request) { + logger.debug('session connecting'); + logger.debug('emit "connecting"'); + this.emit('connecting', { + request: request + }); + } + }, { + key: "_progress", + value: function _progress(originator, response) { + logger.debug('session progress'); + logger.debug('emit "progress"'); + this.emit('progress', { + originator: originator, + response: response || null + }); + } + }, { + key: "_accepted", + value: function _accepted(originator, message) { + logger.debug('session accepted'); + this._start_time = new Date(); + logger.debug('emit "accepted"'); + this.emit('accepted', { + originator: originator, + response: message || null + }); + } + }, { + key: "_confirmed", + value: function _confirmed(originator, ack) { + logger.debug('session confirmed'); + this._is_confirmed = true; + logger.debug('emit "confirmed"'); + this.emit('confirmed', { + originator: originator, + ack: ack || null + }); + } + }, { + key: "_ended", + value: function _ended(originator, message, cause) { + logger.debug('session ended'); + this._end_time = new Date(); + this._close(); + logger.debug('emit "ended"'); + this.emit('ended', { + originator: originator, + message: message || null, + cause: cause + }); + } + }, { + key: "_failed", + value: function _failed(originator, message, cause) { + logger.debug('session failed'); + + // Emit private '_failed' event first. + logger.debug('emit "_failed"'); + this.emit('_failed', { + originator: originator, + message: message || null, + cause: cause + }); + this._close(); + logger.debug('emit "failed"'); + this.emit('failed', { + originator: originator, + message: message || null, + cause: cause + }); + } + }, { + key: "_onhold", + value: function _onhold(originator) { + logger.debug('session onhold'); + this._setLocalMediaStatus(); + logger.debug('emit "hold"'); + this.emit('hold', { + originator: originator + }); + } + }, { + key: "_onunhold", + value: function _onunhold(originator) { + logger.debug('session onunhold'); + this._setLocalMediaStatus(); + logger.debug('emit "unhold"'); + this.emit('unhold', { + originator: originator + }); + } + }, { + key: "_onmute", + value: function _onmute(_ref5) { + var audio = _ref5.audio, + video = _ref5.video; + logger.debug('session onmute'); + this._setLocalMediaStatus(); + logger.debug('emit "muted"'); + this.emit('muted', { + audio: audio, + video: video + }); + } + }, { + key: "_onunmute", + value: function _onunmute(_ref6) { + var audio = _ref6.audio, + video = _ref6.video; + logger.debug('session onunmute'); + this._setLocalMediaStatus(); + logger.debug('emit "unmuted"'); + this.emit('unmuted', { + audio: audio, + video: video + }); + } + }], [{ + key: "C", + get: + /** + * Expose C object. + */ + function get() { + return C; + } + }]); + return RTCSession; +}(EventEmitter); +},{"./Constants":2,"./Dialog":3,"./Exceptions":6,"./Logger":9,"./RTCSession/DTMF":16,"./RTCSession/Info":17,"./RTCSession/ReferNotifier":18,"./RTCSession/ReferSubscriber":19,"./RequestSender":21,"./SIPMessage":22,"./Timers":25,"./Transactions":26,"./URI":29,"./Utils":30,"events":33,"sdp-transform":39}],16:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('../Logger'); +var JsSIP_C = require('../Constants'); +var Exceptions = require('../Exceptions'); +var Utils = require('../Utils'); +var logger = new Logger('RTCSession:DTMF'); +var C = { + MIN_DURATION: 70, + MAX_DURATION: 6000, + DEFAULT_DURATION: 100, + MIN_INTER_TONE_GAP: 50, + DEFAULT_INTER_TONE_GAP: 500 +}; +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(DTMF, _EventEmitter); + var _super = _createSuper(DTMF); + function DTMF(session) { + var _this; + _classCallCheck(this, DTMF); + _this = _super.call(this); + _this._session = session; + _this._direction = null; + _this._tone = null; + _this._duration = null; + _this._request = null; + return _this; + } + _createClass(DTMF, [{ + key: "tone", + get: function get() { + return this._tone; + } + }, { + key: "duration", + get: function get() { + return this._duration; + } + }, { + key: "send", + value: function send(tone) { + var _this2 = this; + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + if (tone === undefined) { + throw new TypeError('Not enough arguments'); + } + this._direction = 'outgoing'; + + // Check RTCSession Status. + if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) { + throw new Exceptions.InvalidStateError(this._session.status); + } + var extraHeaders = Utils.cloneArray(options.extraHeaders); + this.eventHandlers = Utils.cloneObject(options.eventHandlers); + + // Check tone type. + if (typeof tone === 'string') { + tone = tone.toUpperCase(); + } else if (typeof tone === 'number') { + tone = tone.toString(); + } else { + throw new TypeError("Invalid tone: ".concat(tone)); + } + + // Check tone value. + if (!tone.match(/^[0-9A-DR#*]$/)) { + throw new TypeError("Invalid tone: ".concat(tone)); + } else { + this._tone = tone; + } + + // Duration is checked/corrected in RTCSession. + this._duration = options.duration; + extraHeaders.push('Content-Type: application/dtmf-relay'); + var body = "Signal=".concat(this._tone, "\r\n"); + body += "Duration=".concat(this._duration); + this._session.newDTMF({ + originator: 'local', + dtmf: this, + request: this._request + }); + this._session.sendRequest(JsSIP_C.INFO, { + extraHeaders: extraHeaders, + eventHandlers: { + onSuccessResponse: function onSuccessResponse(response) { + _this2.emit('succeeded', { + originator: 'remote', + response: response + }); + }, + onErrorResponse: function onErrorResponse(response) { + if (_this2.eventHandlers.onFailed) { + _this2.eventHandlers.onFailed(); + } + _this2.emit('failed', { + originator: 'remote', + response: response + }); + }, + onRequestTimeout: function onRequestTimeout() { + _this2._session.onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this2._session.onTransportError(); + }, + onDialogError: function onDialogError() { + _this2._session.onDialogError(); + } + }, + body: body + }); + } + }, { + key: "init_incoming", + value: function init_incoming(request) { + var reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/; + var reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/; + this._direction = 'incoming'; + this._request = request; + request.reply(200); + if (request.body) { + var body = request.body.split('\n'); + if (body.length >= 1) { + if (reg_tone.test(body[0])) { + this._tone = body[0].replace(reg_tone, '$2'); + } + } + if (body.length >= 2) { + if (reg_duration.test(body[1])) { + this._duration = parseInt(body[1].replace(reg_duration, '$2'), 10); + } + } + } + if (!this._duration) { + this._duration = C.DEFAULT_DURATION; + } + if (!this._tone) { + logger.debug('invalid INFO DTMF received, discarded'); + } else { + this._session.newDTMF({ + originator: 'remote', + dtmf: this, + request: request + }); + } + } + }]); + return DTMF; +}(EventEmitter); + +/** + * Expose C object. + */ +module.exports.C = C; +},{"../Constants":2,"../Exceptions":6,"../Logger":9,"../Utils":30,"events":33}],17:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var JsSIP_C = require('../Constants'); +var Exceptions = require('../Exceptions'); +var Utils = require('../Utils'); +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(Info, _EventEmitter); + var _super = _createSuper(Info); + function Info(session) { + var _this; + _classCallCheck(this, Info); + _this = _super.call(this); + _this._session = session; + _this._direction = null; + _this._contentType = null; + _this._body = null; + return _this; + } + _createClass(Info, [{ + key: "contentType", + get: function get() { + return this._contentType; + } + }, { + key: "body", + get: function get() { + return this._body; + } + }, { + key: "send", + value: function send(contentType, body) { + var _this2 = this; + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + this._direction = 'outgoing'; + + /* Igor's change: if INFO without body then Content-Type can be not set */ + if (body && contentType === undefined) { + throw new TypeError('Not enough arguments'); + } + + // Check RTCSession Status. + if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) { + throw new Exceptions.InvalidStateError(this._session.status); + } + this._contentType = contentType; + this._body = body; + var extraHeaders = Utils.cloneArray(options.extraHeaders); + if (contentType) { + // Igor's modification + extraHeaders.push("Content-Type: ".concat(contentType)); + } + this._session.newInfo({ + originator: 'local', + info: this, + request: this.request + }); + this._session.sendRequest(JsSIP_C.INFO, { + extraHeaders: extraHeaders, + eventHandlers: { + onSuccessResponse: function onSuccessResponse(response) { + _this2.emit('succeeded', { + originator: 'remote', + response: response + }); + }, + onErrorResponse: function onErrorResponse(response) { + _this2.emit('failed', { + originator: 'remote', + response: response + }); + }, + onTransportError: function onTransportError() { + _this2._session.onTransportError(); + }, + onRequestTimeout: function onRequestTimeout() { + _this2._session.onRequestTimeout(); + }, + onDialogError: function onDialogError() { + _this2._session.onDialogError(); + } + }, + body: body + }); + } + }, { + key: "init_incoming", + value: function init_incoming(request) { + this._direction = 'incoming'; + this.request = request; + request.reply(200); + this._contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; + this._body = request.body; + this._session.newInfo({ + originator: 'remote', + info: this, + request: request + }); + } + }]); + return Info; +}(EventEmitter); +},{"../Constants":2,"../Exceptions":6,"../Utils":30,"events":33}],18:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var Logger = require('../Logger'); +var JsSIP_C = require('../Constants'); +var logger = new Logger('RTCSession:ReferNotifier'); +var C = { + event_type: 'refer', + body_type: 'message/sipfrag;version=2.0', + expires: 300 +}; +module.exports = /*#__PURE__*/function () { + function ReferNotifier(session, id, expires) { + _classCallCheck(this, ReferNotifier); + this._session = session; + this._id = id; + this._expires = expires || C.expires; + this._active = true; + + // The creation of a Notifier results in an immediate NOTIFY. + this.notify(100); + } + _createClass(ReferNotifier, [{ + key: "notify", + value: function notify(code, reason) { + logger.debug('notify()'); + if (this._active === false) { + return; + } + reason = reason || JsSIP_C.REASON_PHRASE[code] || ''; + var state; + if (code >= 200) { + state = 'terminated;reason=noresource'; + } else { + state = "active;expires=".concat(this._expires); + } + + // Put this in a try/catch block. + // Igor's fix. Added try/catch + try { + this._session.sendRequest(JsSIP_C.NOTIFY, { + extraHeaders: ["Event: ".concat(C.event_type, ";id=").concat(this._id), "Subscription-State: ".concat(state), "Content-Type: ".concat(C.body_type)], + body: "SIP/2.0 ".concat(code, " ").concat(reason), + eventHandlers: { + // If a negative response is received, subscription is canceled. + onErrorResponse: function onErrorResponse() { + this._active = false; + } + } + }); + } catch (e) { + logger.debug('send NOTIFY exception [ignored]'); + } + } + }]); + return ReferNotifier; +}(); +},{"../Constants":2,"../Logger":9}],19:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('../Logger'); +var JsSIP_C = require('../Constants'); +var Grammar = require('../Grammar'); +var Utils = require('../Utils'); +var logger = new Logger('RTCSession:ReferSubscriber'); +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(ReferSubscriber, _EventEmitter); + var _super = _createSuper(ReferSubscriber); + function ReferSubscriber(session) { + var _this; + _classCallCheck(this, ReferSubscriber); + _this = _super.call(this); + _this._id = null; + _this._session = session; + return _this; + } + _createClass(ReferSubscriber, [{ + key: "id", + get: function get() { + return this._id; + } + }, { + key: "sendRefer", + value: function sendRefer(target) { + var _this2 = this; + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + logger.debug('sendRefer()'); + var extraHeaders = Utils.cloneArray(options.extraHeaders); + var eventHandlers = Utils.cloneObject(options.eventHandlers); + + // Set event handlers. + for (var event in eventHandlers) { + if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) { + this.on(event, eventHandlers[event]); + } + } + + // Replaces URI header field. + var replaces = null; + if (options.replaces) { + replaces = options.replaces._request.call_id; + replaces += ";to-tag=".concat(options.replaces._to_tag); + replaces += ";from-tag=".concat(options.replaces._from_tag); + replaces = encodeURIComponent(replaces); + } + + // Refer-To header field. + var referTo = "Refer-To: <".concat(target).concat(replaces ? "?Replaces=".concat(replaces) : '', ">"); + extraHeaders.push(referTo); + + // Referred-By header field (if not already present). + if (!extraHeaders.some(function (header) { + return header.toLowerCase().startsWith('referred-by:'); + })) { + var referredBy = "Referred-By: <".concat(this._session._ua._configuration.uri._scheme, ":").concat(this._session._ua._configuration.uri._user, "@").concat(this._session._ua._configuration.uri._host, ">"); + extraHeaders.push(referredBy); + } + extraHeaders.push("Contact: ".concat(this._session.contact)); + var request = this._session.sendRequest(JsSIP_C.REFER, { + extraHeaders: extraHeaders, + eventHandlers: { + onSuccessResponse: function onSuccessResponse(response) { + _this2._requestSucceeded(response); + }, + onErrorResponse: function onErrorResponse(response) { + _this2._requestFailed(response, JsSIP_C.causes.REJECTED); + }, + onTransportError: function onTransportError() { + _this2._requestFailed(null, JsSIP_C.causes.CONNECTION_ERROR); + }, + onRequestTimeout: function onRequestTimeout() { + _this2._requestFailed(null, JsSIP_C.causes.REQUEST_TIMEOUT); + }, + onDialogError: function onDialogError() { + _this2._requestFailed(null, JsSIP_C.causes.DIALOG_ERROR); + } + } + }); + this._id = request.cseq; + } + }, { + key: "receiveNotify", + value: function receiveNotify(request) { + logger.debug('receiveNotify()'); + if (!request.body) { + return; + } + var status_line = Grammar.parse(request.body.trim().split('\r\n', 1)[0], 'Status_Line'); + if (status_line === -1) { + logger.debug("receiveNotify() | error parsing NOTIFY body: \"".concat(request.body, "\"")); + return; + } + switch (true) { + case /^100$/.test(status_line.status_code): + this.emit('trying', { + request: request, + status_line: status_line + }); + break; + case /^1[0-9]{2}$/.test(status_line.status_code): + this.emit('progress', { + request: request, + status_line: status_line + }); + break; + case /^2[0-9]{2}$/.test(status_line.status_code): + this.emit('accepted', { + request: request, + status_line: status_line + }); + break; + default: + this.emit('failed', { + request: request, + status_line: status_line + }); + break; + } + } + }, { + key: "_requestSucceeded", + value: function _requestSucceeded(response) { + logger.debug('REFER succeeded'); + logger.debug('emit "requestSucceeded"'); + this.emit('requestSucceeded', { + response: response + }); + } + }, { + key: "_requestFailed", + value: function _requestFailed(response, cause) { + logger.debug('REFER failed'); + logger.debug('emit "requestFailed"'); + this.emit('requestFailed', { + response: response || null, + cause: cause + }); + } + }]); + return ReferSubscriber; +}(EventEmitter); +},{"../Constants":2,"../Grammar":7,"../Logger":9,"../Utils":30,"events":33}],20:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var Logger = require('./Logger'); +var Utils = require('./Utils'); +var JsSIP_C = require('./Constants'); +var SIPMessage = require('./SIPMessage'); +var RequestSender = require('./RequestSender'); +var logger = new Logger('Registrator'); +var MIN_REGISTER_EXPIRES = 10; // In seconds. + +module.exports = /*#__PURE__*/function () { + function Registrator(ua, transport) { + _classCallCheck(this, Registrator); + // Force reg_id to 1. + this._reg_id = 1; + this._ua = ua; + this._transport = transport; + this._registrar = ua.configuration.registrar_server; + this._expires = ua.configuration.register_expires; + + // Call-ID and CSeq values RFC3261 10.2. + this._call_id = Utils.createRandomToken(22); + this._cseq = 0; + this._to_uri = ua.configuration.uri; + this._registrationTimer = null; + + // Ongoing Register request. + this._registering = false; + + // Set status. + this._registered = false; + + // Contact header. + this._contact = this._ua.contact.toString(); + + // Sip.ice media feature tag (RFC 5768). + this._contact += ';+sip.ice'; + + // Custom headers for REGISTER and un-REGISTER. + this._extraHeaders = []; + + // Custom Contact header params for REGISTER and un-REGISTER. + this._extraContactParams = ''; + + // Contents of the sip.instance Contact header parameter. + this._sipInstance = "\"\""); + this._contact += ";reg-id=".concat(this._reg_id); + this._contact += ";+sip.instance=".concat(this._sipInstance); + + // Igor's + this._auth = null; + } + _createClass(Registrator, [{ + key: "registered", + get: function get() { + return this._registered; + } + }, { + key: "setExtraHeaders", + value: function setExtraHeaders(extraHeaders) { + if (!Array.isArray(extraHeaders)) { + extraHeaders = []; + } + this._extraHeaders = extraHeaders.slice(); + } + }, { + key: "setExtraContactParams", + value: function setExtraContactParams(extraContactParams) { + if (!(extraContactParams instanceof Object)) { + extraContactParams = {}; + } + + // Reset it. + this._extraContactParams = ''; + for (var param_key in extraContactParams) { + if (Object.prototype.hasOwnProperty.call(extraContactParams, param_key)) { + var param_value = extraContactParams[param_key]; + this._extraContactParams += ";".concat(param_key); + if (param_value) { + this._extraContactParams += "=".concat(param_value); + } + } + } + } + }, { + key: "register", + value: function register() { + var _this = this; + if (this._registering) { + logger.debug('Register request in progress...'); + return; + } + var extraHeaders = this._extraHeaders.slice(); + extraHeaders.push("Contact: ".concat(this._contact, ";expires=").concat(this._expires).concat(this._extraContactParams)); + extraHeaders.push("Expires: ".concat(this._expires)); + if (this._auth) { + extraHeaders.push(this._auth); + } + var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, { + 'to_uri': this._to_uri, + 'call_id': this._call_id, + 'cseq': this._cseq += 1 + }, extraHeaders); + var request_sender = new RequestSender(this._ua, request, { + onRequestTimeout: function onRequestTimeout() { + _this._registrationFailure(null, JsSIP_C.causes.REQUEST_TIMEOUT); + }, + onTransportError: function onTransportError() { + _this._registrationFailure(null, JsSIP_C.causes.CONNECTION_ERROR); + }, + // Increase the CSeq on authentication. + onAuthenticated: function onAuthenticated(authRequest) { + _this._cseq += 1; + + // Cache authorization. Igor's + if (_this._ua.modes.cache_register_auth_mode) { + var name, value; + if (value = authRequest.getHeader(name = 'Authorization')) { + _this._auth = "".concat(name, ": ").concat(value); + } else if (value = authRequest.getHeader(name = 'Proxy-Authorization')) { + _this._auth = "".concat(name, ": ").concat(value); + } + } + }, + onReceiveResponse: function onReceiveResponse(response) { + // Discard responses to older REGISTER/un-REGISTER requests. + if (response.cseq !== _this._cseq) { + return; + } + + // Clear registration timer. + if (_this._registrationTimer !== null) { + clearTimeout(_this._registrationTimer); + _this._registrationTimer = null; + } + switch (true) { + case /^1[0-9]{2}$/.test(response.status_code): + { + // Ignore provisional responses. + break; + } + case /^2[0-9]{2}$/.test(response.status_code): + { + _this._registering = false; + if (!response.hasHeader('Contact')) { + logger.debug('no Contact header in response to REGISTER, response ignored'); + break; + } + var contacts = response.headers['Contact'].reduce(function (a, b) { + return a.concat(b.parsed); + }, []); + + // Get the Contact pointing to us and update the expires value accordingly. + // Try to find a matching Contact using sip.instance and reg-id. + var contact = contacts.find(function (element) { + return _this._sipInstance === element.getParam('+sip.instance') && _this._reg_id === parseInt(element.getParam('reg-id')); + }); + + // If no match was found using the sip.instance try comparing the URIs. + if (!contact) { + contact = contacts.find(function (element) { + return element.uri.user === _this._ua.contact.uri.user; + }); + } + if (!contact) { + logger.debug('no Contact header pointing to us, response ignored'); + break; + } + var expires = contact.getParam('expires'); + if (!expires && response.hasHeader('expires')) { + expires = response.getHeader('expires'); + } + if (!expires) { + expires = _this._expires; + } + expires = Number(expires); + if (expires < MIN_REGISTER_EXPIRES) expires = MIN_REGISTER_EXPIRES; + + /* + Igor's + with expires >= 140 works in intensive timer throttling (timer resolution 60 seconds) + */ + var timeout = expires >= 140 ? expires * 1000 / 2 + Math.floor((expires / 2 - 70) * 1000 * Math.random()) : expires * 1000 - 5000; + + // Re-Register or emit an event before the expiration interval has elapsed. + // For that, decrease the expires value. ie: 3 seconds. + _this._registrationTimer = setTimeout(function () { + _this._registrationTimer = null; + // If there are no listeners for registrationExpiring, renew registration. + // If there are listeners, let the function listening do the register call. + if (_this._ua.listeners('registrationExpiring').length === 0) { + _this.register(); + } else { + _this._ua.emit('registrationExpiring'); + } + }, timeout); + + // Save gruu values. + if (contact.hasParam('temp-gruu')) { + _this._ua.contact.temp_gruu = contact.getParam('temp-gruu').replace(/"/g, ''); + } + if (contact.hasParam('pub-gruu')) { + _this._ua.contact.pub_gruu = contact.getParam('pub-gruu').replace(/"/g, ''); + } + if (!_this._registered) { + _this._registered = true; + _this._ua.registered({ + response: response + }); + } + break; + } + + // Interval too brief RFC3261 10.2.8. + case /^423$/.test(response.status_code): + { + if (response.hasHeader('min-expires')) { + // Increase our registration interval to the suggested minimum. + _this._expires = Number(response.getHeader('min-expires')); + if (_this._expires < MIN_REGISTER_EXPIRES) _this._expires = MIN_REGISTER_EXPIRES; + + // Attempt the registration again immediately. + _this.register(); + } else { + // This response MUST contain a Min-Expires header field. + logger.debug('423 response received for REGISTER without Min-Expires'); + _this._registrationFailure(response, JsSIP_C.causes.SIP_FAILURE_CODE); + } + break; + } + default: + { + var cause = Utils.sipErrorCause(response.status_code); + _this._registrationFailure(response, cause); + } + } + } + }); + this._registering = true; + request_sender.send(); + } + }, { + key: "unregister", + value: function unregister() { + var _this2 = this; + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + if (!this._registered) { + logger.debug('already unregistered'); + return; + } + this._registered = false; + + // Clear the registration timer. + if (this._registrationTimer !== null) { + clearTimeout(this._registrationTimer); + this._registrationTimer = null; + } + var extraHeaders = this._extraHeaders.slice(); + if (options.all) { + extraHeaders.push("Contact: *".concat(this._extraContactParams)); + } else { + extraHeaders.push("Contact: ".concat(this._contact, ";expires=0").concat(this._extraContactParams)); + } + extraHeaders.push('Expires: 0'); + if (this._auth) { + extraHeaders.push(this._auth); + } + var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, { + 'to_uri': this._to_uri, + 'call_id': this._call_id, + 'cseq': this._cseq += 1 + }, extraHeaders); + var request_sender = new RequestSender(this._ua, request, { + onRequestTimeout: function onRequestTimeout() { + _this2._unregistered(null, JsSIP_C.causes.REQUEST_TIMEOUT); + }, + onTransportError: function onTransportError() { + _this2._unregistered(null, JsSIP_C.causes.CONNECTION_ERROR); + }, + // Increase the CSeq on authentication. + onAuthenticated: function onAuthenticated() { + _this2._cseq += 1; + }, + onReceiveResponse: function onReceiveResponse(response) { + switch (true) { + case /^1[0-9]{2}$/.test(response.status_code): + // Ignore provisional responses. + break; + case /^2[0-9]{2}$/.test(response.status_code): + _this2._unregistered(response); + break; + default: + { + var cause = Utils.sipErrorCause(response.status_code); + _this2._unregistered(response, cause); + } + } + } + }); + request_sender.send(); + this._auth = null; // Igor's + } + }, { + key: "close", + value: function close() { + if (this._registered) { + this.unregister(); + } + } + }, { + key: "onTransportClosed", + value: function onTransportClosed() { + this._registering = false; + if (this._registrationTimer !== null) { + clearTimeout(this._registrationTimer); + this._registrationTimer = null; + } + if (this._registered) { + this._registered = false; + this._ua.unregistered({}); + } + } + }, { + key: "_registrationFailure", + value: function _registrationFailure(response, cause) { + this._registering = false; + this._ua.registrationFailed({ + response: response || null, + cause: cause + }); + if (this._registered) { + this._registered = false; + this._ua.unregistered({ + response: response || null, + cause: cause + }); + } + } + }, { + key: "_unregistered", + value: function _unregistered(response, cause) { + this._registering = false; + this._registered = false; + this._ua.unregistered({ + response: response || null, + cause: cause || null + }); + } + }]); + return Registrator; +}(); +},{"./Constants":2,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30}],21:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var DigestAuthentication = require('./DigestAuthentication'); +var Transactions = require('./Transactions'); +var logger = new Logger('RequestSender'); + +// Default event handlers. +var EventHandlers = { + onRequestTimeout: function onRequestTimeout() {}, + onTransportError: function onTransportError() {}, + onReceiveResponse: function onReceiveResponse() {}, + onAuthenticated: function onAuthenticated() {} +}; +module.exports = /*#__PURE__*/function () { + function RequestSender(ua, request, eventHandlers) { + _classCallCheck(this, RequestSender); + this._ua = ua; + this._eventHandlers = eventHandlers; + this._method = request.method; + this._request = request; + this._auth = null; + this._challenged = false; + this._staled = false; + + // Define the undefined handlers. + for (var handler in EventHandlers) { + if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) { + if (!this._eventHandlers[handler]) { + this._eventHandlers[handler] = EventHandlers[handler]; + } + } + } + + // If ua is in closing process or even closed just allow sending Bye and ACK. + if (ua.status === ua.C.STATUS_USER_CLOSED && (this._method !== JsSIP_C.BYE || this._method !== JsSIP_C.ACK)) { + this._eventHandlers.onTransportError(); + } + } + + /** + * Create the client transaction and send the message. + */ + _createClass(RequestSender, [{ + key: "send", + value: function send() { + var _this = this; + var eventHandlers = { + onRequestTimeout: function onRequestTimeout() { + _this._eventHandlers.onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this._eventHandlers.onTransportError(); + }, + onReceiveResponse: function onReceiveResponse(response) { + _this._receiveResponse(response); + } + }; + switch (this._method) { + case 'INVITE': + this.clientTransaction = new Transactions.InviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers); + break; + case 'ACK': + this.clientTransaction = new Transactions.AckClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers); + break; + default: + this.clientTransaction = new Transactions.NonInviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers); + } + // If authorization JWT is present, use it. + if (this._ua._configuration.authorization_jwt) { + this._request.setHeader('Authorization', this._ua._configuration.authorization_jwt); + } + this.clientTransaction.send(); + } + + /** + * Called from client transaction when receiving a correct response to the request. + * Authenticate request if needed or pass the response back to the applicant. + */ + }, { + key: "_receiveResponse", + value: function _receiveResponse(response) { + var challenge; + var authorization_header_name; + var status_code = response.status_code; + + /* + * Authentication + * Authenticate once. _challenged_ flag used to avoid infinite authentications. + */ + if ((status_code === 401 || status_code === 407) && (this._ua.configuration.password !== null || this._ua.configuration.ha1 !== null)) { + // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header. + if (response.status_code === 401) { + challenge = response.parseHeader('www-authenticate'); + authorization_header_name = 'authorization'; + } else { + challenge = response.parseHeader('proxy-authenticate'); + authorization_header_name = 'proxy-authorization'; + } + + // Verify it seems a valid challenge. + if (!challenge) { + logger.debug("".concat(response.status_code, " with wrong or missing challenge, cannot authenticate")); + this._eventHandlers.onReceiveResponse(response); + return; + } + if (!this._challenged || !this._staled && challenge.stale === true) { + if (!this._auth) { + var credential = this._ua.getCredential(challenge.realm); + this._auth = new DigestAuthentication(credential); + } + + // Verify that the challenge is really valid. + if (!this._auth.authenticate(this._request, challenge)) { + this._eventHandlers.onReceiveResponse(response); + return; + } + this._challenged = true; + // Update ha1 and realm in the UA. + this._ua.updateCredential(challenge.realm, this._auth.get('realm'), this._auth.get('ha1')); + if (challenge.stale) { + this._staled = true; + } + this._request = this._request.clone(); + this._request.cseq += 1; + this._request.setHeader('cseq', "".concat(this._request.cseq, " ").concat(this._method)); + this._request.setHeader(authorization_header_name, this._auth.toString()); + this._eventHandlers.onAuthenticated(this._request); + this.send(); + } else { + this._eventHandlers.onReceiveResponse(response); + } + } else { + this._eventHandlers.onReceiveResponse(response); + } + } + }]); + return RequestSender; +}(); +},{"./Constants":2,"./DigestAuthentication":5,"./Logger":9,"./Transactions":26}],22:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var sdp_transform = require('sdp-transform'); +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var Utils = require('./Utils'); +var NameAddrHeader = require('./NameAddrHeader'); +var Grammar = require('./Grammar'); +var logger = new Logger('SIPMessage'); + +/** + * -param {String} method request method + * -param {String} ruri request uri + * -param {UA} ua + * -param {Object} params parameters that will have priority over ua.configuration parameters: + *
+ * - cseq, call_id, from_tag, from_uri, from_display_name, to_uri, to_tag, route_set + * -param {Object} [headers] extra headers + * -param {String} [body] + */ +var OutgoingRequest = /*#__PURE__*/function () { + function OutgoingRequest(method, ruri, ua, params, extraHeaders, body) { + _classCallCheck(this, OutgoingRequest); + // Mandatory parameters check. + if (!method || !ruri || !ua) { + return null; + } + params = params || {}; + this.ua = ua; + this.headers = {}; + this.method = method; + this.ruri = ruri; + this.body = body; + this.extraHeaders = Utils.cloneArray(extraHeaders); + if (this.ua.configuration.extra_headers) { + this.extraHeaders = this.extraHeaders.concat(this.ua.configuration.extra_headers); + } + + // Fill the Common SIP Request Headers. + + // Route. + if (params.route_set) { + this.setHeader('route', params.route_set); + } else if (ua.configuration.use_preloaded_route) { + this.setHeader('route', "<".concat(ua.transport.sip_uri, ";lr>")); + } + + // Via. + // Empty Via header. Will be filled by the client transaction. + this.setHeader('via', ''); + + // Max-Forwards. + this.setHeader('max-forwards', JsSIP_C.MAX_FORWARDS); + + // To + var to_uri = params.to_uri || ruri; + var to_params = params.to_tag ? { + tag: params.to_tag + } : null; + var to_display_name = typeof params.to_display_name !== 'undefined' ? params.to_display_name : null; + this.to = new NameAddrHeader(to_uri, to_display_name, to_params); + this.setHeader('to', this.to.toString()); + + // From. + var from_uri = params.from_uri || ua.configuration.uri; + var from_params = { + tag: params.from_tag || Utils.newTag() + }; + var display_name; + if (typeof params.from_display_name !== 'undefined') { + display_name = params.from_display_name; + } else if (ua.configuration.display_name) { + display_name = ua.configuration.display_name; + } else { + display_name = null; + } + this.from = new NameAddrHeader(from_uri, display_name, from_params); + this.setHeader('from', this.from.toString()); + + // Call-ID. + var call_id = params.call_id || ua.configuration.jssip_id + Utils.createRandomToken(15); + this.call_id = call_id; + this.setHeader('call-id', call_id); + + // CSeq. + var cseq = params.cseq || Math.floor(Math.random() * 10000); + this.cseq = cseq; + this.setHeader('cseq', "".concat(cseq, " ").concat(method)); + } + + /** + * Replace the the given header by the given value. + * -param {String} name header name + * -param {String | Array} value header value + */ + _createClass(OutgoingRequest, [{ + key: "setHeader", + value: function setHeader(name, value) { + // Remove the header from extraHeaders if present. + var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i'); + for (var idx = 0; idx < this.extraHeaders.length; idx++) { + if (regexp.test(this.extraHeaders[idx])) { + this.extraHeaders.splice(idx, 1); + } + } + this.headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value]; + } + + /** + * Get the value of the given header name at the given position. + * -param {String} name header name + * -returns {String|undefined} Returns the specified header, null if header doesn't exist. + */ + }, { + key: "getHeader", + value: function getHeader(name) { + var headers = this.headers[Utils.headerize(name)]; + if (headers) { + if (headers[0]) { + return headers[0]; + } + } else { + var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i'); + var _iterator = _createForOfIteratorHelper(this.extraHeaders), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var header = _step.value; + if (regexp.test(header)) { + return header.substring(header.indexOf(':') + 1).trim(); + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } + return; + } + + /** + * Get the header/s of the given name. + * -param {String} name header name + * -returns {Array} Array with all the headers of the specified name. + */ + }, { + key: "getHeaders", + value: function getHeaders(name) { + var headers = this.headers[Utils.headerize(name)]; + var result = []; + if (headers) { + var _iterator2 = _createForOfIteratorHelper(headers), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var header = _step2.value; + result.push(header); + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + return result; + } else { + var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i'); + var _iterator3 = _createForOfIteratorHelper(this.extraHeaders), + _step3; + try { + for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { + var _header = _step3.value; + if (regexp.test(_header)) { + result.push(_header.substring(_header.indexOf(':') + 1).trim()); + } + } + } catch (err) { + _iterator3.e(err); + } finally { + _iterator3.f(); + } + return result; + } + } + + /** + * Verify the existence of the given header. + * -param {String} name header name + * -returns {boolean} true if header with given name exists, false otherwise + */ + }, { + key: "hasHeader", + value: function hasHeader(name) { + if (this.headers[Utils.headerize(name)]) { + return true; + } else { + var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i'); + var _iterator4 = _createForOfIteratorHelper(this.extraHeaders), + _step4; + try { + for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { + var header = _step4.value; + if (regexp.test(header)) { + return true; + } + } + } catch (err) { + _iterator4.e(err); + } finally { + _iterator4.f(); + } + } + return false; + } + + /** + * Parse the current body as a SDP and store the resulting object + * into this.sdp. + * -param {Boolean} force: Parse even if this.sdp already exists. + * + * Returns this.sdp. + */ + }, { + key: "parseSDP", + value: function parseSDP(force) { + if (!force && this.sdp) { + return this.sdp; + } else { + this.sdp = sdp_transform.parse(this.body || ''); + return this.sdp; + } + } + }, { + key: "toString", + value: function toString() { + var msg = "".concat(this.method, " ").concat(this.ruri, " SIP/2.0\r\n"); + for (var headerName in this.headers) { + if (Object.prototype.hasOwnProperty.call(this.headers, headerName)) { + var _iterator5 = _createForOfIteratorHelper(this.headers[headerName]), + _step5; + try { + for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { + var headerValue = _step5.value; + msg += "".concat(headerName, ": ").concat(headerValue, "\r\n"); + } + } catch (err) { + _iterator5.e(err); + } finally { + _iterator5.f(); + } + } + } + var _iterator6 = _createForOfIteratorHelper(this.extraHeaders), + _step6; + try { + for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { + var header = _step6.value; + msg += "".concat(header.trim(), "\r\n"); + } + + // Supported. + } catch (err) { + _iterator6.e(err); + } finally { + _iterator6.f(); + } + var supported = []; + switch (this.method) { + case JsSIP_C.REGISTER: + supported.push('path', 'gruu'); + break; + case JsSIP_C.INVITE: + if (this.ua.configuration.session_timers) { + supported.push('timer'); + } + if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) { + supported.push('gruu'); + } + supported.push('ice', 'replaces'); + break; + case JsSIP_C.UPDATE: + if (this.ua.configuration.session_timers) { + supported.push('timer'); + } + supported.push('ice'); + break; + } + supported.push('outbound'); + var userAgent = this.ua.configuration.user_agent || JsSIP_C.USER_AGENT; + + // Allow. + msg += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n"); + msg += "Supported: ".concat(supported, "\r\n"); + msg += "User-Agent: ".concat(userAgent, "\r\n"); + if (this.body) { + var length = Utils.str_utf8_length(this.body); + msg += "Content-Length: ".concat(length, "\r\n\r\n"); + msg += this.body; + } else { + msg += 'Content-Length: 0\r\n\r\n'; + } + return msg; + } + }, { + key: "clone", + value: function clone() { + var request = new OutgoingRequest(this.method, this.ruri, this.ua); + Object.keys(this.headers).forEach(function (name) { + request.headers[name] = this.headers[name].slice(); + }, this); + request.body = this.body; + request.extraHeaders = Utils.cloneArray(this.extraHeaders); + request.to = this.to; + request.from = this.from; + request.call_id = this.call_id; + request.cseq = this.cseq; + return request; + } + }]); + return OutgoingRequest; +}(); +var InitialOutgoingInviteRequest = /*#__PURE__*/function (_OutgoingRequest) { + _inherits(InitialOutgoingInviteRequest, _OutgoingRequest); + var _super = _createSuper(InitialOutgoingInviteRequest); + function InitialOutgoingInviteRequest(ruri, ua, params, extraHeaders, body) { + var _this; + _classCallCheck(this, InitialOutgoingInviteRequest); + _this = _super.call(this, JsSIP_C.INVITE, ruri, ua, params, extraHeaders, body); + _this.transaction = null; + return _this; + } + _createClass(InitialOutgoingInviteRequest, [{ + key: "cancel", + value: function cancel(reason) { + this.transaction.cancel(reason); + } + }, { + key: "clone", + value: function clone() { + var request = new InitialOutgoingInviteRequest(this.ruri, this.ua); + Object.keys(this.headers).forEach(function (name) { + request.headers[name] = this.headers[name].slice(); + }, this); + request.body = this.body; + request.extraHeaders = Utils.cloneArray(this.extraHeaders); + request.to = this.to; + request.from = this.from; + request.call_id = this.call_id; + request.cseq = this.cseq; + request.transaction = this.transaction; + return request; + } + }]); + return InitialOutgoingInviteRequest; +}(OutgoingRequest); +var IncomingMessage = /*#__PURE__*/function () { + function IncomingMessage() { + _classCallCheck(this, IncomingMessage); + this.data = null; + this.headers = null; + this.method = null; + this.via = null; + this.via_branch = null; + this.call_id = null; + this.cseq = null; + this.from = null; + this.from_tag = null; + this.to = null; + this.to_tag = null; + this.body = null; + this.sdp = null; + } + + /** + * Insert a header of the given name and value into the last position of the + * header array. + */ + _createClass(IncomingMessage, [{ + key: "addHeader", + value: function addHeader(name, value) { + var header = { + raw: value + }; + name = Utils.headerize(name); + if (this.headers[name]) { + this.headers[name].push(header); + } else { + this.headers[name] = [header]; + } + } + + /** + * Get the value of the given header name at the given position. + */ + }, { + key: "getHeader", + value: function getHeader(name) { + var header = this.headers[Utils.headerize(name)]; + if (header) { + if (header[0]) { + return header[0].raw; + } + } else { + return; + } + } + + /** + * Get the header/s of the given name. + */ + }, { + key: "getHeaders", + value: function getHeaders(name) { + var headers = this.headers[Utils.headerize(name)]; + var result = []; + if (!headers) { + return []; + } + var _iterator7 = _createForOfIteratorHelper(headers), + _step7; + try { + for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { + var header = _step7.value; + result.push(header.raw); + } + } catch (err) { + _iterator7.e(err); + } finally { + _iterator7.f(); + } + return result; + } + + /** + * Verify the existence of the given header. + */ + }, { + key: "hasHeader", + value: function hasHeader(name) { + return this.headers[Utils.headerize(name)] ? true : false; + } + + /** + * Parse the given header on the given index. + * -param {String} name header name + * -param {Number} [idx=0] header index + * -returns {Object|undefined} Parsed header object, undefined if the header + * is not present or in case of a parsing error. + */ + }, { + key: "parseHeader", + value: function parseHeader(name) { + var idx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + name = Utils.headerize(name); + if (!this.headers[name]) { + logger.debug("header \"".concat(name, "\" not present")); + return; + } else if (idx >= this.headers[name].length) { + logger.debug("not so many \"".concat(name, "\" headers present")); + return; + } + var header = this.headers[name][idx]; + var value = header.raw; + if (header.parsed) { + return header.parsed; + } + + // Substitute '-' by '_' for grammar rule matching. + var parsed = Grammar.parse(value, name.replace(/-/g, '_')); + if (parsed === -1) { + this.headers[name].splice(idx, 1); // delete from headers + logger.debug("error parsing \"".concat(name, "\" header field with value \"").concat(value, "\"")); + return; + } else { + header.parsed = parsed; + return parsed; + } + } + + /** + * Message Header attribute selector. Alias of parseHeader. + * -param {String} name header name + * -param {Number} [idx=0] header index + * -returns {Object|undefined} Parsed header object, undefined if the header + * is not present or in case of a parsing error. + * + * -example + * message.s('via',3).port + */ + }, { + key: "s", + value: function s(name, idx) { + return this.parseHeader(name, idx); + } + + /** + * Replace the value of the given header by the value. + * -param {String} name header name + * -param {String} value header value + */ + }, { + key: "setHeader", + value: function setHeader(name, value) { + var header = { + raw: value + }; + this.headers[Utils.headerize(name)] = [header]; + } + + /** + * Parse the current body as a SDP and store the resulting object + * into this.sdp. + * -param {Boolean} force: Parse even if this.sdp already exists. + * + * Returns this.sdp. + */ + }, { + key: "parseSDP", + value: function parseSDP(force) { + if (!force && this.sdp) { + return this.sdp; + } else { + this.sdp = sdp_transform.parse(this.body || ''); + return this.sdp; + } + } + }, { + key: "toString", + value: function toString() { + return this.data; + } + }]); + return IncomingMessage; +}(); +var IncomingRequest = /*#__PURE__*/function (_IncomingMessage) { + _inherits(IncomingRequest, _IncomingMessage); + var _super2 = _createSuper(IncomingRequest); + function IncomingRequest(ua) { + var _this2; + _classCallCheck(this, IncomingRequest); + _this2 = _super2.call(this); + _this2.ua = ua; + _this2.headers = {}; + _this2.ruri = null; + _this2.transport = null; + _this2.server_transaction = null; + return _this2; + } + + /** + * Stateful reply. + * -param {Number} code status code + * -param {String} reason reason phrase + * -param {Object} headers extra headers + * -param {String} body body + * -param {Function} [onSuccess] onSuccess callback + * -param {Function} [onFailure] onFailure callback + */ + _createClass(IncomingRequest, [{ + key: "reply", + value: function reply(code, reason, extraHeaders, body, onSuccess, onFailure) { + var supported = []; + var to = this.getHeader('To'); + code = code || null; + reason = reason || null; + + // Validate code and reason values. + if (!code || code < 100 || code > 699) { + throw new TypeError("Invalid status_code: ".concat(code)); + } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) { + throw new TypeError("Invalid reason_phrase: ".concat(reason)); + } + reason = reason || JsSIP_C.REASON_PHRASE[code] || ''; + extraHeaders = Utils.cloneArray(extraHeaders); + if (this.ua.configuration.extra_headers) { + extraHeaders = extraHeaders.concat(this.ua.configuration.extra_headers); + } + var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n"); + if (this.method === JsSIP_C.INVITE && code > 100 && code <= 200) { + var headers = this.getHeaders('record-route'); + var _iterator8 = _createForOfIteratorHelper(headers), + _step8; + try { + for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { + var header = _step8.value; + response += "Record-Route: ".concat(header, "\r\n"); + } + } catch (err) { + _iterator8.e(err); + } finally { + _iterator8.f(); + } + } + var vias = this.getHeaders('via'); + var _iterator9 = _createForOfIteratorHelper(vias), + _step9; + try { + for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) { + var via = _step9.value; + response += "Via: ".concat(via, "\r\n"); + } + } catch (err) { + _iterator9.e(err); + } finally { + _iterator9.f(); + } + if (!this.to_tag && code > 100) { + to += ";tag=".concat(Utils.newTag()); + } else if (this.to_tag && !this.s('to').hasParam('tag')) { + to += ";tag=".concat(this.to_tag); + } + response += "To: ".concat(to, "\r\n"); + response += "From: ".concat(this.getHeader('From'), "\r\n"); + response += "Call-ID: ".concat(this.call_id, "\r\n"); + response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n"); + var _iterator10 = _createForOfIteratorHelper(extraHeaders), + _step10; + try { + for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) { + var _header2 = _step10.value; + response += "".concat(_header2.trim(), "\r\n"); + } + + // Supported. + } catch (err) { + _iterator10.e(err); + } finally { + _iterator10.f(); + } + switch (this.method) { + case JsSIP_C.INVITE: + if (this.ua.configuration.session_timers) { + supported.push('timer'); + } + if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) { + supported.push('gruu'); + } + supported.push('ice', 'replaces'); + break; + case JsSIP_C.UPDATE: + if (this.ua.configuration.session_timers) { + supported.push('timer'); + } + if (body) { + supported.push('ice'); + } + supported.push('replaces'); + } + supported.push('outbound'); + + // Allow and Accept. + if (this.method === JsSIP_C.OPTIONS) { + response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n"); + response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n"); + } else if (code === 405) { + response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n"); + } else if (code === 415) { + response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n"); + } + response += "Supported: ".concat(supported, "\r\n"); + if (body) { + var length = Utils.str_utf8_length(body); + response += 'Content-Type: application/sdp\r\n'; + response += "Content-Length: ".concat(length, "\r\n\r\n"); + response += body; + } else { + response += "Content-Length: ".concat(0, "\r\n\r\n"); + } + this.server_transaction.receiveResponse(code, response, onSuccess, onFailure); + } + + /** + * Stateless reply. + * -param {Number} code status code + * -param {String} reason reason phrase + */ + }, { + key: "reply_sl", + value: function reply_sl() { + var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var vias = this.getHeaders('via'); + + // Validate code and reason values. + if (!code || code < 100 || code > 699) { + throw new TypeError("Invalid status_code: ".concat(code)); + } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) { + throw new TypeError("Invalid reason_phrase: ".concat(reason)); + } + reason = reason || JsSIP_C.REASON_PHRASE[code] || ''; + var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n"); + var _iterator11 = _createForOfIteratorHelper(vias), + _step11; + try { + for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) { + var via = _step11.value; + response += "Via: ".concat(via, "\r\n"); + } + } catch (err) { + _iterator11.e(err); + } finally { + _iterator11.f(); + } + var to = this.getHeader('To'); + if (!this.to_tag && code > 100) { + to += ";tag=".concat(Utils.newTag()); + } else if (this.to_tag && !this.s('to').hasParam('tag')) { + to += ";tag=".concat(this.to_tag); + } + response += "To: ".concat(to, "\r\n"); + response += "From: ".concat(this.getHeader('From'), "\r\n"); + response += "Call-ID: ".concat(this.call_id, "\r\n"); + response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n"); + if (this.ua.configuration.extra_headers) { + var _iterator12 = _createForOfIteratorHelper(this.ua.configuration.extra_headers), + _step12; + try { + for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) { + var header = _step12.value; + response += "".concat(header.trim(), "\r\n"); + } + } catch (err) { + _iterator12.e(err); + } finally { + _iterator12.f(); + } + } + response += "Content-Length: ".concat(0, "\r\n\r\n"); + this.transport.send(response); + } + }]); + return IncomingRequest; +}(IncomingMessage); +var IncomingResponse = /*#__PURE__*/function (_IncomingMessage2) { + _inherits(IncomingResponse, _IncomingMessage2); + var _super3 = _createSuper(IncomingResponse); + function IncomingResponse() { + var _this3; + _classCallCheck(this, IncomingResponse); + _this3 = _super3.call(this); + _this3.headers = {}; + _this3.status_code = null; + _this3.reason_phrase = null; + return _this3; + } + return _createClass(IncomingResponse); +}(IncomingMessage); +module.exports = { + OutgoingRequest: OutgoingRequest, + InitialOutgoingInviteRequest: InitialOutgoingInviteRequest, + IncomingRequest: IncomingRequest, + IncomingResponse: IncomingResponse +}; +},{"./Constants":2,"./Grammar":7,"./Logger":9,"./NameAddrHeader":11,"./Utils":30,"sdp-transform":39}],23:[function(require,module,exports){ +"use strict"; + +var Logger = require('./Logger'); +var Utils = require('./Utils'); +var Grammar = require('./Grammar'); +var logger = new Logger('Socket'); + +/** + * Interface documentation: https://jssip.net/documentation/$last_version/api/socket/ + * + * interface Socket { + * attribute String via_transport + * attribute String url + * attribute String sip_uri + * + * method connect(); + * method disconnect(); + * method send(data); + * + * attribute EventHandler onconnect + * attribute EventHandler ondisconnect + * attribute EventHandler ondata + * } + * + */ + +exports.isSocket = function (socket) { + // Ignore if an array is given. + if (Array.isArray(socket)) { + return false; + } + if (typeof socket === 'undefined') { + logger.warn('undefined JsSIP.Socket instance'); + return false; + } + + // Check Properties. + try { + if (!Utils.isString(socket.url)) { + logger.warn('missing or invalid JsSIP.Socket url property'); + throw new Error('Missing or invalid JsSIP.Socket url property'); + } + if (!Utils.isString(socket.via_transport)) { + logger.warn('missing or invalid JsSIP.Socket via_transport property'); + throw new Error('Missing or invalid JsSIP.Socket via_transport property'); + } + if (Grammar.parse(socket.sip_uri, 'SIP_URI') === -1) { + logger.warn('missing or invalid JsSIP.Socket sip_uri property'); + throw new Error('missing or invalid JsSIP.Socket sip_uri property'); + } + } catch (e) { + return false; + } + + // Check Methods. + try { + ['connect', 'disconnect', 'send'].forEach(function (method) { + if (!Utils.isFunction(socket[method])) { + logger.warn("missing or invalid JsSIP.Socket method: ".concat(method)); + throw new Error("Missing or invalid JsSIP.Socket method: ".concat(method)); + } + }); + } catch (e) { + return false; + } + return true; +}; +},{"./Grammar":7,"./Logger":9,"./Utils":30}],24:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var Utils = require('./Utils'); +var Grammar = require('./Grammar'); +var SIPMessage = require('./SIPMessage'); +var RequestSender = require('./RequestSender'); +var Dialog = require('./Dialog'); +var logger = new Logger('Subscriber'); + +/** + * Termination codes. + */ +var C = { + // Termination codes. + SUBSCRIBE_RESPONSE_TIMEOUT: 0, + SUBSCRIBE_TRANSPORT_ERROR: 1, + SUBSCRIBE_NON_OK_RESPONSE: 2, + SUBSCRIBE_BAD_OK_RESPONSE: 3, + SUBSCRIBE_FAILED_AUTHENTICATION: 4, + UNSUBSCRIBE_TIMEOUT: 5, + RECEIVE_FINAL_NOTIFY: 6, + RECEIVE_BAD_NOTIFY: 7, + // Subscriber states. + STATE_PENDING: 0, + STATE_ACTIVE: 1, + STATE_TERMINATED: 2, + STATE_INIT: 3, + STATE_NOTIFY_WAIT: 4 +}; + +/** + * RFC 6665 Subscriber implementation. + */ +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(Subscriber, _EventEmitter); + var _super = _createSuper(Subscriber); + /** + * @param {UA} ua - reference to JsSIP.UA + * @param {string} target + * @param {string} eventName - Event header value. May end with optional ;id=xxx + * @param {string} accept - Accept header value. + * + * @param {SubscriberOption} options - optional parameters. + * @param {number} expires - Expires header value. Default is 900. + * @param {string} contentType - Content-Type header value. Used for SUBSCRIBE with body + * @param {string} allowEvents - Allow-Events header value. + * @param {RequestParams} params - Will have priority over ua.configuration. + * If set please define: to_uri, to_display_name, from_uri, from_display_name + * @param {Array} extraHeaders - Additional SIP headers. + */ + function Subscriber(ua, target, eventName, accept, _ref) { + var _this; + var expires = _ref.expires, + contentType = _ref.contentType, + allowEvents = _ref.allowEvents, + params = _ref.params, + extraHeaders = _ref.extraHeaders; + _classCallCheck(this, Subscriber); + logger.debug('new'); + _this = _super.call(this); + + // Check that arguments are defined + if (!target) { + throw new TypeError('target is undefined'); + } + if (!eventName) { + throw new TypeError('eventName is undefined'); + } + if (!accept) { + throw new TypeError('accept is undefined'); + } + _this._ua = ua; + _this._target = target; + if (expires !== 0 && !expires) { + expires = 900; + } + _this._expires = expires; + + // Used to subscribe with body. + _this._content_type = contentType; + + // Set initial subscribe parameters. + _this._params = Utils.cloneObject(params); + if (!_this._params.from_uri) { + _this._params.from_uri = _this._ua.configuration.uri; + } + _this._params.from_tag = Utils.newTag(); + _this._params.to_tag = null; + _this._params.call_id = Utils.createRandomToken(20); + + // Create subscribe cseq if not defined custom cseq. + if (_this._params.cseq === undefined) { + _this._params.cseq = Math.floor(Math.random() * 10000 + 1); + } + + // Subscriber state. + _this._state = C.STATE_INIT; + + // Dialog + _this._dialog = null; + + // To refresh subscription. + _this._expires_timer = null; + _this._expires_timestamp = null; + + // To prevent duplicate terminated call. + _this._terminated = false; + + // After send un-subscribe wait final notify limited time. + _this._unsubscribe_timeout_timer = null; + + // Custom session empty object for high level use. + _this.data = {}; + var parsed = Grammar.parse(eventName, 'Event'); + if (parsed === -1) { + throw new TypeError('eventName - wrong format'); + } + _this._event_name = parsed.event; + _this._event_id = parsed.params && parsed.params.id; + var eventValue = _this._event_name; + if (_this._event_id) { + eventValue += ";id=".concat(_this._event_id); + } + _this._headers = Utils.cloneArray(extraHeaders); + _this._headers = _this._headers.concat(["Event: ".concat(eventValue), "Expires: ".concat(_this._expires), "Accept: ".concat(accept)]); + if (!_this._headers.find(function (header) { + return header.startsWith('Contact'); + })) { + var contact = "Contact: ".concat(_this._ua._contact.toString()); + _this._headers.push(contact); + } + if (allowEvents) { + _this._headers.push("Allow-Events: ".concat(allowEvents)); + } + + // To enqueue subscribes created before receive initial subscribe OK. + _this._queue = []; + return _this; + } + _createClass(Subscriber, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "onRequestTimeout", + value: function onRequestTimeout() { + this._dialogTerminated(C.SUBSCRIBE_RESPONSE_TIMEOUT); + } + }, { + key: "onTransportError", + value: function onTransportError() { + this._dialogTerminated(C.SUBSCRIBE_TRANSPORT_ERROR); + } + + /** + * Dialog callback. + */ + }, { + key: "receiveRequest", + value: function receiveRequest(request) { + if (request.method !== JsSIP_C.NOTIFY) { + logger.warn('received non-NOTIFY request'); + request.reply(405); + return; + } + + // RFC 6665 8.2.1. Check if event header matches. + var event_header = request.parseHeader('Event'); + if (!event_header) { + logger.warn('missed Event header'); + request.reply(400); + this._dialogTerminated(C.RECEIVE_BAD_NOTIFY); + return; + } + var event_name = event_header.event; + var event_id = event_header.params && event_header.params.id; + if (event_name !== this._event_name || event_id !== this._event_id) { + logger.warn('Event header does not match SUBSCRIBE'); + request.reply(489); + this._dialogTerminated(C.RECEIVE_BAD_NOTIFY); + return; + } + + // Process Subscription-State header. + var subs_state = request.parseHeader('subscription-state'); + if (!subs_state) { + logger.warn('missed Subscription-State header'); + request.reply(400); + this._dialogTerminated(C.RECEIVE_BAD_NOTIFY); + return; + } + request.reply(200); + var new_state = this._stateStringToNumber(subs_state.state); + var prev_state = this._state; + if (prev_state !== C.STATE_TERMINATED && new_state !== C.STATE_TERMINATED) { + this._state = new_state; + if (subs_state.expires !== undefined) { + var expires = subs_state.expires; + var expires_timestamp = new Date().getTime() + expires * 1000; + var max_time_deviation = 2000; + + // Expiration time is shorter and the difference is not too small. + if (this._expires_timestamp - expires_timestamp > max_time_deviation) { + logger.debug('update sending re-SUBSCRIBE time'); + this._scheduleSubscribe(expires); + } + } + } + if (prev_state !== C.STATE_PENDING && new_state === C.STATE_PENDING) { + logger.debug('emit "pending"'); + this.emit('pending'); + } else if (prev_state !== C.STATE_ACTIVE && new_state === C.STATE_ACTIVE) { + logger.debug('emit "active"'); + this.emit('active'); + } + var body = request.body; + + // Check if the notify is final. + var is_final = new_state === C.STATE_TERMINATED; + + // Notify event fired only for notify with body. + if (body) { + var content_type = request.getHeader('content-type'); + logger.debug('emit "notify"'); + this.emit('notify', is_final, request, body, content_type); + } + if (is_final) { + var reason = subs_state.reason; + var retry_after = undefined; + if (subs_state.params && subs_state.params['retry-after'] !== undefined) { + retry_after = parseInt(subs_state.params['retry-after']); + } + this._dialogTerminated(C.RECEIVE_FINAL_NOTIFY, reason, retry_after); + } + } + + /** + * User API + */ + + /** + * Send the initial (non-fetch) and subsequent subscribe. + * @param {string} body - subscribe request body. + */ + }, { + key: "subscribe", + value: function subscribe() { + var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + logger.debug('subscribe()'); + if (this._state === C.STATE_INIT) { + this._sendInitialSubscribe(body, this._headers); + } else { + this._sendSubsequentSubscribe(body, this._headers); + } + } + + /** + * terminate. + * Send un-subscribe or fetch-subscribe (with Expires: 0). + * @param {string} body - un-subscribe request body + */ + }, { + key: "terminate", + value: function terminate() { + var _this2 = this; + var body = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + logger.debug('terminate()'); + + // Prevent duplication un-subscribe sending. + if (this._terminated) { + return; + } + this._terminated = true; + + // Set header Expires: 0. + var headers = this._headers.map(function (header) { + return header.startsWith('Expires') ? 'Expires: 0' : header; + }); + if (this._state === C.STATE_INIT) { + // fetch-subscribe - initial subscribe with Expires: 0. + this._sendInitialSubscribe(body, headers); + } else { + this._sendSubsequentSubscribe(body, headers); + } + + // Waiting for the final notify for a while. + var final_notify_timeout = 30000; + this._unsubscribe_timeout_timer = setTimeout(function () { + _this2._dialogTerminated(C.UNSUBSCRIBE_TIMEOUT); + }, final_notify_timeout); + } + + /** + * Get dialog state. + */ + }, { + key: "state", + get: function get() { + return this._state; + } + + /** + * Get dialog id. + */ + }, { + key: "id", + get: function get() { + return this._dialog ? this._dialog.id : null; + } + + /** + * Private API. + */ + }, { + key: "_sendInitialSubscribe", + value: function _sendInitialSubscribe(body, headers) { + var _this3 = this; + if (body) { + if (!this._content_type) { + throw new TypeError('content_type is undefined'); + } + headers = headers.slice(); + headers.push("Content-Type: ".concat(this._content_type)); + } + this._state = C.STATE_NOTIFY_WAIT; + var request = new SIPMessage.OutgoingRequest(JsSIP_C.SUBSCRIBE, this._ua.normalizeTarget(this._target), this._ua, this._params, headers, body); + var request_sender = new RequestSender(this._ua, request, { + onRequestTimeout: function onRequestTimeout() { + _this3.onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this3.onTransportError(); + }, + onReceiveResponse: function onReceiveResponse(response) { + _this3._receiveSubscribeResponse(response); + } + }); + request_sender.send(); + } + }, { + key: "_receiveSubscribeResponse", + value: function _receiveSubscribeResponse(response) { + if (response.status_code >= 200 && response.status_code < 300) { + // Create dialog + if (this._dialog === null) { + var dialog = new Dialog(this, response, 'UAC'); + if (dialog.error) { + // OK response without Contact + logger.warn(dialog.error); + this._dialogTerminated(C.SUBSCRIBE_BAD_OK_RESPONSE); + return; + } + this._dialog = dialog; + logger.debug('emit "accepted"'); + this.emit('accepted'); + + // Subsequent subscribes saved in the queue until dialog created. + var _iterator = _createForOfIteratorHelper(this._queue), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var subscribe = _step.value; + logger.debug('dequeue subscribe'); + this._sendSubsequentSubscribe(subscribe.body, subscribe.headers); + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } + + // Check expires value. + var expires_value = response.getHeader('expires'); + if (expires_value !== 0 && !expires_value) { + logger.warn('response without Expires header'); + + // RFC 6665 3.1.1 subscribe OK response must contain Expires header. + // Use workaround expires value. + expires_value = '900'; + } + var expires = parseInt(expires_value); + if (expires > 0) { + this._scheduleSubscribe(expires); + } + } else if (response.status_code === 401 || response.status_code === 407) { + this._dialogTerminated(C.SUBSCRIBE_FAILED_AUTHENTICATION); + } else if (response.status_code >= 300) { + this._dialogTerminated(C.SUBSCRIBE_NON_OK_RESPONSE); + } + } + }, { + key: "_sendSubsequentSubscribe", + value: function _sendSubsequentSubscribe(body, headers) { + var _this4 = this; + if (this._state === C.STATE_TERMINATED) { + return; + } + if (!this._dialog) { + logger.debug('enqueue subscribe'); + this._queue.push({ + body: body, + headers: headers.slice() + }); + return; + } + if (body) { + if (!this._content_type) { + throw new TypeError('content_type is undefined'); + } + headers = headers.slice(); + headers.push("Content-Type: ".concat(this._content_type)); + } + this._dialog.sendRequest(JsSIP_C.SUBSCRIBE, { + body: body, + extraHeaders: headers, + eventHandlers: { + onRequestTimeout: function onRequestTimeout() { + _this4.onRequestTimeout(); + }, + onTransportError: function onTransportError() { + _this4.onTransportError(); + }, + onSuccessResponse: function onSuccessResponse(response) { + _this4._receiveSubscribeResponse(response); + }, + onErrorResponse: function onErrorResponse(response) { + _this4._receiveSubscribeResponse(response); + }, + onDialogError: function onDialogError(response) { + _this4._receiveSubscribeResponse(response); + } + } + }); + } + }, { + key: "_dialogTerminated", + value: function _dialogTerminated(terminationCode) { + var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; + var retryAfter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined; + // To prevent duplicate emit terminated event. + if (this._state === C.STATE_TERMINATED) { + return; + } + this._state = C.STATE_TERMINATED; + + // Clear timers. + clearTimeout(this._expires_timer); + clearTimeout(this._unsubscribe_timeout_timer); + if (this._dialog) { + this._dialog.terminate(); + this._dialog = null; + } + logger.debug("emit \"terminated\" code=".concat(terminationCode)); + this.emit('terminated', terminationCode, reason, retryAfter); + } + }, { + key: "_scheduleSubscribe", + value: function _scheduleSubscribe(expires) { + var _this5 = this; + /* + If the expires time is less than 140 seconds we do not support Chrome intensive timer throttling mode. + In this case, the re-subcribe is sent 5 seconds before the subscription expiration. + When Chrome is in intensive timer throttling mode, in the worst case, + the timer will be 60 seconds late. + We give the server 10 seconds to make sure it will execute the command even if it is heavily loaded. + As a result, we order the time no later than 70 seconds before the subscription expiration. + Resulting time calculated as half time interval + (half interval - 70) * random. + E.g. expires is 140, re-subscribe will be ordered to send in 70 seconds. + expires is 600, re-subscribe will be ordered to send in 300 + (0 .. 230) seconds. + */ + + var timeout = expires >= 140 ? expires * 1000 / 2 + Math.floor((expires / 2 - 70) * 1000 * Math.random()) : expires * 1000 - 5000; + this._expires_timestamp = new Date().getTime() + expires * 1000; + logger.debug("next SUBSCRIBE will be sent in ".concat(Math.floor(timeout / 1000), " sec")); + clearTimeout(this._expires_timer); + this._expires_timer = setTimeout(function () { + _this5._expires_timer = null; + _this5._sendSubsequentSubscribe(null, _this5._headers); + }, timeout); + } + }, { + key: "_stateStringToNumber", + value: function _stateStringToNumber(strState) { + switch (strState) { + case 'pending': + return C.STATE_PENDING; + case 'active': + return C.STATE_ACTIVE; + case 'terminated': + return C.STATE_TERMINATED; + case 'init': + return C.STATE_INIT; + case 'notify_wait': + return C.STATE_NOTIFY_WAIT; + default: + throw new TypeError('wrong state value'); + } + } + }], [{ + key: "C", + get: + /** + * Expose C object. + */ + function get() { + return C; + } + }]); + return Subscriber; +}(EventEmitter); +},{"./Constants":2,"./Dialog":3,"./Grammar":7,"./Logger":9,"./RequestSender":21,"./SIPMessage":22,"./Utils":30,"events":33}],25:[function(require,module,exports){ +"use strict"; + +var T1 = 500, + T2 = 4000, + T4 = 5000; +module.exports = { + T1: T1, + T2: T2, + T4: T4, + TIMER_B: 64 * T1, + TIMER_D: 0 * T1, + TIMER_F: 64 * T1, + TIMER_H: 64 * T1, + TIMER_I: 0 * T1, + TIMER_J: 0 * T1, + TIMER_K: 0 * T4, + TIMER_L: 64 * T1, + TIMER_M: 64 * T1, + PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1 +}; +},{}],26:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var SIPMessage = require('./SIPMessage'); +var Timers = require('./Timers'); +var loggernict = new Logger('NonInviteClientTransaction'); +var loggerict = new Logger('InviteClientTransaction'); +var loggeract = new Logger('AckClientTransaction'); +var loggernist = new Logger('NonInviteServerTransaction'); +var loggerist = new Logger('InviteServerTransaction'); +var C = { + // Transaction states. + STATUS_TRYING: 1, + STATUS_PROCEEDING: 2, + STATUS_CALLING: 3, + STATUS_ACCEPTED: 4, + STATUS_COMPLETED: 5, + STATUS_TERMINATED: 6, + STATUS_CONFIRMED: 7, + // Transaction types. + NON_INVITE_CLIENT: 'nict', + NON_INVITE_SERVER: 'nist', + INVITE_CLIENT: 'ict', + INVITE_SERVER: 'ist' +}; +var NonInviteClientTransaction = /*#__PURE__*/function (_EventEmitter) { + _inherits(NonInviteClientTransaction, _EventEmitter); + var _super = _createSuper(NonInviteClientTransaction); + function NonInviteClientTransaction(ua, transport, request, eventHandlers) { + var _this; + _classCallCheck(this, NonInviteClientTransaction); + _this = _super.call(this); + _this.type = C.NON_INVITE_CLIENT; + _this.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000)); + _this.ua = ua; + _this.transport = transport; + _this.request = request; + _this.eventHandlers = eventHandlers; + var via = "SIP/2.0/".concat(transport.via_transport); + via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this.id); + _this.request.setHeader('via', via); + _this.ua.newTransaction(_assertThisInitialized(_this)); + return _this; + } + _createClass(NonInviteClientTransaction, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "stateChanged", + value: function stateChanged(state) { + this.state = state; + this.emit('stateChanged'); + } + }, { + key: "send", + value: function send() { + var _this2 = this; + this.stateChanged(C.STATUS_TRYING); + this.F = setTimeout(function () { + _this2.timer_F(); + }, Timers.TIMER_F); + if (!this.transport.send(this.request)) { + this.onTransportError(); + } + } + }, { + key: "onTransportError", + value: function onTransportError() { + loggernict.debug("transport error occurred, deleting transaction ".concat(this.id)); + clearTimeout(this.F); + // Igor: removed clearTimeout(this.K); + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + this.eventHandlers.onTransportError(); + } + }, { + key: "timer_F", + value: function timer_F() { + loggernict.debug("Timer F expired for transaction ".concat(this.id)); + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + this.eventHandlers.onRequestTimeout(); + } + }, { + key: "timer_K", + value: function timer_K() { + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + }, { + key: "receiveResponse", + value: function receiveResponse(response) { + var status_code = response.status_code; + if (status_code < 200) { + switch (this.state) { + case C.STATUS_TRYING: + case C.STATUS_PROCEEDING: + this.stateChanged(C.STATUS_PROCEEDING); + this.eventHandlers.onReceiveResponse(response); + break; + } + } else { + switch (this.state) { + case C.STATUS_TRYING: + case C.STATUS_PROCEEDING: + this.stateChanged(C.STATUS_COMPLETED); + clearTimeout(this.F); + if (status_code === 408) { + this.eventHandlers.onRequestTimeout(); + } else { + this.eventHandlers.onReceiveResponse(response); + } + this.timer_K(); // Igor: direct call timer_K() + break; + case C.STATUS_COMPLETED: + break; + } + } + } + }]); + return NonInviteClientTransaction; +}(EventEmitter); +var InviteClientTransaction = /*#__PURE__*/function (_EventEmitter2) { + _inherits(InviteClientTransaction, _EventEmitter2); + var _super2 = _createSuper(InviteClientTransaction); + function InviteClientTransaction(ua, transport, request, eventHandlers) { + var _this3; + _classCallCheck(this, InviteClientTransaction); + _this3 = _super2.call(this); + _this3.type = C.INVITE_CLIENT; + _this3.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000)); + _this3.ua = ua; + _this3.transport = transport; + _this3.request = request; + _this3.eventHandlers = eventHandlers; + request.transaction = _assertThisInitialized(_this3); + var via = "SIP/2.0/".concat(transport.via_transport); + via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this3.id); + _this3.request.setHeader('via', via); + _this3.ua.newTransaction(_assertThisInitialized(_this3)); + return _this3; + } + _createClass(InviteClientTransaction, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "stateChanged", + value: function stateChanged(state) { + this.state = state; + this.emit('stateChanged'); + } + }, { + key: "send", + value: function send() { + var _this4 = this; + this.stateChanged(C.STATUS_CALLING); + this.B = setTimeout(function () { + _this4.timer_B(); + }, Timers.TIMER_B); + if (!this.transport.send(this.request)) { + this.onTransportError(); + } + } + }, { + key: "onTransportError", + value: function onTransportError() { + clearTimeout(this.B); + // Igor: removed clearTimeout(this.D); + clearTimeout(this.M); + if (this.state !== C.STATUS_ACCEPTED) { + loggerict.debug("transport error occurred, deleting transaction ".concat(this.id)); + this.eventHandlers.onTransportError(); + } + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + + // RFC 6026 7.2. + }, { + key: "timer_M", + value: function timer_M() { + loggerict.debug("Timer M expired for transaction ".concat(this.id)); + if (this.state === C.STATUS_ACCEPTED) { + clearTimeout(this.B); + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + } + + // RFC 3261 17.1.1. + }, { + key: "timer_B", + value: function timer_B() { + loggerict.debug("Timer B expired for transaction ".concat(this.id)); + if (this.state === C.STATUS_CALLING) { + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + this.eventHandlers.onRequestTimeout(); + } + } + }, { + key: "timer_D", + value: function timer_D() { + loggerict.debug("Timer D expired for transaction ".concat(this.id)); + clearTimeout(this.B); + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + }, { + key: "sendACK", + value: function sendACK(response) { + var ack = new SIPMessage.OutgoingRequest(JsSIP_C.ACK, this.request.ruri, this.ua, { + 'route_set': this.request.getHeaders('route'), + 'call_id': this.request.getHeader('call-id'), + 'cseq': this.request.cseq + }); + ack.setHeader('from', this.request.getHeader('from')); + ack.setHeader('via', this.request.getHeader('via')); + ack.setHeader('to', response.getHeader('to')); + this.transport.send(ack); + this.timer_D(); // Igor: direct call timer_D() + } + }, { + key: "cancel", + value: function cancel(reason) { + // Send only if a provisional response (>100) has been received. + if (this.state !== C.STATUS_PROCEEDING) { + return; + } + var cancel = new SIPMessage.OutgoingRequest(JsSIP_C.CANCEL, this.request.ruri, this.ua, { + 'route_set': this.request.getHeaders('route'), + 'call_id': this.request.getHeader('call-id'), + 'cseq': this.request.cseq + }); + cancel.setHeader('from', this.request.getHeader('from')); + cancel.setHeader('via', this.request.getHeader('via')); + cancel.setHeader('to', this.request.getHeader('to')); + if (reason) { + cancel.setHeader('reason', reason); + } + this.transport.send(cancel); + } + }, { + key: "receiveResponse", + value: function receiveResponse(response) { + var _this5 = this; + var status_code = response.status_code; + if (status_code >= 100 && status_code <= 199) { + switch (this.state) { + case C.STATUS_CALLING: + this.stateChanged(C.STATUS_PROCEEDING); + this.eventHandlers.onReceiveResponse(response); + break; + case C.STATUS_PROCEEDING: + this.eventHandlers.onReceiveResponse(response); + break; + } + } else if (status_code >= 200 && status_code <= 299) { + switch (this.state) { + case C.STATUS_CALLING: + case C.STATUS_PROCEEDING: + this.stateChanged(C.STATUS_ACCEPTED); + this.M = setTimeout(function () { + _this5.timer_M(); + }, Timers.TIMER_M); + this.eventHandlers.onReceiveResponse(response); + break; + case C.STATUS_ACCEPTED: + this.eventHandlers.onReceiveResponse(response); + break; + } + } else if (status_code >= 300 && status_code <= 699) { + switch (this.state) { + case C.STATUS_CALLING: + case C.STATUS_PROCEEDING: + this.stateChanged(C.STATUS_COMPLETED); + this.sendACK(response); + this.eventHandlers.onReceiveResponse(response); + break; + case C.STATUS_COMPLETED: + this.sendACK(response); + break; + } + } + } + }]); + return InviteClientTransaction; +}(EventEmitter); +var AckClientTransaction = /*#__PURE__*/function (_EventEmitter3) { + _inherits(AckClientTransaction, _EventEmitter3); + var _super3 = _createSuper(AckClientTransaction); + function AckClientTransaction(ua, transport, request, eventHandlers) { + var _this6; + _classCallCheck(this, AckClientTransaction); + _this6 = _super3.call(this); + _this6.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000)); + _this6.transport = transport; + _this6.request = request; + _this6.eventHandlers = eventHandlers; + var via = "SIP/2.0/".concat(transport.via_transport); + via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this6.id); + _this6.request.setHeader('via', via); + return _this6; + } + _createClass(AckClientTransaction, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "send", + value: function send() { + if (!this.transport.send(this.request)) { + this.onTransportError(); + } + } + }, { + key: "onTransportError", + value: function onTransportError() { + loggeract.debug("transport error occurred for transaction ".concat(this.id)); + this.eventHandlers.onTransportError(); + } + }]); + return AckClientTransaction; +}(EventEmitter); +var NonInviteServerTransaction = /*#__PURE__*/function (_EventEmitter4) { + _inherits(NonInviteServerTransaction, _EventEmitter4); + var _super4 = _createSuper(NonInviteServerTransaction); + function NonInviteServerTransaction(ua, transport, request) { + var _this7; + _classCallCheck(this, NonInviteServerTransaction); + _this7 = _super4.call(this); + _this7.type = C.NON_INVITE_SERVER; + _this7.id = request.via_branch; + _this7.ua = ua; + _this7.transport = transport; + _this7.request = request; + _this7.last_response = ''; + request.server_transaction = _assertThisInitialized(_this7); + _this7.state = C.STATUS_TRYING; + ua.newTransaction(_assertThisInitialized(_this7)); + return _this7; + } + _createClass(NonInviteServerTransaction, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "stateChanged", + value: function stateChanged(state) { + this.state = state; + this.emit('stateChanged'); + } + }, { + key: "timer_J", + value: function timer_J() { + loggernist.debug("Timer J expired for transaction ".concat(this.id)); + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + }, { + key: "onTransportError", + value: function onTransportError() { + if (!this.transportError) { + this.transportError = true; + loggernist.debug("transport error occurred, deleting transaction ".concat(this.id)); + + // Igor: removed clearTimeout(this.J); + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + } + }, { + key: "receiveResponse", + value: function receiveResponse(status_code, response, onSuccess, onFailure) { + if (status_code === 100) { + /* RFC 4320 4.1 + * 'A SIP element MUST NOT + * send any provisional response with a + * Status-Code other than 100 to a non-INVITE request.' + */ + switch (this.state) { + case C.STATUS_TRYING: + this.stateChanged(C.STATUS_PROCEEDING); + if (!this.transport.send(response)) { + this.onTransportError(); + } + break; + case C.STATUS_PROCEEDING: + this.last_response = response; + if (!this.transport.send(response)) { + this.onTransportError(); + if (onFailure) { + onFailure(); + } + } else if (onSuccess) { + onSuccess(); + } + break; + } + } else if (status_code >= 200 && status_code <= 699) { + switch (this.state) { + case C.STATUS_TRYING: + case C.STATUS_PROCEEDING: + this.stateChanged(C.STATUS_COMPLETED); + this.last_response = response; + this.timer_J(); // Igor: direct call timer_J() + if (!this.transport.send(response)) { + this.onTransportError(); + if (onFailure) { + onFailure(); + } + } else if (onSuccess) { + onSuccess(); + } + break; + case C.STATUS_COMPLETED: + break; + } + } + } + }]); + return NonInviteServerTransaction; +}(EventEmitter); +var InviteServerTransaction = /*#__PURE__*/function (_EventEmitter5) { + _inherits(InviteServerTransaction, _EventEmitter5); + var _super5 = _createSuper(InviteServerTransaction); + function InviteServerTransaction(ua, transport, request) { + var _this8; + _classCallCheck(this, InviteServerTransaction); + _this8 = _super5.call(this); + _this8.type = C.INVITE_SERVER; + _this8.id = request.via_branch; + _this8.ua = ua; + _this8.transport = transport; + _this8.request = request; + _this8.last_response = ''; + request.server_transaction = _assertThisInitialized(_this8); + _this8.state = C.STATUS_PROCEEDING; + ua.newTransaction(_assertThisInitialized(_this8)); + _this8.resendProvisionalTimer = null; + request.reply(100); + return _this8; + } + _createClass(InviteServerTransaction, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "stateChanged", + value: function stateChanged(state) { + this.state = state; + this.emit('stateChanged'); + } + }, { + key: "timer_H", + value: function timer_H() { + loggerist.debug("Timer H expired for transaction ".concat(this.id)); + if (this.state === C.STATUS_COMPLETED) { + loggerist.debug('ACK not received, dialog will be terminated'); + } + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + }, { + key: "timer_I", + value: function timer_I() { + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + + // RFC 6026 7.1. + }, { + key: "timer_L", + value: function timer_L() { + loggerist.debug("Timer L expired for transaction ".concat(this.id)); + if (this.state === C.STATUS_ACCEPTED) { + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + } + }, { + key: "onTransportError", + value: function onTransportError() { + if (!this.transportError) { + this.transportError = true; + loggerist.debug("transport error occurred, deleting transaction ".concat(this.id)); + if (this.resendProvisionalTimer !== null) { + clearInterval(this.resendProvisionalTimer); + this.resendProvisionalTimer = null; + } + clearTimeout(this.L); + clearTimeout(this.H); + // Igor: removed clearTimeout(this.I); + + this.stateChanged(C.STATUS_TERMINATED); + this.ua.destroyTransaction(this); + } + } + }, { + key: "resend_provisional", + value: function resend_provisional() { + if (!this.transport.send(this.last_response)) { + this.onTransportError(); + } + } + + // INVITE Server Transaction RFC 3261 17.2.1. + }, { + key: "receiveResponse", + value: function receiveResponse(status_code, response, onSuccess, onFailure) { + var _this9 = this; + if (status_code >= 100 && status_code <= 199) { + switch (this.state) { + case C.STATUS_PROCEEDING: + if (!this.transport.send(response)) { + this.onTransportError(); + } + this.last_response = response; + break; + } + } + if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) { + // Trigger the resendProvisionalTimer only for the first non 100 provisional response. + if (this.resendProvisionalTimer === null) { + this.resendProvisionalTimer = setInterval(function () { + _this9.resend_provisional(); + }, Timers.PROVISIONAL_RESPONSE_INTERVAL); + } + } else if (status_code >= 200 && status_code <= 299) { + switch (this.state) { + case C.STATUS_PROCEEDING: + this.stateChanged(C.STATUS_ACCEPTED); + this.last_response = response; + this.L = setTimeout(function () { + _this9.timer_L(); + }, Timers.TIMER_L); + if (this.resendProvisionalTimer !== null) { + clearInterval(this.resendProvisionalTimer); + this.resendProvisionalTimer = null; + } + + /* falls through */ + case C.STATUS_ACCEPTED: + // Note that this point will be reached for proceeding this.state also. + if (!this.transport.send(response)) { + this.onTransportError(); + if (onFailure) { + onFailure(); + } + } else if (onSuccess) { + onSuccess(); + } + break; + } + } else if (status_code >= 300 && status_code <= 699) { + switch (this.state) { + case C.STATUS_PROCEEDING: + if (this.resendProvisionalTimer !== null) { + clearInterval(this.resendProvisionalTimer); + this.resendProvisionalTimer = null; + } + if (!this.transport.send(response)) { + this.onTransportError(); + if (onFailure) { + onFailure(); + } + } else { + this.stateChanged(C.STATUS_COMPLETED); + this.H = setTimeout(function () { + _this9.timer_H(); + }, Timers.TIMER_H); + if (onSuccess) { + onSuccess(); + } + } + break; + } + } + } + }]); + return InviteServerTransaction; +}(EventEmitter); +/** + * INVITE: + * _true_ if retransmission + * _false_ new request + * + * ACK: + * _true_ ACK to non2xx response + * _false_ ACK must be passed to TU (accepted state) + * ACK to 2xx response + * + * CANCEL: + * _true_ no matching invite transaction + * _false_ matching invite transaction and no final response sent + * + * OTHER: + * _true_ retransmission + * _false_ new request + */ +function checkTransaction(_ref, request) { + var _transactions = _ref._transactions; + var tr; + switch (request.method) { + case JsSIP_C.INVITE: + tr = _transactions.ist[request.via_branch]; + if (tr) { + switch (tr.state) { + case C.STATUS_PROCEEDING: + tr.transport.send(tr.last_response); + break; + + // RFC 6026 7.1 Invite retransmission. + // Received while in C.STATUS_ACCEPTED state. Absorb it. + case C.STATUS_ACCEPTED: + break; + } + return true; + } + break; + case JsSIP_C.ACK: + tr = _transactions.ist[request.via_branch]; + + // RFC 6026 7.1. + if (tr) { + if (tr.state === C.STATUS_ACCEPTED) { + return false; + } else if (tr.state === C.STATUS_COMPLETED) { + tr.state = C.STATUS_CONFIRMED; + tr.timer_I(); // Igor: direct call timer_I() + + return true; + } + } + // ACK to 2XX Response. + else { + return false; + } + break; + case JsSIP_C.CANCEL: + tr = _transactions.ist[request.via_branch]; + if (tr) { + request.reply_sl(200); + if (tr.state === C.STATUS_PROCEEDING) { + return false; + } else { + return true; + } + } else { + request.reply_sl(481); + return true; + } + default: + // Non-INVITE Server Transaction RFC 3261 17.2.2. + tr = _transactions.nist[request.via_branch]; + if (tr) { + switch (tr.state) { + case C.STATUS_TRYING: + break; + case C.STATUS_PROCEEDING: + case C.STATUS_COMPLETED: + tr.transport.send(tr.last_response); + break; + } + return true; + } + break; + } +} +module.exports = { + C: C, + NonInviteClientTransaction: NonInviteClientTransaction, + InviteClientTransaction: InviteClientTransaction, + AckClientTransaction: AckClientTransaction, + NonInviteServerTransaction: NonInviteServerTransaction, + InviteServerTransaction: InviteServerTransaction, + checkTransaction: checkTransaction +}; +},{"./Constants":2,"./Logger":9,"./SIPMessage":22,"./Timers":25,"events":33}],27:[function(require,module,exports){ +"use strict"; + +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var Logger = require('./Logger'); +var Socket = require('./Socket'); +var JsSIP_C = require('./Constants'); +var logger = new Logger('Transport'); + +/** + * Constants + */ +var C = { + // Transport status. + STATUS_CONNECTED: 0, + STATUS_CONNECTING: 1, + STATUS_DISCONNECTED: 2, + // Socket status. + SOCKET_STATUS_READY: 0, + SOCKET_STATUS_ERROR: 1, + // Recovery options. + recovery_options: { + // minimum interval in seconds between recover attempts. + min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL, + // maximum interval in seconds between recover attempts. + max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL + } +}; + +/* + * Manages one or multiple JsSIP.Socket instances. + * Is reponsible for transport recovery logic among all socket instances. + * + * @socket JsSIP::Socket instance + */ +module.exports = /*#__PURE__*/function () { + // Igor's added reference to ua + function Transport(ua, sockets) { + var recovery_options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : C.recovery_options; + _classCallCheck(this, Transport); + logger.debug('new()'); + this._ua = ua; + this.status = C.STATUS_DISCONNECTED; + + // Current socket. + this.socket = null; + + // Socket collection. + this.sockets = []; + this.recovery_options = recovery_options; + this.recover_attempts = 0; + this.recovery_timer = null; + this.close_requested = false; + + // It seems that TextDecoder is not available in some versions of React-Native. + // See https://github.com/versatica/JsSIP/issues/695 + try { + this.textDecoder = new TextDecoder('utf8'); + } catch (error) { + logger.warn("cannot use TextDecoder: ".concat(error)); + } + if (typeof sockets === 'undefined') { + throw new TypeError('Invalid argument.' + ' undefined \'sockets\' argument'); + } + if (!(sockets instanceof Array)) { + sockets = [sockets]; + } + sockets.forEach(function (socket) { + if (!Socket.isSocket(socket.socket)) { + throw new TypeError('Invalid argument.' + ' invalid \'JsSIP.Socket\' instance'); + } + if (socket.weight && !Number(socket.weight)) { + throw new TypeError('Invalid argument.' + ' \'weight\' attribute is not a number'); + } + this.sockets.push({ + socket: socket.socket, + weight: socket.weight || 0, + status: C.SOCKET_STATUS_READY + }); + }, this); + + // Get the socket with higher weight. + this._getSocket(); + } + + /** + * Instance Methods + */ + _createClass(Transport, [{ + key: "via_transport", + get: function get() { + return this.socket.via_transport; + } + }, { + key: "url", + get: function get() { + return this.socket.url; + } + }, { + key: "sip_uri", + get: function get() { + return this.socket.sip_uri; + } + }, { + key: "connect", + value: function connect() { + logger.debug('connect()'); + if (this.isConnected()) { + logger.debug('Transport is already connected'); + return; + } else if (this.isConnecting()) { + logger.debug('Transport is connecting'); + return; + } + this.close_requested = false; + this.status = C.STATUS_CONNECTING; + this.onconnecting({ + socket: this.socket, + attempts: this.recover_attempts + }); + if (!this.close_requested) { + // Bind socket event callbacks. + this.socket.onconnect = this._onConnect.bind(this); + this.socket.ondisconnect = this._onDisconnect.bind(this); + this.socket.ondata = this._onData.bind(this); + this.socket.connect(); + } + return; + } + }, { + key: "disconnect", + value: function disconnect() { + logger.debug('close()'); + this.close_requested = true; + this.recover_attempts = 0; + this.status = C.STATUS_DISCONNECTED; + + // Clear recovery_timer. + if (this.recovery_timer !== null) { + clearTimeout(this.recovery_timer); + this.recovery_timer = null; + } + + // Unbind socket event callbacks. + this.socket.onconnect = function () {}; + this.socket.ondisconnect = function () {}; + this.socket.ondata = function () {}; + this.socket.disconnect(); + this.ondisconnect({ + socket: this.socket, + error: false + }); + } + }, { + key: "send", + value: function send(data) { + logger.debug('send()'); + if (!this.isConnected()) { + logger.warn('unable to send message, transport is not connected'); + return false; + } + var message = data.toString(); + logger.debug("sending message:\n\n".concat(message, "\n")); + return this.socket.send(message); + } + }, { + key: "isConnected", + value: function isConnected() { + return this.status === C.STATUS_CONNECTED; + } + }, { + key: "isConnecting", + value: function isConnecting() { + return this.status === C.STATUS_CONNECTING; + } + + /** + * Private API. + */ + + /** + * Igor's extension + */ + }, { + key: "_get_number_of_sbc", + value: function _get_number_of_sbc() { + return this.sockets.length; + } + }, { + key: "_switch_sbc", + value: function _switch_sbc() { + var savedCallback = this.ondisconnect; + this.ondisconnect = function () {}; + this.disconnect(); + this.ondisconnect = savedCallback; + this.close_requested = false; + this.sockets.forEach(function (socket) { + if (this.socket === socket.socket) { + socket.status = C.SOCKET_STATUS_ERROR; + } + }, this); + this._getSocket(); + this.connect(); + } + + /** + * Igor's extension + */ + }, { + key: "_register_redirect", + value: function _register_redirect(url) { + var foundSocket = null; + var _iterator = _createForOfIteratorHelper(this.sockets), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var _s = _step.value; + if (_s.socket.url === url) { + foundSocket = _s.socket; + break; + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + if (foundSocket === null && !url.includes(':', 6)) { + url += ':443'; + var _iterator2 = _createForOfIteratorHelper(this.sockets), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var s = _step2.value; + if (s.socket.url === url) { + foundSocket = s.socket; + break; + } + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + } + if (foundSocket === null) { + return false; + } + var savedCallback = this.ondisconnect; + this.ondisconnect = function () {}; + this.disconnect(); + this.ondisconnect = savedCallback; + this.socket = foundSocket; + this.connect(); + return true; + } + }, { + key: "_reconnect", + value: function _reconnect() { + var _this = this; + this.recover_attempts += 1; + var k = Math.floor(Math.random() * Math.pow(2, this.recover_attempts) + 1); + if (k < this.recovery_options.min_interval) { + k = this.recovery_options.min_interval; + } else if (k > this.recovery_options.max_interval) { + k = this.recovery_options.max_interval; + } + logger.debug("reconnection attempt: ".concat(this.recover_attempts, ". next connection attempt in ").concat(k, " seconds")); + this.recovery_timer = setTimeout(function () { + if (!_this.close_requested && !(_this.isConnected() || _this.isConnecting())) { + // Get the next available socket with higher weight. + _this._getSocket(); + + // Connect the socket. + _this.connect(); + } + }, k * 1000); + } + + /** + * get the next available socket with higher weight + */ + }, { + key: "_getSocket", + value: function _getSocket() { + var candidates = []; + this.sockets.forEach(function (socket) { + if (socket.status === C.SOCKET_STATUS_ERROR) { + return; // continue the array iteration + } else if (candidates.length === 0) { + candidates.push(socket); + } else if (socket.weight > candidates[0].weight) { + candidates = [socket]; + } else if (socket.weight === candidates[0].weight) { + candidates.push(socket); + } + }); + if (candidates.length === 0) { + // All sockets have failed. reset sockets status. + this.sockets.forEach(function (socket) { + socket.status = C.SOCKET_STATUS_READY; + }); + + // Get next available socket. + this._getSocket(); + return; + } + var idx = Math.floor(Math.random() * candidates.length); + this.socket = candidates[idx].socket; + } + + /** + * Socket Event Handlers + */ + }, { + key: "_onConnect", + value: function _onConnect() { + this.recover_attempts = 0; + + // Igor's mode + this._ha_connect_time = undefined; + // end of mode + + this.status = C.STATUS_CONNECTED; + + // Clear recovery_timer. + if (this.recovery_timer !== null) { + clearTimeout(this.recovery_timer); + this.recovery_timer = null; + } + this.onconnect({ + socket: this + }); + } + }, { + key: "_onDisconnect", + value: function _onDisconnect(error, code, reason) { + // Igor's mode + var prevStatus = this.status; + // end of mode + + this.status = C.STATUS_DISCONNECTED; + this.ondisconnect({ + socket: this.socket, + error: error, + code: code, + reason: reason + }); + if (this.close_requested) { + return; + } + + // Igor's mode + if (this._ua.modes.sbc_ha_pairs_mode !== undefined) { + if (prevStatus === C.STATUS_CONNECTED) { + logger.debug("AC: SBC HA pairs mode: Reconnect to the same SBC ".concat(this._ua.modes.sbc_ha_pairs_mode, " seconds left")); + this._ha_connect_time = new Date().getTime() + this._ua.modes.sbc_ha_pairs_mode * 1000; + this._connect2(); + return; + } + if (this._ha_connect_time !== undefined) { + var interval = this._ha_connect_time - new Date().getTime(); + if (interval > 0) { + logger.debug("AC: SBC HA pairs mode: Repeat ".concat(interval / 1000, " seconds left")); + this._connect2(); + return; + } else { + logger.debug('AC: SBC HA pairs mode: Failed'); + this._ha_connect_time = undefined; + } + } + } + // end of mode + + // Update socket status. + this.sockets.forEach(function (socket) { + if (this.socket === socket.socket) { + socket.status = C.SOCKET_STATUS_ERROR; + } + }, this); + this._reconnect(); + } + + // Igor's mode. Connect with limited number of attempts per second. + }, { + key: "_connect2", + value: function _connect2() { + var _this2 = this; + var delay = 0; + var MinDelay = 500; + if (this._ha_last_connect) { + var elapsed = new Date().getTime() - this._ha_last_connect; + delay = elapsed > MinDelay ? 0 : MinDelay - elapsed; + } + + // logger.debug('AC: SBC HA pairs mode: wait before connect ' + delay/1000); + this.recovery_timer = setTimeout(function () { + if (!_this2.close_requested && !(_this2.isConnected() || _this2.isConnecting())) { + _this2._ha_last_connect = new Date().getTime(); + _this2.connect(); + } + }, delay); + } + // end of mode + }, { + key: "_onData", + value: function _onData(data) { + // CRLF Keep Alive response from server. Ignore it. + if (data === '\r\n') { + logger.debug('received message with CRLF Keep Alive response'); + return; + } + + // Binary message. + else if (typeof data !== 'string') { + try { + if (this.textDecoder) data = this.textDecoder.decode(data);else data = String.fromCharCode.apply(null, new Uint8Array(data)); + } catch (evt) { + logger.debug('received binary message failed to be converted into string,' + ' message discarded'); + return; + } + logger.debug("received binary message:\n\n".concat(data, "\n")); + } + + // Text message. + else { + logger.debug("received text message:\n\n".concat(data, "\n")); + } + this.ondata({ + transport: this, + message: data + }); + } + }]); + return Transport; +}(); +},{"./Constants":2,"./Logger":9,"./Socket":23}],28:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +var EventEmitter = require('events').EventEmitter; +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var Registrator = require('./Registrator'); +var RTCSession = require('./RTCSession'); +var Subscriber = require('./Subscriber'); +var Notifier = require('./Notifier'); +var Message = require('./Message'); +var Options = require('./Options'); +var Transactions = require('./Transactions'); +var Transport = require('./Transport'); +var Utils = require('./Utils'); +var Exceptions = require('./Exceptions'); +var URI = require('./URI'); +var Parser = require('./Parser'); +var SIPMessage = require('./SIPMessage'); +var sanityCheck = require('./sanityCheck'); +var config = require('./Config'); +var logger = new Logger('UA'); +var C = { + // UA status codes. + STATUS_INIT: 0, + STATUS_READY: 1, + STATUS_USER_CLOSED: 2, + STATUS_NOT_READY: 3, + // UA error codes. + CONFIGURATION_ERROR: 1, + NETWORK_ERROR: 2 +}; + +/** + * The User-Agent class. + * @class JsSIP.UA + * @param {Object} configuration Configuration parameters. + * @throws {JsSIP.Exceptions.ConfigurationError} If a configuration parameter is invalid. + * @throws {TypeError} If no configuration is given. + */ +module.exports = /*#__PURE__*/function (_EventEmitter) { + _inherits(UA, _EventEmitter); + var _super = _createSuper(UA); + function UA(configuration) { + var _this; + _classCallCheck(this, UA); + /* Igor's fix: don't show password + logger.debug('new() [configuration:%o]', configuration); + */ + _this = _super.call(this); + + /* Igor's extension: modes */ + _this.modes = {}; + + /* Igor's extension: multiple credentials */ + _this._credentials = {}; + _this._cache = { + credentials: {} + }; + _this._configuration = Object.assign({}, config.settings); + _this._dynConfiguration = {}; + _this._dialogs = {}; + + // User actions outside any session/dialog (MESSAGE/OPTIONS). + _this._applicants = {}; + _this._sessions = {}; + _this._transport = null; + _this._contact = null; + _this._status = C.STATUS_INIT; + _this._error = null; + _this._transactions = { + nist: {}, + nict: {}, + ist: {}, + ict: {} + }; + + // Custom UA empty object for high level use. + _this._data = {}; + _this._closeTimer = null; + + // Check configuration argument. + if (configuration === undefined) { + throw new TypeError('Not enough arguments'); + } + + // Load configuration. + try { + _this._loadConfig(configuration); + } catch (e) { + _this._status = C.STATUS_NOT_READY; + _this._error = C.CONFIGURATION_ERROR; + throw e; + } + + // Initialize registrator. + _this._registrator = new Registrator(_assertThisInitialized(_this)); + return _this; + } + _createClass(UA, [{ + key: "C", + get: function get() { + return C; + } + }, { + key: "status", + get: function get() { + return this._status; + } + }, { + key: "contact", + get: function get() { + return this._contact; + } + }, { + key: "configuration", + get: function get() { + return this._configuration; + } + }, { + key: "transport", + get: function get() { + return this._transport; + } + + // ================= + // High Level API + // ================= + + /** + * Connect to the server if status = STATUS_INIT. + * Resume UA after being closed. + */ + }, { + key: "start", + value: function start() { + logger.debug('start()'); + if (this._status === C.STATUS_INIT) { + this._transport.connect(); + } else if (this._status === C.STATUS_USER_CLOSED) { + logger.debug('restarting UA'); + + // Disconnect. + if (this._closeTimer !== null) { + clearTimeout(this._closeTimer); + this._closeTimer = null; + this._transport.disconnect(); + } + + // Reconnect. + this._status = C.STATUS_INIT; + this._transport.connect(); + } else if (this._status === C.STATUS_READY) { + logger.debug('UA is in READY status, not restarted'); + } else { + logger.debug('ERROR: connection is down, Auto-Recovery system is trying to reconnect'); + } + + // Set dynamic configuration. + this._dynConfiguration.register = this._configuration.register; + } + + /** + * Register. + */ + }, { + key: "register", + value: function register() { + logger.debug('register()'); + this._dynConfiguration.register = true; + this._registrator.register(); + } + + /** + * Unregister. + */ + }, { + key: "unregister", + value: function unregister(options) { + logger.debug('unregister()'); + this._dynConfiguration.register = false; + this._registrator.unregister(options); + } + + /** + * Get the Registrator instance. + */ + }, { + key: "registrator", + value: function registrator() { + return this._registrator; + } + + /** + * Registration state. + */ + }, { + key: "isRegistered", + value: function isRegistered() { + return this._registrator.registered; + } + + /** + * Connection state. + */ + }, { + key: "isConnected", + value: function isConnected() { + return this._transport.isConnected(); + } + + /** + * Make an outgoing call. + * + * -param {String} target + * -param {Object} [options] + * + * -throws {TypeError} + * + */ + }, { + key: "call", + value: function call(target, options) { + logger.debug('call()'); + var session = new RTCSession(this); + session.connect(target, options); + return session; + } + + /** + * Send a message. + * + * -param {String} target + * -param {String} body + * -param {Object} [options] + * + * -throws {TypeError} + * + */ + }, { + key: "sendMessage", + value: function sendMessage(target, body, options) { + logger.debug('sendMessage()'); + var message = new Message(this); + message.send(target, body, options); + return message; + } + + /** + * Create subscriber instance + */ + }, { + key: "subscribe", + value: function subscribe(target, eventName, accept, options) { + logger.debug('subscribe()'); + return new Subscriber(this, target, eventName, accept, options); + } + + /** + * Create notifier instance + */ + }, { + key: "notify", + value: function notify(subscribe, contentType, options) { + logger.debug('notify()'); + return new Notifier(this, subscribe, contentType, options); + } + + /** + * Igor's extension. Multi realm authorization + */ + }, { + key: "addCredential", + value: function addCredential(credential) { + this._credentials[credential.realm] = Utils.cloneObject(credential); + } + }, { + key: "getCredential", + value: function getCredential(realm) { + var credential = this._credentials[realm]; + return credential ? credential : { + username: this._configuration.authorization_user, + password: this._configuration.password, + realm: this._configuration.realm, + ha1: this._configuration.ha1 + }; + } + }, { + key: "updateCredential", + value: function updateCredential(challengeRealm, realm, ha1) { + var credential = this._credentials[challengeRealm]; + if (credential) { + credential.realm = realm; + credential.ha1 = ha1; + } else { + this.set('realm', realm); + this.set('ha1', ha1); + } + } + + /** + * Send a SIP OPTIONS. + * + * -param {String} target + * -param {String} [body] + * -param {Object} [options] + * + * -throws {TypeError} + * + */ + }, { + key: "sendOptions", + value: function sendOptions(target, body, options) { + logger.debug('sendOptions()'); + var message = new Options(this); + message.send(target, body, options); + return message; + } + + /** + * Terminate ongoing sessions. + */ + }, { + key: "terminateSessions", + value: function terminateSessions(options) { + logger.debug('terminateSessions()'); + for (var idx in this._sessions) { + if (!this._sessions[idx].isEnded()) { + this._sessions[idx].terminate(options); + } + } + } + + /** + * Gracefully close. + * + */ + }, { + key: "stop", + value: function stop() { + var _this2 = this; + logger.debug('stop()'); + + // Remove dynamic settings. + this._dynConfiguration = {}; + if (this._status === C.STATUS_USER_CLOSED) { + logger.debug('UA already closed'); + return; + } + + // Close registrator. + this._registrator.close(); + + // If there are session wait a bit so CANCEL/BYE can be sent and their responses received. + var num_sessions = Object.keys(this._sessions).length; + + // Run _terminate_ on every Session. + for (var session in this._sessions) { + if (Object.prototype.hasOwnProperty.call(this._sessions, session)) { + logger.debug("closing session ".concat(session)); + try { + this._sessions[session].terminate(); + } catch (error) {} + } + } + + // Run _close_ on every applicant. + for (var applicant in this._applicants) { + if (Object.prototype.hasOwnProperty.call(this._applicants, applicant)) try { + this._applicants[applicant].close(); + } catch (error) {} + } + this._status = C.STATUS_USER_CLOSED; + var num_transactions = Object.keys(this._transactions.nict).length + Object.keys(this._transactions.nist).length + Object.keys(this._transactions.ict).length + Object.keys(this._transactions.ist).length; + if (num_transactions === 0 && num_sessions === 0) { + this._transport.disconnect(); + } else { + this._closeTimer = setTimeout(function () { + _this2._closeTimer = null; + _this2._transport.disconnect(); + }, 2000); + } + } + + /** + * Normalice a string into a valid SIP request URI + * -param {String} target + * -returns {JsSIP.URI|undefined} + */ + }, { + key: "normalizeTarget", + value: function normalizeTarget(target) { + return Utils.normalizeTarget(target, this._configuration.hostport_params); + } + + /** + * Allow retrieving configuration and autogenerated fields in runtime. + */ + }, { + key: "get", + value: function get(parameter) { + switch (parameter) { + case 'authorization_user': + return this._configuration.authorization_user; + case 'realm': + return this._configuration.realm; + case 'ha1': + return this._configuration.ha1; + case 'authorization_jwt': + return this._configuration.authorization_jwt; + default: + logger.warn('get() | cannot get "%s" parameter in runtime', parameter); + return undefined; + } + } + + /** + * Allow configuration changes in runtime. + * Returns true if the parameter could be set. + */ + }, { + key: "set", + value: function set(parameter, value) { + switch (parameter) { + case 'authorization_user': + { + this._configuration.authorization_user = String(value); + break; + } + case 'password': + { + this._configuration.password = String(value); + break; + } + case 'realm': + { + this._configuration.realm = String(value); + break; + } + case 'ha1': + { + this._configuration.ha1 = String(value); + // Delete the plain SIP password. + this._configuration.password = null; + break; + } + case 'authorization_jwt': + { + this._configuration.authorization_jwt = String(value); + break; + } + case 'display_name': + { + this._configuration.display_name = value; + break; + } + default: + logger.warn('set() | cannot set "%s" parameter in runtime', parameter); + return false; + } + return true; + } + + /* Igor's extension */ + }, { + key: "registerRedirect", + value: function registerRedirect(uri) { + if (!this._transport._register_redirect(uri)) { + logger.debug("registerRedirect: ignored, \"".concat(uri, "\" is not found in configuration")); + return false; + } + return true; + } + + /* Igor's extension */ + }, { + key: "switchSBC", + value: function switchSBC(unregister) { + if (this._transport._get_number_of_sbc() < 2) { + logger.debug('switchSBC: ignored, no other SBC'); + return false; + } + if (unregister) { + this._registrator._unregistered(null, JsSIP_C.causes.CONNECTION_ERROR); + } + this._transport._switch_sbc(); + return true; + } + + /* Igor's extension */ + }, { + key: "getNumberOfSBC", + value: function getNumberOfSBC() { + return this._transport._get_number_of_sbc(); + } + + // ========================== + // Event Handlers. + // ========================== + + /** + * new Transaction + */ + }, { + key: "newTransaction", + value: function newTransaction(transaction) { + this._transactions[transaction.type][transaction.id] = transaction; + this.emit('newTransaction', { + transaction: transaction + }); + } + + /** + * Transaction destroyed. + */ + }, { + key: "destroyTransaction", + value: function destroyTransaction(transaction) { + delete this._transactions[transaction.type][transaction.id]; + this.emit('transactionDestroyed', { + transaction: transaction + }); + } + + /** + * new Dialog + */ + }, { + key: "newDialog", + value: function newDialog(dialog) { + this._dialogs[dialog.id] = dialog; + } + + /** + * Dialog destroyed. + */ + }, { + key: "destroyDialog", + value: function destroyDialog(dialog) { + delete this._dialogs[dialog.id]; + } + + /** + * new Message + */ + }, { + key: "newMessage", + value: function newMessage(message, data) { + this._applicants[message] = message; + this.emit('newMessage', data); + } + + /** + * new Options + */ + }, { + key: "newOptions", + value: function newOptions(message, data) { + this._applicants[message] = message; + this.emit('newOptions', data); + } + + /** + * Message destroyed. + */ + }, { + key: "destroyMessage", + value: function destroyMessage(message) { + delete this._applicants[message]; + } + + /** + * new RTCSession + */ + }, { + key: "newRTCSession", + value: function newRTCSession(session, data) { + this._sessions[session.id] = session; + this.emit('newRTCSession', data); + } + + /** + * RTCSession destroyed. + */ + }, { + key: "destroyRTCSession", + value: function destroyRTCSession(session) { + delete this._sessions[session.id]; + } + + /** + * Registered + */ + }, { + key: "registered", + value: function registered(data) { + this.emit('registered', data); + } + + /** + * Unregistered + */ + }, { + key: "unregistered", + value: function unregistered(data) { + this.emit('unregistered', data); + } + + /** + * Registration Failed + */ + }, { + key: "registrationFailed", + value: function registrationFailed(data) { + this.emit('registrationFailed', data); + } + + // ========================= + // ReceiveRequest. + // ========================= + + /** + * Request reception + */ + }, { + key: "receiveRequest", + value: function receiveRequest(request) { + var method = request.method; + + // Check that request URI points to us. + if (request.ruri.user !== this._configuration.uri.user && request.ruri.user !== this._contact.uri.user) { + logger.debug('Request-URI does not point to us'); + if (request.method !== JsSIP_C.ACK) { + request.reply_sl(404); + } + return; + } + + // Check request URI scheme. + if (request.ruri.scheme === JsSIP_C.SIPS) { + request.reply_sl(416); + return; + } + + // Check transaction. + if (Transactions.checkTransaction(this, request)) { + return; + } + + // Create the server transaction. + if (method === JsSIP_C.INVITE) { + /* eslint-disable no-new */ + new Transactions.InviteServerTransaction(this, this._transport, request); + /* eslint-enable no-new */ + } else if (method !== JsSIP_C.ACK && method !== JsSIP_C.CANCEL) { + /* eslint-disable no-new */ + new Transactions.NonInviteServerTransaction(this, this._transport, request); + /* eslint-enable no-new */ + } + + /* RFC3261 12.2.2 + * Requests that do not change in any way the state of a dialog may be + * received within a dialog (for example, an OPTIONS request). + * They are processed as if they had been received outside the dialog. + */ + if (method === JsSIP_C.OPTIONS) { + if (this.listeners('newOptions').length === 0) { + request.reply(200); + return; + } + var message = new Options(this); + message.init_incoming(request); + } else if (method === JsSIP_C.MESSAGE) { + if (this.listeners('newMessage').length === 0) { + request.reply(405); + return; + } + var _message = new Message(this); + _message.init_incoming(request); + } else if (method === JsSIP_C.SUBSCRIBE) { + if (this.listeners('newSubscribe').length === 0) { + request.reply(405); + return; + } + } else if (method === JsSIP_C.INVITE) { + // Initial INVITE. + if (!request.to_tag && this.listeners('newRTCSession').length === 0) { + request.reply(405); + return; + } + } + var dialog; + var session; + + // Initial Request. + if (!request.to_tag) { + switch (method) { + case JsSIP_C.INVITE: + if (window.RTCPeerConnection) { + // TODO + if (request.hasHeader('replaces')) { + var replaces = request.replaces; + dialog = this._findDialog(replaces.call_id, replaces.from_tag, replaces.to_tag); + if (dialog) { + session = dialog.owner; + if (!session.isEnded()) { + session.receiveRequest(request); + } else { + request.reply(603); + } + } else { + request.reply(481); + } + } else { + session = new RTCSession(this); + session.init_incoming(request); + } + } else { + logger.warn('INVITE received but WebRTC is not supported'); + request.reply(488); + } + break; + case JsSIP_C.BYE: + // Out of dialog BYE received. + request.reply(481); + break; + case JsSIP_C.CANCEL: + session = this._findSession(request); + if (session) { + session.receiveRequest(request); + } else { + logger.debug('received CANCEL request for a non existent session'); + } + break; + case JsSIP_C.ACK: + /* Absorb it. + * ACK request without a corresponding Invite Transaction + * and without To tag. + */ + break; + case JsSIP_C.NOTIFY: + // Receive new sip event. + this.emit('sipEvent', { + event: request.event, + request: request + }); + request.reply(200); + break; + case JsSIP_C.SUBSCRIBE: + this.emit('newSubscribe', { + event: request.event, + request: request + }); + break; + default: + request.reply(405); + break; + } + } + // In-dialog request. + else { + dialog = this._findDialog(request.call_id, request.from_tag, request.to_tag); + if (dialog) { + dialog.receiveRequest(request); + } else if (method === JsSIP_C.NOTIFY) { + session = this._findSession(request); + if (session) { + session.receiveRequest(request); + } else { + logger.debug('received NOTIFY request for a non existent subscription'); + request.reply(481, 'Subscription does not exist'); + } + } + + /* RFC3261 12.2.2 + * Request with to tag, but no matching dialog found. + * Exception: ACK for an Invite request for which a dialog has not + * been created. + */else if (method !== JsSIP_C.ACK) { + request.reply(481); + } + } + } + + // ================= + // Utils. + // ================= + + /** + * Get the session to which the request belongs to, if any. + */ + }, { + key: "_findSession", + value: function _findSession(_ref) { + var call_id = _ref.call_id, + from_tag = _ref.from_tag, + to_tag = _ref.to_tag; + var sessionIDa = call_id + from_tag; + var sessionA = this._sessions[sessionIDa]; + var sessionIDb = call_id + to_tag; + var sessionB = this._sessions[sessionIDb]; + if (sessionA) { + return sessionA; + } else if (sessionB) { + return sessionB; + } else { + return null; + } + } + + /** + * Get the dialog to which the request belongs to, if any. + */ + }, { + key: "_findDialog", + value: function _findDialog(call_id, from_tag, to_tag) { + var id = call_id + from_tag + to_tag; + var dialog = this._dialogs[id]; + if (dialog) { + return dialog; + } else { + id = call_id + to_tag + from_tag; + dialog = this._dialogs[id]; + if (dialog) { + return dialog; + } else { + return null; + } + } + } + }, { + key: "_loadConfig", + value: function _loadConfig(configuration) { + // Check and load the given configuration. + try { + config.load(this._configuration, configuration); + } catch (e) { + throw e; + } + + // Post Configuration Process. + + // Allow passing 0 number as display_name. + if (this._configuration.display_name === 0) { + this._configuration.display_name = '0'; + } + + // Instance-id for GRUU. + if (!this._configuration.instance_id) { + this._configuration.instance_id = Utils.newUUID(); + } + + // Jssip_id instance parameter. Static random tag of length 5. + this._configuration.jssip_id = Utils.createRandomToken(5); + + // String containing this._configuration.uri without scheme and user. + var hostport_params = this._configuration.uri.clone(); + hostport_params.user = null; + this._configuration.hostport_params = hostport_params.toString().replace(/^sip:/i, ''); + + // Transport. + try { + // Igor's modification: added UA to transport + this._transport = new Transport(this, this._configuration.sockets, { + // Recovery options. + max_interval: this._configuration.connection_recovery_max_interval, + min_interval: this._configuration.connection_recovery_min_interval + }); + + // Transport event callbacks. + this._transport.onconnecting = onTransportConnecting.bind(this); + this._transport.onconnect = onTransportConnect.bind(this); + this._transport.ondisconnect = onTransportDisconnect.bind(this); + this._transport.ondata = onTransportData.bind(this); + } catch (e) { + logger.warn(e); + throw new Exceptions.ConfigurationError('sockets', this._configuration.sockets); + } + + // Remove sockets instance from configuration object. + delete this._configuration.sockets; + + // Check whether authorization_user is explicitly defined. + // Take 'this._configuration.uri.user' value if not. + if (!this._configuration.authorization_user) { + this._configuration.authorization_user = this._configuration.uri.user; + } + + // If no 'registrar_server' is set use the 'uri' value without user portion and + // without URI params/headers. + if (!this._configuration.registrar_server) { + var registrar_server = this._configuration.uri.clone(); + registrar_server.user = null; + registrar_server.clearParams(); + registrar_server.clearHeaders(); + this._configuration.registrar_server = registrar_server; + } + + // User no_answer_timeout. + this._configuration.no_answer_timeout *= 1000; + + // Via Host. + if (this._configuration.contact_uri) { + this._configuration.via_host = this._configuration.contact_uri.host; + } + + // Contact URI. + else { + this._configuration.contact_uri = new URI('sip', Utils.createRandomToken(8), this._configuration.via_host, null, { + transport: 'ws' + }); + } + this._contact = { + pub_gruu: null, + temp_gruu: null, + uri: this._configuration.contact_uri, + toString: function toString() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var anonymous = options.anonymous || null; + var outbound = options.outbound || null; + var contact = '<'; + if (anonymous) { + contact += this.temp_gruu || 'sip:anonymous@anonymous.invalid;transport=ws'; + } else { + contact += this.pub_gruu || this.uri.toString(); + } + if (outbound && (anonymous ? !this.temp_gruu : !this.pub_gruu)) { + contact += ';ob'; + } + contact += '>'; + return contact; + } + }; + + // Seal the configuration. + var writable_parameters = ['authorization_user', 'password', 'realm', 'ha1', 'authorization_jwt', 'display_name', 'register']; + for (var parameter in this._configuration) { + if (Object.prototype.hasOwnProperty.call(this._configuration, parameter)) { + if (writable_parameters.indexOf(parameter) !== -1) { + Object.defineProperty(this._configuration, parameter, { + writable: true, + configurable: false + }); + } else { + Object.defineProperty(this._configuration, parameter, { + writable: false, + configurable: false + }); + } + } + } + logger.debug('configuration parameters after validation:'); + for (var _parameter in this._configuration) { + // Only show the user user configurable parameters. + if (Object.prototype.hasOwnProperty.call(config.settings, _parameter)) { + switch (_parameter) { + case 'uri': + case 'registrar_server': + logger.debug("- ".concat(_parameter, ": ").concat(this._configuration[_parameter])); + break; + case 'password': + case 'ha1': + case 'authorization_jwt': + logger.debug("- ".concat(_parameter, ": NOT SHOWN")); + break; + default: + logger.debug("- ".concat(_parameter, ": ").concat(JSON.stringify(this._configuration[_parameter]))); + } + } + } + return; + } + }], [{ + key: "C", + get: + // Expose C object. + function get() { + return C; + } + }]); + return UA; +}(EventEmitter); + +/** + * Transport event handlers + */ + +// Transport connecting event. +function onTransportConnecting(data) { + this.emit('connecting', data); +} + +// Transport connected event. +function onTransportConnect(data) { + if (this._status === C.STATUS_USER_CLOSED) { + return; + } + this._status = C.STATUS_READY; + this._error = null; + this.emit('connected', data); + if (this._dynConfiguration.register) { + this._registrator.register(); + } +} + +// Transport disconnected event. +function onTransportDisconnect(data) { + // Run _onTransportError_ callback on every client transaction using _transport_. + var client_transactions = ['nict', 'ict', 'nist', 'ist']; + for (var _i = 0, _client_transactions = client_transactions; _i < _client_transactions.length; _i++) { + var type = _client_transactions[_i]; + for (var id in this._transactions[type]) { + if (Object.prototype.hasOwnProperty.call(this._transactions[type], id)) { + this._transactions[type][id].onTransportError(); + } + } + } + this.emit('disconnected', data); + + // Call registrator _onTransportClosed_. + this._registrator.onTransportClosed(); + if (this._status !== C.STATUS_USER_CLOSED) { + this._status = C.STATUS_NOT_READY; + this._error = C.NETWORK_ERROR; + } +} + +// Transport data event. +function onTransportData(data) { + var transport = data.transport; + var message = data.message; + message = Parser.parseMessage(message, this); + if (!message) { + return; + } + if (this._status === C.STATUS_USER_CLOSED && message instanceof SIPMessage.IncomingRequest) { + return; + } + + // Do some sanity check. + if (!sanityCheck(message, this, transport)) { + return; + } + if (message instanceof SIPMessage.IncomingRequest) { + message.transport = transport; + this.receiveRequest(message); + } else if (message instanceof SIPMessage.IncomingResponse) { + /* Unike stated in 18.1.2, if a response does not match + * any transaction, it is discarded here and no passed to the core + * in order to be discarded there. + */ + + var transaction; + switch (message.method) { + case JsSIP_C.INVITE: + transaction = this._transactions.ict[message.via_branch]; + if (transaction) { + transaction.receiveResponse(message); + } + break; + case JsSIP_C.ACK: + // Just in case ;-). + break; + default: + transaction = this._transactions.nict[message.via_branch]; + if (transaction) { + transaction.receiveResponse(message); + } + break; + } + } +} +},{"./Config":1,"./Constants":2,"./Exceptions":6,"./Logger":9,"./Message":10,"./Notifier":12,"./Options":13,"./Parser":14,"./RTCSession":15,"./Registrator":20,"./SIPMessage":22,"./Subscriber":24,"./Transactions":26,"./Transport":27,"./URI":29,"./Utils":30,"./sanityCheck":32,"events":33}],29:[function(require,module,exports){ +"use strict"; + +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var JsSIP_C = require('./Constants'); +var Utils = require('./Utils'); +var Grammar = require('./Grammar'); + +/** + * -param {String} [scheme] + * -param {String} [user] + * -param {String} host + * -param {String} [port] + * -param {Object} [parameters] + * -param {Object} [headers] + * + */ +module.exports = /*#__PURE__*/function () { + function URI(scheme, user, host, port) { + var parameters = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + var headers = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {}; + _classCallCheck(this, URI); + // Checks. + if (!host) { + throw new TypeError('missing or invalid "host" parameter'); + } + + // Initialize parameters. + this._parameters = {}; + this._headers = {}; + this._scheme = scheme || JsSIP_C.SIP; + this._user = user; + this._host = host; + this._port = port; + for (var param in parameters) { + if (Object.prototype.hasOwnProperty.call(parameters, param)) { + this.setParam(param, parameters[param]); + } + } + for (var header in headers) { + if (Object.prototype.hasOwnProperty.call(headers, header)) { + this.setHeader(header, headers[header]); + } + } + } + _createClass(URI, [{ + key: "scheme", + get: function get() { + return this._scheme; + }, + set: function set(value) { + this._scheme = value.toLowerCase(); + } + }, { + key: "user", + get: function get() { + return this._user; + }, + set: function set(value) { + this._user = value; + } + }, { + key: "host", + get: function get() { + return this._host; + }, + set: function set(value) { + this._host = value.toLowerCase(); + } + }, { + key: "port", + get: function get() { + return this._port; + }, + set: function set(value) { + this._port = value === 0 ? value : parseInt(value, 10) || null; + } + }, { + key: "setParam", + value: function setParam(key, value) { + if (key) { + this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString(); + } + } + }, { + key: "getParam", + value: function getParam(key) { + if (key) { + return this._parameters[key.toLowerCase()]; + } + } + }, { + key: "hasParam", + value: function hasParam(key) { + if (key) { + return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false; + } + } + }, { + key: "deleteParam", + value: function deleteParam(parameter) { + parameter = parameter.toLowerCase(); + if (this._parameters.hasOwnProperty(parameter)) { + var value = this._parameters[parameter]; + delete this._parameters[parameter]; + return value; + } + } + }, { + key: "clearParams", + value: function clearParams() { + this._parameters = {}; + } + }, { + key: "setHeader", + value: function setHeader(name, value) { + this._headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value]; + } + }, { + key: "getHeader", + value: function getHeader(name) { + if (name) { + return this._headers[Utils.headerize(name)]; + } + } + }, { + key: "hasHeader", + value: function hasHeader(name) { + if (name) { + return this._headers.hasOwnProperty(Utils.headerize(name)) && true || false; + } + } + }, { + key: "deleteHeader", + value: function deleteHeader(header) { + header = Utils.headerize(header); + if (this._headers.hasOwnProperty(header)) { + var value = this._headers[header]; + delete this._headers[header]; + return value; + } + } + }, { + key: "clearHeaders", + value: function clearHeaders() { + this._headers = {}; + } + }, { + key: "clone", + value: function clone() { + return new URI(this._scheme, this._user, this._host, this._port, JSON.parse(JSON.stringify(this._parameters)), JSON.parse(JSON.stringify(this._headers))); + } + }, { + key: "toString", + value: function toString() { + var headers = []; + var uri = "".concat(this._scheme, ":"); + if (this._user) { + uri += "".concat(Utils.escapeUser(this._user), "@"); + } + uri += this._host; + if (this._port || this._port === 0) { + uri += ":".concat(this._port); + } + for (var parameter in this._parameters) { + if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) { + uri += ";".concat(parameter); + if (this._parameters[parameter] !== null) { + uri += "=".concat(this._parameters[parameter]); + } + } + } + for (var header in this._headers) { + if (Object.prototype.hasOwnProperty.call(this._headers, header)) { + var _iterator = _createForOfIteratorHelper(this._headers[header]), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var item = _step.value; + headers.push("".concat(header, "=").concat(item)); + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } + } + if (headers.length > 0) { + uri += "?".concat(headers.join('&')); + } + return uri; + } + }, { + key: "toAor", + value: function toAor(show_port) { + var aor = "".concat(this._scheme, ":"); + if (this._user) { + aor += "".concat(Utils.escapeUser(this._user), "@"); + } + aor += this._host; + if (show_port && (this._port || this._port === 0)) { + aor += ":".concat(this._port); + } + return aor; + } + }], [{ + key: "parse", + value: + /** + * Parse the given string and returns a JsSIP.URI instance or undefined if + * it is an invalid URI. + */ + function parse(uri) { + uri = Grammar.parse(uri, 'SIP_URI'); + if (uri !== -1) { + return uri; + } else { + return undefined; + } + } + }]); + return URI; +}(); +},{"./Constants":2,"./Grammar":7,"./Utils":30}],30:[function(require,module,exports){ +"use strict"; + +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +var JsSIP_C = require('./Constants'); +var URI = require('./URI'); +var Grammar = require('./Grammar'); +exports.str_utf8_length = function (string) { + return unescape(encodeURIComponent(string)).length; +}; + +// Used by 'hasMethods'. +var isFunction = exports.isFunction = function (fn) { + if (fn !== undefined) { + return Object.prototype.toString.call(fn) === '[object Function]' ? true : false; + } else { + return false; + } +}; +exports.isString = function (str) { + if (str !== undefined) { + return Object.prototype.toString.call(str) === '[object String]' ? true : false; + } else { + return false; + } +}; +exports.isDecimal = function (num) { + return !isNaN(num) && parseFloat(num) === parseInt(num, 10); +}; +exports.isEmpty = function (value) { + return value === null || value === '' || value === undefined || Array.isArray(value) && value.length === 0 || typeof value === 'number' && isNaN(value); +}; +exports.hasMethods = function (obj) { + for (var _len = arguments.length, methodNames = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + methodNames[_key - 1] = arguments[_key]; + } + for (var _i = 0, _methodNames = methodNames; _i < _methodNames.length; _i++) { + var methodName = _methodNames[_i]; + if (isFunction(obj[methodName])) { + return false; + } + } + return true; +}; + +// Used by 'newTag'. +var createRandomToken = exports.createRandomToken = function (size) { + var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 32; + var i, + r, + token = ''; + for (i = 0; i < size; i++) { + r = Math.random() * base | 0; + token += r.toString(base); + } + return token; +}; +exports.newTag = function () { + return createRandomToken(10); +}; + +// https://stackoverflow.com/users/109538/broofa. +exports.newUUID = function () { + var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = Math.random() * 16 | 0, + v = c === 'x' ? r : r & 0x3 | 0x8; + return v.toString(16); + }); + return UUID; +}; +exports.hostType = function (host) { + if (!host) { + return; + } else { + host = Grammar.parse(host, 'host'); + if (host !== -1) { + return host.host_type; + } + } +}; + +/** +* Hex-escape a SIP URI user. +* Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F). +* +* Used by 'normalizeTarget'. +*/ +var escapeUser = exports.escapeUser = function (user) { + return encodeURIComponent(decodeURIComponent(user)).replace(/%3A/ig, ':').replace(/%2B/ig, '+').replace(/%3F/ig, '?').replace(/%2F/ig, '/'); +}; + +/** +* Normalize SIP URI. +* NOTE: It does not allow a SIP URI without username. +* Accepts 'sip', 'sips' and 'tel' URIs and convert them into 'sip'. +* Detects the domain part (if given) and properly hex-escapes the user portion. +* If the user portion has only 'tel' number symbols the user portion is clean of 'tel' visual separators. +*/ +exports.normalizeTarget = function (target, domain) { + // If no target is given then raise an error. + if (!target) { + return; + // If a URI instance is given then return it. + } else if (target instanceof URI) { + return target; + + // If a string is given split it by '@': + // - Last fragment is the desired domain. + // - Otherwise append the given domain argument. + } else if (typeof target === 'string') { + var target_array = target.split('@'); + var target_user; + var target_domain; + switch (target_array.length) { + case 1: + if (!domain) { + return; + } + target_user = target; + target_domain = domain; + break; + case 2: + target_user = target_array[0]; + target_domain = target_array[1]; + break; + default: + target_user = target_array.slice(0, target_array.length - 1).join('@'); + target_domain = target_array[target_array.length - 1]; + } + + // Remove the URI scheme (if present). + target_user = target_user.replace(/^(sips?|tel):/i, ''); + + // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols. + if (/^[-.()]*\+?[0-9\-.()]+$/.test(target_user)) { + target_user = target_user.replace(/[-.()]/g, ''); + } + + // Build the complete SIP URI. + target = "".concat(JsSIP_C.SIP, ":").concat(escapeUser(target_user), "@").concat(target_domain); + + // Finally parse the resulting URI. + var uri; + if (uri = URI.parse(target)) { + return uri; + } else { + return; + } + } else { + return; + } +}; +exports.headerize = function (string) { + var exceptions = { + 'Call-Id': 'Call-ID', + 'Cseq': 'CSeq', + 'Www-Authenticate': 'WWW-Authenticate' + }; + var name = string.toLowerCase().replace(/_/g, '-').split('-'); + var hname = ''; + var parts = name.length; + var part; + for (part = 0; part < parts; part++) { + if (part !== 0) { + hname += '-'; + } + hname += name[part].charAt(0).toUpperCase() + name[part].substring(1); + } + if (exceptions[hname]) { + hname = exceptions[hname]; + } + return hname; +}; +exports.sipErrorCause = function (status_code) { + for (var cause in JsSIP_C.SIP_ERROR_CAUSES) { + if (JsSIP_C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) { + return JsSIP_C.causes[cause]; + } + } + return JsSIP_C.causes.SIP_FAILURE_CODE; +}; + +/** +* Generate a random Test-Net IP (https://tools.ietf.org/html/rfc5735) +*/ +exports.getRandomTestNetIP = function () { + function getOctet(from, to) { + return Math.floor(Math.random() * (to - from + 1) + from); + } + return "192.0.2.".concat(getOctet(1, 254)); +}; + +// MD5 (Message-Digest Algorithm) https://www.webtoolkit.info. +exports.calculateMD5 = function (string) { + function rotateLeft(lValue, iShiftBits) { + return lValue << iShiftBits | lValue >>> 32 - iShiftBits; + } + function addUnsigned(lX, lY) { + var lX8 = lX & 0x80000000; + var lY8 = lY & 0x80000000; + var lX4 = lX & 0x40000000; + var lY4 = lY & 0x40000000; + var lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); + if (lX4 & lY4) { + return lResult ^ 0x80000000 ^ lX8 ^ lY8; + } + if (lX4 | lY4) { + if (lResult & 0x40000000) { + return lResult ^ 0xC0000000 ^ lX8 ^ lY8; + } else { + return lResult ^ 0x40000000 ^ lX8 ^ lY8; + } + } else { + return lResult ^ lX8 ^ lY8; + } + } + function doF(x, y, z) { + return x & y | ~x & z; + } + function doG(x, y, z) { + return x & z | y & ~z; + } + function doH(x, y, z) { + return x ^ y ^ z; + } + function doI(x, y, z) { + return y ^ (x | ~z); + } + function doFF(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(doF(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + function doGG(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(doG(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + function doHH(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(doH(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + function doII(a, b, c, d, x, s, ac) { + a = addUnsigned(a, addUnsigned(addUnsigned(doI(b, c, d), x), ac)); + return addUnsigned(rotateLeft(a, s), b); + } + function convertToWordArray(str) { + var lWordCount; + var lMessageLength = str.length; + var lNumberOfWords_temp1 = lMessageLength + 8; + var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - lNumberOfWords_temp1 % 64) / 64; + var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; + var lWordArray = new Array(lNumberOfWords - 1); + var lBytePosition = 0; + var lByteCount = 0; + while (lByteCount < lMessageLength) { + lWordCount = (lByteCount - lByteCount % 4) / 4; + lBytePosition = lByteCount % 4 * 8; + lWordArray[lWordCount] = lWordArray[lWordCount] | str.charCodeAt(lByteCount) << lBytePosition; + lByteCount++; + } + lWordCount = (lByteCount - lByteCount % 4) / 4; + lBytePosition = lByteCount % 4 * 8; + lWordArray[lWordCount] = lWordArray[lWordCount] | 0x80 << lBytePosition; + lWordArray[lNumberOfWords - 2] = lMessageLength << 3; + lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; + return lWordArray; + } + function wordToHex(lValue) { + var wordToHexValue = '', + wordToHexValue_temp = '', + lByte, + lCount; + for (lCount = 0; lCount <= 3; lCount++) { + lByte = lValue >>> lCount * 8 & 255; + wordToHexValue_temp = "0".concat(lByte.toString(16)); + wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2); + } + return wordToHexValue; + } + function utf8Encode(str) { + // Igor's fix to correctly calculate auth-int + // str = str.replace(/\r\n/g, '\n'); + var utftext = ''; + for (var n = 0; n < str.length; n++) { + var _c = str.charCodeAt(n); + if (_c < 128) { + utftext += String.fromCharCode(_c); + } else if (_c > 127 && _c < 2048) { + utftext += String.fromCharCode(_c >> 6 | 192); + utftext += String.fromCharCode(_c & 63 | 128); + } else { + utftext += String.fromCharCode(_c >> 12 | 224); + utftext += String.fromCharCode(_c >> 6 & 63 | 128); + utftext += String.fromCharCode(_c & 63 | 128); + } + } + return utftext; + } + var x = []; + var k, AA, BB, CC, DD, a, b, c, d; + var S11 = 7, + S12 = 12, + S13 = 17, + S14 = 22; + var S21 = 5, + S22 = 9, + S23 = 14, + S24 = 20; + var S31 = 4, + S32 = 11, + S33 = 16, + S34 = 23; + var S41 = 6, + S42 = 10, + S43 = 15, + S44 = 21; + string = utf8Encode(string); + x = convertToWordArray(string); + a = 0x67452301; + b = 0xEFCDAB89; + c = 0x98BADCFE; + d = 0x10325476; + for (k = 0; k < x.length; k += 16) { + AA = a; + BB = b; + CC = c; + DD = d; + a = doFF(a, b, c, d, x[k + 0], S11, 0xD76AA478); + d = doFF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); + c = doFF(c, d, a, b, x[k + 2], S13, 0x242070DB); + b = doFF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); + a = doFF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); + d = doFF(d, a, b, c, x[k + 5], S12, 0x4787C62A); + c = doFF(c, d, a, b, x[k + 6], S13, 0xA8304613); + b = doFF(b, c, d, a, x[k + 7], S14, 0xFD469501); + a = doFF(a, b, c, d, x[k + 8], S11, 0x698098D8); + d = doFF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); + c = doFF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); + b = doFF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); + a = doFF(a, b, c, d, x[k + 12], S11, 0x6B901122); + d = doFF(d, a, b, c, x[k + 13], S12, 0xFD987193); + c = doFF(c, d, a, b, x[k + 14], S13, 0xA679438E); + b = doFF(b, c, d, a, x[k + 15], S14, 0x49B40821); + a = doGG(a, b, c, d, x[k + 1], S21, 0xF61E2562); + d = doGG(d, a, b, c, x[k + 6], S22, 0xC040B340); + c = doGG(c, d, a, b, x[k + 11], S23, 0x265E5A51); + b = doGG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); + a = doGG(a, b, c, d, x[k + 5], S21, 0xD62F105D); + d = doGG(d, a, b, c, x[k + 10], S22, 0x2441453); + c = doGG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); + b = doGG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); + a = doGG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); + d = doGG(d, a, b, c, x[k + 14], S22, 0xC33707D6); + c = doGG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); + b = doGG(b, c, d, a, x[k + 8], S24, 0x455A14ED); + a = doGG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); + d = doGG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); + c = doGG(c, d, a, b, x[k + 7], S23, 0x676F02D9); + b = doGG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); + a = doHH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); + d = doHH(d, a, b, c, x[k + 8], S32, 0x8771F681); + c = doHH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); + b = doHH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); + a = doHH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); + d = doHH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); + c = doHH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); + b = doHH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); + a = doHH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); + d = doHH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); + c = doHH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); + b = doHH(b, c, d, a, x[k + 6], S34, 0x4881D05); + a = doHH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); + d = doHH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); + c = doHH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); + b = doHH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); + a = doII(a, b, c, d, x[k + 0], S41, 0xF4292244); + d = doII(d, a, b, c, x[k + 7], S42, 0x432AFF97); + c = doII(c, d, a, b, x[k + 14], S43, 0xAB9423A7); + b = doII(b, c, d, a, x[k + 5], S44, 0xFC93A039); + a = doII(a, b, c, d, x[k + 12], S41, 0x655B59C3); + d = doII(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); + c = doII(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); + b = doII(b, c, d, a, x[k + 1], S44, 0x85845DD1); + a = doII(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); + d = doII(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); + c = doII(c, d, a, b, x[k + 6], S43, 0xA3014314); + b = doII(b, c, d, a, x[k + 13], S44, 0x4E0811A1); + a = doII(a, b, c, d, x[k + 4], S41, 0xF7537E82); + d = doII(d, a, b, c, x[k + 11], S42, 0xBD3AF235); + c = doII(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); + b = doII(b, c, d, a, x[k + 9], S44, 0xEB86D391); + a = addUnsigned(a, AA); + b = addUnsigned(b, BB); + c = addUnsigned(c, CC); + d = addUnsigned(d, DD); + } + var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); + return temp.toLowerCase(); +}; +exports.closeMediaStream = function (stream) { + if (!stream) { + return; + } + + // Latest spec states that MediaStream has no stop() method and instead must + // call stop() on every MediaStreamTrack. + try { + var tracks; + if (stream.getTracks) { + tracks = stream.getTracks(); + var _iterator = _createForOfIteratorHelper(tracks), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var track = _step.value; + track.stop(); + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + } else { + tracks = stream.getAudioTracks(); + var _iterator2 = _createForOfIteratorHelper(tracks), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var _track = _step2.value; + _track.stop(); + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + tracks = stream.getVideoTracks(); + var _iterator3 = _createForOfIteratorHelper(tracks), + _step3; + try { + for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { + var _track2 = _step3.value; + _track2.stop(); + } + } catch (err) { + _iterator3.e(err); + } finally { + _iterator3.f(); + } + } + } catch (error) { + // Deprecated by the spec, but still in use. + // NOTE: In Temasys IE plugin stream.stop is a callable 'object'. + if (typeof stream.stop === 'function' || _typeof(stream.stop) === 'object') { + stream.stop(); + } + } +}; +exports.cloneArray = function (array) { + return array && array.slice() || []; +}; +exports.cloneObject = function (obj) { + var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + return obj && Object.assign({}, obj) || fallback; +}; +},{"./Constants":2,"./Grammar":7,"./URI":29}],31:[function(require,module,exports){ +"use strict"; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +var Logger = require('./Logger'); +var Grammar = require('./Grammar'); +var logger = new Logger('WebSocketInterface'); +module.exports = /*#__PURE__*/function () { + function WebSocketInterface(url) { + _classCallCheck(this, WebSocketInterface); + logger.debug('new() [url:"%s"]', url); + this._url = url; + this._sip_uri = null; + this._via_transport = null; + this._ws = null; + var parsed_url = Grammar.parse(url, 'absoluteURI'); + if (parsed_url === -1) { + logger.warn("invalid WebSocket URI: ".concat(url)); + throw new TypeError("Invalid argument: ".concat(url)); + } else if (parsed_url.scheme !== 'wss' && parsed_url.scheme !== 'ws') { + logger.warn("invalid WebSocket URI scheme: ".concat(parsed_url.scheme)); + throw new TypeError("Invalid argument: ".concat(url)); + } else { + this._sip_uri = "sip:".concat(parsed_url.host).concat(parsed_url.port ? ":".concat(parsed_url.port) : '', ";transport=ws"); + this._via_transport = parsed_url.scheme.toUpperCase(); + } + } + _createClass(WebSocketInterface, [{ + key: "via_transport", + get: function get() { + return this._via_transport; + }, + set: function set(value) { + this._via_transport = value.toUpperCase(); + } + }, { + key: "sip_uri", + get: function get() { + return this._sip_uri; + } + }, { + key: "url", + get: function get() { + return this._url; + } + }, { + key: "connect", + value: function connect() { + logger.debug('connect()'); + if (this.isConnected()) { + logger.debug("WebSocket ".concat(this._url, " is already connected")); + return; + } else if (this.isConnecting()) { + logger.debug("WebSocket ".concat(this._url, " is connecting")); + return; + } + if (this._ws) { + this.disconnect(); + } + logger.debug("connecting to WebSocket ".concat(this._url)); + try { + this._ws = new WebSocket(this._url, 'sip'); + this._ws.binaryType = 'arraybuffer'; + this._ws.onopen = this._onOpen.bind(this); + this._ws.onclose = this._onClose.bind(this); + this._ws.onmessage = this._onMessage.bind(this); + this._ws.onerror = this._onError.bind(this); + } catch (e) { + this._onError(e); + } + } + }, { + key: "disconnect", + value: function disconnect() { + logger.debug('disconnect()'); + if (this._ws) { + // Unbind websocket event callbacks. + this._ws.onopen = function () {}; + this._ws.onclose = function () {}; + this._ws.onmessage = function () {}; + this._ws.onerror = function () {}; + this._ws.close(); + this._ws = null; + } + } + }, { + key: "send", + value: function send(message) { + logger.debug('send()'); + if (this.isConnected()) { + this._ws.send(message); + return true; + } else { + logger.warn('unable to send message, WebSocket is not open'); + return false; + } + } + }, { + key: "isConnected", + value: function isConnected() { + return this._ws && this._ws.readyState === this._ws.OPEN; + } + }, { + key: "isConnecting", + value: function isConnecting() { + return this._ws && this._ws.readyState === this._ws.CONNECTING; + } + + /** + * WebSocket Event Handlers + */ + }, { + key: "_onOpen", + value: function _onOpen() { + logger.debug("WebSocket ".concat(this._url, " connected")); + this.onconnect(); + } + }, { + key: "_onClose", + value: function _onClose(_ref) { + var wasClean = _ref.wasClean, + code = _ref.code, + reason = _ref.reason; + logger.debug("WebSocket ".concat(this._url, " closed")); + if (wasClean === false) { + logger.debug('WebSocket abrupt disconnection'); + } + this.ondisconnect(!wasClean, code, reason); + } + }, { + key: "_onMessage", + value: function _onMessage(_ref2) { + var data = _ref2.data; + logger.debug('received WebSocket message'); + this.ondata(data); + } + }, { + key: "_onError", + value: function _onError(e) { + logger.warn("WebSocket ".concat(this._url, " error: "), e); + } + }]); + return WebSocketInterface; +}(); +},{"./Grammar":7,"./Logger":9}],32:[function(require,module,exports){ +"use strict"; + +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +var Logger = require('./Logger'); +var JsSIP_C = require('./Constants'); +var SIPMessage = require('./SIPMessage'); +var Utils = require('./Utils'); +var logger = new Logger('sanityCheck'); + +// Checks for requests and responses. +var all = [minimumHeaders]; + +// Checks for requests. +var requests = [rfc3261_8_2_2_1, rfc3261_16_3_4, rfc3261_18_3_request, rfc3261_8_2_2_2]; + +// Checks for responses. +var responses = [rfc3261_8_1_3_3, rfc3261_18_3_response]; + +// local variables. +var message; +var ua; +var transport; +module.exports = function (m, u, t) { + message = m; + ua = u; + transport = t; + var _iterator = _createForOfIteratorHelper(all), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var _check2 = _step.value; + if (_check2() === false) { + return false; + } + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + if (message instanceof SIPMessage.IncomingRequest) { + var _iterator2 = _createForOfIteratorHelper(requests), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var check = _step2.value; + if (check() === false) { + return false; + } + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + } else if (message instanceof SIPMessage.IncomingResponse) { + var _iterator3 = _createForOfIteratorHelper(responses), + _step3; + try { + for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { + var _check = _step3.value; + if (_check() === false) { + return false; + } + } + } catch (err) { + _iterator3.e(err); + } finally { + _iterator3.f(); + } + } + + // Everything is OK. + return true; +}; + +/* + * Sanity Check for incoming Messages + * + * Requests: + * - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme + * - _rfc3261_16_3_4_ Receive a Request already sent by us + * Does not look at via sent-by but at jssip_id, which is inserted as + * a prefix in all initial requests generated by the ua + * - _rfc3261_18_3_request_ Body Content-Length + * - _rfc3261_8_2_2_2_ Merged Requests + * + * Responses: + * - _rfc3261_8_1_3_3_ Multiple Via headers + * - _rfc3261_18_3_response_ Body Content-Length + * + * All: + * - Minimum headers in a SIP message + */ + +// Sanity Check functions for requests. +function rfc3261_8_2_2_1() { + if (message.s('to').uri.scheme !== 'sip') { + reply(416); + return false; + } +} +function rfc3261_16_3_4() { + if (!message.to_tag) { + if (message.call_id.substr(0, 5) === ua.configuration.jssip_id) { + reply(482); + return false; + } + } +} +function rfc3261_18_3_request() { + var len = Utils.str_utf8_length(message.body); + var contentLength = message.getHeader('content-length'); + if (len < contentLength) { + reply(400); + return false; + } +} +function rfc3261_8_2_2_2() { + var fromTag = message.from_tag; + var call_id = message.call_id; + var cseq = message.cseq; + var tr; + + // Accept any in-dialog request. + if (message.to_tag) { + return; + } + + // INVITE request. + if (message.method === JsSIP_C.INVITE) { + // If the branch matches the key of any IST then assume it is a retransmission + // and ignore the INVITE. + // TODO: we should reply the last response. + if (ua._transactions.ist[message.via_branch]) { + return false; + } + // Otherwise check whether it is a merged request. + else { + for (var transaction in ua._transactions.ist) { + if (Object.prototype.hasOwnProperty.call(ua._transactions.ist, transaction)) { + tr = ua._transactions.ist[transaction]; + if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { + reply(482); + return false; + } + } + } + } + } + + // Non INVITE request. + + // If the branch matches the key of any NIST then assume it is a retransmission + // and ignore the request. + // TODO: we should reply the last response. + else if (ua._transactions.nist[message.via_branch]) { + return false; + } + + // Otherwise check whether it is a merged request. + else { + for (var _transaction in ua._transactions.nist) { + if (Object.prototype.hasOwnProperty.call(ua._transactions.nist, _transaction)) { + tr = ua._transactions.nist[_transaction]; + if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) { + reply(482); + return false; + } + } + } + } +} + +// Sanity Check functions for responses. +function rfc3261_8_1_3_3() { + if (message.getHeaders('via').length > 1) { + logger.debug('more than one Via header field present in the response, dropping the response'); + return false; + } +} +function rfc3261_18_3_response() { + var len = Utils.str_utf8_length(message.body), + contentLength = message.getHeader('content-length'); + if (len < contentLength) { + logger.debug('message body length is lower than the value in Content-Length header field, dropping the response'); + return false; + } +} + +// Sanity Check functions for requests and responses. +function minimumHeaders() { + var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via']; + for (var _i = 0, _mandatoryHeaders = mandatoryHeaders; _i < _mandatoryHeaders.length; _i++) { + var header = _mandatoryHeaders[_i]; + if (!message.hasHeader(header)) { + logger.debug("missing mandatory header field : ".concat(header, ", dropping the response")); + return false; + } + } +} + +// Reply. +function reply(status_code) { + var vias = message.getHeaders('via'); + var to; + var response = "SIP/2.0 ".concat(status_code, " ").concat(JsSIP_C.REASON_PHRASE[status_code], "\r\n"); + var _iterator4 = _createForOfIteratorHelper(vias), + _step4; + try { + for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { + var via = _step4.value; + response += "Via: ".concat(via, "\r\n"); + } + } catch (err) { + _iterator4.e(err); + } finally { + _iterator4.f(); + } + to = message.getHeader('To'); + if (!message.to_tag) { + to += ";tag=".concat(Utils.newTag()); + } + response += "To: ".concat(to, "\r\n"); + response += "From: ".concat(message.getHeader('From'), "\r\n"); + response += "Call-ID: ".concat(message.call_id, "\r\n"); + response += "CSeq: ".concat(message.cseq, " ").concat(message.method, "\r\n"); + response += '\r\n'; + transport.send(response); +} +},{"./Constants":2,"./Logger":9,"./SIPMessage":22,"./Utils":30}],33:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var objectCreate = Object.create || objectCreatePolyfill +var objectKeys = Object.keys || objectKeysPolyfill +var bind = Function.prototype.bind || functionBindPolyfill + +function EventEmitter() { + if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) { + this._events = objectCreate(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +var hasDefineProperty; +try { + var o = {}; + if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 }); + hasDefineProperty = o.x === 0; +} catch (err) { hasDefineProperty = false } +if (hasDefineProperty) { + Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + // check whether the input is a positive number (whose value is zero or + // greater and not a NaN). + if (typeof arg !== 'number' || arg < 0 || arg !== arg) + throw new TypeError('"defaultMaxListeners" must be a positive number'); + defaultMaxListeners = arg; + } + }); +} else { + EventEmitter.defaultMaxListeners = defaultMaxListeners; +} + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || isNaN(n)) + throw new TypeError('"n" argument must be a positive number'); + this._maxListeners = n; + return this; +}; + +function $getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} + +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return $getMaxListeners(this); +}; + +// These standalone emit* functions are used to optimize calling of event +// handlers for fast cases because emit() itself often has a variable number of +// arguments and can be deoptimized because of that. These functions always have +// the same number of arguments and thus do not get deoptimized, so the code +// inside them can execute faster. +function emitNone(handler, isFn, self) { + if (isFn) + handler.call(self); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self); + } +} +function emitOne(handler, isFn, self, arg1) { + if (isFn) + handler.call(self, arg1); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1); + } +} +function emitTwo(handler, isFn, self, arg1, arg2) { + if (isFn) + handler.call(self, arg1, arg2); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2); + } +} +function emitThree(handler, isFn, self, arg1, arg2, arg3) { + if (isFn) + handler.call(self, arg1, arg2, arg3); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2, arg3); + } +} + +function emitMany(handler, isFn, self, args) { + if (isFn) + handler.apply(self, args); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].apply(self, args); + } +} + +EventEmitter.prototype.emit = function emit(type) { + var er, handler, len, args, i, events; + var doError = (type === 'error'); + + events = this._events; + if (events) + doError = (doError && events.error == null); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + if (arguments.length > 1) + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Unhandled "error" event. (' + er + ')'); + err.context = er; + throw err; + } + return false; + } + + handler = events[type]; + + if (!handler) + return false; + + var isFn = typeof handler === 'function'; + len = arguments.length; + switch (len) { + // fast cases + case 1: + emitNone(handler, isFn, this); + break; + case 2: + emitOne(handler, isFn, this, arguments[1]); + break; + case 3: + emitTwo(handler, isFn, this, arguments[1], arguments[2]); + break; + case 4: + emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); + break; + // slower + default: + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + emitMany(handler, isFn, this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + + events = target._events; + if (!events) { + events = target._events = objectCreate(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (!existing) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + } else { + // If we've already got an array, just append. + if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + } + + // Check for listener leak + if (!existing.warned) { + m = $getMaxListeners(target); + if (m && m > 0 && existing.length > m) { + existing.warned = true; + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' "' + String(type) + '" listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit.'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + if (typeof console === 'object' && console.warn) { + console.warn('%s: %s', w.name, w.message); + } + } + } + } + + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + switch (arguments.length) { + case 0: + return this.listener.call(this.target); + case 1: + return this.listener.call(this.target, arguments[0]); + case 2: + return this.listener.call(this.target, arguments[0], arguments[1]); + case 3: + return this.listener.call(this.target, arguments[0], arguments[1], + arguments[2]); + default: + var args = new Array(arguments.length); + for (var i = 0; i < args.length; ++i) + args[i] = arguments[i]; + this.listener.apply(this.target, args); + } + } +} + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = bind.call(onceWrapper, state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; + +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + + events = this._events; + if (!events) + return this; + + list = events[type]; + if (!list) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else + spliceOne(list, position); + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (!events) + return this; + + // not listening for removeListener, no need to emit + if (!events.removeListener) { + if (arguments.length === 0) { + this._events = objectCreate(null); + this._eventsCount = 0; + } else if (events[type]) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = objectKeys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = objectCreate(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (!events) + return []; + + var evlistener = events[type]; + if (!evlistener) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener) { + return evlistener.length; + } + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; +}; + +// About 1.5x faster than the two-arg version of Array#splice(). +function spliceOne(list, index) { + for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) + list[i] = list[k]; + list.pop(); +} + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function objectCreatePolyfill(proto) { + var F = function() {}; + F.prototype = proto; + return new F; +} +function objectKeysPolyfill(obj) { + var keys = []; + for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) { + keys.push(k); + } + return k; +} +function functionBindPolyfill(context) { + var fn = this; + return function () { + return fn.apply(context, arguments); + }; +} + +},{}],34:[function(require,module,exports){ +(function (process){(function (){ +/* eslint-env browser */ + +/** + * This is the web browser implementation of `debug()`. + */ + +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = localstorage(); +exports.destroy = (() => { + let warned = false; + + return () => { + if (!warned) { + warned = true; + console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); + } + }; +})(); + +/** + * Colors. + */ + +exports.colors = [ + '#0000CC', + '#0000FF', + '#0033CC', + '#0033FF', + '#0066CC', + '#0066FF', + '#0099CC', + '#0099FF', + '#00CC00', + '#00CC33', + '#00CC66', + '#00CC99', + '#00CCCC', + '#00CCFF', + '#3300CC', + '#3300FF', + '#3333CC', + '#3333FF', + '#3366CC', + '#3366FF', + '#3399CC', + '#3399FF', + '#33CC00', + '#33CC33', + '#33CC66', + '#33CC99', + '#33CCCC', + '#33CCFF', + '#6600CC', + '#6600FF', + '#6633CC', + '#6633FF', + '#66CC00', + '#66CC33', + '#9900CC', + '#9900FF', + '#9933CC', + '#9933FF', + '#99CC00', + '#99CC33', + '#CC0000', + '#CC0033', + '#CC0066', + '#CC0099', + '#CC00CC', + '#CC00FF', + '#CC3300', + '#CC3333', + '#CC3366', + '#CC3399', + '#CC33CC', + '#CC33FF', + '#CC6600', + '#CC6633', + '#CC9900', + '#CC9933', + '#CCCC00', + '#CCCC33', + '#FF0000', + '#FF0033', + '#FF0066', + '#FF0099', + '#FF00CC', + '#FF00FF', + '#FF3300', + '#FF3333', + '#FF3366', + '#FF3399', + '#FF33CC', + '#FF33FF', + '#FF6600', + '#FF6633', + '#FF9900', + '#FF9933', + '#FFCC00', + '#FFCC33' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +// eslint-disable-next-line complexity +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) { + return true; + } + + // Internet Explorer and Edge do not support colors. + if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { + return false; + } + + // Is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // Is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // Is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // Double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + args[0] = (this.useColors ? '%c' : '') + + this.namespace + + (this.useColors ? ' %c' : ' ') + + args[0] + + (this.useColors ? '%c ' : ' ') + + '+' + module.exports.humanize(this.diff); + + if (!this.useColors) { + return; + } + + const c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit'); + + // The final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + let index = 0; + let lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, match => { + if (match === '%%') { + return; + } + index++; + if (match === '%c') { + // We only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.debug()` when available. + * No-op when `console.debug` is not a "function". + * If `console.debug` is not available, falls back + * to `console.log`. + * + * @api public + */ +exports.log = console.debug || console.log || (() => {}); + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ +function save(namespaces) { + try { + if (namespaces) { + exports.storage.setItem('debug', namespaces); + } else { + exports.storage.removeItem('debug'); + } + } catch (error) { + // Swallow + // XXX (@Qix-) should we be logging these? + } +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ +function load() { + let r; + try { + r = exports.storage.getItem('debug'); + } catch (error) { + // Swallow + // XXX (@Qix-) should we be logging these? + } + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context + // The Browser also has localStorage in the global context. + return localStorage; + } catch (error) { + // Swallow + // XXX (@Qix-) should we be logging these? + } +} + +module.exports = require('./common')(exports); + +const {formatters} = module.exports; + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +formatters.j = function (v) { + try { + return JSON.stringify(v); + } catch (error) { + return '[UnexpectedJSONParseError]: ' + error.message; + } +}; + +}).call(this)}).call(this,require('_process')) +},{"./common":35,"_process":37}],35:[function(require,module,exports){ + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + */ + +function setup(env) { + createDebug.debug = createDebug; + createDebug.default = createDebug; + createDebug.coerce = coerce; + createDebug.disable = disable; + createDebug.enable = enable; + createDebug.enabled = enabled; + createDebug.humanize = require('ms'); + createDebug.destroy = destroy; + + Object.keys(env).forEach(key => { + createDebug[key] = env[key]; + }); + + /** + * The currently active debug mode names, and names to skip. + */ + + createDebug.names = []; + createDebug.skips = []; + + /** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + createDebug.formatters = {}; + + /** + * Selects a color for a debug namespace + * @param {String} namespace The namespace string for the debug instance to be colored + * @return {Number|String} An ANSI color code for the given namespace + * @api private + */ + function selectColor(namespace) { + let hash = 0; + + for (let i = 0; i < namespace.length; i++) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return createDebug.colors[Math.abs(hash) % createDebug.colors.length]; + } + createDebug.selectColor = selectColor; + + /** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + function createDebug(namespace) { + let prevTime; + let enableOverride = null; + let namespacesCache; + let enabledCache; + + function debug(...args) { + // Disabled? + if (!debug.enabled) { + return; + } + + const self = debug; + + // Set `diff` timestamp + const curr = Number(new Date()); + const ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + args[0] = createDebug.coerce(args[0]); + + if (typeof args[0] !== 'string') { + // Anything else let's inspect with %O + args.unshift('%O'); + } + + // Apply any `formatters` transformations + let index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => { + // If we encounter an escaped % then don't increase the array index + if (match === '%%') { + return '%'; + } + index++; + const formatter = createDebug.formatters[format]; + if (typeof formatter === 'function') { + const val = args[index]; + match = formatter.call(self, val); + + // Now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // Apply env-specific formatting (colors, etc.) + createDebug.formatArgs.call(self, args); + + const logFn = self.log || createDebug.log; + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.useColors = createDebug.useColors(); + debug.color = createDebug.selectColor(namespace); + debug.extend = extend; + debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release. + + Object.defineProperty(debug, 'enabled', { + enumerable: true, + configurable: false, + get: () => { + if (enableOverride !== null) { + return enableOverride; + } + if (namespacesCache !== createDebug.namespaces) { + namespacesCache = createDebug.namespaces; + enabledCache = createDebug.enabled(namespace); + } + + return enabledCache; + }, + set: v => { + enableOverride = v; + } + }); + + // Env-specific initialization logic for debug instances + if (typeof createDebug.init === 'function') { + createDebug.init(debug); + } + + return debug; + } + + function extend(namespace, delimiter) { + const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace); + newDebug.log = this.log; + return newDebug; + } + + /** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + function enable(namespaces) { + createDebug.save(namespaces); + createDebug.namespaces = namespaces; + + createDebug.names = []; + createDebug.skips = []; + + let i; + const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + const len = split.length; + + for (i = 0; i < len; i++) { + if (!split[i]) { + // ignore empty strings + continue; + } + + namespaces = split[i].replace(/\*/g, '.*?'); + + if (namespaces[0] === '-') { + createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$')); + } else { + createDebug.names.push(new RegExp('^' + namespaces + '$')); + } + } + } + + /** + * Disable debug output. + * + * @return {String} namespaces + * @api public + */ + function disable() { + const namespaces = [ + ...createDebug.names.map(toNamespace), + ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) + ].join(','); + createDebug.enable(''); + return namespaces; + } + + /** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + function enabled(name) { + if (name[name.length - 1] === '*') { + return true; + } + + let i; + let len; + + for (i = 0, len = createDebug.skips.length; i < len; i++) { + if (createDebug.skips[i].test(name)) { + return false; + } + } + + for (i = 0, len = createDebug.names.length; i < len; i++) { + if (createDebug.names[i].test(name)) { + return true; + } + } + + return false; + } + + /** + * Convert regexp to namespace + * + * @param {RegExp} regxep + * @return {String} namespace + * @api private + */ + function toNamespace(regexp) { + return regexp.toString() + .substring(2, regexp.toString().length - 2) + .replace(/\.\*\?$/, '*'); + } + + /** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + function coerce(val) { + if (val instanceof Error) { + return val.stack || val.message; + } + return val; + } + + /** + * XXX DO NOT USE. This is a temporary stub function. + * XXX It WILL be removed in the next major release. + */ + function destroy() { + console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); + } + + createDebug.enable(createDebug.load()); + + return createDebug; +} + +module.exports = setup; + +},{"ms":36}],36:[function(require,module,exports){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var w = d * 7; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isFinite(val)) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'weeks': + case 'week': + case 'w': + return n * w; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return Math.round(ms / d) + 'd'; + } + if (msAbs >= h) { + return Math.round(ms / h) + 'h'; + } + if (msAbs >= m) { + return Math.round(ms / m) + 'm'; + } + if (msAbs >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return plural(ms, msAbs, d, 'day'); + } + if (msAbs >= h) { + return plural(ms, msAbs, h, 'hour'); + } + if (msAbs >= m) { + return plural(ms, msAbs, m, 'minute'); + } + if (msAbs >= s) { + return plural(ms, msAbs, s, 'second'); + } + return ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, msAbs, n, name) { + var isPlural = msAbs >= n * 1.5; + return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); +} + +},{}],37:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],38:[function(require,module,exports){ +var grammar = module.exports = { + v: [{ + name: 'version', + reg: /^(\d*)$/ + }], + o: [{ + // o=- 20518 0 IN IP4 203.0.113.1 + // NB: sessionId will be a String in most cases because it is huge + name: 'origin', + reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/, + names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'], + format: '%s %s %d %s IP%d %s' + }], + // default parsing of these only (though some of these feel outdated) + s: [{ name: 'name' }], + i: [{ name: 'description' }], + u: [{ name: 'uri' }], + e: [{ name: 'email' }], + p: [{ name: 'phone' }], + z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly... + r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly + // k: [{}], // outdated thing ignored + t: [{ + // t=0 0 + name: 'timing', + reg: /^(\d*) (\d*)/, + names: ['start', 'stop'], + format: '%d %d' + }], + c: [{ + // c=IN IP4 10.47.197.26 + name: 'connection', + reg: /^IN IP(\d) (\S*)/, + names: ['version', 'ip'], + format: 'IN IP%d %s' + }], + b: [{ + // b=AS:4000 + push: 'bandwidth', + reg: /^(TIAS|AS|CT|RR|RS):(\d*)/, + names: ['type', 'limit'], + format: '%s:%s' + }], + m: [{ + // m=video 51744 RTP/AVP 126 97 98 34 31 + // NB: special - pushes to session + // TODO: rtp/fmtp should be filtered by the payloads found here? + reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/, + names: ['type', 'port', 'protocol', 'payloads'], + format: '%s %d %s %s' + }], + a: [ + { + // a=rtpmap:110 opus/48000/2 + push: 'rtp', + reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/, + names: ['payload', 'codec', 'rate', 'encoding'], + format: function (o) { + return (o.encoding) + ? 'rtpmap:%d %s/%s/%s' + : o.rate + ? 'rtpmap:%d %s/%s' + : 'rtpmap:%d %s'; + } + }, + { + // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000 + // a=fmtp:111 minptime=10; useinbandfec=1 + push: 'fmtp', + reg: /^fmtp:(\d*) ([\S| ]*)/, + names: ['payload', 'config'], + format: 'fmtp:%d %s' + }, + { + // a=control:streamid=0 + name: 'control', + reg: /^control:(.*)/, + format: 'control:%s' + }, + { + // a=rtcp:65179 IN IP4 193.84.77.194 + name: 'rtcp', + reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/, + names: ['port', 'netType', 'ipVer', 'address'], + format: function (o) { + return (o.address != null) + ? 'rtcp:%d %s IP%d %s' + : 'rtcp:%d'; + } + }, + { + // a=rtcp-fb:98 trr-int 100 + push: 'rtcpFbTrrInt', + reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/, + names: ['payload', 'value'], + format: 'rtcp-fb:%s trr-int %d' + }, + { + // a=rtcp-fb:98 nack rpsi + push: 'rtcpFb', + reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/, + names: ['payload', 'type', 'subtype'], + format: function (o) { + return (o.subtype != null) + ? 'rtcp-fb:%s %s %s' + : 'rtcp-fb:%s %s'; + } + }, + { + // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset + // a=extmap:1/recvonly URI-gps-string + // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24 + push: 'ext', + reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/, + names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'], + format: function (o) { + return ( + 'extmap:%d' + + (o.direction ? '/%s' : '%v') + + (o['encrypt-uri'] ? ' %s' : '%v') + + ' %s' + + (o.config ? ' %s' : '') + ); + } + }, + { + // a=extmap-allow-mixed + name: 'extmapAllowMixed', + reg: /^(extmap-allow-mixed)/ + }, + { + // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32 + push: 'crypto', + reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/, + names: ['id', 'suite', 'config', 'sessionConfig'], + format: function (o) { + return (o.sessionConfig != null) + ? 'crypto:%d %s %s %s' + : 'crypto:%d %s %s'; + } + }, + { + // a=setup:actpass + name: 'setup', + reg: /^setup:(\w*)/, + format: 'setup:%s' + }, + { + // a=connection:new + name: 'connectionType', + reg: /^connection:(new|existing)/, + format: 'connection:%s' + }, + { + // a=mid:1 + name: 'mid', + reg: /^mid:([^\s]*)/, + format: 'mid:%s' + }, + { + // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a + name: 'msid', + reg: /^msid:(.*)/, + format: 'msid:%s' + }, + { + // a=ptime:20 + name: 'ptime', + reg: /^ptime:(\d*(?:\.\d*)*)/, + format: 'ptime:%d' + }, + { + // a=maxptime:60 + name: 'maxptime', + reg: /^maxptime:(\d*(?:\.\d*)*)/, + format: 'maxptime:%d' + }, + { + // a=sendrecv + name: 'direction', + reg: /^(sendrecv|recvonly|sendonly|inactive)/ + }, + { + // a=ice-lite + name: 'icelite', + reg: /^(ice-lite)/ + }, + { + // a=ice-ufrag:F7gI + name: 'iceUfrag', + reg: /^ice-ufrag:(\S*)/, + format: 'ice-ufrag:%s' + }, + { + // a=ice-pwd:x9cml/YzichV2+XlhiMu8g + name: 'icePwd', + reg: /^ice-pwd:(\S*)/, + format: 'ice-pwd:%s' + }, + { + // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33 + name: 'fingerprint', + reg: /^fingerprint:(\S*) (\S*)/, + names: ['type', 'hash'], + format: 'fingerprint:%s %s' + }, + { + // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host + // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10 + // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10 + // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10 + // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10 + push:'candidates', + reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/, + names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'], + format: function (o) { + var str = 'candidate:%s %d %s %d %s %d typ %s'; + + str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v'; + + // NB: candidate has three optional chunks, so %void middles one if it's missing + str += (o.tcptype != null) ? ' tcptype %s' : '%v'; + + if (o.generation != null) { + str += ' generation %d'; + } + + str += (o['network-id'] != null) ? ' network-id %d' : '%v'; + str += (o['network-cost'] != null) ? ' network-cost %d' : '%v'; + return str; + } + }, + { + // a=end-of-candidates (keep after the candidates line for readability) + name: 'endOfCandidates', + reg: /^(end-of-candidates)/ + }, + { + // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ... + name: 'remoteCandidates', + reg: /^remote-candidates:(.*)/, + format: 'remote-candidates:%s' + }, + { + // a=ice-options:google-ice + name: 'iceOptions', + reg: /^ice-options:(\S*)/, + format: 'ice-options:%s' + }, + { + // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1 + push: 'ssrcs', + reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/, + names: ['id', 'attribute', 'value'], + format: function (o) { + var str = 'ssrc:%d'; + if (o.attribute != null) { + str += ' %s'; + if (o.value != null) { + str += ':%s'; + } + } + return str; + } + }, + { + // a=ssrc-group:FEC 1 2 + // a=ssrc-group:FEC-FR 3004364195 1080772241 + push: 'ssrcGroups', + // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E + reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/, + names: ['semantics', 'ssrcs'], + format: 'ssrc-group:%s %s' + }, + { + // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV + name: 'msidSemantic', + reg: /^msid-semantic:\s?(\w*) (\S*)/, + names: ['semantic', 'token'], + format: 'msid-semantic: %s %s' // space after ':' is not accidental + }, + { + // a=group:BUNDLE audio video + push: 'groups', + reg: /^group:(\w*) (.*)/, + names: ['type', 'mids'], + format: 'group:%s %s' + }, + { + // a=rtcp-mux + name: 'rtcpMux', + reg: /^(rtcp-mux)/ + }, + { + // a=rtcp-rsize + name: 'rtcpRsize', + reg: /^(rtcp-rsize)/ + }, + { + // a=sctpmap:5000 webrtc-datachannel 1024 + name: 'sctpmap', + reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/, + names: ['sctpmapNumber', 'app', 'maxMessageSize'], + format: function (o) { + return (o.maxMessageSize != null) + ? 'sctpmap:%s %s %s' + : 'sctpmap:%s %s'; + } + }, + { + // a=x-google-flag:conference + name: 'xGoogleFlag', + reg: /^x-google-flag:([^\s]*)/, + format: 'x-google-flag:%s' + }, + { + // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0 + push: 'rids', + reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/, + names: ['id', 'direction', 'params'], + format: function (o) { + return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s'; + } + }, + { + // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250] + // a=imageattr:* send [x=800,y=640] recv * + // a=imageattr:100 recv [x=320,y=240] + push: 'imageattrs', + reg: new RegExp( + // a=imageattr:97 + '^imageattr:(\\d+|\\*)' + + // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] + '[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)' + + // recv [x=330,y=250] + '(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?' + ), + names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'], + format: function (o) { + return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : ''); + } + }, + { + // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8 + // a=simulcast:recv 1;4,5 send 6;7 + name: 'simulcast', + reg: new RegExp( + // a=simulcast: + '^simulcast:' + + // send 1,2,3;~4,~5 + '(send|recv) ([a-zA-Z0-9\\-_~;,]+)' + + // space + recv 6;~7,~8 + '(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?' + + // end + '$' + ), + names: ['dir1', 'list1', 'dir2', 'list2'], + format: function (o) { + return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : ''); + } + }, + { + // old simulcast draft 03 (implemented by Firefox) + // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03 + // a=simulcast: recv pt=97;98 send pt=97 + // a=simulcast: send rid=5;6;7 paused=6,7 + name: 'simulcast_03', + reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/, + names: ['value'], + format: 'simulcast: %s' + }, + { + // a=framerate:25 + // a=framerate:29.97 + name: 'framerate', + reg: /^framerate:(\d+(?:$|\.\d+))/, + format: 'framerate:%s' + }, + { + // RFC4570 + // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5 + name: 'sourceFilter', + reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/, + names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'], + format: 'source-filter: %s %s %s %s %s' + }, + { + // a=bundle-only + name: 'bundleOnly', + reg: /^(bundle-only)/ + }, + { + // a=label:1 + name: 'label', + reg: /^label:(.+)/, + format: 'label:%s' + }, + { + // RFC version 26 for SCTP over DTLS + // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5 + name: 'sctpPort', + reg: /^sctp-port:(\d+)$/, + format: 'sctp-port:%s' + }, + { + // RFC version 26 for SCTP over DTLS + // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6 + name: 'maxMessageSize', + reg: /^max-message-size:(\d+)$/, + format: 'max-message-size:%s' + }, + { + // RFC7273 + // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37 + push:'tsRefClocks', + reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/, + names: ['clksrc', 'clksrcExt'], + format: function (o) { + return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : ''); + } + }, + { + // RFC7273 + // a=mediaclk:direct=963214424 + name:'mediaClk', + reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/, + names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'], + format: function (o) { + var str = 'mediaclk:'; + str += (o.id != null ? 'id=%s %s' : '%v%s'); + str += (o.mediaClockValue != null ? '=%s' : ''); + str += (o.rateNumerator != null ? ' rate=%s' : ''); + str += (o.rateDenominator != null ? '/%s' : ''); + return str; + } + }, + { + // a=keywds:keywords + name: 'keywords', + reg: /^keywds:(.+)$/, + format: 'keywds:%s' + }, + { + // a=content:main + name: 'content', + reg: /^content:(.+)/, + format: 'content:%s' + }, + // BFCP https://tools.ietf.org/html/rfc4583 + { + // a=floorctrl:c-s + name: 'bfcpFloorCtrl', + reg: /^floorctrl:(c-only|s-only|c-s)/, + format: 'floorctrl:%s' + }, + { + // a=confid:1 + name: 'bfcpConfId', + reg: /^confid:(\d+)/, + format: 'confid:%s' + }, + { + // a=userid:1 + name: 'bfcpUserId', + reg: /^userid:(\d+)/, + format: 'userid:%s' + }, + { + // a=floorid:1 + name: 'bfcpFloorId', + reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/, + names: ['id', 'mStream'], + format: 'floorid:%s mstrm:%s' + }, + { + // any a= that we don't understand is kept verbatim on media.invalid + push: 'invalid', + names: ['value'] + } + ] +}; + +// set sensible defaults to avoid polluting the grammar with boring details +Object.keys(grammar).forEach(function (key) { + var objs = grammar[key]; + objs.forEach(function (obj) { + if (!obj.reg) { + obj.reg = /(.*)/; + } + if (!obj.format) { + obj.format = '%s'; + } + }); +}); + +},{}],39:[function(require,module,exports){ +var parser = require('./parser'); +var writer = require('./writer'); + +exports.write = writer; +exports.parse = parser.parse; +exports.parseParams = parser.parseParams; +exports.parseFmtpConfig = parser.parseFmtpConfig; // Alias of parseParams(). +exports.parsePayloads = parser.parsePayloads; +exports.parseRemoteCandidates = parser.parseRemoteCandidates; +exports.parseImageAttributes = parser.parseImageAttributes; +exports.parseSimulcastStreamList = parser.parseSimulcastStreamList; + +},{"./parser":40,"./writer":41}],40:[function(require,module,exports){ +var toIntIfInt = function (v) { + return String(Number(v)) === v ? Number(v) : v; +}; + +var attachProperties = function (match, location, names, rawName) { + if (rawName && !names) { + location[rawName] = toIntIfInt(match[1]); + } + else { + for (var i = 0; i < names.length; i += 1) { + if (match[i+1] != null) { + location[names[i]] = toIntIfInt(match[i+1]); + } + } + } +}; + +var parseReg = function (obj, location, content) { + var needsBlank = obj.name && obj.names; + if (obj.push && !location[obj.push]) { + location[obj.push] = []; + } + else if (needsBlank && !location[obj.name]) { + location[obj.name] = {}; + } + var keyLocation = obj.push ? + {} : // blank object that will be pushed + needsBlank ? location[obj.name] : location; // otherwise, named location or root + + attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name); + + if (obj.push) { + location[obj.push].push(keyLocation); + } +}; + +var grammar = require('./grammar'); +var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/); + +exports.parse = function (sdp) { + var session = {} + , media = [] + , location = session; // points at where properties go under (one of the above) + + // parse lines we understand + sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) { + var type = l[0]; + var content = l.slice(2); + if (type === 'm') { + media.push({rtp: [], fmtp: []}); + location = media[media.length-1]; // point at latest media line + } + + for (var j = 0; j < (grammar[type] || []).length; j += 1) { + var obj = grammar[type][j]; + if (obj.reg.test(content)) { + return parseReg(obj, location, content); + } + } + }); + + session.media = media; // link it up + return session; +}; + +var paramReducer = function (acc, expr) { + var s = expr.split(/=(.+)/, 2); + if (s.length === 2) { + acc[s[0]] = toIntIfInt(s[1]); + } else if (s.length === 1 && expr.length > 1) { + acc[s[0]] = undefined; + } + return acc; +}; + +exports.parseParams = function (str) { + return str.split(/;\s?/).reduce(paramReducer, {}); +}; + +// For backward compatibility - alias will be removed in 3.0.0 +exports.parseFmtpConfig = exports.parseParams; + +exports.parsePayloads = function (str) { + return str.toString().split(' ').map(Number); +}; + +exports.parseRemoteCandidates = function (str) { + var candidates = []; + var parts = str.split(' ').map(toIntIfInt); + for (var i = 0; i < parts.length; i += 3) { + candidates.push({ + component: parts[i], + ip: parts[i + 1], + port: parts[i + 2] + }); + } + return candidates; +}; + +exports.parseImageAttributes = function (str) { + return str.split(' ').map(function (item) { + return item.substring(1, item.length-1).split(',').reduce(paramReducer, {}); + }); +}; + +exports.parseSimulcastStreamList = function (str) { + return str.split(';').map(function (stream) { + return stream.split(',').map(function (format) { + var scid, paused = false; + + if (format[0] !== '~') { + scid = toIntIfInt(format); + } else { + scid = toIntIfInt(format.substring(1, format.length)); + paused = true; + } + + return { + scid: scid, + paused: paused + }; + }); + }); +}; + +},{"./grammar":38}],41:[function(require,module,exports){ +var grammar = require('./grammar'); + +// customized util.format - discards excess arguments and can void middle ones +var formatRegExp = /%[sdv%]/g; +var format = function (formatStr) { + var i = 1; + var args = arguments; + var len = args.length; + return formatStr.replace(formatRegExp, function (x) { + if (i >= len) { + return x; // missing argument + } + var arg = args[i]; + i += 1; + switch (x) { + case '%%': + return '%'; + case '%s': + return String(arg); + case '%d': + return Number(arg); + case '%v': + return ''; + } + }); + // NB: we discard excess arguments - they are typically undefined from makeLine +}; + +var makeLine = function (type, obj, location) { + var str = obj.format instanceof Function ? + (obj.format(obj.push ? location : location[obj.name])) : + obj.format; + + var args = [type + '=' + str]; + if (obj.names) { + for (var i = 0; i < obj.names.length; i += 1) { + var n = obj.names[i]; + if (obj.name) { + args.push(location[obj.name][n]); + } + else { // for mLine and push attributes + args.push(location[obj.names[i]]); + } + } + } + else { + args.push(location[obj.name]); + } + return format.apply(null, args); +}; + +// RFC specified order +// TODO: extend this with all the rest +var defaultOuterOrder = [ + 'v', 'o', 's', 'i', + 'u', 'e', 'p', 'c', + 'b', 't', 'r', 'z', 'a' +]; +var defaultInnerOrder = ['i', 'c', 'b', 'a']; + + +module.exports = function (session, opts) { + opts = opts || {}; + // ensure certain properties exist + if (session.version == null) { + session.version = 0; // 'v=0' must be there (only defined version atm) + } + if (session.name == null) { + session.name = ' '; // 's= ' must be there if no meaningful name set + } + session.media.forEach(function (mLine) { + if (mLine.payloads == null) { + mLine.payloads = ''; + } + }); + + var outerOrder = opts.outerOrder || defaultOuterOrder; + var innerOrder = opts.innerOrder || defaultInnerOrder; + var sdp = []; + + // loop through outerOrder for matching properties on session + outerOrder.forEach(function (type) { + grammar[type].forEach(function (obj) { + if (obj.name in session && session[obj.name] != null) { + sdp.push(makeLine(type, obj, session)); + } + else if (obj.push in session && session[obj.push] != null) { + session[obj.push].forEach(function (el) { + sdp.push(makeLine(type, obj, el)); + }); + } + }); + }); + + // then for each media line, follow the innerOrder + session.media.forEach(function (mLine) { + sdp.push(makeLine('m', grammar.m[0], mLine)); + + innerOrder.forEach(function (type) { + grammar[type].forEach(function (obj) { + if (obj.name in mLine && mLine[obj.name] != null) { + sdp.push(makeLine(type, obj, mLine)); + } + else if (obj.push in mLine && mLine[obj.push] != null) { + mLine[obj.push].forEach(function (el) { + sdp.push(makeLine(type, obj, el)); + }); + } + }); + }); + }); + + return sdp.join('\r\n') + '\r\n'; +}; + +},{"./grammar":38}],42:[function(require,module,exports){ +module.exports={ + "name": "jssip", + "title": "JsSIP", + "description": "the Javascript SIP library", + "version": "3.10.0", + "homepage": "https://jssip.net", + "contributors": [ + "José Luis Millán (https://github.com/jmillan)", + "Iñaki Baz Castillo (https://inakibaz.me)" + ], + "types": "lib/JsSIP.d.ts", + "main": "lib-es5/JsSIP.js", + "keywords": [ + "sip", + "websocket", + "webrtc", + "node", + "browser", + "library" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/versatica/JsSIP.git" + }, + "bugs": { + "url": "https://github.com/versatica/JsSIP/issues" + }, + "dependencies": { + "@types/events": "^3.0.0", + "@types/debug": "^4.1.7", + "debug": "^4.3.1", + "events": "^3.3.0", + "sdp-transform": "^2.14.1" + }, + "devDependencies": { + "@babel/core": "^7.19.6", + "@babel/preset-env": "^7.19.4", + "ansi-colors": "^3.2.4", + "browserify": "^16.5.1", + "eslint": "^5.16.0", + "fancy-log": "^1.3.3", + "gulp": "^4.0.2", + "gulp-babel": "^8.0.0", + "gulp-eslint": "^5.0.0", + "gulp-expect-file": "^1.0.2", + "gulp-header": "^2.0.9", + "gulp-nodeunit-runner": "^0.2.2", + "gulp-plumber": "^1.2.1", + "gulp-rename": "^1.4.0", + "gulp-uglify-es": "^1.0.4", + "pegjs": "^0.7.0", + "vinyl-buffer": "^1.0.1", + "vinyl-source-stream": "^2.0.0" + }, + "scripts": { + "lint": "node npm-scripts.js lint", + "test": "node npm-scripts.js test", + "prepublish": "node npm-scripts.js prepublish", + "release": "node npm-scripts.js release" + } +} + +},{}]},{},[8])(8) +}); diff --git a/js/tracer.js b/js/tracer.js new file mode 100644 index 0000000..2498170 --- /dev/null +++ b/js/tracer.js @@ -0,0 +1,204 @@ +// +// WebRTC tracer (logging tool) +// For Chrome,Firefox and Safari; +// +// Igor Kolosov AudioCodes Ltd 2020 +// Last edit 29-Mar-2020 +webrtcTracer = function (showCaller=false) { + function detectBrowser() { + if (navigator.mozGetUserMedia) return 'firefox' + if (navigator.webkitGetUserMedia) return 'chrome'; + if (window.safari !== undefined) return 'safari'; + return 'other'; + } + + function createTimestamp(date = null) { + if (date === null) + date = new Date(); + let h = date.getHours(); + let m = date.getMinutes(); + let s = date.getSeconds(); + let ms = date.getMilliseconds(); + return ((h < 10) ? '0' + h : h) + ':' + ((m < 10) ? '0' + m : m) + ':' + ((s < 10) ? '0' + s : s) + '.' + ('00' + ms).slice(-3) + ' '; + } + + function caller(withfn) { + let browser = detectBrowser(); + let st = (new Error()).stack.split('\n'); + let s = st[browser === 'chrome' ? 4 : 3]; + let i = s.lastIndexOf('/'); + let loc = s.substring(i+1); + i = loc.lastIndexOf(':'); + loc = loc.substring(0, i); + let func = ''; + if( browser === 'chrome'){ + func = s.trim().split(' ')[1] + '() '; + if (func.startsWith('https://')) + func = ''; + } else if(browser === 'firefox' || browser === 'safari'){ + i = s.indexOf('@'); + if( i !== -1 ){ + func = s.substring(0, i) + '() '; + } + } + return (withfn ? func : '') + loc; + } + + const tlog = function (...args) { + console.log.apply(console, ['%c' + createTimestamp() + '[webrtc] ' + args[0] + + (showCaller ? ('\n{' + caller(true) + '}') : ''), 'background:MediumSpringGreen;color:black;',].concat(args.slice(1))); + } + + if (navigator.mediaDevices.getUserMedia) { + const origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (...args) { + tlog('getUserMedia', ...args); + return origGetUserMedia(...args); + }; + } + + // RTCPeerConnection + const origConnectionSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; + window.RTCPeerConnection.prototype.setLocalDescription = function (...args) { + tlog('connection setLocalDescription', ...args); + return origConnectionSetLocalDescription.apply(this, args); + } + + const origConnectionSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function (...args) { + tlog('connection setRemoteDescription', ...args); + return origConnectionSetRemoteDescription.apply(this, args); + } + + const origConnectionCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function (...args) { + tlog('connection createOffer', ...args); + return origConnectionCreateOffer.apply(this, args); + } + + const origConnectionCreateAnswer = window.RTCPeerConnection.prototype.createAnswer; + window.RTCPeerConnection.prototype.createAnswer = function (...args) { + tlog('connection createAnswer', ...args); + return origConnectionCreateAnswer.apply(this, args); + } + + const origConnectionAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function (...args) { + tlog('connection addTrack', ...args); + return origConnectionAddTrack.apply(this, args); + } + + const origConnectionRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function (...args) { + tlog('connection removeTrack', ...args); + return origConnectionRemoveTrack.apply(this, args); + } + + const origConnectionGetSenders = window.RTCPeerConnection.prototype.getSenders; + window.RTCPeerConnection.prototype.getSenders = function (...args) { + let result = origConnectionGetSenders.apply(this, args); + tlog('connection getSenders', result); + return result; + } + + const origConnectionGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + window.RTCPeerConnection.prototype.getReceivers = function (...args) { + let result = origConnectionGetReceivers.apply(this, args); + tlog('connection getReceivers', result); + return result; + } + + const origConnectionGetTransceivers = window.RTCPeerConnection.prototype.getTransceivers; + window.RTCPeerConnection.prototype.getTransceivers = function (...args) { + let result = origConnectionGetTransceivers.apply(this, args); + //tlog('connection getTransceivers', result); + return result; + } + + + const origConnectionIceGatheringState = Object.getOwnPropertyDescriptor( + window.RTCPeerConnection.prototype, 'iceGatheringState'); + Object.defineProperty(window.RTCPeerConnection.prototype, 'iceGatheringState', { + get() { + let value = origConnectionIceGatheringState.get.call(this); + tlog('connection iceGatheringState: "' + value + '"'); + return value; + } + }); + + const origConnectionIceConnectionState = Object.getOwnPropertyDescriptor( + window.RTCPeerConnection.prototype, 'iceConnectionState'); + Object.defineProperty(window.RTCPeerConnection.prototype, 'iceConnectionState', { + get() { + let value = origConnectionIceConnectionState.get.call(this); + tlog('connection iceConnectionState: "' + value + '"'); + return value; + } + }); + + const origConnectionAddEventListener = window.RTCPeerConnection.prototype.addEventListener; + window.RTCPeerConnection.prototype.addEventListener = function (...args) { + tlog('connection addEventListener ' + args[0]); + return origConnectionAddEventListener.apply(this, args); + } + + const origConnectionRemoveEventListener = window.RTCPeerConnection.prototype.removeEventListener; + window.RTCPeerConnection.prototype.removeEventListener = function (...args) { + tlog('connection removeEventListener ' + args[0]); + return origConnectionRemoveEventListener.apply(this, args); + } + + // MediaStream + const origStreamGetTracks = window.MediaStream.prototype.getTracks; + window.MediaStream.prototype.getTracks = function (...args) { + let result = origStreamGetTracks.apply(this, args); + //tlog('stream getTracks():', result); + return result; + } + + const origStreamGetAudioTracks = window.MediaStream.prototype.getAudioTracks; + window.MediaStream.prototype.getAudioTracks = function (...args) { + let result = origStreamGetAudioTracks.apply(this, args); + //tlog('stream getAudioTracks():', result); + return result; + } + + const origStreamGetVideoTracks = window.MediaStream.prototype.getVideoTracks; + window.MediaStream.prototype.getVideoTracks = function (...args) { + let result = origStreamGetVideoTracks.apply(this, args); + //tlog('stream getVideoTracks():', result); + return result; + } + + const origStreamRemoveTrack = window.MediaStream.prototype.removeTrack; + window.MediaStream.prototype.removeTrack = function (...args) { + tlog(`stream removeTrack ${args[0].kind}`); + return origStreamRemoveTrack.apply(this, args); + } + + // Media Stream Track + const origTrackStop = window.MediaStreamTrack.prototype.stop; + window.MediaStreamTrack.prototype.stop = function (...args) { + tlog(`${this.kind} track stop()`); + return origTrackStop.apply(this, ...args); + } + + const origTrackEnabled = Object.getOwnPropertyDescriptor( + window.MediaStreamTrack.prototype, 'enabled'); + const origTrackKind = Object.getOwnPropertyDescriptor( + window.MediaStreamTrack.prototype, 'kind'); + + Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { + get() { + let kind = origTrackKind.get.call(this); + let enabled = origTrackEnabled.get.call(this); + //tlog(`${kind} track enabled: ${enabled}`); + return enabled; + }, + set(value) { + let kind = origTrackKind.get.call(this); + tlog(`${kind} track set enabled=${value}`); + origTrackEnabled.set.call(this, value); + } + }); +}; \ No newline at end of file diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 0000000..550ff6a --- /dev/null +++ b/js/utils.js @@ -0,0 +1,1930 @@ +'use strict'; +/* + * The utilities used to build our phone examples. + + * You may consider them an optional part of our SDK. + * You can use them if they are suitable for your project or replace them with other libraries. + * For example instead provided in this file AudioPlayer you may use other audio library, + * instead storageLoadConfig other library to work with local storage, etc. + * + * Load/save configuration from/to local storage + * - storageLoadConfig + * - storageSaveConfig + * + * IndexedDB + * - AbstractDb (abstract indexeddb with single store) + * - CallLogDb (call log indexeddb) + * - VoiceDb (recorded voice messages indexeddb) + * - MessageDb (received text messages indexeddb) + * + * Audio, video + * - AudioPlayer2 + * - MRecorder + * - AnsweringMachine + * + * SIP + * - AlertInfo parser + * - XVoiceQuality parser + * + * Conference + * - CallAudioMixer + * - CallVideoMixer + * + * loadJavaScript (dinamically load arbitrary javascript) + * SelectDevices (enumerate and select microphone, camera, speaker) + * + * Igor Kolosov AudioCodes 2022 + * Last edit 11-Aug-2022 + */ + +/** + * Load JSON object from local storage + * + * If object does not exist, will be used default value. + * If object exists, and has version different from default value version, will be used default value. + * + * The version used to override browser local storage value to default value from site. + * + * Example: + * We upgrade in our site phone from version 1.1 to 1.2. + * There are many users of phone version 1.1 in the world and they store some phone configuration + * to browser local storage. + * In phone version 1.2 the construction of the configuration object is different. + * To prevent errors, we should change version of default configuration object in our site, + * it forces to load updated version instead using saved in local storage. + * (See phone prototype config.js) + * + * For debugging can be used storeBack = true, + * to edit stored value via browser dev. tools. + */ +function storageLoadConfig(name, defValue = null, useLog = true, storeBack = false) { + let str_value = localStorage.getItem(name); + let value = null; + let isLoaded = false; + let isReplaced = false; + let isDefault; + if (str_value) { + isLoaded = true; + value = JSON.parse(str_value); + } + if (value === null || (defValue !== null && value.version !== defValue.version)) { + if (isLoaded) + isReplaced = true; + isLoaded = false; + isDefault = true; + if (defValue !== null) + value = dataDeepCopy(defValue); + } else { + isDefault = dataEquals(value, defValue); + } + if (useLog) { + console.log('Used %s %s', value !== null ? (isDefault ? 'default' : 'custom') : 'null', name); + } + if (value !== null && (isReplaced || (storeBack && !isLoaded))) + localStorage.setItem(name, JSON.stringify(value)); + return value; +} + +/** + * Save JSON object to local storage. + * + * Default value is optional. + * If it's provided and object has default value, it will be removed from local storage. + */ +function storageSaveConfig(name, value, defValue = null) { + if (defValue === null || !dataEquals(value, defValue)) { + if (defValue !== null && defValue.version && !value.version) + value.version = defValue.version; + localStorage.setItem(name, JSON.stringify(value)); + } else { + localStorage.removeItem(name); + } +} + +// Objects deep equals +function dataEquals(obj1, obj2) { + if (obj1 === null || obj2 === null) return obj1 === obj2; + for (let p in obj1) { + if (obj1.hasOwnProperty(p) !== obj2.hasOwnProperty(p)) return false; + switch (typeof (obj1[p])) { + case 'object': + if (!dataEquals(obj1[p], obj2[p])) return false; + break; + case 'function': // No compare functions. + break; + default: + if (obj1[p] != obj2[p]) return false; + } + } + for (let p in obj2) { + if (typeof (obj1[p]) == 'undefined') return false; + } + return true; +} + +function dataDeepCopy(src) { + if (src === null) + return null; + let dst = Array.isArray(src) ? [] : {}; + for (let p in src) { + switch (typeof (src[p])) { + case 'object': + dst[p] = dataDeepCopy(src[p]); + break; + case 'function': // No copy + break; + default: + dst[p] = src[p]; + break; + } + } + return dst; +} + + +/** + * Database with single store and with copy of the store in memory - objects list + * Purpose: make the list persistent. + * Key is part of record, based on current time, unique and has name 'id' + * Number of objects in store is limited, oldest objects will be deleted. + * If needed, additional stores can be added: override open(), + * and use get(), put(), clear(), delete() methods with store name. + */ +class AbstractDb { + constructor(dbName, storeName, maxSize) { + this.dbName = dbName; + this.storeName = storeName; + this.maxSize = maxSize; // max number of objects + this.db = null; + this.list = []; // default store copy in memory. + this.idSeqNumber = -1; // to generate unique key. + } + + // Create store unique key. (no more than 1 million in the same millisecond) + // key must be part or record and have name 'id' + createId(time) { + this.idSeqNumber = (this.idSeqNumber + 1) % 1000000; // range 0..999999 + return time.toString() + '-' + ('00000' + this.idSeqNumber.toString()).slice(-6); + } + + // Open the database, if needed create it. + open() { + return new Promise((resolve, reject) => { + let r = indexedDB.open(this.dbName); + r.onupgradeneeded = (e) => { + e.target.result.createObjectStore(this.storeName, { keyPath: 'id' }); + } + r.onsuccess = () => { + this.db = r.result; + resolve(); + } + r.onerror = r.onblocked = () => { reject(r.error); }; + }); + } + + // load records to memory, ordered by time, if needed delete oldest records + load() { + return new Promise((resolve, reject) => { + if (this.db === null) { reject('db is null'); return; } + let trn = this.db.transaction(this.storeName, 'readwrite'); + trn.onerror = () => { reject(trn.error); } + let store = trn.objectStore(this.storeName) + let onsuccess = (list) => { + this.list = list; + let nDel = this.list.length - this.maxSize; + if (nDel <= 0) { + resolve(); + } else { + let r = store.delete(IDBKeyRange.upperBound(this.list[nDel - 1].id)); + r.onerror = () => { reject(r.error); } + r.onsuccess = () => { + this.list = this.list.splice(-this.maxSize); + resolve(); + } + } + } + let onerror = (e) => { reject(e); } + let getAll = store.getAll ? this._getAllBuiltIn : this._getAllCursor; + getAll(store, onsuccess, onerror); + }); + } + + _getAllBuiltIn(store, onsuccess, onerror) { // Chrome, Firefox + let r = store.getAll(); + r.onerror = () => onerror(r.error); + r.onsuccess = () => onsuccess(r.result); + } + + _getAllCursor(store, onsuccess, onerror) { // Legacy Edge + let list = []; + let r = store.openCursor(); + r.onerror = () => onerror(r.error); + r.onsuccess = (e) => { + let cursor = e.target.result; + if (cursor) { + list.push(cursor.value); + cursor.continue(); + } else { + onsuccess(list); + } + }; + } + + // Add new record. If needed delete oldest records + add(record) { + return new Promise((resolve, reject) => { + if (this.db === null) { reject('db is null'); return; } + let trn = this.db.transaction(this.storeName, 'readwrite'); + trn.onerror = () => { reject(trn.error); } + let store = trn.objectStore(this.storeName) + let r = store.add(record); + r.onerror = () => { reject(r.error); } + r.onsuccess = () => { + this.list.push(record); + let nDel = this.list.length - this.maxSize; + if (nDel <= 0) { + resolve(); + } else { + r = store.delete(IDBKeyRange.upperBound(this.list[nDel - 1].id)); + r.onerror = () => { reject(r.error); } + r.onsuccess = () => { + this.list = this.list.splice(-this.maxSize); + resolve(); + } + } + } + }); + } + + // Update record with some unique id. + update(record) { + let index = this.list.findIndex((r) => r.id === record.id); + if (index == -1) + return Promise.reject('Record is not found'); + this.list[index] = record; + return this._exec('put', this.storeName, record); + } + + // Delete record with the key (if store is default delete also from list) + delete(id, storeName = this.storeName) { + if (storeName === this.storeName) { + let index = this.list.findIndex((r) => r.id === id); + if (index == -1) + return Promise.reject('Record is not found'); + this.list.splice(index, 1); + } + return this._exec('delete', storeName, id); + } + + // Clear all store records + clear(storeName = this.storeName) { + this.list = []; + return this._exec('clear', storeName); + } + + get(key, storeName) { + return this._exec('get', storeName, key); + } + + put(record, storeName) { + return this._exec('put', storeName, record); + } + + // Single transaction operation. + _exec(op, storeName, data) { + return new Promise((resolve, reject) => { + if (this.db === null) { reject('db is null'); return; } + let trn = this.db.transaction(storeName, 'readwrite'); + trn.onerror = () => { reject(trn.error); } + let store = trn.objectStore(storeName) + let r; + switch (op) { + case 'clear': + r = store.clear(); + break; + case 'delete': + r = store.delete(data); + break; + case 'put': + r = store.put(data); + break; + case 'get': + r = store.get(data); + break; + default: + reject('db: wrong request'); + return; + } + r.onerror = () => { reject(r.error); } + r.onsuccess = () => { resolve(r.result); } + }); + } +} + + +/** + * To keep phone call logs. + */ +class CallLogDb extends AbstractDb { + constructor(maxSize) { + super('phone', 'call_log', maxSize); + } +} + +/* + * To use with automatic answer machine. Created 2 stores: + * 'records' default store, to save last (up to maxSize) answer records. + * 'greeting' additional store, to save custom greeting. + */ +class VoiceDb extends AbstractDb { + constructor(maxSize) { + super('voice_db', 'records', maxSize); + } + + open() { + return new Promise((resolve, reject) => { + let r = indexedDB.open(this.dbName); + r.onupgradeneeded = (e) => { + e.target.result.createObjectStore(this.storeName, { keyPath: 'id' }); + e.target.result.createObjectStore('greeting', { keyPath: 'id' }); + } + r.onsuccess = () => { + this.db = r.result; + resolve(); + } + r.onerror = r.onblocked = () => { reject(r.error); }; + }); + } +} + +/** + * To keep incoming text messages. + */ +class MessageDb extends AbstractDb { + constructor(maxSize) { + super('message_db', 'messages', maxSize); + } +} + +/* + * AudioPlayer2 + * + * There are audio web API: + * - HTMLAudioElement (Can be associated with speaker. Chrome only) + * - Audio Context. (Uses default speaker) + * + * For most operation systems and browsers HTMLAudioElement is best option. + * The exception is macOS Safari and all iOS browsers (WebKit codebase) + * WebKit HTMLAudioElement is about unusable for our case. + * + * AudioPlayer2 can be configured to use HTMLAudioElement or AudioContext API to + * play sound. + * Both modes used AudioContext API to generate tones and sending audio stream. + * + * Igor Kolosov AudioCodes Ltd 2022 + */ +class AudioPlayer2 { + constructor() { + this.browser = this._browser(); + this.speakerDeviceId = undefined; // undefined - don't use setSinkId, null or string uses setSinkId() + this.ringerDeviceId = undefined; // additional loudspeaker to play rings + this.useAudioElement = undefined; // true/false switch HTMLAudioElement/AudioContext API + this.logger = console.log; + this.sounds = {}; // Sounds + this.sound = null; // Current sound + this.ringer = null; // Ringer sound + this.ssound = null; // Short sound + this.audioCtx = null; + this.dtmfTones = { + '1': [{ f: [697, 1209], t: 0.2 }], + '2': [{ f: [697, 1336], t: 0.2 }], + '3': [{ f: [697, 1477], t: 0.2 }], + '4': [{ f: [770, 1209], t: 0.2 }], + '5': [{ f: [770, 1336], t: 0.2 }], + '6': [{ f: [770, 1477], t: 0.2 }], + '7': [{ f: [852, 1209], t: 0.2 }], + '8': [{ f: [852, 1336], t: 0.2 }], + '9': [{ f: [852, 1477], t: 0.2 }], + '*': [{ f: [941, 1209], t: 0.2 }], + '0': [{ f: [941, 1336], t: 0.2 }], + '#': [{ f: [941, 1477], t: 0.2 }], + 'A': [{ f: [697, 1633], t: 0.2 }], + 'B': [{ f: [770, 1633], t: 0.2 }], + 'C': [{ f: [852, 1633], t: 0.2 }], + 'D': [{ f: [941, 1633], t: 0.2 }] + }; + } + + /** + * User can select API by setting: + * useAudioElement: true + * useAudioElement: false + * useAudioElement: undefined (default) - API selected according using browser: + * used AudioElement API, except macOS Safari and any iOS browsers. + */ + init(options = { logger: null, audioCtx: null, useAudioElement: undefined }) { + this.logger = options.logger ? options.logger : console.log; + this.audioCtx = options.audioCtx ? options.audioCtx : new (window.AudioContext || window.webkitAudioContext)(); + if (options.useAudioElement === true || options.useAudioElement === false) + this.useAudioElement = options.useAudioElement; // user can select using API. + else // or API will be selected automatically + this.useAudioElement = !['safari', 'safari|ios'].includes(this.browser); + + this.logger(`AudioPlayer2: init ${this.useAudioElement ? 'AudioElement' : 'AudioContext'} (${this.browser})`); + } + + // Set earpeace device for play(). For AudioElement mode in Chrome + setSpeakerId(deviceId) { + this.logger(`AudioPlayer2: setSpeakerId(${deviceId})`); + this.speakerDeviceId = (deviceId !== null) ? deviceId : ''; + } + + // Set loudspeaker device for playRing(). For AudioElement mode in Chrome + setRingerId(deviceId) { + this.logger(`AudioPlayer2: setRingerId(${deviceId})`); + this.ringerDeviceId = (deviceId) ? deviceId : null; + } + + _browser() { + if (/iPad|iPhone|iPod/.test(navigator.userAgent)) + return 'safari|ios'; // all iOS browsers (includes Safari, Chrome or Firefox) + if (navigator.mozGetUserMedia) + return 'firefox'; + if (navigator.webkitGetUserMedia) + return 'chrome'; + if (window.safari) + return 'safari'; + return 'other'; + } + + // To support auto-play policy. + isDisabled() { + if (this.audioCtx.state === 'interrupted') + this.logger('AudioPlayer2: isDisabled() state = interrupted ! Hello from iOS'); + + if (['chrome', 'safari', 'safari|ios'].includes(this.browser)) { + return this.audioCtx.state === 'suspended'; + } else { + return false; + } + } + + enable() { + if (['chrome', 'safari', 'safari|ios'].includes(this.browser)) { + return this.audioCtx.resume(); + } else { + return Promise.resolve(); + } + } + + /* + * Download MP3 sounds. Resolved when all sounds are loaded + */ + downloadSounds(path, soundList) { + this.logger(`AudioPlayer2: downloadSounds ${path} ${JSON.stringify(soundList)}`); + if (!this.useAudioElement && ['safari', 'safari|ios'].includes(this.browser)) { + this._setDecodeAudioDataShim(this.audioCtx); + } + let readyList = []; + for (let sound of soundList) { + let name, sname; + if (typeof sound === 'string') { + name = sname = sound; + } else { + name = Object.keys(sound)[0]; + sname = sound[name]; + } + let file = path + sname + '.mp3'; + readyList.push(this.useAudioElement ? this._downloadSound1(name, file) : this._downloadSound2(name, file)); + } + return Promise.allSettled(readyList); + } + + generateTonesSuite(suite) { + this.logger('AudioPlayer2: generateTonesSuite'); + let readyList = []; + for (let toneName of Object.keys(suite)) { + let toneDefinition = suite[toneName]; + readyList.push(this.useAudioElement ? this._generateTone1(toneName, toneDefinition) : this._generateTone2(toneName, toneDefinition)); + } + return Promise.allSettled(readyList); + } + + /** + * Play sound in speaker + * + * @param options + * name sound clip name (must be set) + * + * volume = 0 .. 1.0 Default 1.0 (for iOS HTMLAudioElement always 1.0) + * loop = true/false Endless loop + * repeat = number Repeat times + * + * streamDestination (undefined by default), value mediaStreamDestination. + * Assign output to audio stream instead of speaker. + * + * @returns Promise to check when playing is finished. + */ + play(options, streamDestination = undefined) { + if (this.isDisabled()) { + this.logger(`AudioPlayer2: play: ${JSON.stringify(options)} [Sound is disabled]`); + return Promise.resolve(); + } + if (this.useAudioElement) { + return streamDestination ? this._playStream1(options, streamDestination) : this._play1(options); + } else { + return this._play2(options, streamDestination); + } + } + + /** + * Play ringing additionaly in loudspeaker (if configured) + * + * Note: the same sound name cannot be used in play() and playRing() - + * because for each sound name created own HTMLAudioElement associated with + * speaker. + * So if for play() and playRing() used the same MP3 sound file, + * use it with different sound names. (e.g. 'ring' and 'r_ring' in our examples) + */ + playRing(options) { + if (this.isDisabled()) { + this.logger(`AudioPlayer2: playRing: ${JSON.stringify(options)} [Sound is disabled]`); + return Promise.resolve(); + } + return this.useAudioElement ? this._playRing1(options) : Promise.resolve(); + } + + /** + * Stops playing. (if played) + * Stops play() and playRing(), does not stop playShortSound() + */ + stop() { + this.useAudioElement ? this._stop1() : this._stop2(); + } + + /* + * For independent of play(), playRing() and stop() usage. + * Cannot be stopped. + */ + playShortSound(options) { + if (!this.audioCtx) + return Promise.reject('No audio context'); + return this.useAudioElement ? this._playShortSound1(options) : this._playShortSound2(options); + } + + /* + HTMLAudioElement implementation + */ + _downloadSound1(name, file) { + let audioElem = new Audio(file); + this.sounds[name] = { + audioElem: audioElem, + deviceId: '', // associated device id + source: null, // linked MediaElementSource + streamDestination: null // linked StreamDestination + }; + return new Promise((resolved, rejected) => { + audioElem.oncanplaythrough = resolved; + if (['safari', 'safari|ios'].includes(this.browser)) { + audioElem.oncanplay = resolved; + audioElem.onloadedmetadata = resolved; + } + audioElem.onerror = rejected; + }); + } + + _generateTone1(toneName, toneDefinition) { + return this._generateTone(toneDefinition) + .then(data => { + let audioElem = new Audio(); + let blob = this._createBlob1(data); + audioElem.src = URL.createObjectURL(blob); + this.sounds[toneName] = { + audioElem: audioElem, + deviceId: '', // associated device id + source: null, + streamDestination: null + }; + }); + } + + // Convert AudioBuffer to WAV Blob. + // Thanks to https://github.com/mattdiamond/Recorderjs MIT lisence + _createBlob1(audioBuffer) { + function writeString(view, offset, string) { + for (let i = 0; i < string.length; i++) { + view.setUint8(offset + i, string.charCodeAt(i)) + } + } + function floatTo16BitPCM(output, offset, input, k) { + for (let i = 0; i < input.length; i++, offset += 2) { + let v = input[i] / k; + let s = Math.max(-1, Math.min(1, v)) + output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true) + } + } + function normalize(input) { + let max = 0, min = 0; + for (let i = 0; i < input.length; i++) { + let v = input[i]; + max = Math.max(max, v) + min = Math.min(min, v) + } + return (max - min) / 2; + } + let samples = audioBuffer.getChannelData(0); + let sampleRate = audioBuffer.sampleRate; + let format = 1; + let bitDepth = 16; + let bytesPerSample = bitDepth / 8; + let numChannels = 1; + let blockAlign = numChannels * bytesPerSample; + + let buffer = new ArrayBuffer(44 + samples.length * bytesPerSample); + let view = new DataView(buffer); + + writeString(view, 0, 'RIFF'); + view.setUint32(4, 36 + samples.length * bytesPerSample, true); + writeString(view, 8, 'WAVE'); + writeString(view, 12, 'fmt '); + view.setUint32(16, 16, true); + view.setUint16(20, format, true); + view.setUint16(22, numChannels, true); + view.setUint32(24, sampleRate, true); + view.setUint32(28, sampleRate * blockAlign, true); + view.setUint16(32, blockAlign, true); + view.setUint16(34, bitDepth, true); + writeString(view, 36, 'data'); + view.setUint32(40, samples.length * bytesPerSample, true); + let k = normalize(samples); + floatTo16BitPCM(view, 44, samples, k); + return new Blob([buffer], { type: "audio/wav" }); + } + + _play1(options) { + this.logger(`AudioPlayer2 [AudioElement]: play: ${JSON.stringify(options)}`); + return this._play1_impl(options, 'sound', this.speakerDeviceId); + } + + _playRing1(options) { + if (!this.ringerDeviceId) + return Promise.resolve(); + this.logger(`AudioPlayer2 [AudioElement]: playRing: ${JSON.stringify(options)}`); + return this._play1_impl(options, 'ringer', this.ringerDeviceId); + } + + _playShortSound1(options) { + return this._play1_impl(options, 'ssound', this.speakerDeviceId); + } + + _play1_impl(options, sname, deviceId) { + this._silentStop1(this[sname]); + + let sound = this[sname] = this.sounds[options.name]; + if (!sound) { + this.logger(`AudioPlayer2 [AudioElement]: missed sound: "${options.name}"`); + return Promise.reject(); + } + if (sound.source) { + this.logger(`AudioPlayer2 [AudioElement]: sound "${options.name}" was used for streaming`); + return Promise.reject(); + } + + return Promise.resolve() + .then(() => { + if (deviceId !== undefined && sound.audioElem.setSinkId !== undefined) { + if (sound.deviceId === deviceId) { + return Promise.resolve(); + } else { + this.logger(`AudioPlayer2 [AudioElement]: "${options.name}": setSinkId deviceId="${deviceId}"`); + return sound.audioElem.setSinkId(deviceId); + } + } else { + return Promise.resolve(); + } + }) + .then(() => { + sound.deviceId = deviceId; + }) + .catch((e) => { + // Sometimes there is Chrome error: 'The operation could not be performed and was aborted' + this.logger(`AudioPlayer2 [AudioElement]: HTMLAudioElement.setSinkId error "${e.message}" [used default speaker]`); + }) + .then(() => { + sound.audioElem.volume = options.volume !== undefined ? options.volume : 1.0; + sound.audioElem.loop = !!options.loop && options.repeat === undefined; + let repeat = options.repeat !== undefined ? options.repeat : 1; + + return new Promise((resolve) => { + sound.audioElem.onended = () => { + if (--repeat > 0 && this[sname]) { + sound.audioElem.currentTime = 0; + sound.audioElem.play() + .catch((e) => { + this.logger('AudioPlayer2 [AudioElement]: play error', e); + }); + } else { + resolve(); + } + } + sound.audioElem.currentTime = 0; + sound.audioElem.play() + .catch((e) => { + this.logger('AudioPlayer2 [AudioElement]: play error', e); + }); + }); + }); + } + + _playStream1(options, streamDestination) { + this.logger(`AudioPlayer2 [AudioElement]: play stream: ${JSON.stringify(options)}`); + this._silentStop1(this.sound); + this.sound = this.sounds[options.name]; + if (!this.sound) { + this.logger(`AudioPlayer2 [AudioElement]: missed media file: "${options.name}"`); + return Promise.reject(); + } + + return new Promise((resolve) => { + this.sound.audioElem.volume = options.volume !== undefined ? options.volume : 1.0; + this.sound.audioElem.loop = !!options.loop && options.repeat === undefined; + let repeat = options.repeat !== undefined ? options.repeat : 1; + + this.sound.audioElem.onended = () => { + if (--repeat > 0 && this.sound) { + this.sound.audioElem.currentTime = 0; + this.sound.audioElem.play() + .catch((e) => { + this.logger('AudioPlayer2 [AudioElement]: streaming error', e); + }); + } else { + this.logger('AudioPlayer2 [AudioElement]: stopped'); + resolve(); + } + } + this.sound.audioElem.currentTime = 0; + // It's workaround of the issue: https://bugs.chromium.org/p/chromium/issues/detail?id=429204 + // (The Audio cannot be used in createMediaElementSource again) + if (!this.sound.source) { + this.sound.source = this.audioCtx.createMediaElementSource(this.sound.audioElem); + } + this.sound.streamDestination = streamDestination; + this.sound.source.connect(this.sound.streamDestination); + this.sound.audioElem.play() + .catch((e) => { + this.logger('AudioPlayer2 [AudioElement]: streaming error', e); + }); + }); + } + + _stop1() { + this.logger('AudioPlayer2 [AudioElement]: stop'); + this._silentStop1(this.sound); + this.sound = null; + this._silentStop1(this.ringer); + this.ringer = null; + } + + _silentStop1(sound) { + if (!sound) + return; + + sound.audioElem.pause(); + + if (sound.source) { + try { + sound.source && sound.source.disconnect(); + sound.streamDestination && sound.streamDestination.disconnect(); + sound.streamDestination = null; + } catch (e) { + this.logger('AudioPlayer2 [AudioElement]: disconnect AudioContext error', e); + } + } + } + + /* + AudioContext implementation + */ + _downloadSound2(name, file) { + return fetch(file, { credentials: 'same-origin' }) + .then(response => { + if (response.status >= 200 && response.status <= 299) + return response.arrayBuffer() + .catch(() => { + throw 'download body error'; + }); + throw response.status === 404 ? 'file not found' : 'download error'; + }) + .then(data => { + return this.audioCtx.decodeAudioData(data) + .catch(() => { + throw 'decoding error'; + }); + }) + .then(decodedData => { + this.sounds[name] = { + data: decodedData, + source: null, + gain: null, + streamDestination: null + }; + }) + .catch(e => { + this.logger('AudioPlayer2 [AudioContext]: ' + e + ': ' + file); + }); + } + + _generateTone2(toneName, toneDefinition) { + return this._generateTone(toneDefinition) + .then(data => { + if (data) { + this.sounds[toneName] = { + data: data, + source: null, + gain: null, + streamDestination: null, + }; + } + }) + } + + _play2(options, streamDestination = null) { + this.logger(`AudioPlayer2 [AudioContext]: ${streamDestination ? 'playStream' : 'play'}: ${JSON.stringify(options)}`); + this._silentStop2(this.sound); + let sound = this.sounds[options.name]; + if (!sound) { + this.logger(`AudioPlayer2 [AudioContext]: missed media: "${options.name}"`); + return Promise.reject(); + } + this.sound = sound = Object.assign({}, sound); + + return new Promise((resolve, reject) => { + try { + sound.source = this.audioCtx.createBufferSource(); + sound.source.buffer = sound.data; + + sound.source.onended = () => { + this.logger(`AudioPlayer2 [AudioContext]: onended ${options.name}`); + this._silentStop2(sound); + resolve(true); + } + sound.source.onerror = () => { + this.logger(`AudioPlayer2 [AudioContext]: onerror ${options.name}`); + this._silentStop2(sound); + reject(new Error('onerror callback')); + } + + sound.gain = this.audioCtx.createGain(); + let volume = options.volume ? options.volume : 1.0; + sound.gain.gain.setValueAtTime(volume, this.audioCtx.currentTime); + sound.source.connect(sound.gain); + if (streamDestination) { + sound.streamDestination = streamDestination; + sound.gain.connect(sound.streamDestination); + } else { + sound.streamDestination = null; + sound.gain.connect(this.audioCtx.destination); + } + + if (options.loop === true || options.repeat) { + sound.source.loop = true; + sound.source.loopStart = 0; + } + + let duration = null; + if (options.repeat) { + duration = this.sound.source.buffer.duration * options.repeat; + } + + sound.source.start(0, 0); + if (duration) + sound.source.stop(this.audioCtx.currentTime + duration); + } catch (e) { + this.logger('AudioPlayer2 [AudioContext]: play error', e); + this._silentStop2(sound); + reject(e); + } + }); + } + + _playShortSound2(options) { + let source; + let gain; + function release() { + try { + source && source.stop(); + gain && gain.disconnect(); + source && source.disconnect(); + } catch (e) { + this.logger('AudioPlayer [AudioContext]: playShortSound: release error', e); + } + } + return new Promise((resolve, reject) => { + try { + let sound = this.sounds[options.name]; + if (!sound) { + `AudioPlayer2 [AudioContext]: playShortSound: no sound: "${options.name}"` + reject('No sound'); + return; + } + source = this.audioCtx.createBufferSource(); + source.buffer = sound.data; + source.onended = () => { + release(); + resolve(); + } + source.onerror = (e) => { + release(); + reject(e); + } + gain = this.audioCtx.createGain(); + let volume = options.volume ? options.volume : 1.0; + gain.gain.setValueAtTime(volume, this.audioCtx.currentTime); + source.connect(gain); + gain.connect(this.audioCtx.destination); + source.start(); + } catch (e) { + this.logger('AudioPlayer [AudioContext]: playShortSound error', e); + reject(e); + } + }); + } + + _stop2() { + this.logger('AudioPlayer2 [AudioContext]: stop'); + this._silentStop2(this.sound); + this.sound = null; + } + + _silentStop2(sound) { + if (!sound || !sound.source) { + return; + } + try { + sound.source && sound.source.stop(); + } catch (e) { + } + + try { + sound.gain && sound.gain.disconnect(); + sound.source && sound.source.disconnect(); + sound.streamDestination && sound.streamDestination.disconnect(); + sound.gain = null; + sound.source = null; + sound.streamDestination = null; + } catch (e) { + this.logger('AudioPlayer2 [AudioContext]: release resources error', e); + } + } + + /* + Used in both implementations + */ + // for Safari + _setDecodeAudioDataShim(audioCtx) { + let origDecodeAudioData = audioCtx.decodeAudioData; + audioCtx.decodeAudioData = (data) => new Promise((resolve, reject) => { + origDecodeAudioData.call(audioCtx, data, (d) => resolve(d), (e) => reject(e)) + }); + } + + // for Safari + _setStartRenderingShim(offlineCtx) { + let origStartRendering = offlineCtx.startRendering; + offlineCtx.startRendering = () => new Promise((resolve) => { + offlineCtx.oncomplete = (e) => { resolve(e.renderedBuffer); } + origStartRendering.call(offlineCtx); + }); + } + + _generateTone(toneDefinition) { + function getArray(e) { + if (e === undefined) return []; + if (Array.isArray(e)) return e; + return [e]; + } + try { + let duration = 0; + let oscillatorNumber = 0; + for (let step of toneDefinition) { + duration += step.t; + oscillatorNumber = Math.max(oscillatorNumber, getArray(step.f).length); + } + let channels = 1; + let sampleRate = this.audioCtx.sampleRate; + let frameCount = sampleRate * duration; + let offlineCtx = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(channels, frameCount, sampleRate); + if (this.browser === 'safari' || this.browser === 'safari|ios') + this._setStartRenderingShim(offlineCtx); + + let oscillators = new Array(oscillatorNumber); + for (let i = 0; i < oscillators.length; i++) { + oscillators[i] = offlineCtx.createOscillator(); + oscillators[i].connect(offlineCtx.destination); + } + + let time = 0; + for (let i = 0, num = toneDefinition.length; i < num; i++) { + let step = toneDefinition[i]; + let frequencies = getArray(step.f); + for (let j = 0; j < oscillators.length; j++) { + let f = (j < frequencies.length) ? frequencies[j] : 0; + oscillators[j].frequency.setValueAtTime(f, offlineCtx.currentTime + time); + } + time += step.t; + } + + for (let o of oscillators) { + o.start(0); + o.stop(offlineCtx.currentTime + duration); + } + + return offlineCtx.startRendering() + .then(renderedBuffer => { + for (let o of oscillators) + o.disconnect(); + return renderedBuffer; + }); + } catch (e) { + this.logger('AudioPlayer2: cannot generate tone', e); + return Promise.reject(e); + } + } +} + +/* + * Recording audio/video. + * For modern browsers only. Used MediaRecorder API. + * Can be used in Chrome, Edge, Firefox and Safari + */ +class MRecorder { + constructor() { + this.logger = null; + this.audioCtx = null; + this.chunks = []; + this.recorder = null; + this.browser = this._browser(); + this.defaultOptions = { + 'chrome': { + audio: { mimeType: 'audio/webm;codec=opus' }, + /* + Chrome 91 mediaRecorder + + Not supported: + video: { mimeType: 'video/mp4;codecs=h264,opus' } + video: { mimeType: 'video/webm;codecs=av1x,opus' } // Could be supported in the future. + + Supported: + video: { mimeType: 'video/webm;codecs=avc1,opus' } // CodecID: V_MPEG4/ISO/AVC It's H264 + video: { mimeType: 'video/webm;codecs=h264,opus' } // CodecID: V_MPEG4/ISO/AVC It's H264 + video: { mimeType: 'video/webm;codecs=vp8,opus' } // CodecID: V_VP8 + video: { mimeType: 'video/webm;codecs=vp9,opus' } // CodecID: V_VP9 + */ + video: { mimeType: 'video/webm;codecs=vp8,opus' } + }, + 'firefox': { + audio: { mimeType: 'audio/webm;codec=opus' }, + video: { mimeType: 'video/webm;codecs=vp8,opus' } + }, + 'safari': { + audio: { mimeType: 'audio/mp4' }, + video: { mimeType: 'video/mp4' }, + }, + 'ios_safari': { + audio: { mimeType: 'audio/mp4' }, + video: { mimeType: 'video/mp4' }, + }, + 'other': { + audio: { mimeType: 'audio/webm' }, + } + }[this.browser]; + this.selectedOptions = null; + } + + _browser() { + if (/iPad|iPhone|iPod/.test(navigator.userAgent)) + return 'ios_safari'; + if (navigator.mozGetUserMedia) + return 'firefox'; + if (navigator.webkitGetUserMedia) // Work only for secure connection + return 'chrome'; + if (window.safari) + return 'safari'; + return 'other'; + } + + init(logger, audioCtx) { + this.logger = logger; + this.audioCtx = audioCtx; + } + + isRecording() { + return this.recorder && this.recorder.state === 'recording'; + } + + recordStream(stream, options) { + this.logger(`MRecorder: recordStream()`); + this.create(stream, options); + return this.start() + .then(blob => { + this.closeStream(); + return blob; + }); + } + + static canBeUsed() { + return typeof MediaRecorder === 'function'; + } + + /** + * To record only audio from audio/video stream use: + * stream = new MediaStream(stream.getAudioTracks()); + * + * To set non-default browser codecs use: + * options = { mimeType: 'video/webm;codecs=vp9,opus' }; + */ + create(stream, options = null) { + let isVideo = stream.getVideoTracks().length > 0; + if (!options && isVideo && !this.defaultOptions.video) { + isVideo = false; + this.logger(`Warning: video mime undefined for ${this.browser}, records audio only`); + } + if (!options) { + options = isVideo ? this.defaultOptions.video : this.defaultOptions.audio; + } + this.selectedOptions = options; + this.logger(`MRecorder recorded ${isVideo ? '"video"' : '"audio"'}. Options: ${JSON.stringify(this.selectedOptions)}`); + this.recorder = new MediaRecorder(stream, this.selectedOptions); + } + + start() { + return new Promise((resolve, reject) => { + this.chunks = []; + this.recorder.ondataavailable = (e) => { + this.chunks.push(e.data); + }; + this.recorder.onerror = (e) => { + reject(e); + } + this.recorder.onstop = () => { + this.logger(`MRecorder: create blob`); + resolve(new Blob(this.chunks, { type: this.selectedOptions.mimeType })); + this.chunks = []; + }; + this.recorder.start(); + }); + } + + stop() { + if (!this.recorder || this.recorder.state !== 'recording') + return; + this.logger('MRecorder: stop'); + this.recorder.stop(); + } + + closeStream() { + for (let track of this.recorder.stream.getTracks()) + track.stop(); + } +} + +/** + * Automatic answering machine. + * Play greeting, record answer. + */ +class AnsweringMachine { + constructor() { + this.use = true; + this.startDelay = 16; + this.recordDuration = 20; + this.run = false; + this.logger = null; + this.call = null; + this.streamDest = null; + this.answerTimer = null; + this.recordingTimer = null; + this.audioPlayer = null; + this.recorder = null; + this.logger = null; + } + + init(audioPlayer, recorder) { + this.audioPlayer = audioPlayer; + this.logger = audioPlayer.logger; + this.recorder = recorder; + } + + startTimer(call, answerCallback) { + this.call = call; + this.stopTimer(); + this.answerTimer = setTimeout(() => { + this.run = true; + answerCallback(); + }, this.startDelay * 1000); + } + + stopTimer() { + if (this.answerTimer !== null) { + clearTimeout(this.answerTimer); + this.answerTimer = null; + } + } + + setStreamDestination(streamDest) { + this.streamDest = streamDest; + } + + // Called if a call is terminated. + stop(call) { + if (call === this.call) { + this.stopTimer(); + this.recorder.stop(); + if (this.recordingTimer !== null) { + clearTimeout(this.recordingTimer); + this.recordingTimer = null; + } + this.run = false; + } + } + + // Use destination stream, instead speaker. + playGreeting() { + return this.audioPlayer.play({ + name: 'greeting', + volume: 1.0, + startDelay: 1.6 + }, this.streamDest) + .then(() => { + return this.audioPlayer.play({ + name: 'beep', + volume: 0.2, + }, this.streamDest); + }) + } + + // Record remote stream of the call. + recordAnswer(remoteStream) { + this.recorder.create(remoteStream); + + this.recordingTimer = setTimeout(() => { + this.logger('AnsweringMachine: maximum recording time reached.'); + this.recorder.stop(); + }, this.recordDuration * 1000); + + return this.recorder.start() + .then(blob => { + this.run = false; + return blob; + }); + } +} + +/** + * SIP Alert-Info header parser. + * + * Alert-Info = "Alert-Info" HCOLON alert-param *(COMMA alert-param) + * alert-param = LAQUOT absoluteURI RAQUOT *( SEMI generic-param ) + */ +class AlertInfo { + constructor(incomingMsg) { + this.parsed = []; + try { + for (let hh of incomingMsg.getHeaders('alert-info')) { + for (let h of hh.split(',')) { + this._parseHeader(h); + } + } + } catch (e) { + console.log('Alert-Info parsing error', e); + } + } + + _parseHeader(h) { + let st = h.split(';'); + let url; + let pr_st = 0; + if (st[0].startsWith('<') && st[0].endsWith('>')) { + url = st[0].slice(1, -1); + pr_st = 1; + } + let params = new Map(); + for (let pr of st.slice(pr_st)) { + let eq = pr.indexOf('='); + if (eq !== -1) { + let k = pr.substring(0, eq); + let v = pr.substring(eq + 1); + if (v.startsWith('"') && v.endsWith('"')) + v = v.slice(1, -1); + params.set(k.toLowerCase(), v.toLowerCase()); + } + } + this.parsed.push({ url: url, params: params }); + } + + exists() { + return this.parsed.length > 0; + } + + param(key, ix = 0) { + if (ix >= this.parsed.length) + return null; + return this.parsed[ix].params.get(key) + } + + url(ix = 0) { + return this.parsed[ix].url; + } + + getDelay(ix = 0) { + let delay = this.param('delay', ix); + if (!delay) + return -1; + return parseInt(delay); + } + + hasAutoAnswer(ix = 0) { + return this.param('info', ix) === 'alert-autoanswer'; + } +} + +/* + * AudioCodes X-VoiceQuality header parser + */ +function getXVoiceQuality(request) { + let header = request.getHeader('X-VoiceQuality'); + if (!header) { + return undefined; + } + let words = header.trim().split(' '); + if (words.length !== 2) { // should be 2 tokens. + console.log('X-VoiceQuality header: parsing problem: must be 2 tokens'); + return undefined; + } + let score = parseInt(words[0]); + if (isNaN(score)) { + console.log('X-VoiceQuality header: parsing problem: the first token is not number'); + return undefined; + } + let color = words[1].trim().toLowerCase(); + return { score, color }; +} + +/** + * Audio mixer (for audio conference) + */ +class CallAudioMixer { + // For each call created audio mixer instance. + // Аudio context can be taken from audio player + constructor(audioCtx, call) { + this.audioCtx = audioCtx; + this.dest = this.audioCtx.createMediaStreamDestination(); + this.calls = []; + let source = this.audioCtx.createMediaStreamSource(call.getRTCLocalStream()); + source.connect(this.dest); + this.calls.push({ call, source }); + } + + // Close mixer, release all resources. + close() { + if (this.dest !== null) { + this.dest.disconnect(); + this.dest = null; + } + for (let c of this.calls) { + c.source.disconnect(); + } + this.calls = []; + } + + // Get mixed audio stream + getMix() { return this.dest.stream; } + + // Add call to mixer. + // Returns true if added, false if the call is already added. + add(call) { + let ix = this.calls.findIndex(c => c.call === call); + if (ix !== -1) + return false; + let stream = call.getRTCRemoteStream(); + let source = this.audioCtx.createMediaStreamSource(stream); + source.connect(this.dest); + this.calls.push({ call, source }); + return true; + } + + // Remove call from mixer + // Returns true if removed. + // Returns false, if the call was not added, or cannot be removed, because set in constructor. + remove(call) { + let ix = this.calls.findIndex(c => c.call === call); + if (ix === -1 || ix === 0) + return false; + this.calls[ix].source.disconnect(); + this.calls.splice(ix, 1); + return true; + } + + // Returns string with calls list + toString() { return 'audio mixer ' + this.calls.map((c) => c.call.data['_line_index'] + 1); } +} + +/** + * Video mixer (for video conference) + */ +class CallVideoMixer { + // Used single instance for all calls. + constructor() { + this.layout = 'compact'; + this.run = false; + this.calls = []; + this.localVideo = null; + this.canvas = null; + this.canvasCtx = null; + this.canvasBackground = "#F5F5F5"; // light smoke + this.width = 160; + this.height = 120; + this.nVideo = 0; + this.drawInterval = 100; + this.remoteVideoId = ''; + this.frame = 1; + this.data = {}; + } + + // Set canvas id. + // Set local video element id. + // Set remote video element id prefix. (will be added video element index 0, 1, ...) + setElements(canvasId, localVideoId, remoteVideoId) { + this.canvas = document.getElementById(canvasId); + this.canvasCtx = this.canvas.getContext('2d'); + this.localVideo = document.getElementById(localVideoId); + this.remoteVideoId = remoteVideoId; + } + + // Set number of frames per seconds of mixed stream. + // For example: 1, 2, 5, 10, 20, 50. + // Default: 10 + setFPS(v) { this.setDrawInterval(1000 / v); } + + // Set interval between draw (milliseconds) + // Default: 100 + // It can be set also via setFPS + setDrawInterval(v) { this.drawInterval = v; } + + // Set calls video layout: 'linear' or 'compact' + // Default: 'compact' + setLayout(v) { + switch (v) { + case 'linear': + case 'compact': + this.layout = v; + break; + default: + throw new TypeError(`Unknown layout: ${v}`); + } + this.resize(); + } + + // Set call video size (pixels) + // Default w=160, h=120 + setSize(w, h) { + this.width = w; + this.height = h; + this.resize(); + } + + // Set call video sizes (pixels) + // size likes: {width: '160px', height: '120px'} + setSizes(size) { // format {width: '160px', height: '120px'} + let w = parseInt(size.width.slice(0, -2)); + let h = parseInt(size.height.slice(0, -2)); + this.setSize(w, h); + } + + // Returns true when mixer is started + isOn() { return this.run; } + + // Start mixer + start() { + if (this.run) + return; + setTimeout(this._draw.bind(this), this.drawInterval); + this.run = true; + } + + // Stop mixer, remove all calls, release resources. + // After using stop the mixer can be restarted. + stop() { + while (this.calls.length > 0) + this.remove(this.calls[0].call); + this.run = false; + } + + // Get mixed video stream for added call. + getMix(call) { + let ix = this.calls.findIndex(d => d.call === call); + return (ix !== -1) ? this.calls[ix].mix : null; + } + + // Add call to mixer or update send/receive mode. + // Returns true if send video was added (should be replaced connection sender track) + add(call, send = true, receive = true) { + let ix = this.calls.findIndex(d => d.call === call); + if (ix === -1) { + return this._add(call, send, receive); + } else { + return this._update(ix, send, receive); + } + } + + _add(call, send, receive) { + let mix = send ? this.canvas.captureStream() : null; + let elt = receive ? document.getElementById(this.remoteVideoId + call.data['_line_index']) : null; + let x = 0; + let y = 0; + this.calls.push({ call, elt, mix, x, y }); + if (elt !== null) + this.resize(); + return mix !== null; + } + + _update(ix, send, receive) { + let d = this.calls[ix]; + let sendModified = false; + if (send) { + if (d.mix === null) { + d.mix = this.canvas.captureStream(); + sendModified = true; + } + } else { + if (d.mix !== null) { + for (let track of d.mix.getVideoTracks()) + track.stop(); + d.mix = null; + sendModified = true; + } + } + if (receive) { + if (d.elt === null) { + d.elt = document.getElementById(this.remoteVideoId + d.call.data['_line_index']); + this.resize(); + } + } else { + if (d.elt !== null) { + d.elt = null; + this.resize(); + } + } + return sendModified; + } + + // Remove call from mixer. + // Returns true if removed, false if was not added. + remove(call) { + let ix = this.calls.findIndex(d => d.call === call); + //console.log('video mixer: remove call with index=', call.data['_line_index'], ix); + if (ix === -1) + return false; + let d = this.calls[ix]; + if (d.mix !== null) { + for (let track of d.mix.getVideoTracks()) + track.stop(); + } + this.calls.splice(ix, 1); + if (d.elt !== null) + this.resize(); + return true; + } + + // number of video displayed in canvas + _nVideo() { + let n = 0; + if (this.localVideo.srcObject !== null) + n++; + for (let d of this.calls) + if (d.elt !== null) + n++; + return n; + } + + // Resize video layout then changed number of video channels + // Used when added/removed local video channel. + // Called automatically in methods: add, remove, setLayout, setSize + // + // Warning: it's designed for 5 lines phone ! + // Max number of video controls is 6 (including local video) + // If you use more lines, please modify this method. + // + // Video layouts + // linear 0 1 0 1 2 0 1 2 3 0 1 2 3 4 .... + // + // compact 0 1 0 1 0 1 0 1 2 0 1 2 + // 2 2 3 3 4 3 4 5 + resize() { + this.nVideo = this._nVideo(); // number of shown video + //console.log(`videoMixer: resize nVideo=${this.nVideo} [${this.localVideo.srcObject !== null ? 'with local':'without local'} video]`); + switch (this.layout) { + case 'linear': + this.canvas.width = (this.width + this.frame) * this.nVideo; + this.canvas.height = this.height; + break; + case 'compact': + if (this.nVideo <= 2) { + this.canvas.width = (this.width + this.frame) * this.nVideo; + this.canvas.height = this.height; + } else if (this.nVideo <= 4) { + this.canvas.width = (this.width + this.frame) * 2; + this.canvas.height = this.height * 2 + this.frame; + } else { + this.canvas.width = this.width * 3; + this.canvas.height = this.height * 2 + this.frame; + } + break; + } + + this.canvasCtx.fillStyle = this.canvasBackground; + this.canvasCtx.fillRect(0, 0, this.canvas.width, this.canvas.height); + + // sort calls by line index + this.calls.sort((d1, d2) => d1.call.data['_line_index'] - d2.call.data['_line_index']); + + // reorder pictures in canvas + let ix = 0; + if (this.localVideo.srcObject !== null) + ix++; + for (let d of this.calls) { + if (d.elt !== null) { + let [x, y] = this._location(ix); + d.x = x; + d.y = y; + ix++; + } + } + } + + // Calculate video picture location by index. + // + // Warning: it's designed for 5 lines phone ! + // Max number of video controls is 6 (including local video) + // If you use more lines, modify this method + _location(ix) { + let w = this.width + this.frame; + let h = this.height + this.frame; + switch (this.layout) { + case 'linear': + return [ix * w, 0]; + case 'compact': + switch (this.nVideo) { + case 0: + case 1: + case 2: + return [ix * w, 0]; + case 3: + return (ix < 2) ? [w, 0] : [w * (ix - 2) + 0.5 * w, h]; + case 4: + return (ix < 2) ? [w, 0] : [w * (ix - 2), h]; + case 5: + return (ix < 3) ? [w * ix, 0] : [w * (ix - 3) + 0.5 * w, h]; + case 6: + return (ix < 3) ? [w * ix, 0] : [w * (ix - 3), h]; + } + } + } + + _draw() { + if (!this.run) + return; + try { + if (this.nVideo > 0) { + if (this.localVideo.srcObject !== null) + this.canvasCtx.drawImage(this.localVideo, 0, 0, this.width, this.height); + for (let d of this.calls) { + if (d.elt !== null) + this.canvasCtx.drawImage(d.elt, d.x, d.y, this.width, this.height); + } + } + } catch (e) { + console.log(e); + } + setTimeout(this._draw.bind(this), this.drawInterval); + } + + // Returns string with calls list + toString() { + if (this.run) { + return 'video mixer ' + this.calls.map((c) => `${c.call.data['_line_index'] + 1}${c.mix !== null ? 's' : ''}${c.elt !== null ? 'r' : ''}`); + } else { + return 'video mixer is off'; + } + } +} + +// Dynamically load arbitrary javascript +function loadJavaScript(url) { + return new Promise((resolve, reject) => { + let script = document.createElement('script'); + script.onload = resolve; + script.onerror = reject; + script.src = url; + document.head.appendChild(script); + }); +} + +/** + * Enumerate available devices: microphones, cameras, speakers (only Chrome provides speakers). + * Allow select devices, save the selection to local storage. + * Restore the device selection in the next sessions. + * + * Selected microphone and camera used in getUserMedia method as deviceId constraint. + * Selected speaker and ringer associated with HTMLAudioElement by setSinkId method (only in Chrome). + */ +class SelectDevices { + // Parameters can be modified before enumerate() method. + constructor() { + this.defaultPseudoDevice = true; + this.names = []; + this.enumerateDevices = AudioCodesUA.instance.getWR().mediaDevices.enumerateDevices; // enumerate devices function. + this.browserDefaultLabel = '-- browser default--'; // default pseudo device - means do not use deviceId and sinkId + this.emptyLabel = '-- no label --'; // for label = '' in incomplete device list + this.previousSelection = null; // device selection from local storage + } + + setDevices(defaultPseudoDevice, devices) { + this.defaultPseudoDevice = defaultPseudoDevice; + this.names = []; + for (let device of devices) { + if (!['audioinput', 'audiooutput', 'videoinput'].includes(device.kind)) + throw new TypeException(`Illegal kind: ${device.kind}`) + this.names.push(device.name); + this[device.name] = { kind: device.kind }; + } + } + + setEnumerateDevices(method) { + this.enumerateDevices = method; + } + + enumerate(useGetUserMediaIfNeed) { + let stream = null; + let incomplete = false; + return Promise.resolve() + .then(() => + this.doEnumerate()) + .then((inc) => { + incomplete = inc; + if (incomplete && useGetUserMediaIfNeed) { + return AudioCodesUA.instance.getWR().getUserMedia({ audio: true, video: true }); + } else { + return Promise.resolve(null); + } + }) + .then((s) => { + stream = s; + if (stream) { + // For incomplete device list repeat with open stream. + return this.doEnumerate(); + } + }) + .then(() => { + if (stream) { + incomplete = false; + stream.getTracks().forEach(track => track.stop()); + } + }) + .then(() => { + // Restore previous selection. + if (this.previousSelection) { + for (let name of this.names) { + if (!this.findPreviousSelection(name)) { + if (incomplete) + this.addPreviousSelection(name); + } + } + } + }); + } + + // Without open stream by getUserMedia (or without permission to use microphone/camera) + // device list will be incomplete: + // some devices will be with empty string label, some devices can be missed. + doEnumerate() { + let incomplete = false; // exists incomplete device lists + let emptyLabel = this.emptyLabel; + + function setLabel(device, str) { + if (str) + return str; + incomplete = device.incomplete = true; + return emptyLabel; + } + + // reset device list and selection index. + for (let name of this.names) { + let device = this.getDevice(name); + device.incomplete = false; + if (this.defaultPseudoDevice) { + device.index = 0; // selected browser default pseudo-device. + device.list = [{ deviceId: null, label: this.browserDefaultLabel }]; + } else { + device.index = -1; // device is not selected. + device.list = []; + } + } + + return this.enumerateDevices() + .then((infos) => { + for (let info of infos) { + for (let name of this.names) { + let device = this.getDevice(name); + if (info.kind === device.kind) { + device.list.push({ deviceId: info.deviceId, label: setLabel(device, info.label) }) + } + } + } + }) + .then(() => { + return incomplete; + }); + } + + // Select device using previously saved device label + findPreviousSelection(name) { + let device = this.getDevice(name); + let sel = this.previousSelection && this.previousSelection[name]; + if (!sel || sel.label === this.emptyLabel) + return false; + for (let ix = 0; ix < device.list.length; ix++) { + if (device.list[ix].label === sel.label) { + device.index = ix; + return true; + } + } + return false; + } + + // Without open stream by getUserMedia enumerate devices provides incomplete device list. + // In the case we add previously selected device to the incomplete list. + // Problem: previously used USB or bluetooth headset/camera could be disconnected. + addPreviousSelection(name) { + let device = this.getDevice(name); + let sel = this.previousSelection && this.previousSelection[name]; + if (sel && sel.label !== this.browserDefaultLabel && sel.label !== this.emptyLabel) { + AudioCodesUA.ac_log(`devices: added previously selected ${name} "${sel.label}"`); + device.list.push(sel); + device.index = device.list.length - 1; + } + } + + // Returns selected device object { deviceId: '', label: ''} + getDevice(name) { + if (!this[name]) + throw new TypeError(`wrong device name: ${name}`); + return this[name]; + } + + getSelected(name) { + let device = this.getDevice(name); + if (device.list.length === 0 || device.index === -1) // device list is empty or device is not selected + return { deviceId: null, label: this.emptyLabel }; + return device.list[device.index]; + } + + getNumber(name) { + return this.getDevice(name).list.length; + } + + // Set selected by GUI device + setSelectedIndex(name, index) { + let device = this.getDevice(name); + if (index < 0 || index >= device.list.length) + throw new RangeError(`setSelectedIndex ${name} index=${index}`); + device.index = index; + } + + // Store selected devices. Supposed local storage usage. + store() { + this.previousSelection = null; + for (let name of this.names) { + let device = this.getDevice(name); + if (device.list.length === 0 || device.index === -1) + continue; + if (!this.previousSelection) + this.previousSelection = {}; + this.previousSelection[name] = this.getSelected(name); + } + return this.previousSelection; + } + + // Load previously stored selected devices. Can be null if no stored devices. + load(obj) { + this.previousSelection = obj; + } + + // Device connected/removed event + addDeviceChangeListener(listener) { + AudioCodesUA.instance.getWR().mediaDevices.addDeviceChangeListener(listener); + } + + removeDeviceChangeListener(listener) { + AudioCodesUA.instance.getWR().mediaDevices.removeDeviceChangeListener(listener); + } +} diff --git a/js/utils_es5.js b/js/utils_es5.js new file mode 100644 index 0000000..9b3319d --- /dev/null +++ b/js/utils_es5.js @@ -0,0 +1,2455 @@ +'use strict'; + +/* + * The utilities used to build our phone examples. + + * You may consider them an optional part of our SDK. + * You can use them if they are suitable for your project or replace them with other libraries. + * For example instead provided in this file AudioPlayer you may use other audio library, + * instead storageLoadConfig other library to work with local storage, etc. + * + * Load/save configuration from/to local storage + * - storageLoadConfig + * - storageSaveConfig + * + * IndexedDB + * - AbstractDb (abstract indexeddb with single store) + * - CallLogDb (call log indexeddb) + * - VoiceDb (recorded voice messages indexeddb) + * - MessageDb (received text messages indexeddb) + * + * Audio, video + * - AudioPlayer2 + * - MRecorder + * - AnsweringMachine + * + * SIP + * - AlertInfo parser + * - XVoiceQuality parser + * + * Conference + * - CallAudioMixer + * - CallVideoMixer + * + * loadJavaScript (dinamically load arbitrary javascript) + * SelectDevices (enumerate and select microphone, camera, speaker) + * + * Igor Kolosov AudioCodes 2022 + * Last edit 11-Aug-2022 + */ + +/** + * Load JSON object from local storage + * + * If object does not exist, will be used default value. + * If object exists, and has version different from default value version, will be used default value. + * + * The version used to override browser local storage value to default value from site. + * + * Example: + * We upgrade in our site phone from version 1.1 to 1.2. + * There are many users of phone version 1.1 in the world and they store some phone configuration + * to browser local storage. + * In phone version 1.2 the construction of the configuration object is different. + * To prevent errors, we should change version of default configuration object in our site, + * it forces to load updated version instead using saved in local storage. + * (See phone prototype config.js) + * + * For debugging can be used storeBack = true, + * to edit stored value via browser dev. tools. + */ +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } +function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } +function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } +function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } +function storageLoadConfig(name) { + var defValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var useLog = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + var storeBack = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + var str_value = localStorage.getItem(name); + var value = null; + var isLoaded = false; + var isReplaced = false; + var isDefault; + if (str_value) { + isLoaded = true; + value = JSON.parse(str_value); + } + if (value === null || defValue !== null && value.version !== defValue.version) { + if (isLoaded) isReplaced = true; + isLoaded = false; + isDefault = true; + if (defValue !== null) value = dataDeepCopy(defValue); + } else { + isDefault = dataEquals(value, defValue); + } + if (useLog) { + console.log('Used %s %s', value !== null ? isDefault ? 'default' : 'custom' : 'null', name); + } + if (value !== null && (isReplaced || storeBack && !isLoaded)) localStorage.setItem(name, JSON.stringify(value)); + return value; +} + +/** + * Save JSON object to local storage. + * + * Default value is optional. + * If it's provided and object has default value, it will be removed from local storage. + */ +function storageSaveConfig(name, value) { + var defValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + if (defValue === null || !dataEquals(value, defValue)) { + if (defValue !== null && defValue.version && !value.version) value.version = defValue.version; + localStorage.setItem(name, JSON.stringify(value)); + } else { + localStorage.removeItem(name); + } +} + +// Objects deep equals +function dataEquals(obj1, obj2) { + if (obj1 === null || obj2 === null) return obj1 === obj2; + for (var p in obj1) { + if (obj1.hasOwnProperty(p) !== obj2.hasOwnProperty(p)) return false; + switch (_typeof(obj1[p])) { + case 'object': + if (!dataEquals(obj1[p], obj2[p])) return false; + break; + case 'function': + // No compare functions. + break; + default: + if (obj1[p] != obj2[p]) return false; + } + } + for (var _p in obj2) { + if (typeof obj1[_p] == 'undefined') return false; + } + return true; +} +function dataDeepCopy(src) { + if (src === null) return null; + var dst = Array.isArray(src) ? [] : {}; + for (var p in src) { + switch (_typeof(src[p])) { + case 'object': + dst[p] = dataDeepCopy(src[p]); + break; + case 'function': + // No copy + break; + default: + dst[p] = src[p]; + break; + } + } + return dst; +} + +/** + * Database with single store and with copy of the store in memory - objects list + * Purpose: make the list persistent. + * Key is part of record, based on current time, unique and has name 'id' + * Number of objects in store is limited, oldest objects will be deleted. + * If needed, additional stores can be added: override open(), + * and use get(), put(), clear(), delete() methods with store name. + */ +var AbstractDb = /*#__PURE__*/function () { + function AbstractDb(dbName, storeName, maxSize) { + _classCallCheck(this, AbstractDb); + this.dbName = dbName; + this.storeName = storeName; + this.maxSize = maxSize; // max number of objects + this.db = null; + this.list = []; // default store copy in memory. + this.idSeqNumber = -1; // to generate unique key. + } + + // Create store unique key. (no more than 1 million in the same millisecond) + // key must be part or record and have name 'id' + _createClass(AbstractDb, [{ + key: "createId", + value: function createId(time) { + this.idSeqNumber = (this.idSeqNumber + 1) % 1000000; // range 0..999999 + return time.toString() + '-' + ('00000' + this.idSeqNumber.toString()).slice(-6); + } + + // Open the database, if needed create it. + }, { + key: "open", + value: function open() { + var _this = this; + return new Promise(function (resolve, reject) { + var r = indexedDB.open(_this.dbName); + r.onupgradeneeded = function (e) { + e.target.result.createObjectStore(_this.storeName, { + keyPath: 'id' + }); + }; + r.onsuccess = function () { + _this.db = r.result; + resolve(); + }; + r.onerror = r.onblocked = function () { + reject(r.error); + }; + }); + } + + // load records to memory, ordered by time, if needed delete oldest records + }, { + key: "load", + value: function load() { + var _this2 = this; + return new Promise(function (resolve, reject) { + if (_this2.db === null) { + reject('db is null'); + return; + } + var trn = _this2.db.transaction(_this2.storeName, 'readwrite'); + trn.onerror = function () { + reject(trn.error); + }; + var store = trn.objectStore(_this2.storeName); + var onsuccess = function onsuccess(list) { + _this2.list = list; + var nDel = _this2.list.length - _this2.maxSize; + if (nDel <= 0) { + resolve(); + } else { + var r = store["delete"](IDBKeyRange.upperBound(_this2.list[nDel - 1].id)); + r.onerror = function () { + reject(r.error); + }; + r.onsuccess = function () { + _this2.list = _this2.list.splice(-_this2.maxSize); + resolve(); + }; + } + }; + var onerror = function onerror(e) { + reject(e); + }; + var getAll = store.getAll ? _this2._getAllBuiltIn : _this2._getAllCursor; + getAll(store, onsuccess, onerror); + }); + } + }, { + key: "_getAllBuiltIn", + value: function _getAllBuiltIn(store, onsuccess, onerror) { + // Chrome, Firefox + var r = store.getAll(); + r.onerror = function () { + return onerror(r.error); + }; + r.onsuccess = function () { + return onsuccess(r.result); + }; + } + }, { + key: "_getAllCursor", + value: function _getAllCursor(store, onsuccess, onerror) { + // Legacy Edge + var list = []; + var r = store.openCursor(); + r.onerror = function () { + return onerror(r.error); + }; + r.onsuccess = function (e) { + var cursor = e.target.result; + if (cursor) { + list.push(cursor.value); + cursor["continue"](); + } else { + onsuccess(list); + } + }; + } + + // Add new record. If needed delete oldest records + }, { + key: "add", + value: function add(record) { + var _this3 = this; + return new Promise(function (resolve, reject) { + if (_this3.db === null) { + reject('db is null'); + return; + } + var trn = _this3.db.transaction(_this3.storeName, 'readwrite'); + trn.onerror = function () { + reject(trn.error); + }; + var store = trn.objectStore(_this3.storeName); + var r = store.add(record); + r.onerror = function () { + reject(r.error); + }; + r.onsuccess = function () { + _this3.list.push(record); + var nDel = _this3.list.length - _this3.maxSize; + if (nDel <= 0) { + resolve(); + } else { + r = store["delete"](IDBKeyRange.upperBound(_this3.list[nDel - 1].id)); + r.onerror = function () { + reject(r.error); + }; + r.onsuccess = function () { + _this3.list = _this3.list.splice(-_this3.maxSize); + resolve(); + }; + } + }; + }); + } + + // Update record with some unique id. + }, { + key: "update", + value: function update(record) { + var index = this.list.findIndex(function (r) { + return r.id === record.id; + }); + if (index == -1) return Promise.reject('Record is not found'); + this.list[index] = record; + return this._exec('put', this.storeName, record); + } + + // Delete record with the key (if store is default delete also from list) + }, { + key: "delete", + value: function _delete(id) { + var storeName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.storeName; + if (storeName === this.storeName) { + var index = this.list.findIndex(function (r) { + return r.id === id; + }); + if (index == -1) return Promise.reject('Record is not found'); + this.list.splice(index, 1); + } + return this._exec('delete', storeName, id); + } + + // Clear all store records + }, { + key: "clear", + value: function clear() { + var storeName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.storeName; + this.list = []; + return this._exec('clear', storeName); + } + }, { + key: "get", + value: function get(key, storeName) { + return this._exec('get', storeName, key); + } + }, { + key: "put", + value: function put(record, storeName) { + return this._exec('put', storeName, record); + } + + // Single transaction operation. + }, { + key: "_exec", + value: function _exec(op, storeName, data) { + var _this4 = this; + return new Promise(function (resolve, reject) { + if (_this4.db === null) { + reject('db is null'); + return; + } + var trn = _this4.db.transaction(storeName, 'readwrite'); + trn.onerror = function () { + reject(trn.error); + }; + var store = trn.objectStore(storeName); + var r; + switch (op) { + case 'clear': + r = store.clear(); + break; + case 'delete': + r = store["delete"](data); + break; + case 'put': + r = store.put(data); + break; + case 'get': + r = store.get(data); + break; + default: + reject('db: wrong request'); + return; + } + r.onerror = function () { + reject(r.error); + }; + r.onsuccess = function () { + resolve(r.result); + }; + }); + } + }]); + return AbstractDb; +}(); +/** + * To keep phone call logs. + */ +var CallLogDb = /*#__PURE__*/function (_AbstractDb) { + _inherits(CallLogDb, _AbstractDb); + var _super = _createSuper(CallLogDb); + function CallLogDb(maxSize) { + _classCallCheck(this, CallLogDb); + return _super.call(this, 'phone', 'call_log', maxSize); + } + return _createClass(CallLogDb); +}(AbstractDb); +/* + * To use with automatic answer machine. Created 2 stores: + * 'records' default store, to save last (up to maxSize) answer records. + * 'greeting' additional store, to save custom greeting. + */ +var VoiceDb = /*#__PURE__*/function (_AbstractDb2) { + _inherits(VoiceDb, _AbstractDb2); + var _super2 = _createSuper(VoiceDb); + function VoiceDb(maxSize) { + _classCallCheck(this, VoiceDb); + return _super2.call(this, 'voice_db', 'records', maxSize); + } + _createClass(VoiceDb, [{ + key: "open", + value: function open() { + var _this5 = this; + return new Promise(function (resolve, reject) { + var r = indexedDB.open(_this5.dbName); + r.onupgradeneeded = function (e) { + e.target.result.createObjectStore(_this5.storeName, { + keyPath: 'id' + }); + e.target.result.createObjectStore('greeting', { + keyPath: 'id' + }); + }; + r.onsuccess = function () { + _this5.db = r.result; + resolve(); + }; + r.onerror = r.onblocked = function () { + reject(r.error); + }; + }); + } + }]); + return VoiceDb; +}(AbstractDb); +/** + * To keep incoming text messages. + */ +var MessageDb = /*#__PURE__*/function (_AbstractDb3) { + _inherits(MessageDb, _AbstractDb3); + var _super3 = _createSuper(MessageDb); + function MessageDb(maxSize) { + _classCallCheck(this, MessageDb); + return _super3.call(this, 'message_db', 'messages', maxSize); + } + return _createClass(MessageDb); +}(AbstractDb); +/* + * AudioPlayer2 + * + * There are audio web API: + * - HTMLAudioElement (Can be associated with speaker. Chrome only) + * - Audio Context. (Uses default speaker) + * + * For most operation systems and browsers HTMLAudioElement is best option. + * The exception is macOS Safari and all iOS browsers (WebKit codebase) + * WebKit HTMLAudioElement is about unusable for our case. + * + * AudioPlayer2 can be configured to use HTMLAudioElement or AudioContext API to + * play sound. + * Both modes used AudioContext API to generate tones and sending audio stream. + * + * Igor Kolosov AudioCodes Ltd 2022 + */ +var AudioPlayer2 = /*#__PURE__*/function () { + function AudioPlayer2() { + _classCallCheck(this, AudioPlayer2); + this.browser = this._browser(); + this.speakerDeviceId = undefined; // undefined - don't use setSinkId, null or string uses setSinkId() + this.ringerDeviceId = undefined; // additional loudspeaker to play rings + this.useAudioElement = undefined; // true/false switch HTMLAudioElement/AudioContext API + this.logger = console.log; + this.sounds = {}; // Sounds + this.sound = null; // Current sound + this.ringer = null; // Ringer sound + this.ssound = null; // Short sound + this.audioCtx = null; + this.dtmfTones = { + '1': [{ + f: [697, 1209], + t: 0.2 + }], + '2': [{ + f: [697, 1336], + t: 0.2 + }], + '3': [{ + f: [697, 1477], + t: 0.2 + }], + '4': [{ + f: [770, 1209], + t: 0.2 + }], + '5': [{ + f: [770, 1336], + t: 0.2 + }], + '6': [{ + f: [770, 1477], + t: 0.2 + }], + '7': [{ + f: [852, 1209], + t: 0.2 + }], + '8': [{ + f: [852, 1336], + t: 0.2 + }], + '9': [{ + f: [852, 1477], + t: 0.2 + }], + '*': [{ + f: [941, 1209], + t: 0.2 + }], + '0': [{ + f: [941, 1336], + t: 0.2 + }], + '#': [{ + f: [941, 1477], + t: 0.2 + }], + 'A': [{ + f: [697, 1633], + t: 0.2 + }], + 'B': [{ + f: [770, 1633], + t: 0.2 + }], + 'C': [{ + f: [852, 1633], + t: 0.2 + }], + 'D': [{ + f: [941, 1633], + t: 0.2 + }] + }; + } + + /** + * User can select API by setting: + * useAudioElement: true + * useAudioElement: false + * useAudioElement: undefined (default) - API selected according using browser: + * used AudioElement API, except macOS Safari and any iOS browsers. + */ + _createClass(AudioPlayer2, [{ + key: "init", + value: function init() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { + logger: null, + audioCtx: null, + useAudioElement: undefined + }; + this.logger = options.logger ? options.logger : console.log; + this.audioCtx = options.audioCtx ? options.audioCtx : new (window.AudioContext || window.webkitAudioContext)(); + if (options.useAudioElement === true || options.useAudioElement === false) this.useAudioElement = options.useAudioElement; // user can select using API. + else + // or API will be selected automatically + this.useAudioElement = !['safari', 'safari|ios'].includes(this.browser); + this.logger("AudioPlayer2: init ".concat(this.useAudioElement ? 'AudioElement' : 'AudioContext', " (").concat(this.browser, ")")); + } + + // Set earpeace device for play(). For AudioElement mode in Chrome + }, { + key: "setSpeakerId", + value: function setSpeakerId(deviceId) { + this.logger("AudioPlayer2: setSpeakerId(".concat(deviceId, ")")); + this.speakerDeviceId = deviceId !== null ? deviceId : ''; + } + + // Set loudspeaker device for playRing(). For AudioElement mode in Chrome + }, { + key: "setRingerId", + value: function setRingerId(deviceId) { + this.logger("AudioPlayer2: setRingerId(".concat(deviceId, ")")); + this.ringerDeviceId = deviceId ? deviceId : null; + } + }, { + key: "_browser", + value: function _browser() { + if (/iPad|iPhone|iPod/.test(navigator.userAgent)) return 'safari|ios'; // all iOS browsers (includes Safari, Chrome or Firefox) + if (navigator.mozGetUserMedia) return 'firefox'; + if (navigator.webkitGetUserMedia) return 'chrome'; + if (window.safari) return 'safari'; + return 'other'; + } + + // To support auto-play policy. + }, { + key: "isDisabled", + value: function isDisabled() { + if (this.audioCtx.state === 'interrupted') this.logger('AudioPlayer2: isDisabled() state = interrupted ! Hello from iOS'); + if (['chrome', 'safari', 'safari|ios'].includes(this.browser)) { + return this.audioCtx.state === 'suspended'; + } else { + return false; + } + } + }, { + key: "enable", + value: function enable() { + if (['chrome', 'safari', 'safari|ios'].includes(this.browser)) { + return this.audioCtx.resume(); + } else { + return Promise.resolve(); + } + } + + /* + * Download MP3 sounds. Resolved when all sounds are loaded + */ + }, { + key: "downloadSounds", + value: function downloadSounds(path, soundList) { + this.logger("AudioPlayer2: downloadSounds ".concat(path, " ").concat(JSON.stringify(soundList))); + if (!this.useAudioElement && ['safari', 'safari|ios'].includes(this.browser)) { + this._setDecodeAudioDataShim(this.audioCtx); + } + var readyList = []; + var _iterator = _createForOfIteratorHelper(soundList), + _step; + try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var sound = _step.value; + var name = void 0, + sname = void 0; + if (typeof sound === 'string') { + name = sname = sound; + } else { + name = Object.keys(sound)[0]; + sname = sound[name]; + } + var file = path + sname + '.mp3'; + readyList.push(this.useAudioElement ? this._downloadSound1(name, file) : this._downloadSound2(name, file)); + } + } catch (err) { + _iterator.e(err); + } finally { + _iterator.f(); + } + return Promise.allSettled(readyList); + } + }, { + key: "generateTonesSuite", + value: function generateTonesSuite(suite) { + this.logger('AudioPlayer2: generateTonesSuite'); + var readyList = []; + for (var _i = 0, _Object$keys = Object.keys(suite); _i < _Object$keys.length; _i++) { + var toneName = _Object$keys[_i]; + var toneDefinition = suite[toneName]; + readyList.push(this.useAudioElement ? this._generateTone1(toneName, toneDefinition) : this._generateTone2(toneName, toneDefinition)); + } + return Promise.allSettled(readyList); + } + + /** + * Play sound in speaker + * + * @param options + * name sound clip name (must be set) + * + * volume = 0 .. 1.0 Default 1.0 (for iOS HTMLAudioElement always 1.0) + * loop = true/false Endless loop + * repeat = number Repeat times + * + * streamDestination (undefined by default), value mediaStreamDestination. + * Assign output to audio stream instead of speaker. + * + * @returns Promise to check when playing is finished. + */ + }, { + key: "play", + value: function play(options) { + var streamDestination = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined; + if (this.isDisabled()) { + this.logger("AudioPlayer2: play: ".concat(JSON.stringify(options), " [Sound is disabled]")); + return Promise.resolve(); + } + if (this.useAudioElement) { + return streamDestination ? this._playStream1(options, streamDestination) : this._play1(options); + } else { + return this._play2(options, streamDestination); + } + } + + /** + * Play ringing additionaly in loudspeaker (if configured) + * + * Note: the same sound name cannot be used in play() and playRing() - + * because for each sound name created own HTMLAudioElement associated with + * speaker. + * So if for play() and playRing() used the same MP3 sound file, + * use it with different sound names. (e.g. 'ring' and 'r_ring' in our examples) + */ + }, { + key: "playRing", + value: function playRing(options) { + if (this.isDisabled()) { + this.logger("AudioPlayer2: playRing: ".concat(JSON.stringify(options), " [Sound is disabled]")); + return Promise.resolve(); + } + return this.useAudioElement ? this._playRing1(options) : Promise.resolve(); + } + + /** + * Stops playing. (if played) + * Stops play() and playRing(), does not stop playShortSound() + */ + }, { + key: "stop", + value: function stop() { + this.useAudioElement ? this._stop1() : this._stop2(); + } + + /* + * For independent of play(), playRing() and stop() usage. + * Cannot be stopped. + */ + }, { + key: "playShortSound", + value: function playShortSound(options) { + if (!this.audioCtx) return Promise.reject('No audio context'); + return this.useAudioElement ? this._playShortSound1(options) : this._playShortSound2(options); + } + + /* + HTMLAudioElement implementation + */ + }, { + key: "_downloadSound1", + value: function _downloadSound1(name, file) { + var _this6 = this; + var audioElem = new Audio(file); + this.sounds[name] = { + audioElem: audioElem, + deviceId: '', + // associated device id + source: null, + // linked MediaElementSource + streamDestination: null // linked StreamDestination + }; + + return new Promise(function (resolved, rejected) { + audioElem.oncanplaythrough = resolved; + if (['safari', 'safari|ios'].includes(_this6.browser)) { + audioElem.oncanplay = resolved; + audioElem.onloadedmetadata = resolved; + } + audioElem.onerror = rejected; + }); + } + }, { + key: "_generateTone1", + value: function _generateTone1(toneName, toneDefinition) { + var _this7 = this; + return this._generateTone(toneDefinition).then(function (data) { + var audioElem = new Audio(); + var blob = _this7._createBlob1(data); + audioElem.src = URL.createObjectURL(blob); + _this7.sounds[toneName] = { + audioElem: audioElem, + deviceId: '', + // associated device id + source: null, + streamDestination: null + }; + }); + } + + // Convert AudioBuffer to WAV Blob. + // Thanks to https://github.com/mattdiamond/Recorderjs MIT lisence + }, { + key: "_createBlob1", + value: function _createBlob1(audioBuffer) { + function writeString(view, offset, string) { + for (var i = 0; i < string.length; i++) { + view.setUint8(offset + i, string.charCodeAt(i)); + } + } + function floatTo16BitPCM(output, offset, input, k) { + for (var i = 0; i < input.length; i++, offset += 2) { + var v = input[i] / k; + var s = Math.max(-1, Math.min(1, v)); + output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); + } + } + function normalize(input) { + var max = 0, + min = 0; + for (var i = 0; i < input.length; i++) { + var v = input[i]; + max = Math.max(max, v); + min = Math.min(min, v); + } + return (max - min) / 2; + } + var samples = audioBuffer.getChannelData(0); + var sampleRate = audioBuffer.sampleRate; + var format = 1; + var bitDepth = 16; + var bytesPerSample = bitDepth / 8; + var numChannels = 1; + var blockAlign = numChannels * bytesPerSample; + var buffer = new ArrayBuffer(44 + samples.length * bytesPerSample); + var view = new DataView(buffer); + writeString(view, 0, 'RIFF'); + view.setUint32(4, 36 + samples.length * bytesPerSample, true); + writeString(view, 8, 'WAVE'); + writeString(view, 12, 'fmt '); + view.setUint32(16, 16, true); + view.setUint16(20, format, true); + view.setUint16(22, numChannels, true); + view.setUint32(24, sampleRate, true); + view.setUint32(28, sampleRate * blockAlign, true); + view.setUint16(32, blockAlign, true); + view.setUint16(34, bitDepth, true); + writeString(view, 36, 'data'); + view.setUint32(40, samples.length * bytesPerSample, true); + var k = normalize(samples); + floatTo16BitPCM(view, 44, samples, k); + return new Blob([buffer], { + type: "audio/wav" + }); + } + }, { + key: "_play1", + value: function _play1(options) { + this.logger("AudioPlayer2 [AudioElement]: play: ".concat(JSON.stringify(options))); + return this._play1_impl(options, 'sound', this.speakerDeviceId); + } + }, { + key: "_playRing1", + value: function _playRing1(options) { + if (!this.ringerDeviceId) return Promise.resolve(); + this.logger("AudioPlayer2 [AudioElement]: playRing: ".concat(JSON.stringify(options))); + return this._play1_impl(options, 'ringer', this.ringerDeviceId); + } + }, { + key: "_playShortSound1", + value: function _playShortSound1(options) { + return this._play1_impl(options, 'ssound', this.speakerDeviceId); + } + }, { + key: "_play1_impl", + value: function _play1_impl(options, sname, deviceId) { + var _this8 = this; + this._silentStop1(this[sname]); + var sound = this[sname] = this.sounds[options.name]; + if (!sound) { + this.logger("AudioPlayer2 [AudioElement]: missed sound: \"".concat(options.name, "\"")); + return Promise.reject(); + } + if (sound.source) { + this.logger("AudioPlayer2 [AudioElement]: sound \"".concat(options.name, "\" was used for streaming")); + return Promise.reject(); + } + return Promise.resolve().then(function () { + if (deviceId !== undefined && sound.audioElem.setSinkId !== undefined) { + if (sound.deviceId === deviceId) { + return Promise.resolve(); + } else { + _this8.logger("AudioPlayer2 [AudioElement]: \"".concat(options.name, "\": setSinkId deviceId=\"").concat(deviceId, "\"")); + return sound.audioElem.setSinkId(deviceId); + } + } else { + return Promise.resolve(); + } + }).then(function () { + sound.deviceId = deviceId; + })["catch"](function (e) { + // Sometimes there is Chrome error: 'The operation could not be performed and was aborted' + _this8.logger("AudioPlayer2 [AudioElement]: HTMLAudioElement.setSinkId error \"".concat(e.message, "\" [used default speaker]")); + }).then(function () { + sound.audioElem.volume = options.volume !== undefined ? options.volume : 1.0; + sound.audioElem.loop = !!options.loop && options.repeat === undefined; + var repeat = options.repeat !== undefined ? options.repeat : 1; + return new Promise(function (resolve) { + sound.audioElem.onended = function () { + if (--repeat > 0 && _this8[sname]) { + sound.audioElem.currentTime = 0; + sound.audioElem.play()["catch"](function (e) { + _this8.logger('AudioPlayer2 [AudioElement]: play error', e); + }); + } else { + resolve(); + } + }; + sound.audioElem.currentTime = 0; + sound.audioElem.play()["catch"](function (e) { + _this8.logger('AudioPlayer2 [AudioElement]: play error', e); + }); + }); + }); + } + }, { + key: "_playStream1", + value: function _playStream1(options, streamDestination) { + var _this9 = this; + this.logger("AudioPlayer2 [AudioElement]: play stream: ".concat(JSON.stringify(options))); + this._silentStop1(this.sound); + this.sound = this.sounds[options.name]; + if (!this.sound) { + this.logger("AudioPlayer2 [AudioElement]: missed media file: \"".concat(options.name, "\"")); + return Promise.reject(); + } + return new Promise(function (resolve) { + _this9.sound.audioElem.volume = options.volume !== undefined ? options.volume : 1.0; + _this9.sound.audioElem.loop = !!options.loop && options.repeat === undefined; + var repeat = options.repeat !== undefined ? options.repeat : 1; + _this9.sound.audioElem.onended = function () { + if (--repeat > 0 && _this9.sound) { + _this9.sound.audioElem.currentTime = 0; + _this9.sound.audioElem.play()["catch"](function (e) { + _this9.logger('AudioPlayer2 [AudioElement]: streaming error', e); + }); + } else { + _this9.logger('AudioPlayer2 [AudioElement]: stopped'); + resolve(); + } + }; + _this9.sound.audioElem.currentTime = 0; + // It's workaround of the issue: https://bugs.chromium.org/p/chromium/issues/detail?id=429204 + // (The Audio cannot be used in createMediaElementSource again) + if (!_this9.sound.source) { + _this9.sound.source = _this9.audioCtx.createMediaElementSource(_this9.sound.audioElem); + } + _this9.sound.streamDestination = streamDestination; + _this9.sound.source.connect(_this9.sound.streamDestination); + _this9.sound.audioElem.play()["catch"](function (e) { + _this9.logger('AudioPlayer2 [AudioElement]: streaming error', e); + }); + }); + } + }, { + key: "_stop1", + value: function _stop1() { + this.logger('AudioPlayer2 [AudioElement]: stop'); + this._silentStop1(this.sound); + this.sound = null; + this._silentStop1(this.ringer); + this.ringer = null; + } + }, { + key: "_silentStop1", + value: function _silentStop1(sound) { + if (!sound) return; + sound.audioElem.pause(); + if (sound.source) { + try { + sound.source && sound.source.disconnect(); + sound.streamDestination && sound.streamDestination.disconnect(); + sound.streamDestination = null; + } catch (e) { + this.logger('AudioPlayer2 [AudioElement]: disconnect AudioContext error', e); + } + } + } + + /* + AudioContext implementation + */ + }, { + key: "_downloadSound2", + value: function _downloadSound2(name, file) { + var _this10 = this; + return fetch(file, { + credentials: 'same-origin' + }).then(function (response) { + if (response.status >= 200 && response.status <= 299) return response.arrayBuffer()["catch"](function () { + throw 'download body error'; + }); + throw response.status === 404 ? 'file not found' : 'download error'; + }).then(function (data) { + return _this10.audioCtx.decodeAudioData(data)["catch"](function () { + throw 'decoding error'; + }); + }).then(function (decodedData) { + _this10.sounds[name] = { + data: decodedData, + source: null, + gain: null, + streamDestination: null + }; + })["catch"](function (e) { + _this10.logger('AudioPlayer2 [AudioContext]: ' + e + ': ' + file); + }); + } + }, { + key: "_generateTone2", + value: function _generateTone2(toneName, toneDefinition) { + var _this11 = this; + return this._generateTone(toneDefinition).then(function (data) { + if (data) { + _this11.sounds[toneName] = { + data: data, + source: null, + gain: null, + streamDestination: null + }; + } + }); + } + }, { + key: "_play2", + value: function _play2(options) { + var _this12 = this; + var streamDestination = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + this.logger("AudioPlayer2 [AudioContext]: ".concat(streamDestination ? 'playStream' : 'play', ": ").concat(JSON.stringify(options))); + this._silentStop2(this.sound); + var sound = this.sounds[options.name]; + if (!sound) { + this.logger("AudioPlayer2 [AudioContext]: missed media: \"".concat(options.name, "\"")); + return Promise.reject(); + } + this.sound = sound = Object.assign({}, sound); + return new Promise(function (resolve, reject) { + try { + sound.source = _this12.audioCtx.createBufferSource(); + sound.source.buffer = sound.data; + sound.source.onended = function () { + _this12.logger("AudioPlayer2 [AudioContext]: onended ".concat(options.name)); + _this12._silentStop2(sound); + resolve(true); + }; + sound.source.onerror = function () { + _this12.logger("AudioPlayer2 [AudioContext]: onerror ".concat(options.name)); + _this12._silentStop2(sound); + reject(new Error('onerror callback')); + }; + sound.gain = _this12.audioCtx.createGain(); + var volume = options.volume ? options.volume : 1.0; + sound.gain.gain.setValueAtTime(volume, _this12.audioCtx.currentTime); + sound.source.connect(sound.gain); + if (streamDestination) { + sound.streamDestination = streamDestination; + sound.gain.connect(sound.streamDestination); + } else { + sound.streamDestination = null; + sound.gain.connect(_this12.audioCtx.destination); + } + if (options.loop === true || options.repeat) { + sound.source.loop = true; + sound.source.loopStart = 0; + } + var duration = null; + if (options.repeat) { + duration = _this12.sound.source.buffer.duration * options.repeat; + } + sound.source.start(0, 0); + if (duration) sound.source.stop(_this12.audioCtx.currentTime + duration); + } catch (e) { + _this12.logger('AudioPlayer2 [AudioContext]: play error', e); + _this12._silentStop2(sound); + reject(e); + } + }); + } + }, { + key: "_playShortSound2", + value: function _playShortSound2(options) { + var _this13 = this; + var source; + var gain; + function release() { + try { + source && source.stop(); + gain && gain.disconnect(); + source && source.disconnect(); + } catch (e) { + this.logger('AudioPlayer [AudioContext]: playShortSound: release error', e); + } + } + return new Promise(function (resolve, reject) { + try { + var sound = _this13.sounds[options.name]; + if (!sound) { + "AudioPlayer2 [AudioContext]: playShortSound: no sound: \"".concat(options.name, "\""); + reject('No sound'); + return; + } + source = _this13.audioCtx.createBufferSource(); + source.buffer = sound.data; + source.onended = function () { + release(); + resolve(); + }; + source.onerror = function (e) { + release(); + reject(e); + }; + gain = _this13.audioCtx.createGain(); + var volume = options.volume ? options.volume : 1.0; + gain.gain.setValueAtTime(volume, _this13.audioCtx.currentTime); + source.connect(gain); + gain.connect(_this13.audioCtx.destination); + source.start(); + } catch (e) { + _this13.logger('AudioPlayer [AudioContext]: playShortSound error', e); + reject(e); + } + }); + } + }, { + key: "_stop2", + value: function _stop2() { + this.logger('AudioPlayer2 [AudioContext]: stop'); + this._silentStop2(this.sound); + this.sound = null; + } + }, { + key: "_silentStop2", + value: function _silentStop2(sound) { + if (!sound || !sound.source) { + return; + } + try { + sound.source && sound.source.stop(); + } catch (e) {} + try { + sound.gain && sound.gain.disconnect(); + sound.source && sound.source.disconnect(); + sound.streamDestination && sound.streamDestination.disconnect(); + sound.gain = null; + sound.source = null; + sound.streamDestination = null; + } catch (e) { + this.logger('AudioPlayer2 [AudioContext]: release resources error', e); + } + } + + /* + Used in both implementations + */ + // for Safari + }, { + key: "_setDecodeAudioDataShim", + value: function _setDecodeAudioDataShim(audioCtx) { + var origDecodeAudioData = audioCtx.decodeAudioData; + audioCtx.decodeAudioData = function (data) { + return new Promise(function (resolve, reject) { + origDecodeAudioData.call(audioCtx, data, function (d) { + return resolve(d); + }, function (e) { + return reject(e); + }); + }); + }; + } + + // for Safari + }, { + key: "_setStartRenderingShim", + value: function _setStartRenderingShim(offlineCtx) { + var origStartRendering = offlineCtx.startRendering; + offlineCtx.startRendering = function () { + return new Promise(function (resolve) { + offlineCtx.oncomplete = function (e) { + resolve(e.renderedBuffer); + }; + origStartRendering.call(offlineCtx); + }); + }; + } + }, { + key: "_generateTone", + value: function _generateTone(toneDefinition) { + function getArray(e) { + if (e === undefined) return []; + if (Array.isArray(e)) return e; + return [e]; + } + try { + var duration = 0; + var oscillatorNumber = 0; + var _iterator2 = _createForOfIteratorHelper(toneDefinition), + _step2; + try { + for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { + var _step4 = _step2.value; + duration += _step4.t; + oscillatorNumber = Math.max(oscillatorNumber, getArray(_step4.f).length); + } + } catch (err) { + _iterator2.e(err); + } finally { + _iterator2.f(); + } + var channels = 1; + var sampleRate = this.audioCtx.sampleRate; + var frameCount = sampleRate * duration; + var offlineCtx = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(channels, frameCount, sampleRate); + if (this.browser === 'safari' || this.browser === 'safari|ios') this._setStartRenderingShim(offlineCtx); + var oscillators = new Array(oscillatorNumber); + for (var i = 0; i < oscillators.length; i++) { + oscillators[i] = offlineCtx.createOscillator(); + oscillators[i].connect(offlineCtx.destination); + } + var time = 0; + for (var _i2 = 0, num = toneDefinition.length; _i2 < num; _i2++) { + var step = toneDefinition[_i2]; + var frequencies = getArray(step.f); + for (var j = 0; j < oscillators.length; j++) { + var f = j < frequencies.length ? frequencies[j] : 0; + oscillators[j].frequency.setValueAtTime(f, offlineCtx.currentTime + time); + } + time += step.t; + } + for (var _i3 = 0, _oscillators = oscillators; _i3 < _oscillators.length; _i3++) { + var o = _oscillators[_i3]; + o.start(0); + o.stop(offlineCtx.currentTime + duration); + } + return offlineCtx.startRendering().then(function (renderedBuffer) { + var _iterator3 = _createForOfIteratorHelper(oscillators), + _step3; + try { + for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { + var _o = _step3.value; + _o.disconnect(); + } + } catch (err) { + _iterator3.e(err); + } finally { + _iterator3.f(); + } + return renderedBuffer; + }); + } catch (e) { + this.logger('AudioPlayer2: cannot generate tone', e); + return Promise.reject(e); + } + } + }]); + return AudioPlayer2; +}(); +/* + * Recording audio/video. + * For modern browsers only. Used MediaRecorder API. + * Can be used in Chrome, Edge, Firefox and Safari + */ +var MRecorder = /*#__PURE__*/function () { + function MRecorder() { + _classCallCheck(this, MRecorder); + this.logger = null; + this.audioCtx = null; + this.chunks = []; + this.recorder = null; + this.browser = this._browser(); + this.defaultOptions = { + 'chrome': { + audio: { + mimeType: 'audio/webm;codec=opus' + }, + /* + Chrome 91 mediaRecorder + Not supported: + video: { mimeType: 'video/mp4;codecs=h264,opus' } + video: { mimeType: 'video/webm;codecs=av1x,opus' } // Could be supported in the future. + Supported: + video: { mimeType: 'video/webm;codecs=avc1,opus' } // CodecID: V_MPEG4/ISO/AVC It's H264 + video: { mimeType: 'video/webm;codecs=h264,opus' } // CodecID: V_MPEG4/ISO/AVC It's H264 + video: { mimeType: 'video/webm;codecs=vp8,opus' } // CodecID: V_VP8 + video: { mimeType: 'video/webm;codecs=vp9,opus' } // CodecID: V_VP9 + */ + video: { + mimeType: 'video/webm;codecs=vp8,opus' + } + }, + 'firefox': { + audio: { + mimeType: 'audio/webm;codec=opus' + }, + video: { + mimeType: 'video/webm;codecs=vp8,opus' + } + }, + 'safari': { + audio: { + mimeType: 'audio/mp4' + }, + video: { + mimeType: 'video/mp4' + } + }, + 'ios_safari': { + audio: { + mimeType: 'audio/mp4' + }, + video: { + mimeType: 'video/mp4' + } + }, + 'other': { + audio: { + mimeType: 'audio/webm' + } + } + }[this.browser]; + this.selectedOptions = null; + } + _createClass(MRecorder, [{ + key: "_browser", + value: function _browser() { + if (/iPad|iPhone|iPod/.test(navigator.userAgent)) return 'ios_safari'; + if (navigator.mozGetUserMedia) return 'firefox'; + if (navigator.webkitGetUserMedia) + // Work only for secure connection + return 'chrome'; + if (window.safari) return 'safari'; + return 'other'; + } + }, { + key: "init", + value: function init(logger, audioCtx) { + this.logger = logger; + this.audioCtx = audioCtx; + } + }, { + key: "isRecording", + value: function isRecording() { + return this.recorder && this.recorder.state === 'recording'; + } + }, { + key: "recordStream", + value: function recordStream(stream, options) { + var _this14 = this; + this.logger("MRecorder: recordStream()"); + this.create(stream, options); + return this.start().then(function (blob) { + _this14.closeStream(); + return blob; + }); + } + }, { + key: "create", + value: + /** + * To record only audio from audio/video stream use: + * stream = new MediaStream(stream.getAudioTracks()); + * + * To set non-default browser codecs use: + * options = { mimeType: 'video/webm;codecs=vp9,opus' }; + */ + function create(stream) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var isVideo = stream.getVideoTracks().length > 0; + if (!options && isVideo && !this.defaultOptions.video) { + isVideo = false; + this.logger("Warning: video mime undefined for ".concat(this.browser, ", records audio only")); + } + if (!options) { + options = isVideo ? this.defaultOptions.video : this.defaultOptions.audio; + } + this.selectedOptions = options; + this.logger("MRecorder recorded ".concat(isVideo ? '"video"' : '"audio"', ". Options: ").concat(JSON.stringify(this.selectedOptions))); + this.recorder = new MediaRecorder(stream, this.selectedOptions); + } + }, { + key: "start", + value: function start() { + var _this15 = this; + return new Promise(function (resolve, reject) { + _this15.chunks = []; + _this15.recorder.ondataavailable = function (e) { + _this15.chunks.push(e.data); + }; + _this15.recorder.onerror = function (e) { + reject(e); + }; + _this15.recorder.onstop = function () { + _this15.logger("MRecorder: create blob"); + resolve(new Blob(_this15.chunks, { + type: _this15.selectedOptions.mimeType + })); + _this15.chunks = []; + }; + _this15.recorder.start(); + }); + } + }, { + key: "stop", + value: function stop() { + if (!this.recorder || this.recorder.state !== 'recording') return; + this.logger('MRecorder: stop'); + this.recorder.stop(); + } + }, { + key: "closeStream", + value: function closeStream() { + var _iterator4 = _createForOfIteratorHelper(this.recorder.stream.getTracks()), + _step5; + try { + for (_iterator4.s(); !(_step5 = _iterator4.n()).done;) { + var track = _step5.value; + track.stop(); + } + } catch (err) { + _iterator4.e(err); + } finally { + _iterator4.f(); + } + } + }], [{ + key: "canBeUsed", + value: function canBeUsed() { + return typeof MediaRecorder === 'function'; + } + }]); + return MRecorder; +}(); +/** + * Automatic answering machine. + * Play greeting, record answer. + */ +var AnsweringMachine = /*#__PURE__*/function () { + function AnsweringMachine() { + _classCallCheck(this, AnsweringMachine); + this.use = true; + this.startDelay = 16; + this.recordDuration = 20; + this.run = false; + this.logger = null; + this.call = null; + this.streamDest = null; + this.answerTimer = null; + this.recordingTimer = null; + this.audioPlayer = null; + this.recorder = null; + this.logger = null; + } + _createClass(AnsweringMachine, [{ + key: "init", + value: function init(audioPlayer, recorder) { + this.audioPlayer = audioPlayer; + this.logger = audioPlayer.logger; + this.recorder = recorder; + } + }, { + key: "startTimer", + value: function startTimer(call, answerCallback) { + var _this16 = this; + this.call = call; + this.stopTimer(); + this.answerTimer = setTimeout(function () { + _this16.run = true; + answerCallback(); + }, this.startDelay * 1000); + } + }, { + key: "stopTimer", + value: function stopTimer() { + if (this.answerTimer !== null) { + clearTimeout(this.answerTimer); + this.answerTimer = null; + } + } + }, { + key: "setStreamDestination", + value: function setStreamDestination(streamDest) { + this.streamDest = streamDest; + } + + // Called if a call is terminated. + }, { + key: "stop", + value: function stop(call) { + if (call === this.call) { + this.stopTimer(); + this.recorder.stop(); + if (this.recordingTimer !== null) { + clearTimeout(this.recordingTimer); + this.recordingTimer = null; + } + this.run = false; + } + } + + // Use destination stream, instead speaker. + }, { + key: "playGreeting", + value: function playGreeting() { + var _this17 = this; + return this.audioPlayer.play({ + name: 'greeting', + volume: 1.0, + startDelay: 1.6 + }, this.streamDest).then(function () { + return _this17.audioPlayer.play({ + name: 'beep', + volume: 0.2 + }, _this17.streamDest); + }); + } + + // Record remote stream of the call. + }, { + key: "recordAnswer", + value: function recordAnswer(remoteStream) { + var _this18 = this; + this.recorder.create(remoteStream); + this.recordingTimer = setTimeout(function () { + _this18.logger('AnsweringMachine: maximum recording time reached.'); + _this18.recorder.stop(); + }, this.recordDuration * 1000); + return this.recorder.start().then(function (blob) { + _this18.run = false; + return blob; + }); + } + }]); + return AnsweringMachine; +}(); +/** + * SIP Alert-Info header parser. + * + * Alert-Info = "Alert-Info" HCOLON alert-param *(COMMA alert-param) + * alert-param = LAQUOT absoluteURI RAQUOT *( SEMI generic-param ) + */ +var AlertInfo = /*#__PURE__*/function () { + function AlertInfo(incomingMsg) { + _classCallCheck(this, AlertInfo); + this.parsed = []; + try { + var _iterator5 = _createForOfIteratorHelper(incomingMsg.getHeaders('alert-info')), + _step6; + try { + for (_iterator5.s(); !(_step6 = _iterator5.n()).done;) { + var hh = _step6.value; + var _iterator6 = _createForOfIteratorHelper(hh.split(',')), + _step7; + try { + for (_iterator6.s(); !(_step7 = _iterator6.n()).done;) { + var h = _step7.value; + this._parseHeader(h); + } + } catch (err) { + _iterator6.e(err); + } finally { + _iterator6.f(); + } + } + } catch (err) { + _iterator5.e(err); + } finally { + _iterator5.f(); + } + } catch (e) { + console.log('Alert-Info parsing error', e); + } + } + _createClass(AlertInfo, [{ + key: "_parseHeader", + value: function _parseHeader(h) { + var st = h.split(';'); + var url; + var pr_st = 0; + if (st[0].startsWith('<') && st[0].endsWith('>')) { + url = st[0].slice(1, -1); + pr_st = 1; + } + var params = new Map(); + var _iterator7 = _createForOfIteratorHelper(st.slice(pr_st)), + _step8; + try { + for (_iterator7.s(); !(_step8 = _iterator7.n()).done;) { + var pr = _step8.value; + var eq = pr.indexOf('='); + if (eq !== -1) { + var k = pr.substring(0, eq); + var v = pr.substring(eq + 1); + if (v.startsWith('"') && v.endsWith('"')) v = v.slice(1, -1); + params.set(k.toLowerCase(), v.toLowerCase()); + } + } + } catch (err) { + _iterator7.e(err); + } finally { + _iterator7.f(); + } + this.parsed.push({ + url: url, + params: params + }); + } + }, { + key: "exists", + value: function exists() { + return this.parsed.length > 0; + } + }, { + key: "param", + value: function param(key) { + var ix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + if (ix >= this.parsed.length) return null; + return this.parsed[ix].params.get(key); + } + }, { + key: "url", + value: function url() { + var ix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + return this.parsed[ix].url; + } + }, { + key: "getDelay", + value: function getDelay() { + var ix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + var delay = this.param('delay', ix); + if (!delay) return -1; + return parseInt(delay); + } + }, { + key: "hasAutoAnswer", + value: function hasAutoAnswer() { + var ix = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + return this.param('info', ix) === 'alert-autoanswer'; + } + }]); + return AlertInfo; +}(); +/* + * AudioCodes X-VoiceQuality header parser + */ +function getXVoiceQuality(request) { + var header = request.getHeader('X-VoiceQuality'); + if (!header) { + return undefined; + } + var words = header.trim().split(' '); + if (words.length !== 2) { + // should be 2 tokens. + console.log('X-VoiceQuality header: parsing problem: must be 2 tokens'); + return undefined; + } + var score = parseInt(words[0]); + if (isNaN(score)) { + console.log('X-VoiceQuality header: parsing problem: the first token is not number'); + return undefined; + } + var color = words[1].trim().toLowerCase(); + return { + score: score, + color: color + }; +} + +/** + * Audio mixer (for audio conference) + */ +var CallAudioMixer = /*#__PURE__*/function () { + // For each call created audio mixer instance. + // Аudio context can be taken from audio player + function CallAudioMixer(audioCtx, call) { + _classCallCheck(this, CallAudioMixer); + this.audioCtx = audioCtx; + this.dest = this.audioCtx.createMediaStreamDestination(); + this.calls = []; + var source = this.audioCtx.createMediaStreamSource(call.getRTCLocalStream()); + source.connect(this.dest); + this.calls.push({ + call: call, + source: source + }); + } + + // Close mixer, release all resources. + _createClass(CallAudioMixer, [{ + key: "close", + value: function close() { + if (this.dest !== null) { + this.dest.disconnect(); + this.dest = null; + } + var _iterator8 = _createForOfIteratorHelper(this.calls), + _step9; + try { + for (_iterator8.s(); !(_step9 = _iterator8.n()).done;) { + var c = _step9.value; + c.source.disconnect(); + } + } catch (err) { + _iterator8.e(err); + } finally { + _iterator8.f(); + } + this.calls = []; + } + + // Get mixed audio stream + }, { + key: "getMix", + value: function getMix() { + return this.dest.stream; + } + + // Add call to mixer. + // Returns true if added, false if the call is already added. + }, { + key: "add", + value: function add(call) { + var ix = this.calls.findIndex(function (c) { + return c.call === call; + }); + if (ix !== -1) return false; + var stream = call.getRTCRemoteStream(); + var source = this.audioCtx.createMediaStreamSource(stream); + source.connect(this.dest); + this.calls.push({ + call: call, + source: source + }); + return true; + } + + // Remove call from mixer + // Returns true if removed. + // Returns false, if the call was not added, or cannot be removed, because set in constructor. + }, { + key: "remove", + value: function remove(call) { + var ix = this.calls.findIndex(function (c) { + return c.call === call; + }); + if (ix === -1 || ix === 0) return false; + this.calls[ix].source.disconnect(); + this.calls.splice(ix, 1); + return true; + } + + // Returns string with calls list + }, { + key: "toString", + value: function toString() { + return 'audio mixer ' + this.calls.map(function (c) { + return c.call.data['_line_index'] + 1; + }); + } + }]); + return CallAudioMixer; +}(); +/** + * Video mixer (for video conference) + */ +var CallVideoMixer = /*#__PURE__*/function () { + // Used single instance for all calls. + function CallVideoMixer() { + _classCallCheck(this, CallVideoMixer); + this.layout = 'compact'; + this.run = false; + this.calls = []; + this.localVideo = null; + this.canvas = null; + this.canvasCtx = null; + this.canvasBackground = "#F5F5F5"; // light smoke + this.width = 160; + this.height = 120; + this.nVideo = 0; + this.drawInterval = 100; + this.remoteVideoId = ''; + this.frame = 1; + this.data = {}; + } + + // Set canvas id. + // Set local video element id. + // Set remote video element id prefix. (will be added video element index 0, 1, ...) + _createClass(CallVideoMixer, [{ + key: "setElements", + value: function setElements(canvasId, localVideoId, remoteVideoId) { + this.canvas = document.getElementById(canvasId); + this.canvasCtx = this.canvas.getContext('2d'); + this.localVideo = document.getElementById(localVideoId); + this.remoteVideoId = remoteVideoId; + } + + // Set number of frames per seconds of mixed stream. + // For example: 1, 2, 5, 10, 20, 50. + // Default: 10 + }, { + key: "setFPS", + value: function setFPS(v) { + this.setDrawInterval(1000 / v); + } + + // Set interval between draw (milliseconds) + // Default: 100 + // It can be set also via setFPS + }, { + key: "setDrawInterval", + value: function setDrawInterval(v) { + this.drawInterval = v; + } + + // Set calls video layout: 'linear' or 'compact' + // Default: 'compact' + }, { + key: "setLayout", + value: function setLayout(v) { + switch (v) { + case 'linear': + case 'compact': + this.layout = v; + break; + default: + throw new TypeError("Unknown layout: ".concat(v)); + } + this.resize(); + } + + // Set call video size (pixels) + // Default w=160, h=120 + }, { + key: "setSize", + value: function setSize(w, h) { + this.width = w; + this.height = h; + this.resize(); + } + + // Set call video sizes (pixels) + // size likes: {width: '160px', height: '120px'} + }, { + key: "setSizes", + value: function setSizes(size) { + // format {width: '160px', height: '120px'} + var w = parseInt(size.width.slice(0, -2)); + var h = parseInt(size.height.slice(0, -2)); + this.setSize(w, h); + } + + // Returns true when mixer is started + }, { + key: "isOn", + value: function isOn() { + return this.run; + } + + // Start mixer + }, { + key: "start", + value: function start() { + if (this.run) return; + setTimeout(this._draw.bind(this), this.drawInterval); + this.run = true; + } + + // Stop mixer, remove all calls, release resources. + // After using stop the mixer can be restarted. + }, { + key: "stop", + value: function stop() { + while (this.calls.length > 0) { + this.remove(this.calls[0].call); + } + this.run = false; + } + + // Get mixed video stream for added call. + }, { + key: "getMix", + value: function getMix(call) { + var ix = this.calls.findIndex(function (d) { + return d.call === call; + }); + return ix !== -1 ? this.calls[ix].mix : null; + } + + // Add call to mixer or update send/receive mode. + // Returns true if send video was added (should be replaced connection sender track) + }, { + key: "add", + value: function add(call) { + var send = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + var receive = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + var ix = this.calls.findIndex(function (d) { + return d.call === call; + }); + if (ix === -1) { + return this._add(call, send, receive); + } else { + return this._update(ix, send, receive); + } + } + }, { + key: "_add", + value: function _add(call, send, receive) { + var mix = send ? this.canvas.captureStream() : null; + var elt = receive ? document.getElementById(this.remoteVideoId + call.data['_line_index']) : null; + var x = 0; + var y = 0; + this.calls.push({ + call: call, + elt: elt, + mix: mix, + x: x, + y: y + }); + if (elt !== null) this.resize(); + return mix !== null; + } + }, { + key: "_update", + value: function _update(ix, send, receive) { + var d = this.calls[ix]; + var sendModified = false; + if (send) { + if (d.mix === null) { + d.mix = this.canvas.captureStream(); + sendModified = true; + } + } else { + if (d.mix !== null) { + var _iterator9 = _createForOfIteratorHelper(d.mix.getVideoTracks()), + _step10; + try { + for (_iterator9.s(); !(_step10 = _iterator9.n()).done;) { + var track = _step10.value; + track.stop(); + } + } catch (err) { + _iterator9.e(err); + } finally { + _iterator9.f(); + } + d.mix = null; + sendModified = true; + } + } + if (receive) { + if (d.elt === null) { + d.elt = document.getElementById(this.remoteVideoId + d.call.data['_line_index']); + this.resize(); + } + } else { + if (d.elt !== null) { + d.elt = null; + this.resize(); + } + } + return sendModified; + } + + // Remove call from mixer. + // Returns true if removed, false if was not added. + }, { + key: "remove", + value: function remove(call) { + var ix = this.calls.findIndex(function (d) { + return d.call === call; + }); + //console.log('video mixer: remove call with index=', call.data['_line_index'], ix); + if (ix === -1) return false; + var d = this.calls[ix]; + if (d.mix !== null) { + var _iterator10 = _createForOfIteratorHelper(d.mix.getVideoTracks()), + _step11; + try { + for (_iterator10.s(); !(_step11 = _iterator10.n()).done;) { + var track = _step11.value; + track.stop(); + } + } catch (err) { + _iterator10.e(err); + } finally { + _iterator10.f(); + } + } + this.calls.splice(ix, 1); + if (d.elt !== null) this.resize(); + return true; + } + + // number of video displayed in canvas + }, { + key: "_nVideo", + value: function _nVideo() { + var n = 0; + if (this.localVideo.srcObject !== null) n++; + var _iterator11 = _createForOfIteratorHelper(this.calls), + _step12; + try { + for (_iterator11.s(); !(_step12 = _iterator11.n()).done;) { + var d = _step12.value; + if (d.elt !== null) n++; + } + } catch (err) { + _iterator11.e(err); + } finally { + _iterator11.f(); + } + return n; + } + + // Resize video layout then changed number of video channels + // Used when added/removed local video channel. + // Called automatically in methods: add, remove, setLayout, setSize + // + // Warning: it's designed for 5 lines phone ! + // Max number of video controls is 6 (including local video) + // If you use more lines, please modify this method. + // + // Video layouts + // linear 0 1 0 1 2 0 1 2 3 0 1 2 3 4 .... + // + // compact 0 1 0 1 0 1 0 1 2 0 1 2 + // 2 2 3 3 4 3 4 5 + }, { + key: "resize", + value: function resize() { + this.nVideo = this._nVideo(); // number of shown video + //console.log(`videoMixer: resize nVideo=${this.nVideo} [${this.localVideo.srcObject !== null ? 'with local':'without local'} video]`); + switch (this.layout) { + case 'linear': + this.canvas.width = (this.width + this.frame) * this.nVideo; + this.canvas.height = this.height; + break; + case 'compact': + if (this.nVideo <= 2) { + this.canvas.width = (this.width + this.frame) * this.nVideo; + this.canvas.height = this.height; + } else if (this.nVideo <= 4) { + this.canvas.width = (this.width + this.frame) * 2; + this.canvas.height = this.height * 2 + this.frame; + } else { + this.canvas.width = this.width * 3; + this.canvas.height = this.height * 2 + this.frame; + } + break; + } + this.canvasCtx.fillStyle = this.canvasBackground; + this.canvasCtx.fillRect(0, 0, this.canvas.width, this.canvas.height); + + // sort calls by line index + this.calls.sort(function (d1, d2) { + return d1.call.data['_line_index'] - d2.call.data['_line_index']; + }); + + // reorder pictures in canvas + var ix = 0; + if (this.localVideo.srcObject !== null) ix++; + var _iterator12 = _createForOfIteratorHelper(this.calls), + _step13; + try { + for (_iterator12.s(); !(_step13 = _iterator12.n()).done;) { + var d = _step13.value; + if (d.elt !== null) { + var _this$_location = this._location(ix), + _this$_location2 = _slicedToArray(_this$_location, 2), + x = _this$_location2[0], + y = _this$_location2[1]; + d.x = x; + d.y = y; + ix++; + } + } + } catch (err) { + _iterator12.e(err); + } finally { + _iterator12.f(); + } + } + + // Calculate video picture location by index. + // + // Warning: it's designed for 5 lines phone ! + // Max number of video controls is 6 (including local video) + // If you use more lines, modify this method + }, { + key: "_location", + value: function _location(ix) { + var w = this.width + this.frame; + var h = this.height + this.frame; + switch (this.layout) { + case 'linear': + return [ix * w, 0]; + case 'compact': + switch (this.nVideo) { + case 0: + case 1: + case 2: + return [ix * w, 0]; + case 3: + return ix < 2 ? [w, 0] : [w * (ix - 2) + 0.5 * w, h]; + case 4: + return ix < 2 ? [w, 0] : [w * (ix - 2), h]; + case 5: + return ix < 3 ? [w * ix, 0] : [w * (ix - 3) + 0.5 * w, h]; + case 6: + return ix < 3 ? [w * ix, 0] : [w * (ix - 3), h]; + } + } + } + }, { + key: "_draw", + value: function _draw() { + if (!this.run) return; + try { + if (this.nVideo > 0) { + if (this.localVideo.srcObject !== null) this.canvasCtx.drawImage(this.localVideo, 0, 0, this.width, this.height); + var _iterator13 = _createForOfIteratorHelper(this.calls), + _step14; + try { + for (_iterator13.s(); !(_step14 = _iterator13.n()).done;) { + var d = _step14.value; + if (d.elt !== null) this.canvasCtx.drawImage(d.elt, d.x, d.y, this.width, this.height); + } + } catch (err) { + _iterator13.e(err); + } finally { + _iterator13.f(); + } + } + } catch (e) { + console.log(e); + } + setTimeout(this._draw.bind(this), this.drawInterval); + } + + // Returns string with calls list + }, { + key: "toString", + value: function toString() { + if (this.run) { + return 'video mixer ' + this.calls.map(function (c) { + return "".concat(c.call.data['_line_index'] + 1).concat(c.mix !== null ? 's' : '').concat(c.elt !== null ? 'r' : ''); + }); + } else { + return 'video mixer is off'; + } + } + }]); + return CallVideoMixer; +}(); // Dynamically load arbitrary javascript +function loadJavaScript(url) { + return new Promise(function (resolve, reject) { + var script = document.createElement('script'); + script.onload = resolve; + script.onerror = reject; + script.src = url; + document.head.appendChild(script); + }); +} + +/** + * Enumerate available devices: microphones, cameras, speakers (only Chrome provides speakers). + * Allow select devices, save the selection to local storage. + * Restore the device selection in the next sessions. + * + * Selected microphone and camera used in getUserMedia method as deviceId constraint. + * Selected speaker and ringer associated with HTMLAudioElement by setSinkId method (only in Chrome). + */ +var SelectDevices = /*#__PURE__*/function () { + // Parameters can be modified before enumerate() method. + function SelectDevices() { + _classCallCheck(this, SelectDevices); + this.defaultPseudoDevice = true; + this.names = []; + this.enumerateDevices = AudioCodesUA.instance.getWR().mediaDevices.enumerateDevices; // enumerate devices function. + this.browserDefaultLabel = '-- browser default--'; // default pseudo device - means do not use deviceId and sinkId + this.emptyLabel = '-- no label --'; // for label = '' in incomplete device list + this.previousSelection = null; // device selection from local storage + } + _createClass(SelectDevices, [{ + key: "setDevices", + value: function setDevices(defaultPseudoDevice, devices) { + this.defaultPseudoDevice = defaultPseudoDevice; + this.names = []; + var _iterator14 = _createForOfIteratorHelper(devices), + _step15; + try { + for (_iterator14.s(); !(_step15 = _iterator14.n()).done;) { + var device = _step15.value; + if (!['audioinput', 'audiooutput', 'videoinput'].includes(device.kind)) throw new TypeException("Illegal kind: ".concat(device.kind)); + this.names.push(device.name); + this[device.name] = { + kind: device.kind + }; + } + } catch (err) { + _iterator14.e(err); + } finally { + _iterator14.f(); + } + } + }, { + key: "setEnumerateDevices", + value: function setEnumerateDevices(method) { + this.enumerateDevices = method; + } + }, { + key: "enumerate", + value: function enumerate(useGetUserMediaIfNeed) { + var _this19 = this; + var stream = null; + var incomplete = false; + return Promise.resolve().then(function () { + return _this19.doEnumerate(); + }).then(function (inc) { + incomplete = inc; + if (incomplete && useGetUserMediaIfNeed) { + return AudioCodesUA.instance.getWR().getUserMedia({ + audio: true, + video: true + }); + } else { + return Promise.resolve(null); + } + }).then(function (s) { + stream = s; + if (stream) { + // For incomplete device list repeat with open stream. + return _this19.doEnumerate(); + } + }).then(function () { + if (stream) { + incomplete = false; + stream.getTracks().forEach(function (track) { + return track.stop(); + }); + } + }).then(function () { + // Restore previous selection. + if (_this19.previousSelection) { + var _iterator15 = _createForOfIteratorHelper(_this19.names), + _step16; + try { + for (_iterator15.s(); !(_step16 = _iterator15.n()).done;) { + var name = _step16.value; + if (!_this19.findPreviousSelection(name)) { + if (incomplete) _this19.addPreviousSelection(name); + } + } + } catch (err) { + _iterator15.e(err); + } finally { + _iterator15.f(); + } + } + }); + } + + // Without open stream by getUserMedia (or without permission to use microphone/camera) + // device list will be incomplete: + // some devices will be with empty string label, some devices can be missed. + }, { + key: "doEnumerate", + value: function doEnumerate() { + var _this20 = this; + var incomplete = false; // exists incomplete device lists + var emptyLabel = this.emptyLabel; + function setLabel(device, str) { + if (str) return str; + incomplete = device.incomplete = true; + return emptyLabel; + } + + // reset device list and selection index. + var _iterator16 = _createForOfIteratorHelper(this.names), + _step17; + try { + for (_iterator16.s(); !(_step17 = _iterator16.n()).done;) { + var name = _step17.value; + var device = this.getDevice(name); + device.incomplete = false; + if (this.defaultPseudoDevice) { + device.index = 0; // selected browser default pseudo-device. + device.list = [{ + deviceId: null, + label: this.browserDefaultLabel + }]; + } else { + device.index = -1; // device is not selected. + device.list = []; + } + } + } catch (err) { + _iterator16.e(err); + } finally { + _iterator16.f(); + } + return this.enumerateDevices().then(function (infos) { + var _iterator17 = _createForOfIteratorHelper(infos), + _step18; + try { + for (_iterator17.s(); !(_step18 = _iterator17.n()).done;) { + var info = _step18.value; + var _iterator18 = _createForOfIteratorHelper(_this20.names), + _step19; + try { + for (_iterator18.s(); !(_step19 = _iterator18.n()).done;) { + var name = _step19.value; + var device = _this20.getDevice(name); + if (info.kind === device.kind) { + device.list.push({ + deviceId: info.deviceId, + label: setLabel(device, info.label) + }); + } + } + } catch (err) { + _iterator18.e(err); + } finally { + _iterator18.f(); + } + } + } catch (err) { + _iterator17.e(err); + } finally { + _iterator17.f(); + } + }).then(function () { + return incomplete; + }); + } + + // Select device using previously saved device label + }, { + key: "findPreviousSelection", + value: function findPreviousSelection(name) { + var device = this.getDevice(name); + var sel = this.previousSelection && this.previousSelection[name]; + if (!sel || sel.label === this.emptyLabel) return false; + for (var ix = 0; ix < device.list.length; ix++) { + if (device.list[ix].label === sel.label) { + device.index = ix; + return true; + } + } + return false; + } + + // Without open stream by getUserMedia enumerate devices provides incomplete device list. + // In the case we add previously selected device to the incomplete list. + // Problem: previously used USB or bluetooth headset/camera could be disconnected. + }, { + key: "addPreviousSelection", + value: function addPreviousSelection(name) { + var device = this.getDevice(name); + var sel = this.previousSelection && this.previousSelection[name]; + if (sel && sel.label !== this.browserDefaultLabel && sel.label !== this.emptyLabel) { + AudioCodesUA.ac_log("devices: added previously selected ".concat(name, " \"").concat(sel.label, "\"")); + device.list.push(sel); + device.index = device.list.length - 1; + } + } + + // Returns selected device object { deviceId: '', label: ''} + }, { + key: "getDevice", + value: function getDevice(name) { + if (!this[name]) throw new TypeError("wrong device name: ".concat(name)); + return this[name]; + } + }, { + key: "getSelected", + value: function getSelected(name) { + var device = this.getDevice(name); + if (device.list.length === 0 || device.index === -1) + // device list is empty or device is not selected + return { + deviceId: null, + label: this.emptyLabel + }; + return device.list[device.index]; + } + }, { + key: "getNumber", + value: function getNumber(name) { + return this.getDevice(name).list.length; + } + + // Set selected by GUI device + }, { + key: "setSelectedIndex", + value: function setSelectedIndex(name, index) { + var device = this.getDevice(name); + if (index < 0 || index >= device.list.length) throw new RangeError("setSelectedIndex ".concat(name, " index=").concat(index)); + device.index = index; + } + + // Store selected devices. Supposed local storage usage. + }, { + key: "store", + value: function store() { + this.previousSelection = null; + var _iterator19 = _createForOfIteratorHelper(this.names), + _step20; + try { + for (_iterator19.s(); !(_step20 = _iterator19.n()).done;) { + var name = _step20.value; + var device = this.getDevice(name); + if (device.list.length === 0 || device.index === -1) continue; + if (!this.previousSelection) this.previousSelection = {}; + this.previousSelection[name] = this.getSelected(name); + } + } catch (err) { + _iterator19.e(err); + } finally { + _iterator19.f(); + } + return this.previousSelection; + } + + // Load previously stored selected devices. Can be null if no stored devices. + }, { + key: "load", + value: function load(obj) { + this.previousSelection = obj; + } + + // Device connected/removed event + }, { + key: "addDeviceChangeListener", + value: function addDeviceChangeListener(listener) { + AudioCodesUA.instance.getWR().mediaDevices.addDeviceChangeListener(listener); + } + }, { + key: "removeDeviceChangeListener", + value: function removeDeviceChangeListener(listener) { + AudioCodesUA.instance.getWR().mediaDevices.removeDeviceChangeListener(listener); + } + }]); + return SelectDevices; +}(); \ No newline at end of file