{"version":3,"sources":["lib/styles.js","lib/lib.js","lib/i18n.js","index.js","App.js","components/Layout.js","components/WindowSize.js","Talk.js","components/DialPad.js","lib/sdp.js","serviceWorker.js","app_setup.js","lib/xlog.js"],"names":["MaterialTheme","light","MainColor","ComplementaryColor","SecondaryColor","SeparatorColor","UnderlayColor","SearchBarColor","FacebookColor","GoogleColor","TabBarIconColor","LinkColor","ButtonBackgroundColor","ButtonDisabledColor","ErrorColor","ColorCollection","ChannelAdminNavBarColor","TextColor","color","PrimaryTextOpacity","opacity","SecondaryTextOpacity","HintTextOpacity","DividersTextOpacity","PrimaryText","SecondaryText","HintText","DividersText","StatusBarBackgroundColor","backgroundColor","AppBarBackgroundColor","BackgroundColor","DialogBackgroundColor","NavBarBackButtonText","NavBarBackButtonImage","tintColor","TabBar","borderTopWidth","borderColor","dark","_objectSpread2","default","timerPad","num","slice","value","constructor","Object","secs","minutes","Math","floor","hours","_i18nJs","_interopRequireDefault","__webpack_require__","I18n","defaultLocale","fallbacks","locale","window","navigator","language","translations","AHOY","Reload","ExtraNetworkCall","AhoyCall","Talking","CallConnecting","Calling_from","Call_processing","CallEnding","NetworkUnavailable","PleaseCheckNetworkDesc","IncorrectWebCallData","WebWarning","_react","_reactDom","_App","serviceWorker","_interopRequireWildcard","_queryString","_FontAwesome","_MaterialIcons","iconFontStyles","concat","iconFontFontAwesome","iconFontMaterial","style","document","createElement","type","styleSheet","cssText","appendChild","createTextNode","head","query","callHash","location","pathname","split","queryString","parse","search","ReactDOM","render","getElementById","unregister","DetectRTC","_Layout","_WindowSize","_util","LIB","_app_setup","_autobindDecorator","SIP","_i18n","_Talk","_reactNativeWeb","_reactNativeElements","_styles","_axios","_reactModal","_sdpTransform","LibSDP","Theme","require","AppSetup","Modal","setAppElement","App","autobind","props","_this","_classCallCheck2","this","_possibleConstructorReturn2","_getPrototypeOf2","call","remoteAudio","session","ua","shouldRegisterAfterConnect","sdp","state","call_session_active","call_session_callid","call_session_event","session_call_start_time","localMediaStream","remoteMediaStream","RENDER","appInitialized","webcallInfo","calleeNumber","calleeName","caller","callerPwd","modal","isModalOpen","view","talkingCallInfo","error","info","randomValue","Date","now","toString","setState","triggerRender","unsupportedMsg","isWebRTCSupported","isWebSocketsSupported","isWebSocketsBlocked","available","osName","browser","isSafari","method","url","landingServerDomain","data","WebCallToken","key","landingServerClientKey","res","resData","errorCode","WebCallData","callee","callee_description","caller_pwd","_context3","t0","_this2","getWebCallInfo","then","_webcallInfo","catch","err","detectRTCProcess","onDetectRTCLoad","_this2$detectRTCCheck","detectRTCCheckAvailability","muted","Promise","resolve","reject","load","stop","e","setup","closeSipUaInstance","UA","getSipUaInitSettings","setSipUaEvents","level","category","label","content","customServerIpPort","rel100","sipUaInfo","uri","authorizationUser","password","userAgentString","noAnswerTimeout","log","builtinEnabled","connector","logSipJSConnector","register","autostart","registerOptions","expires","transportOptions","wsServers","connectionTimeout","maxReconnectionAttempts","reconnectionTimeout","keepAliveInterval","traceSip","logToConsole","sessionDescriptionHandlerFactoryOptions","getSessionDescriptionHandlerOptions","isUaInit","serverIpPort","serverProtocol","t","length","substring","username","isDebug","customCallerUsername","customCallerPassword","repeat","C","supported","REQUIRED","UNSUPPORTED","_ref","arguments","undefined","_ref$headers","headers","_ref$returnObj","returnObj","extraHeadersObj","X-RTP-ENCRYPT-METHOD","X-WEBCALL-HASH","extraHeadersArray","keys","forEach","k","push","_this3","sipExtraHeaderRegister","on","args","attempts","isRegistered","extraHeaders","getSipAppendExtraHeaders","cause","status_code","reason_phrase","_ref2","_asyncToGenerator2","_regenerator","mark","_callee4","wrap","_context4","prev","next","_x3","apply","message","body","callInfo","parseCallInfoJson","updateTalkingCallInfoPartial","callid","_this4","pc","sessionDescriptionHandler","peerConnection","remoteStream","MediaStream","getReceivers","receiver","addTrack","track","srcObject","constraints","stream","release","isLocal","candidate","sdpWrapper","response","sdpObj","SDPTransform","media","Array","isArray","play","startTime","round","getTime","destroyCallSession","request","newSession","dtmf","callInfoJsonStr","parsed","JSON","isObject","item","status","Session","STATUS_CONFIRMED","STATUS_WAITING_FOR_ACK","match","preferVideo","extenCallGroup","callerApartmentInfo","nextShouldUseVideo","util","format","sipProxyDomain","sipProxyPort","customSipServer","endsWith","calleeUri","createSipUaInstance","moveTaskToBackAfterEnd","start","sendCall","_context5","stack","shouldUseVideo","_this5","invite","getInviteAcceptOptions","enableVideo","customSdpHacks","callId","setCallSessionEvents","_ref4","_ref4$enableVideo","_ref4$isUaInit","audio","autoGainControl","echoCancellation","noiseSuppression","volume","video","rtcConfiguration","bundlePolicy","iceServers","urls","rtcpMuxPolicy","RTCOfferOptions","iceRestart","voiceActivityDetection","offerToReceiveAudio","offerToReceiveVideo","peerConnectionOptions","iceCheckingTimeout","alwaysAcquireMediaFirst","_ref5","_ref5$enableVideo","_ref5$extenCallGroup","_ref5$callerApartment","sessionDescriptionHandlerOptions","endTime","bye","cancel","_this6","pause","tracks","getTracks","element","index","array","removeTrack","_this7","_this7$detectRTCCheck","handleMakeCall","_this8","expectedHeight","expectedWidth","_this$detectRTCCheckA","_this$state$webcallIn","windowHeight","windowWidth","parseInt","alignItems","justifyContent","View","height","width","maxHeight","maxWidth","styles","readyToCallContainer","Text","fontWeight","fontSize","Button","buttonStyle","borderRadius","onPress","onPressCallButton","icon","name","size","disabled","center","reminderText","warningText","parent","id","ref","isOpen","onAfterOpen","onAfterOpenModal","onRequestClose","onCloseModal","contentLabel","overlay","position","top","left","right","bottom","border","background","overflow","WebkitOverflowScrolling","outline","padding","flex","mainButtonContainer","title","titleStyle","React","Component","StyleSheet","create","alignSelf","borderWidth","borderStyle","hotWrapper","Platform","OS","hot","module","layoutStyle","margin","display","flexDirection","children","PureComponent","ComposedComponent","windowSize","_Component","_this$getWindowSize","getWindowSize","_inherits2","_createClass2","innerHeight","documentElement","clientHeight","offsetHeight","innerWidth","clientWidth","offsetWidth","_this$getWindowSize2","_handleResize","handleResize","bind","addEventListener","setTimeout","removeEventListener","wrappedInstance","_extends2","c","composedComponentName","displayName","DialPadImpl","Talk","talkingCallData","isStart","isStopping","isTimerStarted","dtmfs","isKeyboardOpen","isToggleAudioDeviceOn","isMicMute","isCameraMute","isHangUpBtnPressed","largeVideoRenderTypePreferLocal","shouldShowControlView","callDuration","localCameraFacingModeEnvironment","resetState","isConstructor","nextState","stopCall","callType","handleHangUp","text","button","isLongPress","symbol","handleOnPress","handleDTMF","handleOnBackspace","handleOnReset","getAudioTracks","enabled","nextIsToggleAudioDeviceOn","busytone","nextDuration","reactivateAudioForIosSafariWorkaround","startCallTimer","getType","getVideoTracks","toURL","_this$props$parent$st","calleeThumbnailPath","CallInfo","number","viewType","thumbnailPath","ControlPanel","handleOnKeyboardSwitch","onPressMicMute","onPressCameraMute","onPressChangeAudioRoute","onPressSwitchVideo","onPressOpenDoor","handleAnswerCall","handleRejectCall","handleDialPadOnPress","handleDialPadOnReset","handleDialPadOnBackspace","handleDialPadOnChangeText","flexRow","screenContainer","renderCallInfo","renderControlPanel","calleeType","description","callDurationText","formatCallDuration","flexColumn","numberOfLines","callInfoText","controlPanel","renderRemotePeerProfile","renderCurrentCallStateDescription","renderRealtimeCallInfo","renderCallDuration","renderWebWarning","isAudioDeviceOnStyle","selectedAudioDeviceIcon","buttonDisabled","btnDisabledStyle","notAnsweredYet","notAnsweredYetBtnDisabledStyle","micMuteStyle","buttonIsOn","buttonIsOff","cameraMuteStyle","audioButtonDisabled","audioButtonDisabledStyle","secondControlButtons","ControlButton","supportOpenDoor","controlButtonRow","iconStyle","containerStyle","hangupButtonContainer","ignoreLongPress","dialedNumber","handleOnChangeText","renderCountryPicker","renderKeyboardSwitchButton","renderDialPad","renderTalkingControlPanel","controlButtonContainer","_toConsumableArray2","disabledStyle","defaultProps","paddingHorizontal","paddingVertical","screenContainerVideo","hangupButtonText","controlButtonText","answerButtonContainer","answerButtonText","img","numbers","DialPad","_assertThisInitialized2","renderResetButton","textInputHeight","iconColor","dialInputResetButtonContainer","cca2","countryCallingCode","mainContainer","infoViewContainer","dialInputNumbersContainer","allowFontScaling","dialInputNumbersText","dialPadViewContainer","DialPadCore","DialButton","_this$props","alias","TouchableOpacity","onLongPress","delayLongPress","underlayColor","dialButtonTouchableContainer","dialButtonContainer","dialButtonText","marginLeft","dialButtonTextAlias","buttons","1","2","3","4","5","6","7","8","9","*","0","#","+","dialPadContainer","dialPadRow","textAlign","countryPickerContainer","countryPickerText","paddingLeft","paddingRight","typeof_sdp","sdpStr","sdpType","replace","m","getMediaByType","allowCodecName","codecNameToCode","getCodecPayloadMap","allowCodecCode","_i","_allowCodecName","setPreferCodecOnly","setCustomFmtp","sprop-maxcapturerate","maxplaybackrate","maxaveragebitrate","minptime","maxptime","ptime","cbr","useinbandfec","nextSdpStr","write","i","rtp","payload","codec","toLowerCase","includes","param","splice","payloads","join","codecCode","myConfig","override","fmtp","_getFmtpConfigWithInd","getFmtpConfigWithIndex","config","fmtpStr","convertFmtpObjToStr","parseFmtpConfig","fmtpObj","configArray","hasOwnProperty","publicUrl","URL","process","href","origin","swUrl","isLocalhost","fetch","contentType","get","indexOf","ready","registration","reload","registerValidSW","checkValidServiceWorker","Boolean","hostname","onupdatefound","installingWorker","installing","onstatechange","controller","onUpdate","onSuccess","libTTCPath","os","platform","host","port","Log","xlog","trace","debug","warn","fatal","exports"],"mappings":"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","file":"static/js/main.66f0f307.chunk.js","sourcesContent":["//const MainColor = '#71AAE3';\nconst MainColor = '#658AF9';\nconst ComplementaryColor = '#F9D465';\n//const SecondaryColor = '#DCEDFC';\n//const SecondaryColor = '#E4F4FF';\nconst SecondaryColor = '#E1E8FE';\n//const SeparatorColor = '#D3E2F1';\nconst SeparatorColor = 'lightgrey';\n//const UnderlayColor = '#EDF6FD';\nconst UnderlayColor = '#E8ECF7';\nconst SearchBarColor = '#E4E4E4';\nconst FacebookColor = '#3B5998';\nconst GoogleColor = '#DB3236';\nconst TabBarIconColor = '#FFFFFF';\n//const LinkColor = '#2AAFAB';\nconst LinkColor = '#7E9DFA';\n//const ButtonBackgroundColor = '#96BDEB';\nconst ButtonBackgroundColor = '#658AF9';\nconst ButtonDisabledColor = '#DCDCDC';\n//const ErrorColor = '#EF6C61';\nconst ErrorColor = 'indianred';\nconst ColorCollection = ['#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#FF5722', '#795548', '#9E9E9E', '#607D8B'];\nconst ChannelAdminNavBarColor = '#657bc0';\n\nvar MaterialTheme = {\n light: {\n MainColor,\n ComplementaryColor,\n SecondaryColor,\n SeparatorColor,\n UnderlayColor,\n SearchBarColor,\n FacebookColor,\n GoogleColor,\n TabBarIconColor,\n LinkColor,\n ButtonBackgroundColor,\n ButtonDisabledColor,\n ErrorColor,\n ColorCollection,\n ChannelAdminNavBarColor,\n TextColor: {\n color: '#000000',\n },\n PrimaryTextOpacity: {\n opacity: 0.87,\n },\n SecondaryTextOpacity: {\n opacity: 0.54,\n },\n HintTextOpacity: {\n opacity: 0.38,\n },\n DividersTextOpacity: {\n opacity: 0.12,\n },\n PrimaryText: {\n //opacity: 0.87,\n color: '#000000DE',\n },\n SecondaryText: {\n //opacity: 0.54,\n color: '#0000008A',\n },\n HintText: {\n //opacity: 0.38,\n color: '#00000061',\n },\n DividersText: {\n //opacity: 0.12,\n color: '#0000001F',\n },\n StatusBarBackgroundColor: {\n backgroundColor: '#E0E0E0',\n },\n AppBarBackgroundColor: {\n backgroundColor: '#F5F5F5',\n },\n BackgroundColor: {\n backgroundColor: '#FAFAFA',\n },\n DialogBackgroundColor: {\n backgroundColor: '#FFFFFF',\n },\n NavBarBackButtonText: {\n color: 'white',\n },\n NavBarBackButtonImage: {\n tintColor: 'white',\n },\n TabBar: {\n backgroundColor: 'white',\n borderTopWidth: 1,\n borderColor: '#e2e2e2',\n },\n },\n dark: {\n TextColor: {\n color: '#FFFFFF',\n },\n PrimaryTextOpacity: {\n opacity: 1,\n },\n SecondaryTextOpacity: {\n opacity: 0.70,\n },\n HintTextOpacity: {\n opacity: 0.50,\n },\n DividersTextOpacity: {\n opacity: 0.12,\n },\n PrimaryText: {\n //opacity: 1,\n color: '#FFFFFFFF',\n },\n SecondaryText: {\n //opacity: 0.70,\n color: '#FFFFFFB3',\n },\n HintText: {\n //opacity: 0.50,\n color: '#FFFFFF80',\n },\n DividersText: {\n //opacity: 0.12,\n color: '#FFFFFF1F',\n },\n StatusBarBackgroundColor: {\n backgroundColor: '#000000',\n },\n AppBarBackgroundColor: {\n backgroundColor: '#212121',\n },\n BackgroundColor: {\n backgroundColor: '#303030',\n },\n DialogBackgroundColor: {\n backgroundColor: '#424242',\n },\n }\n};\n\nMaterialTheme['dark'] = {...MaterialTheme['light'], ...MaterialTheme['dark']};\n\nexport { MaterialTheme };\n\n/*\nopacity mapping to HEX\n\n100% — FF\n99% — FC\n98% — FA\n97% — F7\n96% — F5\n95% — F2\n94% — F0\n93% — ED\n92% — EB\n91% — E8\n90% — E6\n89% — E3\n88% — E0\n87% — DE\n86% — DB\n85% — D9\n84% — D6\n83% — D4\n82% — D1\n81% — CF\n80% — CC\n79% — C9\n78% — C7\n77% — C4\n76% — C2\n75% — BF\n74% — BD\n73% — BA\n72% — B8\n71% — B5\n70% — B3\n69% — B0\n68% — AD\n67% — AB\n66% — A8\n65% — A6\n64% — A3\n63% — A1\n62% — 9E\n61% — 9C\n60% — 99\n59% — 96\n58% — 94\n57% — 91\n56% — 8F\n55% — 8C\n54% — 8A\n53% — 87\n52% — 85\n51% — 82\n50% — 80\n49% — 7D\n48% — 7A\n47% — 78\n46% — 75\n45% — 73\n44% — 70\n43% — 6E\n42% — 6B\n41% — 69\n40% — 66\n39% — 63\n38% — 61\n37% — 5E\n36% — 5C\n35% — 59\n34% — 57\n33% — 54\n32% — 52\n31% — 4F\n30% — 4D\n29% — 4A\n28% — 47\n27% — 45\n26% — 42\n25% — 40\n24% — 3D\n23% — 3B\n22% — 38\n21% — 36\n20% — 33\n19% — 30\n18% — 2E\n17% — 2B\n16% — 29\n15% — 26\n14% — 24\n13% — 21\n12% — 1F\n11% — 1C\n10% — 1A\n9% — 17\n8% — 14\n7% — 12\n6% — 0F\n5% — 0D\n4% — 0A\n3% — 08\n2% — 05\n1% — 03\n0% — 00\n*/\n","// --- Returns if a value is an object\nexport function isObject(value) {\n return value && typeof value === 'object' && value.constructor === Object;\n}\n\nexport function timerPad(num) {\n return (\"0\" + num).slice(-2);\n}\n\nexport function formatCallDuration(secs) {\n var minutes = Math.floor(secs / 60);\n var hours = Math.floor(minutes / 60)\n secs = secs % 60;\n minutes = minutes % 60;\n return timerPad(hours) + \":\" + timerPad(minutes) + \":\" + timerPad(secs);\n}\n\n","import I18n from \"i18n-js\";\nI18n.defaultLocale = \"en\"; // --- set fallbacks default language\nI18n.fallbacks = true; // --- enable fallback\nI18n.locale = window.navigator.language; // --- decide user's locale\n\n// --- translations\nI18n.translations = {};\nI18n.translations[\"en\"] = {\n\tAHOY: \"AHOY\",\n\tReload: \"Reload\",\n\tExtraNetworkCall: 'Extra Network Call',\n\tAhoyCall: 'AHOY Free Call',\n\tTalking: 'Talking',\n\tCallConnecting: 'Call Connecting',\n\tCalling_from: 'Calling from',\n\tCall_processing: 'Processing...',\n\tCallEnding: 'Call Ending',\n\tNetworkUnavailable: 'Network Unavailable',\n\tPleaseCheckNetworkDesc: 'Please check your network is stable then try again',\n\tIncorrectWebCallData: 'Incorrect WebCall Data',\n\tWebWarning: 'DO NOT turn off your screen or hide the browser to background',\n}\n\nI18n.translations[\"zh\"] = {\n\tAHOY: \"AHOY\",\n\tReload: \"重新整理\",\n\tExtraNetworkCall: '網外通話',\n\tAhoyCall: 'AHOY 免費通話',\n\tTalking: '通話中',\n\tCallConnecting: '接通中',\n\tCalling_from: '通話來自',\n\tCall_processing: '處理中',\n\tCallEnding: '通話結束中',\n\tNetworkUnavailable: '無法連接上網',\n\tPleaseCheckNetworkDesc: '請確認網路是否穩定, 再試一次',\n\tIncorrectWebCallData: 'WebCall 資料不正確',\n\tWebWarning: 'WebCall 通話中請勿關閉螢幕或將瀏覽器縮小至背景',\n}\n\nexport default I18n;\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\nimport queryString from 'query-string';\n\n// ===== START for react-native-vector-icon =====\n// --- https://github.com/oblador/react-native-vector-icons#web-with-webpack\n// --- should import ttf and generate css for your desired font\n\n// Use prebuilt version of RNVI in dist folder\n//import Icon from 'react-native-vector-icons/dist/FontAwesome';\n\n// Generate required css\nimport iconFontFontAwesome from 'react-native-vector-icons/Fonts/FontAwesome.ttf';\nimport iconFontMaterial from 'react-native-vector-icons/Fonts/MaterialIcons.ttf';\nlet iconFontStyles = '';\niconFontStyles += `@font-face {\n\tsrc: url(${iconFontFontAwesome});\n\tfont-family: FontAwesome;\n}`;\niconFontStyles += `@font-face {\n\tsrc: url(${iconFontMaterial});\n\tfont-family: MaterialIcons;\n}`;\n\n// Create stylesheet\nconst style = document.createElement('style');\nstyle.type = 'text/css';\nif (style.styleSheet) {\n\tstyle.styleSheet.cssText = iconFontStyles;\n} else {\n\tstyle.appendChild(document.createTextNode(iconFontStyles));\n}\n\n// Inject stylesheet\ndocument.head.appendChild(style);\n// ===== END for react-native-vector-icon =====\n\n/*\n * supported query string:\n * customCallerUsername\n * customCallerPassword\n * customSipServer\n */\nlet query = {\n\t//calleeNumber: '',\n\t//calleeName: '',\n\t//caller: '',\n\t//callerPwd: '',\n\tcallHash: window.location.pathname.split(\"/\").slice(-1)[0] || '',\n\tqueryString: queryString.parse(window.location.search) || {}, // --- for full path: `window.location.href`\n};\n\n//console.log('window.location.search = ', window.location.search);\n//console.log('window.location.href = ', window.location.href);\n//console.log('window.location.pathname = ', window.location.pathname);\n\nReactDOM.render(, document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: http://bit.ly/CRA-PWA\nserviceWorker.unregister();\n","import React from 'react'\nimport Layout from './components/Layout.js'\nimport WindowSize from './components/WindowSize.js'\nimport util from 'util'\nimport * as LIB from './lib/lib.js';\nimport AppSetup from './app_setup.js';\nimport autobind from 'autobind-decorator';\nimport * as SIP from 'sip.js';\nimport I18n from './lib/i18n.js';\nimport Talk from './Talk.js'\nimport {\n\tText,\n\tView,\n\tStyleSheet,\n\tPlatform,\n} from 'react-native-web';\n//import MaterialIcon from 'react-native-vector-icons/dist/MaterialIcons';\nimport { \n\tButton as ButtonElement,\n} from 'react-native-elements';\nimport { MaterialTheme } from './lib/styles.js';\nimport axios from 'axios';\nimport Modal from 'react-modal';\nimport SDPTransform from 'sdp-transform'; // --- sdp parser and writer\nimport * as LibSDP from './lib/sdp.js'; // --- sdp manipulate functions\n\nconst xlog = require('./lib/xlog.js'); // --- use reqiure so that we can use `pure_funcs` to strip in production build\n\nconst Theme = MaterialTheme[AppSetup.Theme];\nvar DetectRTC;\n\n// Make sure to bind modal to your appElement (http://reactcommunity.org/react-modal/accessibility/)\nModal.setAppElement('#root')\n\n//import fetch from 'isomorphic-unfetch'\n@autobind\nclass App extends React.Component {\n\tconstructor(props) {\n\t\tsuper(props);\n\t\txlog.info('[App] constructor()');\n\n\t\tthis.remoteAudio = null;\n\t\tthis.session = null;\n\t\tthis.ua = null;\n\t\tthis.shouldRegisterAfterConnect = false;\n\t\tthis.sdp = false;\n\n\t\tthis.state = {\n\t\t\tcall_session_active: false,\n\t\t\tcall_session_callid: '',\n\t\t\tcall_session_event: 'terminated',\n\t\t\tsession_call_start_time: 0,\n\n\t\t\tlocalMediaStream: null,\n\t\t\tremoteMediaStream: null,\n\t\t\tRENDER: '',\n\t\t\tDetectRTC: null,\n\t\t\tappInitialized: false, // --- mainly means: api to get webcall info has finished or not.\n\t\t\twebcallInfo: {\n\t\t\t\tcalleeNumber: '',\n\t\t\t\tcalleeName : '',\n\t\t\t\tcaller: '',\n\t\t\t\tcallerPwd : '',\n\t\t\t},\n\t\t\tmodal: {\n\t\t\t\tisModalOpen: false,\n\t\t\t\tview: null,\n\t\t\t},\n\t\t\ttalkingCallInfo: {},\n\t\t};\n\t}\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('App: componentDidCatch, error = ', error);\n\t\txlog.info('App: componentDidCatch, info = ', info);\n\t}\n\n\tasync triggerRender(randomValue) {\n\t\tif (!randomValue) {\n\t\t\t// --- default use timestamp is enough to trigger re-render\n\t\t\t// --- the side-benifit is we can prevent simutanous calls to re-render since the ms might be the same\n\t\t\trandomValue = Date.now().toString();\n\t\t}\n\t\tthis.setState({RENDER: randomValue});\n\t}\n\n\tasync onDetectRTCLoad() {\n\t\txlog.info('[App] onDetectRTCLoad() DetectRTC = ', DetectRTC);\n\t\tthis.triggerRender();\n\t\tawait this.setState({DetectRTC});\n\t\t/*\n\t\tDetectRTC.hasWebcam; // (has webcam device!)\n\t\tDetectRTC.hasMicrophone; // (has microphone device!)\n\t\tDetectRTC.hasSpeakers; // (has speakers!)\n\t\tDetectRTC.isScreenCapturingSupported; // Chrome, Firefox, Opera, Edge and Android\n\t\tDetectRTC.isSctpDataChannelsSupported;\n\t\tDetectRTC.isRtpDataChannelsSupported;\n\t\tDetectRTC.isAudioContextSupported;\n\t\tDetectRTC.isWebRTCSupported;\n\t\tDetectRTC.isDesktopCapturingSupported;\n\t\tDetectRTC.isMobileDevice;\n\n\t\tDetectRTC.isWebSocketsSupported;\n\t\tDetectRTC.isWebSocketsBlocked;\n\t\tDetectRTC.checkWebSocketsSupport(callback);\n\n\t\tDetectRTC.isWebsiteHasWebcamPermissions;\t\t// getUserMedia allowed for HTTPs domain in Chrome?\n\t\tDetectRTC.isWebsiteHasMicrophonePermissions;\t// getUserMedia allowed for HTTPs domain in Chrome?\n\n\t\tDetectRTC.audioInputDevices;\t// microphones\n\t\tDetectRTC.audioOutputDevices; // speakers\n\t\tDetectRTC.videoInputDevices;\t// cameras\n\n\t\tDetectRTC.osName;\n\t\tDetectRTC.osVersion;\n\n\t\tDetectRTC.browser.name === 'Edge' || 'Chrome' || 'Firefox';\n\t\tDetectRTC.browser.version;\n\t\tDetectRTC.browser.isChrome;\n\t\tDetectRTC.browser.isFirefox;\n\t\tDetectRTC.browser.isOpera;\n\t\tDetectRTC.browser.isIE;\n\t\tDetectRTC.browser.isSafari;\n\t\tDetectRTC.browser.isEdge;\n\n\t\tDetectRTC.browser.isPrivateBrowsing; // incognito or private modes\n\n\t\tDetectRTC.isCanvasSupportsStreamCapturing;\n\t\tDetectRTC.isVideoSupportsStreamCapturing;\n\n\t\tDetectRTC.DetectLocalIPAddress(callback);\n\t\t*/\n\t};\n\n\tdetectRTCCheckAvailability() {\n\t\t// --- will display message when:\n\t\t// --- 1. really unavailable OR 2. debug server\n\t\tlet unsupportedMsg = '';\n\t\tlet available = true;\n\n\t\tif (!this.state.DetectRTC) {\n\t\t\tunsupportedMsg = '偵測程序中或有誤,可能需要重新整理。';\n\t\t\tavailable = true;\n\t\t\treturn { available, unsupportedMsg };\n\t\t}\n\n\t\tif (!this.state.DetectRTC.isWebRTCSupported) {\n\t\t\tunsupportedMsg = '您的瀏覽器不支援語音通訊。建議使用 Chrome 最新版。';\n\t\t\tavailable = false;\n\t\t\treturn { available, unsupportedMsg };\n\t\t} else if (!this.state.DetectRTC.isWebSocketsSupported || this.state.DetectRTC.isWebSocketsBlocked) {\n\t\t\tunsupportedMsg = '您的瀏覽器不支援 WebSocket 連線。';\n\t\t\tavailable = false;\n\t\t\treturn { available, unsupportedMsg };\n\t\t} else if (this.state.DetectRTC.osName === 'iOS' && !this.state.DetectRTC.browser.isSafari) {\n\t\t\tunsupportedMsg = 'iPhone 目前僅支援 Safari\\n請使用 Safari 瀏覽器通話';\n\t\t\tavailable = false;\n\t\t\treturn { available, unsupportedMsg };\n\t\t}\n\t\t\n\t\t// --- do not rely on microphone/speaker detection because it may needs permissions. and is not 100% accurate across browsers.\n\t\t/*\n\t\t// --- mobile always has microphone and speaker phone,\n\t\t// --- some device especially ios will throw false-negative warning\n\t\t// --- that conplains microphone/speaker not found.\n\t\t//if (this.state.DetectRTC.isMobileDevice && this.state.DetectRTC.osName === 'iOS') {\n\t\tif (!this.state.DetectRTC.hasMicrophone) {\n\t\t\tunsupportedMsg = '偵測不到麥克風,請使用支援麥克風的裝置。';\t\t\t\t\t\n\t\t\tavailable = (this.state.DetectRTC.isMobileDevice ? true : false); \n\t\t\treturn { available, unsupportedMsg };\n\t\t} else if (!this.state.DetectRTC.hasSpeakers) {\n\t\t\tunsupportedMsg = '偵測不到音訊播放,請使用支援音訊播放的裝置。';\t\t\t\t\t\n\t\t\tavailable = (this.state.DetectRTC.isMobileDevice ? true : false); \n\t\t\treturn { available, unsupportedMsg };\n\t\t}\n\t\t//} else if (!this.state.DetectRTC.isWebsiteHasMicrophonePermissions) {\n\t\t//\tunsupportedMsg = '需要麥克風權限';\n\t\t//} else if (!this.state.DetectRTC.isPromisesSupported) {\n\t\t//\tunsupportedMsg = '您的瀏覽器版本太舊';\n\t\t//}\n\t\t*/\n\n\t\tavailable = true;\n\t\treturn { available, unsupportedMsg };\n\t}\n\n\tasync getWebCallInfo(callHash) {\n\t\tlet webcallInfo = {\n\t\t\tcalleeNumber: '',\n\t\t\tcalleeName : '',\n\t\t\tcaller: '',\n\t\t\tcallerPwd : '',\n\t\t}\n\t\tif (!callHash) {\n\t\t\t// --- no op\n\t\t} else {\n\t\t\t// --- not hardcoded one, query api\n\t\t\ttry {\n\t\t\t\t// --- keep in mind the CORS issues\n\t\t\t\tlet res = await axios({\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\turl: 'https://' + AppSetup.landingServerDomain + '/api/getWebCallData',\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tWebCallToken: callHash,\n\t\t\t\t\t\tkey: AppSetup.landingServerClientKey, // --- this is required for landing server which simply checks key to prevent randomly, automatically sniffing attacks\n\t\t\t\t\t},\n\t\t\t\t\t// --- if you want to use www-form-urlencoded\n\t\t\t\t\t//headers: {\n\t\t\t\t\t// 'content-type': 'application/x-www-form-urlencoded'\n\t\t\t\t\t//},\n\t\t\t\t\t//data: queryString.stringify({\n\t\t\t\t});\n\n\t\t\t\tlet resData = res.data;\n\n\t\t\t\tif (!resData) {\n\t\t\t\t\txlog.info('[ERROR][API] res is empty');\n\t\t\t\t} else if (resData.errorCode) {\n\t\t\t\t\txlog.info('[ERROR][API] res has errorCode: ' + resData.errorCode);\n\t\t\t\t} else {\n\t\t\t\t\twebcallInfo.calleeNumber = resData.data.WebCallData.callee;\n\t\t\t\t\twebcallInfo.calleeName = resData.data.WebCallData.callee_description;\n\t\t\t\t\twebcallInfo.caller = resData.data.WebCallData.caller;\n\t\t\t\t\twebcallInfo.callerPwd = resData.data.WebCallData.caller_pwd;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\txlog.info('[ERROR][API] exception: ' + err);\n\t\t\t}\n\t\t}\n\n\t\treturn webcallInfo;\n\t}\n\n\tcomponentDidMount() {\n\t\txlog.info('[App] componentDidMount() Enter');\n\n\t\tthis.getWebCallInfo(this.props.query.callHash)\n\t\t.then((webcallInfo) => {\n\t\t\tlet _webcallInfo = { ...webcallInfo };\n\t\t\tif (_webcallInfo.callerPwd) {\n\t\t\t\t_webcallInfo.callerPwd = '*******************';\n\t\t\t}\n\t\t\txlog.info('[App] componentDidMount() async getWebCallInfo(). webcallInfo = ', _webcallInfo);\n\t\t\tthis.setState({ webcallInfo, appInitialized: true });\n\t\t})\n\t\t.catch((err) => {\n\t\t\txlog.info('[App] componentDidMount() async getWebCallInfo() FAILED. err = ', err);\n\t\t\tthis.setState({ appInitialized: true });\n\t\t});\n\n\t\t// --- start etect availability on client\n\t\tthis.detectRTCProcess()\n\t\t.then(this.onDetectRTCLoad)\n\t\t.catch((err) => {\n\t\t\txlog.info('[App] componentDidMount() async detectRTCProcess() FAILED. DetectRTC failed. err = ', err);\n\t\t})\n\t\t.then(() => {\n\t\t\tlet { available, unsupportedMsg } = this.detectRTCCheckAvailability();\n\t\t\txlog.info('[App] componentDidMount() async detectRTCCheckAvailability(). available = %s, unsupportedMsg = %s', available, unsupportedMsg);\n\t\t})\n\n\t\txlog.info('[App] componentDidMount() Leave');\n\t}\n\n\treactivateAudioForIosSafariWorkaround() {\n\t\t//if (DetectRTC.isMobile.iOS() && this.remoteAudio) {\n\t\tif (DetectRTC.osName === 'iOS' && this.remoteAudio) {\n\t\t\txlog.info('[App] reactivateAudioForIosSafariWorkaround() workaround for ios');\n\t\t\tthis.remoteAudio.muted = true;\n\t\t\tthis.remoteAudio.muted = false;\n\t\t}\n\t}\n\n\tdetectRTCProcess() {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tif (!DetectRTC) {\n\t\t\t\tDetectRTC = require('detectrtc');\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tDetectRTC.load(resolve);\n\t\t\t} catch (err) {\n\t\t\t\treject(err);\n\t\t\t}\n\t\t});\n\t}\n\n\tcloseSipUaInstance() {\n\t\t//this.dispatch(Actions.UPDATE_IS_SIP_UA_CLOSING(true));\n\t\tif (this.ua) {\n\t\t\txlog.info(\"[Cue]: closeSipUaInstance()\");\n\t\t\ttry {\n\t\t\t\tthis.ua.stop();\n\t\t\t} catch (e) {\n\t\t\t\t//xlog.info('[ERROR][closeSipUaInstance] err =', e.stack);\n\t\t\t}\n\t\t\tdelete this.ua;\n\t\t\tthis.ua = false;\n\t\t}\n\t\t//this.dispatch(Actions.UPDATE_IS_SIP_UA_CLOSING(false));\n\t\t//this.dispatch(Actions.UPDATE_REGISTER_STATUS(false));\n\t}\n\n\n\tcreateSipUaInstance(setup) {\n\t\tsetup = (typeof setup === 'undefined') ? {} : setup;\n\n\t\ttry {\n\t\t\tthis.closeSipUaInstance();\n\t\t\txlog.info(\"[Cue][createSipUaInstance]\");\n\t\t\tthis.ua = new SIP.UA(this.getSipUaInitSettings(setup)); // --- customServerIpPort: string, rel100: boolean\n\t\t\tthis.setSipUaEvents(setup); // --- moveTaskToBackAfterEnd\n\t\t} catch (err) {\n\t\t\tthis.ua = false;\n\t\t\txlog.info(\"[Cue][createSipUaInstance] this.ua creation failed. catch error=%s\", err);\n\t\t}\n\t}\n\n\tlogSipJSConnector(level, category, label, content) {\n\t\t// --- level: String representing the level of the log message: ('debug', 'log', 'warn', 'error')\n\t\t// --- category: String representing the SIPjs instance class firing the log. ie: 'sipjs.ua'\n\t\t// --- label: String indicating the 'identifier' of the class instanc when the log level is '3' (debug). ie: transaction.id\n\t\t// --- content: String representing the log message\n\n\t\t// --- label is some trasaction tags. it's too verbose for us now.\n\t\tlet msg = `[SipJS][${category}]: ${content}`;\n\t\txlog.info(msg);\n\t}\n\n\t// --- param: customServerIpPort: string, rel100: boolean\n\tgetSipUaInitSettings(setup) {\n\t\tsetup = (typeof setup === 'undefined') ? {} : setup;\n\t\tlet customServerIpPort = (typeof setup.customServerIpPort === 'string') ? setup.customServerIpPort : '';\n\t\tlet rel100 = (setup.rel100 === true) ? true : false;\n\n\t\tlet sipUaInfo = {\n\t\t\turi: '',\n\t\t\tauthorizationUser: '',\n\t\t\tpassword: '',\n\t\t\tuserAgentString: \"AHOY_WebCall\",\n\t\t\tnoAnswerTimeout: 40, // --- default 60, should match with max rintone/vibration length\n\t\t\tlog: {\n\t\t\t\tbuiltinEnabled: false,\n\t\t\t\tlevel: 3,\n\t\t\t\tconnector: this.logSipJSConnector, // move to cue.js\n\t\t\t}, // --- 3, 2, 1, 0 or \"debug\", \"log\", \"warn\", \"error\"; default 2\n\t\t\tregister: false,\n\t\t\tautostart: false,\n\t\t\tregisterOptions: {\n\t\t\t\texpires: 600,\n\t\t\t},\n\t\t\ttransportOptions: {\n\t\t\t\twsServers: '',\n\t\t\t\tconnectionTimeout: 5, // --- default 5\n\t\t\t\tmaxReconnectionAttempts: 3, // --- default 3\n\t\t\t\treconnectionTimeout: 4, // --- default 4\n\t\t\t\t//keepAliveInterval: 0, // --- default 0\n\t\t\t\tkeepAliveInterval: 10, // --- default 0\n\t\t\t\t//traceSip: (process.env.NODE_ENV === 'development'),\n\t\t\t\ttraceSip: (typeof AppSetup.logToConsole === 'boolean' ? AppSetup.logToConsole : false),\n\t\t\t},\n\t\t\tsessionDescriptionHandlerFactoryOptions: this.getSessionDescriptionHandlerOptions({isUaInit: true}),\n\t\t}; // --- use new object\n\n\t\tlet serverIpPort = '';\n\t\tlet serverProtocol = '';\n\n\t\t// --- if we are callee, we should register to where server told us. ignore all server list settings.\n\t\tlet t = customServerIpPort.split(':');\n\t\tif (t.length > 2) {\n\t\t\t// --- contains specified protocol, ex: ws://x.x.x.x:5003\n\t\t\tserverProtocol = t[0];\n\t\t\tserverIpPort = customServerIpPort.substring(serverProtocol.length + 3); // --- 3 is the length of '://'\n\t\t} else {\n\t\t\t// --- not contain specified protocol, ex: x.x.x.x:5003\n\t\t\tserverIpPort = customServerIpPort;\n\t\t\t// --- workaround: choose protocol based on port, old client doesn't support customServerIpPort parsing.\n\t\t\tserverProtocol = (t[t.length - 1] === '5003' ? 'ws' : 'wss');\n\t\t}\n\n\t\tlet username = '';\n\t\tlet password = '';\n\t\t// --- for debug\n\t\tif (AppSetup.isDebug && this.props.query.queryString.customCallerUsername && this.props.query.queryString.customCallerPassword) {\n\t\t\tusername = this.props.query.queryString.customCallerUsername;\n\t\t\tpassword = this.props.query.queryString.customCallerPassword;\n\t\t\txlog.info('[Cue][getSipUaInitSettings] !!! use custom username = %s, password = %s', username, '*'.repeat(password.length));\n\t\t} else if (this.state.webcallInfo.caller && this.state.webcallInfo.callerPwd) {\n\t\t\tusername = this.state.webcallInfo.caller;\n\t\t\tpassword = this.state.webcallInfo.callerPwd;\n\t\t}\n\n\t\tsipUaInfo.uri = username + '@' + serverIpPort;\n\t\tsipUaInfo.authorizationUser = username;\n\t\tsipUaInfo.password = password;\n\n\t\tsipUaInfo.transportOptions.wsServers = [serverProtocol+ '://' + serverIpPort];\n\t\t// --- only outgoing call should add this. \n\t\t// --- since app doesn't have early media to play to remote party\n\t\tif (rel100 === true) {\n\t\t\t//sipUaInfo.rel100 = SIP.C.supported.SUPPORTED;\n\t\t\tsipUaInfo.rel100 = SIP.C.supported.REQUIRED;\n\t\t} else {\n\t\t\tsipUaInfo.rel100 = SIP.C.supported.UNSUPPORTED;\n\t\t}\n\t\treturn sipUaInfo;\n\t}\n\n\tgetSipAppendExtraHeaders({headers = {}, returnObj = false} = {}) {\n\t\tif (!headers) headers = {};\n\t\tlet extraHeadersObj = {\n\t\t\t'X-RTP-ENCRYPT-METHOD': '2',\n\t\t\t'X-WEBCALL-HASH': (this.props.query.callHash ? this.props.query.callHash : ''),\n\t\t\t...headers,\n\t\t}\n\n\t\tif (returnObj === true) {\n\t\t\treturn extraHeadersObj;\n\t\t} else {\n\t\t\tlet extraHeadersArray = [];\n\n\t\t\tObject.keys(extraHeadersObj).forEach((k) => {\n\t\t\t\textraHeadersArray.push(k + ': ' + extraHeadersObj[k]);\n\t\t\t});\n\n\t\t\t// --- sip.js accept only array\n\t\t\treturn extraHeadersArray;\n\t\t}\n\t}\n\n\tsetSipUaEvents(setup) {\n\t\tif (!this.ua) {\n\t\t\txlog.info(\"[Cue][setSipUaEvents] this.ua is empty\");\n\t\t\treturn false;\n\t\t}\n\n\t\tsetup = (typeof setup === 'undefined') ? {} : setup;\n\t\tlet sipExtraHeaderRegister = setup.sipExtraHeaderRegister;\n\n\t\tthis.ua.on('connecting', (args) => {\n\t\t\txlog.info('[SIPUA_EVENT][connecting] attempts: ', args.attempts);\n\t\t});\n\n\t\tthis.ua.on('connected', () => {\n\t\t\txlog.info('[SIPUA_EVENT][connected]');\n\t\t\tif (this.shouldRegisterAfterConnect && !this.ua.isRegistered()) {\n\t\t\t\t// --- if we use push wake up, it means we don't have persistent connections.\n\t\t\t\tthis.ua.register({\n\t\t\t\t\textraHeaders: this.getSipAppendExtraHeaders({headers: sipExtraHeaderRegister, returnObj: false}),\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.shouldRegisterAfterConnect = false;\n\t\t});\n\n\t\tthis.ua.on('disconnected', () => {\n\t\t\txlog.info('[SIPUA_EVENT][disconnected]');\n\t\t\t//this.dispatch(Actions.UPDATE_REGISTER_STATUS(false));\n\t\t});\n\n\t\tthis.ua.on('registered', () => {\n\t\t\txlog.info('[SIPUA_EVENT][registered]');\n\t\t\t//this.dispatch(Actions.UPDATE_REGISTER_STATUS(true));\n\t\t});\n\n\t\tthis.ua.on('unregistered', (cause) => {\n\t\t\tlet cause_text = cause ? cause : '';\n\t\t\txlog.info('[SIPUA_EVENT][unregistered], cause: ', cause_text);\n\t\t\t//this.dispatch(Actions.UPDATE_REGISTER_STATUS(false));\n\t\t});\n\n\t\tthis.ua.on('registrationFailed', (cause) => {\n\t\t\tlet cause_text = cause && typeof cause === 'object' ? cause.status_code + ' - ' + cause.reason_phrase : 'register failed';\n\t\t\txlog.info('[SIPUA_EVENT][registrationFailed], cause: ', cause_text);\n\t\t\t// --- handle push wakeup failed\n\t\t\t//this.dispatch(Actions.UPDATE_REGISTER_STATUS(false));\n\n\t\t\tif (cause && typeof cause === 'object' &&\n\t\t\t\t(cause.status_code === 401 || cause.status_code === 407)) {\n\t\t\t\txlog.info(\"[Cue][SIPUA_EVENT][registrationFailed] Authentication Error\");\n\t\t\t}\n\t\t});\n\n\t\tthis.ua.on('invite', async (session) => {\n\t\t\txlog.info('[SIPUA_EVENT][invite]');\n\t\t});\n\n\t\tthis.ua.on('message', (message) => {\n\t\t\t// --- no need to check callid because \"MESSAGE\" is a independent transaction to \"INVITE\"\n\t\t\t// --- will dispatch to redux and Talk will render related info based on outgoing / incoming\n\t\t\txlog.info('[SIPUA_EVENT][message] received message: ', message.body);\n\n\t\t\tlet callInfo = this.parseCallInfoJson(message.body); // --- should return null or Object\n\t\t\tif (!callInfo) {\n\t\t\t\treturn; // --- parse json failed.\n\t\t\t}\n\n\t\t\tif (Object.keys(callInfo).length > 0) {\n\t\t\t\tthis.updateTalkingCallInfoPartial(callInfo);\n\t\t\t}\n\t\t});\n\t}\n\n\n\tsetCallSessionEvents(callid) {\n\t\t//var shouldPlayBusyTone = false;\n\t\t/*\n\t\t* --- methods in session object would throw:\n\t\t* - dtmf()\n\t\t* - refer()\n\t\t* - hold()\n\t\t* - unhold()\n\t\t* - reject()\n\t\t* - accept()\n\t\t* - cancel()\n\t\t* - InviteClientContext constructor\n\t\t*/\n\n\t\tthis.session.on('trackAdded', () => {\n\t\t\t// --- We need to check the peer connection to determine which track was added\n\t\t\txlog.info(\"[SIPSESSION_EVENT][trackAdded][%s] session.on('trackAdded')\", callid);\n\n\t\t\tvar pc = this.session.sessionDescriptionHandler.peerConnection;\n\n\t\t\t// Gets remote tracks\n\t\t\tvar remoteStream = new MediaStream();\n\t\t\tpc.getReceivers().forEach(function(receiver) {\n\t\t\t\tremoteStream.addTrack(receiver.track);\n\t\t\t});\n\n\t\t\txlog.info(\"[SIPSESSION_EVENT][trackAdded][%s] session.on('trackAdded') remoteStream = \", callid, remoteStream);\n\t\t\tthis.setState({remoteMediaStream: remoteStream}, () => {\n\t\t\t\txlog.info('remoteMediaStream setState finished');\n\t\t\t\tthis.remoteAudio.srcObject = remoteStream;\n\t\t\t});\n\n\t\t\t// Gets local tracks\n\t\t\t/*\n\t\t\tvar localStream = new MediaStream();\n\t\t\tpc.getSenders().forEach(function(sender) {\n\t\t\t\tlocalStream.addTrack(sender.track);\n\t\t\t});\n\t\t\tlocalVideo.srcObject = localStream;\n\t\t\tlocalVideo.play();\n\t\t\t*/\n\t\t});\n\n\t\tthis.session.on('SessionDescriptionHandler-created', (sessionDescriptionHandler) => {\n\t\t\tthis.sessionDescriptionHandler = sessionDescriptionHandler;\n\n\t\t\tthis.sessionDescriptionHandler.on('userMediaRequest', (constraints) => {\n\t\t\t\t// --- object, The constraints that were used with getUserMedia().\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][userMediaRequest][%s] session.on('userMediaRequest') constraints = %j\", callid, constraints);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('userMediaFailed', (error) => {\n\t\t\t\t// --- string, The message returned from the getUserMedia failure.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][userMediaFailed][%s] session.on('userMediaFailed') error = \", error);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('userMedia', (stream) => {\n\t\t\t\t// --- Fired when getUserMedia() returned local media.\n\n\t\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\t\txlog.info('[SIPSESSION_EVENT][userMedia][%s] current call_session_active is false. return.', callid);\n\t\t\t\t\tstream.release();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\t\txlog.info('[SIPSESSION_EVENT][userMedia][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\t\tstream.release();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\txlog.info('[SIPSESSION_EVENT][userMedia][%s] session on userMedia. (local) stream= ', callid, stream);\n\n\t\t\t\t/*\n\t\t\t\t// --- see: handleAnswerCall() muteCamera. we should mute it at the very beginning\n\t\t\t\tif (this.muteCameraForLocalStream) {\n\t\t\t\t\txlog.info(\"[Cue][userMedia] mute localStream at the beginning due to this.muteCameraForLocalStream is true. ( answer without camera )\");\n\t\t\t\t\tlet tracks = stream.getVideoTracks();\n\t\t\t\t\tif (tracks.length > 0) {\n\t\t\t\t\t\ttracks.forEach((element, index, array) => {\n\t\t\t\t\t\t\telement.enabled = false; // --- this also mute\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t*/\n\n\t\t\t\tstream.isLocal = true;\n\t\t\t\tthis.setState({localMediaStream: stream});\n\t\t\t});\n\n\t\t\t/*\n\t\t\t// --- this occurs before callee received `invite` event, so `remoteStream` would never fired. see: ua.on('invite')\n\t\t\tthis.sessionDescriptionHandler.on('addStream', (e) => {\n\t\t\t\t// --- Fired when a new stream is added to the PeerConnection.\n\t\t\t\t// --- Deprecated. Note: This has been deprecated in the WebRTC api for the new addTrack event instead. Neither api is currently fully supported in all browser enviornments.\n\t\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\t\txlog.info('[SIPSESSION_EVENT][addStream][%s] current call_session_active is false. return.', callid);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\t\txlog.info('[SIPSESSION_EVENT][addStream][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\txlog.info('[SIPSESSION_EVENT][addStream][%s] session on addStream. (remote) stream: ', callid, e.stream);\n\t\t\t\t//this.setState({remoteMediaStream: e.stream});\n\t\t\t\t//this.onAddStream();\n\t\t\t\te.stream.isLocal = false;\n\t\t\t\tthis.setState({remoteMediaStream: e.stream}, () => {\n\t\t\t\t\tthis.remoteAudio.srcObject = e.stream;\n\t\t\t\t\tthis.remoteAudio.play().catch(() => {\n\t\t\t\t\t\txlog.info(\"ZXCPOIU play was rejected\");\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t\t*/\n\n\t\t\t/*\n\t\t\t// --- if this event exist, addStream will not fired\n\t\t\tthis.sessionDescriptionHandler.on('addTrack', (track) => {\n\t\t\t\t// --- Fired when a new track is added to the PeerConnection.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][addTrack][%s] session.on('addTrack'), track = \", callid, track);\n\t\t\t\t\t//this.remoteAudio.srcObject = remoteStream;\n\t\t\t\t\t//this.remoteAudio.play().catch(() => {\n\t\t\t\t\t//\txlog.info(\"ZXCPOIU play was rejected\");\n\t\t\t\t\t//});\n\t\t\t});\n\t\t\t*/\n\n\t\t\tthis.sessionDescriptionHandler.on('iceGathering', () => {\n\t\t\t\t// --- Fired when the WebRTC layer has started gathering ICE candidates.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceGathering][%s] session.on('iceGathering') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceCandidate', (candidate) => {\n\t\t\t\t// --- Fired each time the WebRTC layer finds an ICE candidate.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceCandidate][%s] session.on('iceCandidate'), candidate = %s \", callid, candidate);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceGatheringComplete', () => {\n\t\t\t\t// --- Fired when the WebRTC layer has finished gathering ICE candidates.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceGatheringComplete][%s] session.on('iceGatheringComplete') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceConnection', () => {\n\t\t\t\t// --- Fired when the ICE connection state is new.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceConnection][%s] session.on('iceConnection') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceConnectionChecking', () => {\n\t\t\t\t// --- Fired when the ICE connection state is checking.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceConnectionChecking][%s] session.on('iceConnectionChecking') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceConnectionConnected', () => {\n\t\t\t\t// --- Fired when the ICE connection state is connected.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceConnectionConnected][%s] session.on('iceConnectionConnected') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceConnectionCompleted', () => {\n\t\t\t\t// --- Fired when the ICE connection state is completed.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceConnectionCompleted][%s] session.on('iceConnectionCompleted') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceConnectionFailed', () => {\n\t\t\t\t// --- Fired when the ICE connection state is failed.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceConnectionFailed][%s] session.on('iceConnectionFailed') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceConnectionDisconnected', () => {\n\t\t\t\t// --- Fired when the ICE connection state is disconnected.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceConnectionDisconnected][%s] session.on('iceConnectionDisconnected') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('iceConnectionClosed', () => {\n\t\t\t\t// --- Fired when the ICE connection state is closed.\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][iceConnectionClosed][%s] session.on('iceConnectionClosed') \", callid);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('getDescription', (sdpWrapper) => {\n\t\t\t\t// --- sdpWrapper = {type: 'offer/answer', sdp: 'sdp string'}\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][getDescription][%s] session.on('getDescription'), sdpWrapper = %j \", callid, sdpWrapper);\n\t\t\t});\n\n\t\t\tthis.sessionDescriptionHandler.on('setDescription', (sdpWrapper) => {\n\t\t\t\t// --- sdpWrapper = {type: 'offer/answer', sdp: 'sdp string'}\n\t\t\t\txlog.info(\"[SIPSESSION_EVENT][setDescription][%s] session.on('setDescription'), sdpWrapper = %j \", callid, sdpWrapper);\n\t\t\t});\n\n\t\t});\n\n\t\tthis.session.on('progress', (response, cause) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][progress][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][progress][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet cause_text = cause ? cause : '';\n\t\t\tlet status_code = (response && response.status_code ? response.status_code : '');\n\t\t\tlet reason_phrase = (response && response.reason_phrase ? response.reason_phrase : '');\n\t\t\txlog.info('[SIPSESSION_EVENT][progress][%s] session progress. status_code=%s, reason_phrase=%s, cause=%s', callid, status_code, reason_phrase, cause_text);\n\n\t\t\tthis.setState({call_session_event: 'progress'});\n\n\t\t\tif (this.state.call_session_active === 1) {\n\t\t\t\t// --- outgoing\n\t\t\t\t\n\t\t\t\t// --- if it's 180 or 183, and it does contain sdp, stop fake local rinback and use early media\n\t\t\t\tif (response.status_code === 183 || response.status_code === 180) {\n\t\t\t\t\tif (response.body) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tlet sdpObj = SDPTransform.parse(response.body);\n\t\t\t\t\t\t\tif (sdpObj.media && Array.isArray(sdpObj.media) && sdpObj.media.length > 0) {\n\t\t\t\t\t\t\t\txlog.info('[SIPUA_EVENT][progress] received %s and sdp does contain media m line. stop local ringback and use early media as remote ringback', response.status_code);\n\t\t\t\t\t\t\t\t//InCallManager.stopRingback();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\txlog.info('[SIPUA_EVENT][progress] received %s and sdp does NOT contain media m line. keep playing local ringback', response.status_code);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\txlog.info('[SIPUA_EVENT][progress] received %s and has sdp but parsing failed. assumed it contains early media, so stop local ringback', response.status_code);\n\t\t\t\t\t\t\t//InCallManager.stopRingback();\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\txlog.info('[SIPUA_EVENT][progress] received %s and does NOT contain sdp body. keep playing local ringback', response.status_code);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\txlog.info('[SIPUA_EVENT][progress] received %s response', response.status_code);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// --- incoming\n\t\t\t}\n\t\t});\n\n\t\tthis.session.on('accepted', (response, cause) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][accepted][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t} else if (this.state.call_session_active === 1) {\n\t\t\t\t// --- outgoing\n\t\t\t\t//InCallManager.stopRingback();\n\t\t\t\t//RNCallKit.reportConnectedOutgoingCallWithUUID(this.currentCalls[callid].uuid);\n\t\t\t} else if (this.state.call_session_active === 2) {\n\t\t\t\t// --- incoming\n\t\t\t\t//InCallManager.stopRingtone(); // --- handled in handleAnswerCall() and handleRejectCall()\n\t\t\t\t//if (!LIB.useCallKit(this.state.Settings.useNotificationForIncomingCall)) {\n\t\t\t\t//\tInCallManager.start({media: (this.state.globalStatus.shouldUseVideo ? 'video' : 'audio'), ringback: false});\n\t\t\t\t//}\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][accepted][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet cause_text = cause ? cause : '';\n\t\t\tlet status_code = (response && response.status_code ? response.status_code : '');\n\t\t\tlet reason_phrase = (response && response.reason_phrase ? response.reason_phrase : '');\n\t\t\txlog.info('[SIPSESSION_EVENT][accepted][%s] session accepted. status_code=%s, reason_phrase=%s, cause=%s', callid, status_code, reason_phrase, cause_text);\n\n\t\t\t//AhoyReactor.notifyCallEventListener(Constants.AHOY_CALL_EVENTS.ACCEPTED);\n\n\t\t\tthis.setState({call_session_event: 'answered'}, () => {\n\t\t\t\txlog.info('answered: remoteStream = ', this.state.remoteMediaStream);\n\t\t\t\tthis.remoteAudio.srcObject = this.state.remoteMediaStream;\n\t\t\t\tthis.remoteAudio.play()\n\t\t\t\t\t.then(() => {\n\t\t\t\t\t\txlog.info(\"audio.play() succeed.\");\n\t\t\t\t\t})\n\t\t\t\t\t.catch((err) => {\n\t\t\t\t\t\t// --- ZXCPOIU !!!! on safari, should show alert to let user starts play audios, or just play a audio sound before call, and let user checks\n\t\t\t\t\t\txlog.info(\"audio.play() rejected, err = \", err);\n\t\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (this.session.startTime) {\n\t\t\t\tthis.setState({session_call_start_time: Math.round(this.session.startTime.getTime() / 1000)});\n\t\t\t}\n\n\t\t\t// --- dismiss Talking control panel when answered. failure-free\n\t\t\t//this.dismissTalkControlPanel();\n\t\t});\n\n\t\tthis.session.on('rejected', (response, cause) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][rejected][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][rejected][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet cause_text = cause ? cause : '';\n\t\t\tlet status_code = (response && response.status_code ? response.status_code : '');\n\t\t\tlet reason_phrase = (response && response.reason_phrase ? response.reason_phrase : '');\n\t\t\txlog.info('[SIPSESSION_EVENT][rejected][%s] session rejected. status_code=%s, reason_phrase=%s, cause=%s', callid, status_code, reason_phrase, cause_text);\n\t\t});\n\n\t\tthis.session.on('failed', (response, cause) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][failed][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][failed][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet cause_text = cause ? cause : '';\n\t\t\tlet status_code = (response && response.status_code ? response.status_code : '');\n\t\t\tlet reason_phrase = (response && response.reason_phrase ? response.reason_phrase : '');\n\t\t\txlog.info('[SIPSESSION_EVENT][failed][%s] session failed. status_code=%s, reason_phrase=%s, cause=%s', callid, status_code, reason_phrase, cause_text);\n\t\t});\n\n\t\tthis.session.on('terminated', (response, cause) => {\n\t\t\tlet cause_text = cause ? cause : '';\n\t\t\tlet status_code = (response && response.status_code ? response.status_code : '');\n\t\t\tlet reason_phrase = (response && response.reason_phrase ? response.reason_phrase : '');\n \n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][terminated][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][terminated][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][terminated][%s] session terminated. status_code=%s, reason_phrase=%s, cause=%s', callid, status_code, reason_phrase, cause_text);\n\t\t\tthis.setState({call_session_event: 'terminated'});\n\t\t\tthis.destroyCallSession();\n\t\t});\n\n\t\tthis.session.on('cancel', () => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][cancel][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][cancel][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][cancel][%s] session cancel.', callid);\n\t\t\tthis.setState({call_session_event: 'terminated'});\n\t\t});\n\n\t\t//this.session.on('refer', session.followRefer(callback)); // --- follow refer directlly\n\t\tthis.session.on('refer', (request) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][refer][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][refer][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][refer][%s] session refer.', callid);\n\t\t\t//dispatch(Actions.UPDATE_CALL_SESSION_EVENT('refer'))\n\t\t});\n\n\t\tthis.session.on('replaced', (newSession) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][replaced][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][replaced][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][replaced][%s] session replaced.', callid);\n\t\t\t//dispatch(Actions.UPDATE_CALL_SESSION_EVENT('replaced'))\n\t\t});\n\n\t\tthis.session.on('dtmf', (request, dtmf) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][dtmf][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][dtmf][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][dtmf][%s] session dtmf.', callid);\n\t\t\t//dispatch(Actions.UPDATE_CALL_SESSION_EVENT('dtmf'))\n\t\t});\n\n\t\tthis.session.on('muted', (data) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][muted][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][muted][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][muted][%s] session muted.', callid);\n\t\t\t//dispatch(Actions.UPDATE_CALL_SESSION_EVENT('muted'))\n\t\t});\n\n\t\tthis.session.on('unmuted', (data) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][unmuted][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][unmuted][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][unmuted][%s] session unmuted.', callid);\n\t\t\t//dispatch(Actions.UPDATE_CALL_SESSION_EVENT('unmuted'))\n\t\t});\n\n\t\tthis.session.on('bye', (request) => {\n\t\t\tif (this.state.call_session_active === false || this.state.call_session_event === 'terminated') {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][bye][%s] current call_session_active is false. return.', callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (callid !== this.state.call_session_callid) {\n\t\t\t\txlog.info('[SIPSESSION_EVENT][bye][%s] mismatched callid. current: %s', callid, this.state.call_session_callid);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\txlog.info('[SIPSESSION_EVENT][bye][%s] session bye.', callid);\n\t\t});\n\t}\n\n\n\t// --- return Object if succeed, return null if failed\n\tparseCallInfoJson(callInfoJsonStr) {\n\t\tlet parsed;\n\t\tif (!callInfoJsonStr) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tparsed = JSON.parse(callInfoJsonStr);\n\t\t} catch (e) {\n\t\t\txlog.info('[ERROR][SIPUA_EVENT][message] parseCallInfoJson() failed. JSON parse error, e: %s', e.message);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!LIB.isObject(parsed)) {\n\t\t\txlog.info('[ERROR][SIPUA_EVENT][message] parseCallInfoJson() failed. parsed result is not an object');\n\t\t\treturn;\n\t\t}\n\n\t\t// --- only update columns we recognized\n\t\tlet callInfo = {};\n\n\t\t[\n\t\t\t// --- General\n\t\t\t'maxDuration',\n\t\t\t'callerUsername',\n\t\t\t'calleeUsername',\n\t\t\t'callerIsAhoy',\n\t\t\t'calleeIsAhoy',\n\n\t\t\t// --- Outgoing (for Caller to know)\n\t\t\t'calleeType', // --- \"0: onnet, 1: pstn, 2: other sip server, 3: service (e.g. 599)\n\t\t\t\n\t\t\t// --- Open Door\n\t\t\t'supportOpenDoor', // --- '0' / '1'\n\t\t\t'callerApartmentDeviceType',\n\t\t\t'calleeApartmentDeviceType',\n\t\t\t'callerDeviceHardware',\n\t\t\t'calleeDeviceHardware',\n\n\t\t\t// --- Incoming ( for Callee to know )\n\t\t\t'fromhostBridgeNumber',\n\t\t\t'fromhostServiceType',\n\t\t\t'fromhostUserNumber',\n\t\t\t'onnetMatchedPstnReal', // --- string pstn number if onnet matched\n\t\t\t'isSimulRing', // --- '0' / '1'\n\t\t\t'isVpbxRing', // --- '0' / '1'\n\t\t\t'vpbxUserPressed', // --- string, ext number or 'all'\n\t\t].forEach((item) => {\n\t\t\tif (item in parsed) {\n\t\t\t\tcallInfo[item] = parsed[item];\n\t\t\t}\n\t\t});\n\n\t\treturn callInfo;\n\t}\n\n\thandleDTMF(dtmf) {\n\t\txlog.info('handleDTMF(): %s', dtmf);\n\t\tif (this.state.call_session_active !== false\n\t\t\t\t&& this.session\n\t\t\t\t&& (this.session.status === SIP.Session.C.STATUS_CONFIRMED || this.session.status === SIP.Session.C.STATUS_WAITING_FOR_ACK)\n\t\t\t\t&& dtmf.match(/^[0-9A-D#*,]+$/i)) {\n\t\t\tthis.session.dtmf(dtmf);\n\t\t} else {\n\t\t\txlog.info('handleDTMF() %s, no session to send', dtmf);\n\t\t}\n\n\t\t/*\n\t\t// --- enable this if we want play dtmf tone when dialpad pressed.\n\t\tvar dtmfTone;\n\t\tif (dtmf === '*') {\n\t\t\tdtmf = 'star';\n\t\t} else if (dtmf === '#' || dtmf === '+') {\n\t\t\tdtmf = 'pound';\n\t\t}\n\t\tdtmfTone = this.dtmfTone[dtmf] || null;\n\t\tif (dtmfTone) {\n\t\t\t// Play the sound with an onEnd callback\n\t\t\tdtmfTone.play((success) => { xlog.info(`play dtmf ${dtmf} success: ` + success ? 'true' : 'false') ; });\n\t\t\tsetTimeout(() => {\n\t\t\t\t\tdtmfTone.stop();\n\t\t\t}, 50);\n\t\t} else {\n\t\t\txlog.info('dtmf tone not found: ', dtmf);\n\t\t}\n\t\t*/\n\t}\n\n\tasync handleMakeCall({calleeName = '', calleeNumber = '', preferVideo = false, extenCallGroup = '', callerApartmentInfo = ''} = {}) {\n\t\txlog.info('[App] handleMakeCall()');\n\t\ttry {\n\t\t\tif (!calleeNumber) {\n\t\t\t\txlog.info(\"[DEBUG] handleMakeCall() calleeNumber is empty\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tlet nextShouldUseVideo = false;\n\t\t\t// --- check permission or request depends on audio / video usage\n\t\t\t/*\n\t\t\tlet hasEnoughPermission = await this.checkAndRequestPhoneCallPermission(true, nextShouldUseVideo);\n\t\t\tif (!hasEnoughPermission) {\n\t\t\t\txlog.info('handleMakeCall(): FAILED. user denied phone call permission');\n\t\t\t\tLIB.showAlertModal({\n\t\t\t\t\ttitle: I18n.t('Permission_PhoneCallDenied_title'),\n\t\t\t\t\tmsg: I18n.t('Permission_PhoneCallDenied_msg') + '\\n\\n' + I18n.t('ManualGrantPermissionGuide'),\n\t\t\t\t\tbuttons: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: I18n.t('GoToAppPermissionSettings'),\n\t\t\t\t\t\t\tonPress: () => {\n\t\t\t\t\t\t\t\tthis.openAppSettings();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// --- Press Cancel, continue without bother\n\t\t\t\t\t\t\tghost: true,\n\t\t\t\t\t\t\ttext: I18n.t('GotIt'),\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t});\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t*/\n\n\t\t\t// --- FOR DEBUG, not using nginx as reverse proxy, but it needs to install TTC CA on your browser\n\t\t\t//serverIpPort = 'sip.yohalabs.com:443';\n\t\t\t//serverIpPort = 'sip1-dev.yohalabs.com:443';\n\n\t\t\t// --- default use nginx as reverse proxy, because we need Let's Encrypt for browser. sip-proxy.sayahoy.info:443 or sip-proxy-dev.sayahoy.info:443\n\t\t\t// --- change this at app_setup.js\n\t\t\tlet serverIpPort = util.format('%s:%s', AppSetup.sipProxyDomain, AppSetup.sipProxyPort);\n\n\t\t\tif (AppSetup.isDebug && this.props.query.queryString.customSipServer) {\n\t\t\t\t// --- only allow 443 sip server port\n\t\t\t\tlet customSipServer = this.props.query.queryString.customSipServer;\n\t\t\t\tif (!customSipServer.endsWith(':443')) {\n\t\t\t\t\tcustomSipServer += ':443';\n\t\t\t\t}\n\n\t\t\t\t// --- only allow our domain \n\t\t\t\tif (customSipServer.endsWith('sayahoy.info:443') || customSipServer.endsWith('yohalabs.com:443')) {\n\t\t\t\t\tserverIpPort = customSipServer;\n\t\t\t\t\txlog.info('[Cue][handleMakeCall] !!! use custom server: %s', customSipServer);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet calleeUri = 'sip:' + calleeNumber + '@' + serverIpPort;\n\n\t\t\t// --- if we use push wake up, it means we don't have persistent connections.\n\t\t\tif (!this.ua) {\n\t\t\t\tthis.createSipUaInstance({\n\t\t\t\t\tcustomServerIpPort: serverIpPort,\n\t\t\t\t\tmoveTaskToBackAfterEnd: false,\n\t\t\t\t\trel100: true,\n\t\t\t\t});\n\t\t\t\tif (!this.ua) {\n\t\t\t\t\txlog.info(\"[Cue][handleMakeCall] this.ua is empty\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//if (this.ua && !this.ua.isConnected()) {\n\t\t\tif (this.ua) {\n\t\t\t\tthis.ua.start();\n\t\t\t}\n\t\t\t//if ( 0 && this.localMediaStream === false) {\n\t\t\t//\tthis.sipGetMediaStream();\n\t\t\t//}\n\t\t\t//this.dispatch(Actions.UPDATE_CALL_SESSION_EVENT('trying'));\n\t\t\tthis.setState({call_session_event: 'trying'});\n\t\t\treturn this.sendCall(calleeUri, calleeName, calleeNumber, nextShouldUseVideo, extenCallGroup, callerApartmentInfo);\n\t\t} catch (e) {\n\t\t\txlog.info('handleMakeCall(): FAILED. err = %s, stack = ', e, e.stack);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tsendCall(calleeUri, calleeName, calleeNumber, shouldUseVideo, extenCallGroup, callerApartmentInfo) {\n\t\tif (!this.ua) {\n\t\t\txlog.info(\"[Cue][sendCall] this.ua is empty\");\n\t\t\treturn false;\n\t\t}\n\n\t\t// --- the last args is sdp modifiers. An Array of Function returning Promise. Optional modifiers that will be applied to the incoming or outgoing description.\n\t\tthis.session = this.ua.invite(calleeUri, this.getInviteAcceptOptions({enableVideo: shouldUseVideo, extenCallGroup, callerApartmentInfo}), [LibSDP.customSdpHacks]);\n\t\tthis.setState({call_session_active: 1, call_session_callid: this.session.request.callId}, () => {\n\t\t\tthis.setCallSessionEvents(this.session.request.callId);\n\t\t\t//InCallManager.start({media: (shouldUseVideo ? 'video' : 'audio'), ringback: '_DTMF_'});\n\t\t\treturn true;\n\t\t});\n\n\t}\n\n\tgetSessionDescriptionHandlerOptions({enableVideo = '', extenCallGroup = '', callerApartmentInfo = '', isUaInit = false} = {}) {\n\t\t// --- true or https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints\n\t\tlet constraints = {\n\t\t\taudio: {\n\t\t\t\t// --- A ConstrainDOMString object specifying a device ID or an array of device IDs which are acceptable and/or required.\n\t\t\t\t//deviceId\n\n\t\t\t\t// --- A ConstrainDOMString object specifying a group ID or an array of group IDs which are acceptable and/or required.\n\t\t\t\t//groupId\n\n\t\t\t\t// --- A ConstrainBoolean object which specifies whether automatic gain control is preferred and/or required.\n\t\t\t\tautoGainControl: true,\n\n\t\t\t\t// --- A ConstrainLong specifying the channel count or range of channel counts which are acceptable and/or required.\n\t\t\t\t//channelCount\n\n\t\t\t\t// --- A ConstrainBoolean object specifying whether or not echo cancellation is preferred and/or required.\n\t\t\t\techoCancellation: true,\n\n\t\t\t\t// --- A ConstrainDouble specifying the latency or range of latencies which are acceptable and/or required.\n\t\t\t\t//latency\n\n\t\t\t\t// --- A ConstrainBoolean which specifies whether noise suppression is preferred and/or required.\n\t\t\t\tnoiseSuppression: true,\n\n\t\t\t\t// --- A ConstrainLong specifying the sample rate or range of sample rates which are acceptable and/or required.\n\t\t\t\t//sampleRate\n\n\t\t\t\t// --- A ConstrainLong specifying the sample size or range of sample sizes which are acceptable and/or required.\n\t\t\t\t//sampleSize\n\n\t\t\t\t// --- A ConstrainDouble specifying the volume or range of volumes which are acceptable and/or required.\n\t\t\t\tvolume: 0.8,\n\t\t\t},\n\t\t\tvideo: false,\n\t\t\t/*\n\t\t\tvideo: {\n\t\t\t\t// --- A ConstrainDouble specifying the video aspect ratio or range of aspect ratios which are acceptable and/or required.\n\t\t\t\taspectRatio\n\n\t\t\t\t// --- A ConstrainDOMString object specifying a facing or an array of facings which are acceptable and/or required.\n\t\t\t\tfacingMode\n\n\t\t\t\t// --- A ConstrainDouble specifying the frame rate or range of frame rates which are acceptable and/or required.\n\t\t\t\tframeRate\n\n\t\t\t\t// --- A ConstrainLong specifying the video height or range of heights which are acceptable and/or required.\n\t\t\t\theight\n\n\t\t\t\t// --- A ConstrainLong specifying the video width or range of widths which are acceptable and/or required.\n\t\t\t\twidth\n\n\t\t\t\t// --- A ConstrainDOMString object specifying a mode or an array of modes the UA can use to derive the resolution of a video track. Allowed values are none and crop-and-scale. none means that the user agent uses the resolution provided by the camera, its driver or the OS. crop-and-scale means that the user agent can use cropping and downscaling on the camera output in order to satisfy other constraints that affect the resolution.\n\t\t\t\tresizeMode\n\t\t\t}\n\t\t\t*/\n\t\t};\n\n\t\t// --- 500 ~ 5000, default 5000\n\t\tlet iceCheckingTimeout = 5000;\n\n\t\t// --- This is a workaround for some unexpected behavior in Firefox 61+. Default value is false.\n\t\tlet alwaysAcquireMediaFirst = false;\n\n\t\t// --- Array of Function returning Promise. A set of default modifiers to use every time a description is requested or set by the Session Description Handler. These modifiers will occur before modifiers passed by a specific call to the Session Description Handler.\n\t\t//modifiers: [];\n\n\t\t// --- Options to be passed to the WebRTC PeerConnection constructor.\n\t\tlet rtcConfiguration = {\n\t\t\t// --- Specifies how to handle negotiation of candidates when the remote peer is not compatible with the SDP BUNDLE standard. This must be one of the values from the enum RTCBundlePolicy. If this value isn't included in the dictionary, \"balanced\" is assumed.\n\t\t\tbundlePolicy: 'balanced',\n\t\t\t// --- An Array of objects of type RTCCertificate which are used by the connection for authentication. If this property isn't specified, a set of certificates is generated automatically for each RTCPeerConnection instance.\n\t\t\t//certificates: [],\n\t\t\t// --- An unsigned 16-bit integer value which specifies the size of the prefetched ICE candidate pool. The default value is 0 (meaning no candidate prefetching will occur). You may find in some cases that connections can be established more quickly by allowing the ICE agent to start fetching ICE candidates before you start trying to connect, so that they're already available for inspection when RTCPeerConnection.setLocalDescription() is called. Changing the size of the ICE candidate pool may trigger the beginning of ICE gathering.\n\t\t\t//iceCandidatePoolSize: 0,\n\t\t\ticeServers: [\n\t\t\t\t{\n\t\t\t\t\t//urls: ['stun://stun2.yohalabs.com:443']\n\t\t\t\t\turls: ['stun:stun2.yohalabs.com:443']\n\t\t\t\t},\n\t\t\t],\n\t\t\t// --- 'all' - default. 'relay' - Only ICE candidates whose IP addresses are being relayed, such as those being passed through a TURN server, will be considered.\n\t\t\t//iceTransportPolicy: 'all',\n\t\t\t// --- A DOMString which specifies the target peer identity for the RTCPeerConnection. If this value is set (it defaults to null), the RTCPeerConnection will not connect to a remote peer unless it can successfully authenticate with the given name.\n\t\t\t//peerIdentity: '',\n\t\t\t// --- The RTCP mux policy to use when gathering ICE candidates, in order to support non-multiplexed RTCP. The value must be one of those from the RTCRtcpMuxPolicy enum. The default is \"require\".\n\t\t\trtcpMuxPolicy: \"require\", // --- \"negotiate\" is being deprecated\n\t\t};\n\n\t\t// --- Options to be passed to the WebRTC Peer Connection createOffer or createAnswer call.\n\t\tlet RTCOfferOptions = {\n\t\t\t// --- To restart ICE on an active connection, set this to true. This will cause the returned offer to have different credentials than those already in place. If you then apply the returned offer, ICE will restart. Specify false to keep the same credentials and therefore not restart ICE. The default is false.\n\t\t\ticeRestart: false,\n\t\t\t// --- Some codecs and hardware are able to detect when audio begins and ends by watching for \"silence\" (or relatively low sound levels) to occur. This reduces network bandwidth used for audio by only sending audio data when there's actually something to broadcast. However, in some cases, this is unwanted. For example, in the case of music or other non-voice transmission, this can cause loss of important low-volume sounds. Also, emergency calls should never cut audio when quiet. This option defaults to true (voice activity detection enabled).\n\t\t\tvoiceActivityDetection: true,\n\t\t\tofferToReceiveAudio: true,\n\t\t\tofferToReceiveVideo: (enableVideo ? true : false),\n\t\t};\n\n\t\t// --- combine options by type, it's really weird.\n\t\tlet options = {};\n\t\tif (isUaInit) {\n\t\t\toptions = {\n\t\t\t\tconstraints,\n\t\t\t\tpeerConnectionOptions: {\n\t\t\t\t\trtcConfiguration,\n\t\t\t\t\ticeCheckingTimeout,\n\t\t\t\t},\n\t\t\t\talwaysAcquireMediaFirst,\n\t\t\t\tRTCOfferOptions,\n\t\t\t};\n\n\t\t} else {\n\t\t\toptions = {\n\t\t\t\tconstraints,\n\t\t\t\ticeCheckingTimeout,\n\t\t\t\talwaysAcquireMediaFirst,\n\t\t\t\trtcConfiguration,\n\t\t\t\tRTCOfferOptions,\n\t\t\t};\n\t\t}\n\n\t\treturn options;\n\n\t\t// --- sip.js only consumes when making a call\n\t\t/*\n\t\tRTCConstraints: {\n\t\t\tmandatory: {\n\t\t\t},\n\t\t\toptional: [\n\t\t\t\t{DtlsSrtpKeyAgreement: 'true'},\n\t\t\t\t{googDscp: 'true'},\n\t\t\t\t{googIPv6: 'false'},\n\t\t\t],\n\t\t},\n\t\t*/\n\t}\n\n\tgetInviteAcceptOptions({enableVideo = '', extenCallGroup = '', callerApartmentInfo = ''} = {}) {\n\t\tlet options = {\n\t\t\textraHeaders: this.getSipAppendExtraHeaders({extenCallGroup, callerApartmentInfo}),\n\t\t\t//anonymous: false,\t// ---indicating whether the call should be done anonymously. Default value is false\n\t\t\t//rel100: SIP.C.supported.UNSUPPORTED, // --- Optionally declare support or requirement of reliable provisional responses (100rel), as defined in RFC3262. Default is Unsupported.\n\t\t\t//inviteWithoutSdp: false, // --- \tIf true, send the INVITE with no SDP offer. In this case, the SDP offer is to be generated by the remote endpoint, and the SDP answer will be sent in an ACK or PRACK. Default is false (send with SDP).\n\t\t\tsessionDescriptionHandlerOptions: this.getSessionDescriptionHandlerOptions({enableVideo, extenCallGroup, callerApartmentInfo, isUaInit: false}),\n\t\t}\n\n\t\treturn options;\n\t}\n\n\thandleHangUp() {\n\t\ttry {\n\t\t\tif (this.state.call_session_active !== false) {\n\t\t\t\tif (this.session.startTime) {\n\t\t\t\t\tif (!this.session.endTime) {\n\t\t\t\t\t\tthis.session.bye();//{extraHeaders: this.etSipAppendExtraHeaders()}\n\t\t\t\t\t\txlog.info('call hangup');\n\t\t\t\t\t} else {\n\t\t\t\t\t\txlog.info('session already ended');\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (this.state.call_session_active === 1) {\n\t\t\t\t\t\tthis.session.cancel();//{extraHeaders: this.getSipAppendExtraHeaders()}\n\t\t\t\t\t\txlog.info('call canceled');\n\t\t\t\t\t} else if (this.state.call_session_active === 2) {\n\t\t\t\t\t\tthis.session.reject();//{extraHeaders: this.getSipAppendExtraHeaders()}\n\t\t\t\t\t\txlog.info('call rejected');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\txlog.info('no call session to terminate.');\n\t\t\t}\n\t\t} catch (err) {\n\t\t\txlog.info(\"[Cue][handleHangUp] this.session.reject() Exception: %j\", err);\n\t\t\tthis.destroyCallSession();\n\t\t}\n\t\t/*\n\t\t// --- will do this in destroyCallSession()\n\t\tInCallManager.stop({'busytone': false});\n\t\tif (AppSetup.isPushWakeUpEnabled === true) {\n\t\t\t//setTimeout(this.closeSipUaInstance, this.sipCloseLingerMs);\n\t\t\tthis.closeSipUaInstance();\n\t\t}\n\t\tthis.dispatch(Actions.UPDATE_CALL_SESSION_ACTIVE(false));\n\t\tthis.dispatch(Actions.UPDATE_CALL_SESSION_CALLID(''));\n\t\t*/\n\t}\n\n\tupdateTalkingCallInfoPartial(callInfo) {\n\t\tthis.setState({\n\t\t\ttalkingCallInfo: {...this.state.talkingCallInfo, ...callInfo},\n\t\t});\n\t}\n\n\tupdateTalkingCallInfo(talkingCallInfo) {\n\t\tthis.setState({ talkingCallInfo });\n\t}\n\n\tdestroyCallSession(setup) {\n\t\tif (typeof setup === 'undefined') setup = {};\n\t\tthis.remoteAudio.srcObject = null;\n\t\tthis.remoteAudio.pause();\n\t\tthis.session = false;\n\t\tthis.sdp = false;\n\t\tthis.closeSipUaInstance();\n\t\t//this.logSessionTime();\n\t\t//this.updateTalkingCallData(null);\n\n\t\t// --- we only release local media stream. remote will release automatically.\n\t\tif (this.state.localMediaStream !== null) {\n\t\t\t// --- release tracks\n\t\t\tlet tracks = this.state.localMediaStream.getTracks();\n\t\t\tif (tracks && tracks.length > 0) {\n\t\t\t\ttracks.forEach((element, index, array) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.state.localMediaStream.removeTrack(element);\n\t\t\t\t\t} catch (e) { /* just try remove it as clean as possible. do not fail. */ }\n\t\t\t\t});\n\t\t\t}\n\t\t\t// --- release local stream to prevent slowing on the next invoke\n\t\t\ttry {\n\t\t\t\tthis.state.localMediaStream.release();\n\t\t\t} catch (e) { /* just try remove it as clean as possible. do not fail. */ }\n\t\t}\n\n\t\tthis.setState({\n\t\t\tcall_session_active: false,\n\t\t\tcall_session_callid: '',\n\t\t\tsession_call_start_time: 0,\n\t\t\tcall_session_event: 'terminated',\n\n\t\t\tlocalMediaStream: null,\n\t\t\tremoteMediaStream: null,\n\t\t\ttalkingCallInfo: {},\n\t\t});\n\n\t}\n\n\tonPressCallButton(calleeNumber, calleeName) {\n\t\t//this.remoteAudio.play() // --- no need to play here, we've already has user interaction\n\n\t\t// --- start etect availability on client\n\t\tthis.detectRTCProcess()\n\t\t.then(this.onDetectRTCLoad)\n\t\t.catch((err) => {\n\t\t\txlog.info('[App] onPressCallButton().DetectRTCProcess() failed. err = ', err);\n\t\t})\n\t\t.then(() => {\n\t\t\tlet { available, unsupportedMsg } = this.detectRTCCheckAvailability();\n\t\t\txlog.info('[App] onPressCallButton().detectRTCCheckAvailability() available = %s, unsupportedMsg = %s', available, unsupportedMsg);\n\n\t\t\tif (available) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.handleMakeCall({calleeName, calleeNumber, preferVideo: false });\n\t\t\t\t} catch (err) {\n\t\t\t\t\txlog.info('[App] onPressCallButton().handleMakeCall() failed. err = ', err);\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\tonPressCallEndButton() {\n\t\tthis.destroyCallSession();\n\t}\n\n\tonAfterOpenModal() {\n\t}\n\n\tonCloseModal() {\n\t\tthis.setState({\n\t\t\tmodal: {\n\t\t\t\tisModalOpen: false,\n\t\t\t}\n\t\t});\n\t}\n\n\trender() {\n\t\t//xlog.info('[App] render() this.state = ', this.state);\n\n\t\tif (!this.state.appInitialized) {\n\t\t\treturn (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tLoading...\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t)\n\n\t\t} else if (!this.state.webcallInfo.calleeNumber) {\n\t\t\treturn (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{I18n.t('IncorrectWebCallData')}\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t)\n\t\t} else {\n\t\t\t// --- will display message when: 1. debug, 2. really unavailable, see: detectRTCCheckAvailability\n\t\t\tlet { available, unsupportedMsg } = this.detectRTCCheckAvailability();\n\n\t\t\tlet { calleeNumber, calleeName } = this.state.webcallInfo;\n\n\t\t\tlet expectedHeight, expectedWidth;\n\t\t\tif (this.props.windowHeight >= this.props.windowWidth) {\n\t\t\t\t// --- portrait\n\t\t\t\texpectedHeight = this.props.windowHeight * 0.95;\n\t\t\t\texpectedWidth = this.props.windowWidth * 0.95;\n\t\t\t} else {\n\t\t\t\t// --- landscape, use width as height to display as portrait\n\t\t\t\texpectedHeight = this.props.windowHeight * 0.95;\n\t\t\t\texpectedWidth = expectedHeight * 0.5625;\n\t\t\t}\n\t\t\texpectedWidth = parseInt(expectedWidth);\n\t\t\texpectedHeight = parseInt(expectedHeight);\n\n\t\t\t//icon=\n\t\t\t/*\n\t\t\t\t

\n\t\t\t\t\tScreen height is: {this.props.windowHeight}\n\t\t\t\t\t
\n\t\t\t\t\tScreen width is: {this.props.windowWidth}\n\t\t\t\t\t
\n\t\t\t\t\tExpected height is: {expectedHeight}\n\t\t\t\t\t
\n\t\t\t\t\tExpected width is: {expectedWidth}\n\t\t\t\t

\n\t\t\t*/\n\t\t\treturn (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{ this.state.call_session_active === false &&\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t{calleeName}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t { this.onPressCallButton(calleeNumber, calleeName); }}\n\t\t\t\t\t\t\t\t\ticon={{type: 'material', name: 'call', size: 40, color: 'white'}}\n\n\t\t\t\t\t\t\t\t\tdisabled={false}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t{'提醒您︰此為免費電話\\n系統將以免持聽筒通話,建議使用耳麥通話。'}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t{I18n.t('WebWarning')}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{ !!unsupportedMsg && (AppSetup.isDebug || !available) &&\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t{unsupportedMsg}\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\t{ this.state.call_session_active !== false &&\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t{ this.state.modal.isModalOpen && (\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{this.state.modal.view || null}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t)}\n\t\t\t\t\n\t\t\t);\n\t\t}\n\t}\n}\n\nconst styles = StyleSheet.create({\n\treminderText: {\n\t\tcolor: 'grey',\n\t\talignSelf: 'center',\n\t\tfontSize: 16,\n\t},\n\twarningText: {\n\t\tcolor: 'red',\n\t\talignSelf: 'center',\n\t\tfontSize: 16,\n\t},\n\treadyToCallContainer: {\n\t\tflex: 1,\n\t\talignItems: 'center',\n\t\tjustifyContent: 'space-around',\n\t\tborderWidth: 1,\n\t\tpadding: 10,\n\t\tborderColor: '#DDD',\n\t\tborderStyle: 'solid',\n\t},\n\tmainButtonContainer: {\n\t\tborderRadius: 30,\n\t\tborderWidth: 0,\n\t\tbackgroundColor: 'white',\n\t\t//flex: 1,\n\t\t//width: AppSetup.dimensions.width * .95,\n\t\talignSelf: 'stretch',\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t},\n\tcenter: {\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t},\n});\n\n// windowSize will pass height and width to wrapped components\n// --- Screen width is: {this.props.windowWidth}\n// --- Screen height is: {this.props.windowHeight}\nApp = WindowSize(App);\n\nlet hotWrapper = () => () => App;\nif (Platform.OS === 'web') {\n\tconst { hot } = require('react-hot-loader');\n\thotWrapper = hot;\n}\nexport default hotWrapper(module)(App);\n","import React from 'react';\nimport {\n\tView,\n} from 'react-native-web';\n\nconst layoutStyle = {\n\tmargin: 5,\n\tpadding: 5,\n\tborderWidth: 1,\n\tborderColor: '#DDD',\n\tborderStyle: 'solid',\n\tdisplay: 'flex',\n\tflexDirection: \"column\",\n\talignItems: 'center',\n\tjustifyContent: 'center',\n}\n\nclass Layout extends React.PureComponent {\n\n\trender() {\n\t\treturn (\n\t\t\t\n\t\t\t\t{this.props.children}\n\t\t\t\n\t\t);\n\t}\n}\n\nexport default Layout\n","// higher-order component that passes the dimensions of the window as props to\n// the wrapped component\nimport React, { Component } from 'react';\n\nexport default (ComposedComponent) => {\n\n\tclass windowSize extends Component {\n\n\t\tconstructor() {\n\t\t\tsuper();\n\t\t\tlet { height, width } = this.getWindowSize();\n\t\t\tthis.state = { height, width};\n\t\t}\n\n\t\tgetWindowSize() {\n\t\t\treturn {\n\t\t\t\theight: (window.innerHeight || document.documentElement.clientHeight || document.body.offsetHeight || 800),\n\t\t\t\twidth: (window.innerWidth || document.documentElement.clientWidth || document.body.offsetWidth || 480 ),\n\t\t\t};\n\t\t}\n\n\t\thandleResize() {\n\t\t\t// set initial state\n\t\t\tlet { height, width } = this.getWindowSize();\n\t\t\tthis.setState({ height, width });\n\t\t}\n\n\t\tcomponentDidMount() {\n\t\t\t// bind window resize listeners\n\t\t\tthis._handleResize = this.handleResize.bind(this);\n\t\t\twindow.addEventListener('resize', this._handleResize);\n\t\t\tsetTimeout(this._handleResize, 1000);\n\t\t}\n\n\t\tcomponentWillUnmount() {\n\t\t\t// clean up listeners\n\t\t\twindow.removeEventListener('resize', this._handleResize);\n\t\t}\n\n\t\tgetWrappedInstance() {\n\t\t\treturn this.wrappedInstance;\n\t\t}\n\n\t\trender() {\n\t\t\t// pass window dimensions as props to wrapped component\n\t\t\treturn (\n\t\t\t\t { this.wrappedInstance = c; }}\n\t\t\t\t\twindowWidth={this.state.width}\n\t\t\t\t\twindowHeight={this.state.height}\n\t\t\t\t/>\n\t\t\t);\n\t\t}\n\n\t}\n\n\tconst composedComponentName = ComposedComponent.displayName\n\t\t|| ComposedComponent.name\n\t\t|| 'Component';\n\n\twindowSize.displayName = `windowSize(${composedComponentName})`;\n\treturn windowSize;\n\n};\n","import React from 'react';\nimport DialPad, * as DialPadImpl from './components/DialPad';\n//import Empty from './components/Empty';\n//import util from 'util';\nimport * as LIB from './lib/lib.js';\nimport AppSetup from './app_setup.js';\nimport autobind from 'autobind-decorator';\nimport I18n from './lib/i18n.js';\nimport {\n\tText,\n\tView,\n\t//TouchableWithoutFeedback,\n\tStyleSheet,\n} from 'react-native-web';\n\nimport { \n\tButton as ButtonElement,\n} from 'react-native-elements';\n\nimport MaterialIcon from 'react-native-vector-icons/dist/MaterialIcons';\n\n//import debounce from 'lodash/debounce';\nimport { MaterialTheme } from './lib/styles.js';\nconst Theme = MaterialTheme[AppSetup.Theme];\nconst xlog = require('./lib/xlog.js'); // --- use reqiure so that we can use `pure_funcs` to strip in production build\n\n@autobind\nclass Talk extends React.Component {\n\n\tconstructor(props) {\n\t\tsuper(props);\n\t\t//props.redux = {}; // --- workaround\n\n\t\tthis.talkingCallData = null;\n\t\tthis.isStart = true;\n\t\tthis.isStopping = false;\n\t\tthis.isTimerStarted = false;\n\n\t\t// --- use debounce may results in 'setState on unmounted components'\n\t\t//this.onPressMicMute = debounce(this.onPressMicMute, 200);\n\t\t//this.onPressChangeAudioRoute = debounce(this.onPressChangeAudioRoute, 200);\n\t\t//this.onPressCameraMute = debounce(this.onPressCameraMute, 200);\n\t\t//this.onPressSwitchVideo = debounce(this.onPressSwitchVideo, 200);\n\t\t//this.onPressOpenDoor = debounce(this.onPressOpenDoor, 200);\n\t\t//\n\t\tthis.state = {\n\t\t\tdtmfs: '',\n\t\t\tisKeyboardOpen: false,\n\t\t\tview: 'talking',\n\t\t\tisToggleAudioDeviceOn: true, // --- default true\n\t\t\tisMicMute: false,\n\t\t\tisCameraMute: false,\n\t\t\tisHangUpBtnPressed: false,\n\t\t\tlargeVideoRenderTypePreferLocal: false,\n\t\t\tshouldShowControlView: true,\n\t\t\tcallDuration: 0,\n\t\t\tlocalCameraFacingModeEnvironment: false, // --- use use facing mode = \"user\" by default\n\t\t};\n\n\t\tthis.resetState({isConstructor: true});\n\t\txlog.info('Talk.constructor');\n\t}\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('[Talk] componentDidCatch, error = ', error);\n\t\txlog.info('[Talk] componentDidCatch, info = ', info);\n\t}\n\n\tcomponentDidMount() {\n\t\txlog.info('[Talk] componentDidMount');\n\t}\n\n\tcomponentWillUnmount() {\n\t\txlog.info('[Talk] componentWillUnmount');\n\t}\n\n\tresetState(info) {\n\t\tif (!info) {\n\t\t\txlog.info('[Talk] resetState() but info is null');\n\t\t\tinfo = {};\n\t\t}\n\n\t\tlet nextState = {\n\t\t\tdtmfs: '',\n\t\t\tisKeyboardOpen: false,\n\t\t\tview: info.view || 'talking',\n\t\t\tisToggleAudioDeviceOn: true,\n\t\t\tisMicMute: false,\n\t\t\tisCameraMute: false,\n\t\t\tisHangUpBtnPressed: info.stopCall || false,\n\t\t\tlargeVideoRenderTypePreferLocal: false,\n\t\t\tshouldShowControlView: true,\n\t\t\tcallDuration: 0,\n\t\t\tlocalCameraFacingModeEnvironment: false, // --- use use facing mode = \"user\" by default\n\t\t};\n\n\t\tthis.callType = 'outgoing';\n\t\tthis.isTimerStarted = false;\n\n\t\tif (info.isConstructor !== true) {\n\t\t\tthis.setState(nextState);\n\t\t}\n\t}\n\n\thandleHangUp(calleeNumber) {\n\t\txlog.info('Talk.handleHangUp: hangup button pressed');\n\t\tthis.setState({isHangUpBtnPressed: true});\n\t\tthis.props.parent.handleHangUp();\n\t}\n\n\thandleOnKeyboardSwitch() {\n\t\txlog.info('keyboard button pressed ');\n\t\tthis.setState({isKeyboardOpen: !this.state.isKeyboardOpen});\n\t}\n\n\thandleDialPadOnChangeText(text) {\n\t\txlog.info('handleDialPadOnChangeText: text =', text);\n\t\t//DialPadImpl.handleOnChangeText.call(this, text, 'dtmfs');\n\t\tthis.setState({dtmfs: text});\n\t}\n\n\thandleDialPadOnPress(button, isLongPress) {\n\t\txlog.info('handleDialPadOnPress: button=', button, ', isLongPress=', isLongPress);\n\t\tlet symbol = DialPadImpl.handleOnPress.call(this, button, isLongPress, this.state.dtmfs);\n\t\tthis.props.parent.handleDTMF(symbol);\n\t}\n\n\thandleDialPadOnBackspace() {\n\t\txlog.info('handleDialPadOnBackspace()');\n\t\tDialPadImpl.handleOnBackspace.call(this, this.state.dtmfs);\n\t}\n\n\thandleDialPadOnReset() {\n\t\txlog.info('handleDialPadOnReset()');\n\t\tDialPadImpl.handleOnReset.call(this);\n\t}\n\n\tonPressMicMute() {\n\t\tlet { localMediaStream } = this.props.parent.state;\n\t\tlet isMicMute= !this.state.isMicMute;\n\t\tif (localMediaStream !== null) {\n\t\t\tlet tracks = localMediaStream.getAudioTracks();\n\t\t\tif (tracks.length > 0) {\n\t\t\t\ttracks.forEach((element, index, array) => {\n\t\t\t\t\telement.enabled = !isMicMute; // --- this also mute\n\t\t\t\t})\n\t\t\t\t//InCallManager.setMicrophoneMute(isMicMute); // --- only android can shut the mic down programmatically.\n\t\t\t\txlog.info(\"onPressMicMute() set isMicMute = \", isMicMute);\n\t\t\t\tthis.setState({isMicMute: isMicMute});\n\t\t\t}\n\t\t} else {\n\t\t\txlog.info(\"onPressMicMute() localstream is null\");\n\t\t}\n\t}\n\n\tasync onPressChangeAudioRoute() {\n\t\tlet nextIsToggleAudioDeviceOn = !this.state.isToggleAudioDeviceOn;\n\t\tthis.props.parent.remoteAudio.volume = (nextIsToggleAudioDeviceOn ? 1.0 : 0.0);\n\t\tthis.setState({isToggleAudioDeviceOn: nextIsToggleAudioDeviceOn});\n\t}\n\t/*\n\t// --- 20190610: temp disable audio device selection, it may be confusing since AHOY APP is speakerphone toggle instead audio device toggle\n\tasync changeAudioDeviceById(sinkId, lastTry=false) {\n\t\tlet element = this.props.parent.remoteAudio;\n\n\t\tif (typeof element.sinkId !== 'undefined') {\n\t\t\ttry {\n\t\t\t\tawait element.setSinkId(sinkId)\n\t\t\t} catch (err) {\n\t\t\t\tlet errorMessage = err;\n\t\t\t\tif (err.name === 'SecurityError') {\n\t\t\t\t\terrorMessage = `You need to use HTTPS for selecting audio output device: ${err}`;\n\t\t\t\t}\n\t\t\t\txlog.info('changeAudioDeviceById() failed. %s', errorMessage);\n\n\t\t\t\t// --- Jump back to first output device in the list as it's the default.\n\t\t\t\tif (!lastTry) {\n\t\t\t\t\tlet deviceInfos = await navigator.mediaDevices.enumerateDevices();\n\t\t\t\t\tif (deviceInfos.length > 0) {\n\t\t\t\t\t\tlet deviceId = deviceInfos[0].deviceId;\n\t\t\t\t\t\tthis.changeAudioDeviceById(deviceId, true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\txlog.info('[Talk] changeAudioDeviceById() Browser does not support output device selection.');\n\t\t}\n\t}\n\n\tasync onPressChangeAudioRoute() {\n\t\tlet isSinkIdSupported = ('sinkId' in HTMLMediaElement.prototype);\n\t\tif (!isSinkIdSupported) {\n\t\t\txlog.info('onPressChangeAudioRoute() sink id is not supported');\n\t\t}\n\n\t\tlet audioOutputDevices = [];\n\t\ttry {\n\t\t\tlet deviceInfos = await navigator.mediaDevices.enumerateDevices();\n\n\t\t\t// Handles being called several times to update labels. Preserve values.\n\t\t\tfor (let i = 0; i !== deviceInfos.length; ++i) {\n\t\t\t\tlet deviceInfo = deviceInfos[i];\n\t\t\t\tlet title = '';\n\t\t\t\tif (deviceInfo.kind === 'audiooutput') {\n\t\t\t\t\ttitle = deviceInfo.label || `speaker ${audioOutputDevices.length + 1}`;\n\t\t\t\t\tdeviceInfo.title = title;\n\t\t\t\t\taudioOutputDevices.push(deviceInfo);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (audioOutputDevices.length > 0) {\n\t\t\t\tlet modlaView = (\n\t\t\t\t\t\n\t\t\t\t\t\t{audioOutputDevices.map((item, i) => (\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t this.changeAudioDeviceById(item.deviceId)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t))}\n\t\t\t\t\t\n\t\t\t\t);\n\t\t\t\tthis.props.parent.setState({\n\t\t\t\t\tmodal: {\n\t\t\t\t\t\tisModalOpen: true,\n\t\t\t\t\t\tview: modlaView,\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\txlog.info('[Talk] onPressChangeAudioRoute() no audioOutputDevices found');\n\t\t\t}\n\t\t} catch (err) {\n\t\t\txlog.info('[Talk] onPressChangeAudioRoute() failed. ', err);\n\t\t}\n\t}\n\t*/\n\n\tstartTalk(state) {\n\t\tthis.isStart = true;\n\t\tthis.talkingCallData = state;\n\t\tthis.resetState(state);\n\t}\n\n\tstopTalk() {\n\t\tif (this.isStart !== true) return;\n\t\tthis.isStopping = true;\n\t\tthis.props.parent.destroyCallSession({busytone: false});\n\t\t//this.props.dispatch(Actions.UPDATE_TALKING_CALL_DATA(null));\n\t\tthis.resetState({stopCall: true});\n\t\tthis.talkingCallData = null;\n\t\tthis.isStart = false;\n\t\tthis.isStopping = false;\n\t}\n\n\tstartCallTimer() {\n\t\ttry {\n\t\t\tif (!this.isTimerStarted ||\n\t\t\t\t\t!this.props.parent.state.session_call_start_time ||\n\t\t\t\t\t!this.isStart ||\n\t\t\t\t\tthis.isStopping) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\txlog.info('[Talk][startCallTimer] exception. component might be unmounted. err = ', err);\n\t\t\treturn;\n\t\t}\n\t\t//const nextDuration = this.state.callDuration + 1;\n\t\tconst nextDuration = Math.round(Date.now()/1000) - this.props.parent.state.session_call_start_time;\n\n\t\t// --- workaround for ios\n\t\tif (nextDuration > 0 && this.props.parent.state.DetectRTC.osName === 'iOS') {\n\t\t\tif (nextDuration === 1 || nextDuration === 2) {\n\t\t\t\t// --- all ios should have workaround or it will play sound on internal speaker instead loudspeaker.\n\t\t\t\tthis.props.parent.reactivateAudioForIosSafariWorkaround();\n\t\t\t} else {\n\t\t\t\tif (this.props.parent.state.webcallInfo.calleeNumber === '*599' || this.props.parent.state.webcallInfo.calleeNumber === '599599599') {\n\t\t\t\t\t// --- for 599 echo test, it should activate again when ready for test ( after IVR prompt )\n\t\t\t\t\t// --- since we can not detect when the prompt end, just do it at approximately 10 secs\n\t\t\t\t\tif (nextDuration === 10 || nextDuration === 12 || nextDuration === 14) {\n\t\t\t\t\t\tthis.props.parent.reactivateAudioForIosSafariWorkaround();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.setState({callDuration: nextDuration}); // --- should trigger re-render\n\t\tsetTimeout(this.startCallTimer, 1000); // --- check every one second\n\t}\n\n\tgetMediaStreamURL(stream, getType) {\n\t\tif (!stream) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (getType === 'video') {\n\t\t\tif (stream.getVideoTracks().length <= 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tif (getType === 'audio') {\n\t\t\tif (stream.getAudioTracks().length <= 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\treturn stream.toURL();\n\t}\n\n\trenderCallInfo() {\n\t\tconst {\n\t\t\tcalleeNumber,\n\t\t\tcalleeName,\n\t\t\tcalleeThumbnailPath,\n\t\t} = this.props.parent.state.webcallInfo;\n\n\t\treturn (\n\t\t\t\n\t\t);\n\t}\n\n\trenderControlPanel() {\n\t\treturn (\n\t\t\t\n\t\t);\n\t}\n\n\trenderFallbackNotInCallView() {\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{ 'Canceling Call...' }\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n\n\trender() {\n\t\t//if (!this.isStart || this.props.parent.state.talkingCallData === null) {\n\t\t//\treturn this.renderFallbackNotInCallView();\n\t\t//}\n\n\t\t// --- check should we start timer\n\t\tif (!this.isTimerStarted && this.props.parent.state.session_call_start_time) {\n\t\t\tthis.isTimerStarted = true;\n\t\t\tsetTimeout(this.startCallTimer, 1000);\n\t\t}\n\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{ this.renderCallInfo() }\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t{ this.renderControlPanel() }\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n}\n\n//@DebugLifeCycleDecorator\n@autobind\nclass CallInfo extends React.Component {\n\n\t//constructor(props) {\n\t//\tsuper(props);\n\t//}\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('CallInfo: componentDidCatch, error = ', error);\n\t\txlog.info('CallInfo: componentDidCatch, info = ', info);\n\t}\n\n\trenderRealtimeCallInfo() {\n\t\tlet { talkingCallInfo: callInfo } = this.props.parent.state;\n\t\tif (callInfo) {\n\t\t\tif (callInfo.calleeType === '1') {\n\t\t\t\treturn (\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{I18n.t('ExtraNetworkCall')}\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\treturn (\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{I18n.t('AhoyCall')}\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\trenderCallInfoDesc() {\n\t\t// --- webcall only supports outgoing call\n\t\treturn null;\n\n\t\t/*\n\t\t// --- only render for incoming\n\t\tif (this.props.callType !== 'incoming' || !this.props.parent.state.talkingCallData) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// --- apartment callinfo is no supported.\n\t\tif (this.props.parent.state.domainPage === 'apartment') {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet { callInfo } = this.props.parent.state.talkingCallData;\n\t\tif (!callInfo) {\n\t\t\treturn null;\n\t\t}\n\n\t\t//let desc = LIB.getTalkingCallInfoDesc(callInfo); // --- ZXC\n\t\tlet desc = '';\n\t\tif (!desc) {\n\t\t\treturn null;\n\t\t}\n\n\t\t\t//\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t{desc}\n\t\t\t\t\n\t\t\t\n\t\t);\n\t\t*/\n\t}\n\n\trenderCurrentCallStateDescription() {\n\t\tlet description = '';\n\n\t\tif (this.props.call_session_event === 'answered') {\n\t\t\tdescription = I18n.t('Talking');\n\t\t} else if (this.props.isHangUpBtnPressed) {\n\t\t\tdescription = I18n.t('CallEnding') + '...';\n\t\t} else {\n\t\t\tdescription = I18n.t('CallConnecting') + '...';\n\t\t}\n\n\t\tif (description) {\n\t\t\treturn (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{description}\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t);\n\t\t}\n\t}\n\n\trenderCallDuration() {\n\t\tif (this.props.callDuration && this.props.callDuration !== 0) {\n\t\t\t//const callTypeIconName = (this.props.callType === 'incoming' ? 'call-received' : 'call-made');\n\t\t\t//const callTypeIconColor = (this.props.callType === 'incoming' ? Theme.MainColor : 'darkseagreen');\n\t\t\t//\n\t\t\treturn (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{LIB.formatCallDuration(this.props.callDuration)}\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t);\n\t\t}\n\t}\n\n\trenderWebWarning() {\n\t\tif (this.props.callDuration && this.props.callDuration !== 0) {\n\t\t\t//const callTypeIconName = (this.props.callType === 'incoming' ? 'call-received' : 'call-made');\n\t\t\t//const callTypeIconColor = (this.props.callType === 'incoming' ? Theme.MainColor : 'darkseagreen');\n\t\t\t//\n\t\t\treturn (\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{'\\n\\n'}\n\t\t\t\t\t\t{I18n.t('WebWarning')}\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t);\n\t\t}\n\t}\n\n\trenderRemotePeerProfile() {\n\t\tlet displayName = '';\n\t\tlet displayNumber = '';\n\t\t//let thumbnailPath = '';\n\n\t\tdisplayName = this.props.calleeName;\n\t\tdisplayNumber = this.props.number;\n\t\tdisplayNumber = ''; // --- we do not display number\n\t\t//thumbnailPath = this.props.thumbnailPath;\n\n\t\t\t\t\t//\n\t\t\t\t//\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t{ displayName !== '' &&\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t{ displayName }\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{ displayNumber }\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n\n\t// --- Note: when use { condition && , condition should not be a string or integer }\n\t// --- or will throw: Cannot add a child that doesn't have a YogaNode to a parent without a measure function\n\trender() {\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{ this.renderRemotePeerProfile() }\n\t\t\t\t\t\t{ this.renderCurrentCallStateDescription() }\n\t\t\t\t\t\t{ this.renderRealtimeCallInfo() }\n\t\t\t\t\t\t{ this.renderCallDuration() }\n\t\t\t\t\t\t{ this.renderWebWarning() }\n\t\t\t\t\t\t{ /*this.renderCallInfoDesc()*/ }\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n}\n\nclass ControlPanel extends React.Component {\n\n\t//constructor(props) {\n\t//\tsuper(props);\n\t//}\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('ControlPanel: componentDidCatch, error = ', error);\n\t\txlog.info('ControlPanel: componentDidCatch, info = ', info);\n\t}\n\n\trenderTalkingControlPanel() {\n\t\tconst buttonDisabled = this.props.isHangUpBtnPressed;\n\t\tconst btnDisabledStyle = (buttonDisabled ? {color: Theme.ButtonDisabledColor} : {});\n\t\tconst notAnsweredYet = (this.props.call_session_event !== 'answered') ? true : false;\n\t\tconst notAnsweredYetBtnDisabledStyle = (notAnsweredYet ? {color: Theme.ButtonDisabledColor} : {});\n\t\tconst micMuteStyle = (notAnsweredYet) ? {color: Theme.ButtonDisabledColor} : (this.props.isMicMute) ? styles.buttonIsOn : styles.buttonIsOff;\n\t\tconst cameraButtonDisabled = false; // --- always can toggle\n\t\tconst cameraMuteStyle = (cameraButtonDisabled) ? {color: Theme.ButtonDisabledColor} : (this.props.isCameraMute) ? styles.buttonIsOn : styles.buttonIsOff;\n\t\t//const callInfo = displayName + ' - ' + displayNumber;\n\t\t//const callTypeIconName = (this.props.callType === 'incoming' ? 'call-received' : 'call-made');\n\t\t//const callTypeIconColor = (this.props.callType === 'incoming' ? Theme.MainColor : 'darkseagreen');\n\t\tlet isAudioDeviceOnStyle, selectedAudioDeviceIcon;\n\t\t//let audioButtonDisabled = (this.props.callType === 'incoming' && this.props.call_session_event !== 'answered') ? true : false;\n\t\t//let element = this.props.parent.remoteAudio;\n\t\t//let isChangeAudioRouteSupported = (typeof element.sinkId !== 'undefined' ? true : false);\n\t\t//let audioButtonDisabled = (!isChangeAudioRouteSupported || this.props.call_session_event !== 'answered') ? true : false;\n\t\tlet audioButtonDisabled = (this.props.call_session_event !== 'answered') ? true : false;\n\t\tlet audioButtonDisabledStyle = audioButtonDisabled ? {color: Theme.ButtonDisabledColor} : {};\n\n\t\tif (false) {\n\t\t\tif (this.props.parent.state.audioDeviceState !== null) {\n\t\t\t\tif (this.props.parent.state.audioDeviceState.selectedAudioDevice === 'EARPIECE') {\n\t\t\t\t\tisAudioDeviceOnStyle = styles.buttonIsOff;\n\t\t\t\t\tselectedAudioDeviceIcon = \n\t\t\t\t} else if (this.props.parent.state.audioDeviceState.selectedAudioDevice === 'SPEAKER_PHONE') {\n\t\t\t\t\tisAudioDeviceOnStyle = styles.buttonIsOn;\n\t\t\t\t\tselectedAudioDeviceIcon = \n\t\t\t\t} else if (this.props.parent.state.audioDeviceState.selectedAudioDevice === 'BLUETOOTH') {\n\t\t\t\t\tisAudioDeviceOnStyle = styles.buttonIsOn;\n\t\t\t\t\tselectedAudioDeviceIcon = \n\t\t\t\t} else if (this.props.parent.state.audioDeviceState.selectedAudioDevice === 'WIRED_HEADSET') {\n\t\t\t\t\tisAudioDeviceOnStyle = styles.buttonIsOn;\n\t\t\t\t\tselectedAudioDeviceIcon = \n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// --- android would be ready soon. this is just a temporary pre-render according to media type, prevent press if not ready.\n\t\t\t\taudioButtonDisabled = true;\n\t\t\t\taudioButtonDisabledStyle = {color: Theme.ButtonDisabledColor};\n\t\t\t\tisAudioDeviceOnStyle = (this.props.parent.state.shouldUseVideo ? styles.buttonIsOn : styles.buttonIsOff);\n\t\t\t\tselectedAudioDeviceIcon = \n\t\t\t}\n\t\t} else {\n\t\t\t// --- ios\n\t\t\tif (this.props.isToggleAudioDeviceOn === null) {\n\t\t\t\tisAudioDeviceOnStyle = (this.props.parent.state.shouldUseVideo ? styles.buttonIsOn : styles.buttonIsOff); // --- not pressed yet, decide by video type\n\t\t\t} else {\n\t\t\t\tisAudioDeviceOnStyle = (this.props.isToggleAudioDeviceOn ? styles.buttonIsOn : styles.buttonIsOff); // --- pressed, can be determine directly\n\t\t\t}\n\t\t\tselectedAudioDeviceIcon = \n\t\t}\n\n\t\t// --- we want to render openDoor at the middle. so need checks video buttons together.\n\t\tlet secondControlButtons = [];\n\t\tif (this.props.parent.state.shouldUseVideo) {\n\t\t\tsecondControlButtons.push((\n\t\t\t\t\n\t\t\t\t\tdisabled={buttonDisabled}\n\t\t\t\t\tonPress={this.props.onPressSwitchVideo}\n\t\t\t\t/>\n\t\t\t));\n\t\t}\n\t\tif (this.props.parent.state.talkingCallInfo && this.props.parent.state.talkingCallInfo && this.props.parent.state.talkingCallInfo.supportOpenDoor === '1') {\n\t\t\tsecondControlButtons.push((\n\t\t\t\t\n\t\t\t\t\tdisabled={notAnsweredYet || buttonDisabled}\n\t\t\t\t\tonPress={this.props.onPressOpenDoor}\n\t\t\t\t/>\n\t\t\t));\n\t\t}\n\t\tif (this.props.parent.state.shouldUseVideo) {\n\t\t\tsecondControlButtons.push((\n\t\t\t\t\n\t\t\t\t\tdisabled={cameraButtonDisabled || buttonDisabled}\n\t\t\t\t\tonPress={this.props.onPressCameraMute}\n\t\t\t\t/>\n\t\t\t));\n\t\t}\n\n\t\t/*\n\t\t// --- this is a test button for testing some hacks and workaround like mute/unmute, especially on ios safari...\n\t\tsecondControlButtons.push((\n\t\t\t\n\t\t\t\tonPress={() => {\n\t\t\t\t\tconsole.log('ZXCPOIU: muted: ', this.props.parent.remoteAudio.muted);\n\t\t\t\t\tthis.props.parent.remoteAudio.muted = true;\n\t\t\t\t\tconsole.log('ZXCPOIU: muted: ', this.props.parent.remoteAudio.muted);\n\t\t\t\t\tthis.props.parent.remoteAudio.muted = false;\n\t\t\t\t\tconsole.log('ZXCPOIU: muted: ', this.props.parent.remoteAudio.muted);\n\n\t\t\t\t\t//this.props.parent.remoteAudio.play()\n\t\t\t\t\t//.then((info) => {\n\t\t\t\t\t//\txlog.info(\"ZXCPOIU TALK play() SUCCESS, info = \", info);\n\t\t\t\t\t//})\n\t\t\t\t\t//.catch((err) => {\n\t\t\t\t\t//\txlog.info(\"ZXCPOIU TALK play() was rejected, err = \", err);\n\t\t\t\t\t//});\n\t\t\t\t}}\n\t\t\t/>\n\t\t));\n\t\t*/\n\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tdisabled={(false && buttonDisabled)}\n\t\t\t\t\t\tonPress={this.props.handleOnKeyboardSwitch}\n\t\t\t\t\t/>\n\n\t\t\t\t\t\n\t\t\t\t\t\tdisabled={notAnsweredYet || buttonDisabled}\n\t\t\t\t\t\tonPress={this.props.onPressMicMute}\n\t\t\t\t\t/>\n\n\t\t\t\t\t\n\n\t\t\t\t\n\n\t\t\t\t{ secondControlButtons.length > 0 &&\n\t\t\t\t\t\n\t\t\t\t\t\t{secondControlButtons}\n\t\t\t\t\t\n\t\t\t\t}\n\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tdisabled={this.props.isHangUpBtnPressed}\n\t\t\t\t\t\tonPress={this.props.handleHangUp}\n\t\t\t\t\t\tcontainerStyle={styles.hangupButtonContainer}\n\t\t\t\t\t/>\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n\n\trenderDialPad() {\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\tdisabled={this.props.isHangUpBtnPressed}\n\t\t\t\t\t\tonPress={this.props.handleHangUp}\n\t\t\t\t\t\tcontainerStyle={[styles.hangupButtonContainer, {height: 60, width: 60, borderRadius: 30}]}\n\t\t\t\t\t/>\n\t\t\t\t\n\t\t\t\n\t\t)\n\t}\n\n\n\trender() {\n\t\tif (this.props.isKeyboardOpen) {\n\t\t\treturn this.renderDialPad();\n\t\t} else {\n\t\t\treturn this.renderTalkingControlPanel();\n\t\t}\n\t}\n}\n\n//@DebugLifeCycleDecorator\n@autobind\nclass ControlButton extends React.Component {\n\n\t//constructor(props) {\n\t//\tsuper(props);\n\t//}\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('ControlButton: componentDidCatch, error = ', error);\n\t\txlog.info('ControlButton: componentDidCatch, info = ', info);\n\t}\n\n\tstatic defaultProps = {\n\t\tdisabled: false,\n\t\tonPress: () => {},\n\t\ticon: null,\n\t};\n\n\trender() {\n\t\tlet containerStyle = styles.controlButtonContainer;\n\n\t\tif (this.props.containerStyle) {\n\t\t\tif (Array.isArray(this.props.containerStyle)) {\n\t\t\t\tcontainerStyle = [styles.controlButtonContainer, ...this.props.containerStyle];\n\t\t\t} else {\n\t\t\t\tcontainerStyle = [styles.controlButtonContainer, this.props.containerStyle];\n\t\t\t}\n\t\t}\n\n\t\treturn (\n\t\t\t\n\t\t);\n\t}\n}\n\nconst styles = StyleSheet.create({\n\tscreenContainer: {\n\t\tflex: 1,\n\t\tflexDirection: \"column\",\n\t\tpaddingHorizontal: 10,\n\t\tpaddingVertical: 10,\n\t\tbackgroundColor: '#FAFAFA',\n\t},\n\tscreenContainerVideo: {\n\t\tflex: 1,\n\t\tflexDirection: \"column\",\n\t\tbackgroundColor: 'black',\n\t},\n\thangupButtonContainer: {\n\t\theight: 64,\n\t\twidth: 64,\n\t\tborderRadius: 32,\n\t\tborderWidth: 1,\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t\tborderColor: 'red',\n\t\tbackgroundColor: 'red',\n\t},\n\thangupButtonText: {\n\t\t//textAlign: 'center',\n\t\t//fontSize: 30,\n\t\t//color: \"#FAFAFA\",\n\t},\n\tcontrolButtonContainer: {\n\t\theight: 64,\n\t\twidth: 64,\n\t\tborderRadius: 32,\n\t\tborderWidth: 1,\n\t\tborderColor: 'darkgray',\n\t\tmargin: 10,\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t\tbackgroundColor: '#FAFAFA',\n\t},\n\tcontrolButtonText: {\n\t\t//textAlign: 'center',\n\t\t//fontSize: 30,\n\t\tbackgroundColor: 'green',\n\t},\n\tanswerButtonContainer: {\n\t\theight: 64,\n\t\twidth: 64,\n\t\tborderRadius: 32,\n\t\tborderWidth: 1,\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t\tborderColor: Theme.MainColor,\n\t\tbackgroundColor: Theme.MainColor,\n\t},\n\tanswerButtonText: {\n\t\t//textAlign: 'center',\n\t\t//fontSize: 30,\n\t\t//color: \"#FAFAFA\",\n\t},\n\tflexColumn: {\n\t\tflex: 1,\n\t\tflexDirection: 'column',\n\t\tjustifyContent: 'center',\n\t\talignItems: 'center',\n\t},\n\tflexRow: {\n\t\tflex:1,\n\t\tflexDirection: 'row',\n\t\tjustifyContent: 'center',\n\t\talignItems: 'center',\n\t},\n\tcallInfoText: {\n\t\tfontSize: 20,\n\t},\n\tcallDurationText: {\n\t\tfontSize: 20,\n\t},\n\timg: {\n\t\theight: 64,\n\t\twidth: 64,\n\t\tborderRadius: 32,\n\t\tborderWidth: 1,\n\t\tborderColor: 'gainsboro',\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t},\n\tbuttonIsOn: {\n\t\tcolor: Theme.MainColor,\n\t},\n\tbuttonIsOff: {\n\t},\n\tcontrolButtonRow: {\n\t\tflex: 1,\n\t\tflexDirection: 'row',\n\t\tjustifyContent: 'space-around',\n\t\talignItems: 'center',\n\t},\n\tcontrolPanel: {\n\t\tflex: 1,\n\t\tflexDirection: 'column',\n\t\tjustifyContent: 'flex-end',\n\t\tbackgroundColor: 'rgba(255, 255, 255, 0.8)', // --- same with Theme.BackgroundColor #FAFAFA, do not use opacity: 0.7, it will decrease text as well\n\t},\n\tmainButtonContainer: {\n\t\tborderRadius: 30,\n\t\tborderWidth: 0,\n\t\tbackgroundColor: Theme.MainColor,\n\t},\n});\n\nexport default Talk;\n","import React from 'react';\nimport {\n\tView,\n\tText,\n\tStyleSheet,\n\t//TextInput,\n\t//TouchableHighlight,\n\tTouchableOpacity,\n} from 'react-native-web';\nimport PropTypes from 'prop-types';\nimport MaterialIcon from 'react-native-vector-icons/dist/MaterialIcons';\n\nimport AppSetup from '../app_setup.js';\n\nimport {\n\tButton as ButtonElement,\n} from 'react-native-elements';\n\nimport { MaterialTheme } from '..//lib/styles.js';\nconst Theme = MaterialTheme[AppSetup.Theme];\nconst xlog = require('../lib/xlog.js'); // --- use reqiure so that we can use `pure_funcs` to strip in production build\n\nexport default class DialPad extends React.Component {\n\n\tconstructor(props) {\n\t\tsuper(props)\n\t\tthis.handleOnPress = this.handleOnPress.bind(this);\n\t\tthis.handleOnReset = this.handleOnReset.bind(this);\n\t\tthis.handleOnBackspace = this.handleOnBackspace.bind(this);\n\t\tthis.handleOnChangeText = this.handleOnChangeText.bind(this);\n\t\tthis.renderResetButton = this.renderResetButton.bind(this);\n\t\tthis.state = {\n\t\t\ttextInputHeight: 0,\n\t\t};\n\t}\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('DialPad: componentDidCatch, error = ', error);\n\t\txlog.info('DialPad: componentDidCatch, info = ', info);\n\t}\n\n\tstatic propTypes = {\n\t\thandleOnPress: PropTypes.func.isRequired,\n\t\thandleOnReset: PropTypes.func.isRequired,\n\t\thandleOnBackspace: PropTypes.func.isRequired,\n\t\thandleOnChangeText: PropTypes.func.isRequired,\n\t\tdialedNumber: PropTypes.string.isRequired,\n\t\tcca2: PropTypes.string,\n\t\tcountryCallingCode: PropTypes.string,\n\t\tcountryAvailableList: PropTypes.array,\n\t\trenderCountryPicker: PropTypes.bool,\n\t\trenderKeyboardSwitchButton: PropTypes.bool,\n\t\thandleOnKeyboardSwitch: PropTypes.func,\n\t};\n\n\tstatic defaultProps = {\n\t\trenderCountryPicker: true,\n\t};\n\n\thandleOnPress(button, isLongPress) {\n\t\tif (isLongPress && this.props.ignoreLongPress === true) {\n\t\t\treturn;\n\t\t}\n\t\tthis.props.handleOnPress(button, isLongPress);\n\t}\n\n\thandleOnReset() {\n\t\tthis.props.handleOnReset();\n\t}\n\n\thandleOnBackspace() {\n\t\tthis.props.handleOnBackspace();\n\t}\n\n\thandleOnChangeText(text) {\n\t\tthis.props.handleOnChangeText(text);\n\t}\n\n\trenderResetButton() {\n\t\tlet iconColor = (this.props.dialedNumber ? {} : {color: Theme.BackgroundColor.backgroundColor});\n\t\treturn (\n\t\t\t\n\t\t\t/>\n\t\t);\n\t}\n\n\tgetCountryCallingCodeText() {\n\t\tlet prefix = '';\n\t\tif (this.props.cca2 === 'AHOY') {\n\t\t\treturn '';\n\t\t} else {\n\t\t\tprefix = '+';\n\t\t}\n\n\t\treturn prefix + this.props.countryCallingCode\n\t}\n\n\t/*\n\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\tthis.setState({height: event.nativeEvent.contentSize.height});\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tnumberOfLines={1}\n\t\t\t\t\t\t\tunderlineColorAndroid='transparent'\n\t\t\t\t\t\t\tkeyboardType='phone-pad'\n\t\t\t\t\t\t\treturnKeyType='done'\n\t\t\t\t\t\t\tallowFontScaling={false}\n\t\t\t\t\t\t\teditable={false}\n\t\t\t\t\t\t/>\n\t*/\n\trender() {\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t/>\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t{this.props.dialedNumber}\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t{this.renderResetButton()}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t)\n\t}\n}\n\nclass DialButton extends React.Component {\n\n\tstatic displayName = \"DialButton\";\n\tstatic key = \"dial_button\";\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('DialButton: componentDidCatch, error = ', error);\n\t\txlog.info('DialButton: componentDidCatch, info = ', info);\n\t}\n\n\t/*\n\thandleMouseDown(e) {\n\t\tthis.setState({active: true})\n\t}\n\thandleMouseUp(e) {\n\t\tif (this.state.active) {\n\t\t\tthis.setState({active: false})\n\t\t}\n\t}\n\t*/\n\n\trender() {\n\t\tconst { button, handleOnPress } = this.props;\n\t\tconst { symbol, alias, icon } = button;\n\t\treturn (\n\t\t\t handleOnPress(symbol)}\n\t\t\t\tonLongPress={() => handleOnPress(alias, true)}\n\t\t\t\tdelayLongPress={1000}\n\t\t\t\tunderlayColor={Theme.SecondaryColor}\n\t\t\t\tstyle={styles.dialButtonTouchableContainer}\n\t\t\t>\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t{icon ? icon : symbol}\n\t\t\t\t\t\n\t\t\t\t\t{!!alias &&\n\t\t\t\t\t\t{alias}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\n\t\t);\n\t}\n}\n\nclass DialPadCore extends React.Component {\n\n\tstatic displayName = \"DialPadCore\";\n\tstatic key = \"_dial_pad\";\n\n\tcomponentDidCatch(error, info) {\n\t\txlog.info('DialButton: componentDidCatch, error = ', error);\n\t\txlog.info('DialButton: componentDidCatch, info = ', info);\n\t}\n\n\trender() {\n\t\tconst { handleOnPress } = this.props;\n\n\t\tconst buttons = {\n\t\t\t'1': {\n\t\t\t\tsymbol : '1'\n\t\t\t},\n\t\t\t'2': {\n\t\t\t\tsymbol : '2',\n\t\t\t\t//alias\t: 'abc'\n\t\t\t},\n\t\t\t'3': {\n\t\t\t\tsymbol : '3',\n\t\t\t\t//alias\t: 'def'\n\t\t\t},\n\t\t\t'4': {\n\t\t\t\tsymbol : '4',\n\t\t\t\t//alias\t: 'ghi'\n\t\t\t},\n\t\t\t'5': {\n\t\t\t\tsymbol : '5',\n\t\t\t\t//alias\t: 'jkl'\n\t\t\t},\n\t\t\t'6': {\n\t\t\t\tsymbol : '6',\n\t\t\t\t//alias\t: 'mno'\n\t\t\t},\n\t\t\t'7': {\n\t\t\t\tsymbol : '7',\n\t\t\t\t//alias\t: 'pqrs'\n\t\t\t},\n\t\t\t'8': {\n\t\t\t\tsymbol : '8',\n\t\t\t\t//alias\t: 'tuv'\n\t\t\t},\n\t\t\t'9': {\n\t\t\t\tsymbol : '9',\n\t\t\t\t//alias\t: 'wxyz'\n\t\t\t},\n\t\t\t'*': {\n\t\t\t\tsymbol : '*'\n\t\t\t},\n\t\t\t'0': {\n\t\t\t\tsymbol : '0',\n\t\t\t\talias\t: '+'\n\t\t\t},\n\t\t\t'#': {\n\t\t\t\tsymbol : '#'\n\t\t\t},\n\t\t\t'+': {\n\t\t\t\tsymbol : '+'\n\t\t\t},\n\t\t\t/*\n\t\t\t'call': {\n\t\t\t\t//icon : (),\n\t\t\t\t//icon : (),\n\t\t\t\ticon: ,\n\t\t\t\tsymbol : '',\n\t\t\t\taction : 'call'\n\t\t\t},\n\t\t\t'hangup': {\n\t\t\t\t//icon : (),\n\t\t\t\t//icon : (),\n\t\t\t\ticon: ,\n\t\t\t\tsymbol : '',\n\t\t\t\taction : 'hangup'\n\t\t\t}\n\t\t\t*/\n\t\t};\n\t\treturn (\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t)\n\t}\n}\n\n\n// --- If you want to use Higher Order Component, just import it and bind to a proper scope(this), and pass handled dialedNumber in.\n// --- You need to implement handleDialPadOnChangeText() method which handles state changes. then pass you state into impl functions.\n/*\nexport const DEFAULT_STATUS_KEY = 'numbers';\n\nexport function handleOnChangeText(text, k=DEFAULT_STATUS_KEY) {\n\tthis.setState({[k]: text});\n}\n*/\nexport function handleOnPress(symbol, isLongPress, dialedNumber) {\n\tif (!symbol) {\n\t\treturn null;\n\t}\n\tlet numbers;\n\tif (isLongPress) {\n\t\tnumbers = dialedNumber.slice(0, -1);\n\t} else{\n\t\tnumbers = dialedNumber;\n\t}\n\tthis.handleDialPadOnChangeText(`${numbers}${symbol}`);\n\treturn symbol;\n}\n\nexport function handleOnBackspace(dialedNumber) {\n\tthis.handleDialPadOnChangeText(dialedNumber.slice(0, -1));\n}\n\nexport function handleOnReset() {\n\tthis.handleDialPadOnChangeText('');\n}\n\nconst styles = StyleSheet.create({\n\tmainContainer: {\n\t\tflexDirection: 'column',\n\t\tflex: 1,\n\t},\n\tinfoViewContainer: {\n\t\tflexDirection: 'row',\n\t\talignItems: 'center',\n\t},\n\tdialPadViewContainer: {\n\t\tflex: 1,\n\t},\n\tdialButtonTouchableContainer: {\n\t\theight: 50,\n\t\twidth: 50,\n\t\t//borderRadius: 30,\n\t},\n\tdialButtonContainer: {\n\t\tflex: 1,\n\t\tflexDirection: 'row',\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t\t//margin: 5,\n\t\t//padding: 5,\n\t},\n\tdialButtonText: {\n\t\tfontSize: 25,\n\t\ttextAlign: 'center',\n\t},\n\tdialButtonTextAlias: {\n\t\tfontSize: 15,\n\t\tfontWeight: 'normal',\n\t},\n\tdialPadContainer: {\n\t\tflexDirection: 'column',\n\t\tflex: 1,\n\t\tmargin: 1,\n\t},\n\tdialPadRow: {\n\t\tflexDirection: 'row',\n\t\tjustifyContent: 'space-around',\n\t\tmargin: 5,\n\t\tflex: 1,\n\t},\n\tcountryPickerContainer: {\n\t\tflexDirection: 'row',\n\t\tjustifyContent: 'center',\n\t\talignItems: 'center',\n\t\tmarginLeft: 10,\n\t},\n\tcountryPickerText: {\n\t\tflex: 0,\n\t\tcolor: 'grey',\n\t\tfontSize: 16,\n\t\t//marginLeft: 1,\n\t},\n\tdialInputNumbersContainer: {\n\t\tflexDirection: 'row',\n\t\tflex: 1,\n\t\tmarginLeft: 5,\n\t\tjustifyContent: 'center',\n\t\talignItems: 'center',\n\t},\n\tdialInputResetButtonContainer: {\n\t\tpaddingLeft: 10,\n\t\tpaddingRight: 10,\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t\tbackgroundColor: '#FFFFFF',\n\t},\n\tcontrolButtonContainer: {\n\t\talignItems: 'center',\n\t\tjustifyContent: 'center',\n\t\tbackgroundColor: '#FFFFFF',\n\t},\n\tdialInputNumbersText: {\n\t\tflex: 1,\n\t\tfontSize: 25,\n\t\ttextAlign: 'left',\n\t\tcolor: Theme.MainColor,\n\t\tpadding: 0,\n\t},\n});\n","import SDPTransform from 'sdp-transform';\n\nconst xlog = require('./xlog.js');\n\nexport function customSdpHacks(sdp) {\n\t// --- NOTE: reject will terminates the whole call, so only use resolve. means skip if error.\n\treturn new Promise((resolve, reject) => {\n\t\ttry {\n\t\t\t// --- webrtc will pass as {sdp: '', type: 'offer'}\n\t\t\tlet typeof_sdp = typeof sdp;\n\t\t\tlet sdpStr = '';\n\t\t\tlet sdpType = 'unknow';\n\n\t\t\tif (typeof_sdp === 'string') {\n\t\t\t\tsdpStr = sdp;\n\t\t\t} else if (typeof_sdp === 'object' && typeof sdp.sdp === 'string' ) {\n\t\t\t\tsdpStr = sdp.sdp;\n\t\t\t\tsdpType = sdp.type || '';\n\t\t\t} else {\n\t\t\t\txlog.info('customSdpHacks(): unknow sdp type.', sdp);\n\t\t\t\tresolve(sdp);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// --- webcall only cares about outgoing offer, since we do not accept incoming call, so do not bother 'answer' sdp\n\t\t\tif (sdpType !== 'offer') {\n\t\t\t\txlog.info('customSdpHacks(): sdp type \"%s\" is not \"offer\". skip.', sdpType);\n\t\t\t\tresolve(sdp);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\txlog.info('customSdpHacks(): original sdp: type = %s, sdpType = %s, sdp = \\n\\n%s', typeof_sdp, sdpType, sdpStr.replace('\\\\r\\\\n', '\\n'));\n\n\t\t\tlet sdpObj = SDPTransform.parse(sdpStr);\n\n\t\t\tif (!sdpObj.media) {\n\t\t\t\tresolve(sdp);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet m = -1;\n\t\t\tm = getMediaByType(sdpObj.media, 'audio');\n\t\t\tif (m < 0) {\n\t\t\t\tresolve(sdp);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// --- for audio\n\t\t\tlet audio = sdpObj.media[m];\n\t\t\tlet allowCodecName = ['opus', 'pcmu']; // --- allowed codec name in order\n\t\t\tlet codecNameToCode = getCodecPayloadMap(audio, allowCodecName);\n\t\t\tlet allowCodecCode = [];\n\t\t\tfor (let c of allowCodecName) {\n\t\t\t\tif (c in codecNameToCode) {\n\t\t\t\t\tallowCodecCode.push(codecNameToCode[c]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tsetPreferCodecOnly(audio, allowCodecCode);\n\n\t\t\tif ('opus' in codecNameToCode) {\n\t\t\t\t// --- set opus to match with asterisk\n\t\t\t\tlet opusFmtpConfig = {\n\t\t\t\t\t'sprop-maxcapturerate': 16000,\n\t\t\t\t\t'maxplaybackrate': 16000,\n\t\t\t\t\t'maxaveragebitrate': 20000,\n\t\t\t\t\t'minptime': 20,\n\t\t\t\t\t'maxptime': 20,\n\t\t\t\t\t'ptime': 20,\n\t\t\t\t\t'cbr': 1,\n\t\t\t\t\t'useinbandfec': 1,\n\t\t\t\t}\n\t\t\t\tsetCustomFmtp(audio, codecNameToCode['opus'], opusFmtpConfig, true);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t// --- set custom fmtp, is for opus to limit on max bit rate, the purpose is to save bandwidth\n\t\t\tlet customFmtpConfig = {\n\t\t\t\t'sprop-maxcapturerate': 16000,\n\t\t\t\t'maxplaybackrate': 16000,\n\t\t\t}\n\t\t\tsetCustomFmtp(media, payload, customFmtpConfig, true);\n\t\t\t*/\n\n\t\t\t/*\n\t\t\t// --- set new ssrc\n\t\t\tlet objSsrc = {\n\t\t\t\tid: 12345678,\n\t\t\t\tattribute: 'foo',\n\t\t\t\tvalue: 'bar',\n\t\t\t};\n\t\t\tsdpObj.media[0].ssrcs.push(objSsrc);\n\t\t\t*/\n\n\t\t\tlet nextSdpStr = SDPTransform.write(sdpObj);\n\t\t\tif (typeof_sdp === 'string') {\n\t\t\t\tresolve(nextSdpStr);\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tsdp.sdp = nextSdpStr;\n\t\t\t\tresolve(sdp);\n\t\t\t\treturn;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\txlog.info('customSdpHacks(): exception: ', err);\n\t\t\tresolve(sdp);\n\t\t\treturn;\n\t\t}\n\t});\n}\n\nexport function getMediaByType(media, type) {\n\tif (!Array.isArray(media) || media.length <= 0) {\n\t\treturn -1;\n\t}\n\n\tlet m = -1;\n\tfor (let i = 0; i < media.length; i++) {\n\t\tif (media[i].type === type) {\n\t\t\tm = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn m;\n}\n\nexport function getCodecPayloadMap(media, allowCodecName) {\n\tif (!media || !media.rtp || !Array.isArray(media.rtp) || media.rtp.length <= 0) {\n\t\treturn -1\n\t}\n\tlet payload = -1;\n\tlet i = media.rtp.length;\n\tlet codecNameToCode = {}\n\twhile (i--) {\n\t\tlet codec = media.rtp[i].codec;\n\t\tif (codec) {\n\t\t\tcodec = codec.toLowerCase();\n\t\t\tif (allowCodecName.includes(codec)) {\n\t\t\t\tpayload = media.rtp[i].payload;\n\t\t\t\tcodecNameToCode[codec] = payload; // --- ex: opus => 101\n\t\t\t}\n\t\t}\n\t}\n\treturn codecNameToCode;\n}\n\nexport function setPreferCodecOnly(media, allowCodecCode) {\n\tif (!media) { return -1; }\n\tlet params = ['rtp', 'fmtp', 'rtcpFb'];\n\n\tparams.forEach((param, index, array) => {\n\t\tif (Array.isArray(media[param]) && media[param].length > 0) {\n\t\t\tlet i = media[param].length;\n\t\t\twhile (i--) {\n\t\t\t\tif (!allowCodecCode.includes(media[param][i].payload)) {\n\t\t\t\t\tmedia[param].splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tmedia.payloads = allowCodecCode.join(' ');\n}\n\nexport function setCustomFmtp(media, codecCode, myConfig, override) {\n\tif (!codecCode || !myConfig) {\n\t\treturn;\n\t}\n\tif (!media || !media.fmtp || !Array.isArray(media.fmtp) || media.fmtp.length <= 0) {\n\t\treturn;\n\t}\n\n\tlet {config, index} = getFmtpConfigWithIndex(media, codecCode);\n\tif (!config) {\n\t\treturn;\n\t}\n\tlet newConfig;\n\tif (override) {\n\t\tnewConfig = {...config, ...myConfig};\n\t} else {\n\t\tnewConfig = {...myConfig, ...config};\n\t}\n\n\tlet fmtpStr = convertFmtpObjToStr(newConfig);\n\tif (!fmtpStr) {\n\t\treturn;\n\t}\n\n\tmedia.fmtp[index].config = fmtpStr;\n}\n\nexport function getFmtpConfigWithIndex(media, codecCode) {\n\tif (!media || !media.fmtp || !Array.isArray(media.fmtp) || media.fmtp.length <= 0) {\n\t\treturn {};\n\t}\n\n\tlet config = null;\n\tlet index = -1;\n\tfor (let i = 0; i < media.fmtp.length; i++) {\n\t\tif (media.fmtp[i].payload === codecCode) {\n\t\t\ttry {\n\t\t\t\tconfig = SDPTransform.parseFmtpConfig(media.fmtp[i].config);\n\t\t\t\tindex = i;\n\t\t\t\tbreak;\n\t\t\t} catch (err) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t}\n\t}\n\treturn {config, index};\n}\n\nexport function convertFmtpObjToStr(fmtpObj) {\n\tlet configArray = [];\n\tfor (let key in fmtpObj) {\n\t\tif (fmtpObj.hasOwnProperty(key)) {\n\t\t\tconfigArray.push(key.toString() + '=' + fmtpObj[key].toString());\n\t\t}\n\t}\n\tif (configArray.length <= 0) {\n\t\treturn '';\n\t} else {\n\t\treturn configArray.join(';');\n\t}\n}\n\n/*\nvar sdpStr = \"v=0\\r\\n\\\no=- 3058226124508359283 3 IN IP4 127.0.0.1\\r\\n\\\ns=-\\r\\n\\\nt=0 0\\r\\n\\\na=group:BUNDLE audio\\r\\n\\\na=msid-semantic: WMS e9816adf-013c-4532-a144-d5b87e433c1d\\r\\n\\\nm=audio 43027 UDP/TLS/RTP/SAVPF 111 103 9 102 0 8 105 13 126\\r\\n\\\nc=IN IP4 60.250.125.1\\r\\n\\\na=rtcp:50388 IN IP4 60.250.125.1\\r\\n\\\na=candidate:1912282794 1 udp 2122260223 192.168.1.145 33747 typ host generation 0 network-id 3 network-cost 10\\r\\n\\\na=candidate:1912282794 2 udp 2122260222 192.168.1.145 41108 typ host generation 0 network-id 3 network-cost 10\\r\\n\\\na=candidate:4038268958 1 udp 1686052607 60.250.125.1 43027 typ srflx raddr 192.168.1.145 rport 33747 generation 0 network-id 3 network-cost 10\\r\\n\\\na=candidate:4038268958 2 udp 1686052606 60.250.125.1 50388 typ srflx raddr 192.168.1.145 rport 41108 generation 0 network-id 3 network-cost 10\\r\\n\\\na=candidate:1064886874 1 tcp 1518280447 192.168.1.145 54054 typ host tcptype passive generation 0 network-id 3 network-cost 10\\r\\n\\\na=candidate:1064886874 2 tcp 1518280446 192.168.1.145 34246 typ host tcptype passive generation 0 network-id 3 network-cost 10\\r\\n\\\na=ice-ufrag:ywc/\\r\\n\\\na=ice-pwd:qMQPSC7XRXQn9jQB6ZHFEa/0\\r\\n\\\na=fingerprint:sha-256 5E:1F:8D:80:00:83:99:AD:B1:71:48:91:08:00:45:ED:67:B2:7F:37:7F:52:BD:6E:EA:AC:3A:8E:7C:46:01:B0\\r\\n\\\na=setup:actpass\\r\\n\\\na=mid:audio\\r\\n\\\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\n\\\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n\\\na=sendrecv\\r\\n\\\na=rtcp-mux\\r\\n\\\na=rtpmap:111 opus/48000/2\\r\\n\\\na=rtcp-fb:111 transport-cc\\r\\n\\\na=fmtp:111 minptime=10;useinbandfec=1\\r\\n\\\na=rtpmap:103 ISAC/16000\\r\\n\\\na=rtpmap:9 G722/8000\\r\\n\\\na=rtpmap:102 ILBC/8000\\r\\n\\\na=rtpmap:0 PCMU/8000\\r\\n\\\na=rtpmap:8 PCMA/8000\\r\\n\\\na=rtpmap:105 CN/16000\\r\\n\\\na=rtpmap:13 CN/8000\\r\\n\\\na=rtpmap:126 telephone-event/8000\\r\\n\\\na=ssrc:2389753583 cname:SBlo7Qp9L+Cjypud\\r\\n\\\na=ssrc:2389753583 msid:e9816adf-013c-4532-a144-d5b87e433c1d b22ead35-895c-49ad-ad5f-685de077194f\\r\\n\\\na=ssrc:2389753583 mslabel:e9816adf-013c-4532-a144-d5b87e433c1d\\r\\n\\\na=ssrc:2389753583 label:b22ead35-895c-49ad-ad5f-685de077194f\\r\\n\\\n\";\n*/\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read http://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit http://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import os from 'os';\nconst __DEV__ = (process.env.NODE_ENV === 'development'); // --- this node build env is dev or not\n\nconst config = {\n\tlibTTCPath: os.platform() === 'darwin' ? '/Users/libTTC' : '/home/libTTC',\n\thost: '127.0.0.1',\n\tport: (parseInt('9528', 10) || 9528),\n\tlogToConsole: __DEV__ && !('false' === 'false'), // --- should log to console or not\n\tisDebug: __DEV__ && !('false' === 'false'), // --- this server is our dev server or not\n\tlandingServerDomain: 'sayahoy.info', // --- landing server proxies api call to api server\n\tlandingServerClientKey: 'aks3E2ddr4SKOPIJfeh28hsHUJOEHCB293', // --- this is required for landing server which simply checks key to prevent randomly, automatically sniffing attacks\n\t//sipProxyDomain: 'sip-proxy-dev.sayahoy.info', // --- Nginx Let's Encrypt Reverse Proxy to DEV\n\t//sipProxyDomain: 'sip-proxy.sayahoy.info', // --- Nginx Let's Encrypt Reverse Proxy to PRODUCTION\n\t//sipProxyDomain: 'sip1-dev.yohalabs.com', // --- self-signed cert DEV\n\t//sipProxyDomain: 'sip.yohalabs.com', // --- self-signed cert PRODUCTION\n\tsipProxyDomain: 'sip-proxy.sayahoy.info', // --- default use nginx to handle as reverse proxy, web sip client will send invite to it\n\tsipProxyPort: '443',\n\t//sipCallerUsername: '5981034',\n\t//sipCallerPassword: '20262936',\n\tTheme: 'light',\n};\n\nexport default config;\n","import AppSetup from '../app_setup.js';\n\nconst logToConsole = (typeof AppSetup.logToConsole === 'boolean' ? AppSetup.logToConsole : false);\n\nconst Log = require('console-log-level')({\n\tlevel: (logToConsole ? 'info' : 'fatal'),\n});\n\nfunction log(level, args) {\n\tif (logToConsole) {\n\t\tLog[level].apply(null, args);\n\t}\n}\n\nconst xlog = {\n\ttrace: function() {\n\t\tlog('trace', arguments);\n\t},\n\tdebug: function() {\n\t\tlog('debug', arguments);\n\t},\n\tinfo: function() {\n\t\tlog('info', arguments);\n\t},\n\twarn: function() {\n\t\tlog('warn', arguments);\n\t},\n\terror: function() {\n\t\tlog('error', arguments);\n\t},\n\tfatal: function() {\n\t\tlog('fatal', arguments);\n\t},\n}\n\n// --- we use traditional `require()` instead `import()` to use this `xlog` lib,\n// --- this is because we want to use webpack's terser to strip log functions in the prodution bundle via `pure_funcs` under minify\n// --- but it does not support strip `import module` but `require` does the trick, maybe it is due to that webpack\n// --- evaluate `import` first and once which will change the value to `x.default.info()`\nmodule.exports = xlog;\n\n/*\nclass xlog {\n\tstatic log(level, args) {\n\t\tif (logToConsole) {\n\t\t\tLog[level].apply(null, args);\n\t\t}\n\t}\n\n\tstatic trace() {\n\t\txlog.log('trace', arguments);\n\t}\n\n\tstatic debug() {\n\t\txlog.log('debug', arguments);\n\t}\n\n\tstatic info() {\n\t\txlog.log('info', arguments);\n\t}\n\n\tstatic warn() {\n\t\txlog.log('warn', arguments);\n\t}\n\n\tstatic error() {\n\t\txlog.log('error', arguments);\n\t}\n\n\tstatic fatal() {\n\t\txlog.log('fatal', arguments);\n\t}\n}\n\nexport default xlog;\n*/\n\n"],"sourceRoot":""}