├── .github └── workflows │ └── job.yml ├── .gitignore ├── Jenkinsfile ├── README.md ├── app.json ├── chromeExten-plivo ├── README.md ├── background.js ├── css │ ├── bootstrap.min.css │ └── newstyle.css ├── icon.png ├── img │ └── plivo-logo.png ├── index.html ├── js │ └── customclient.js ├── lib │ ├── bootstrap.min.js │ └── jquery.min.js └── manifest.json ├── ci └── config.yml ├── electronApp-plivo ├── LICENSE.md ├── README.md ├── css │ ├── despic.png │ └── newstyle.css ├── img │ ├── favicon.png │ ├── micdenied.png │ └── plivo-logo.png ├── index.html ├── js │ └── customclient.js ├── lib │ ├── jquery-ui.min.js │ └── jquery.min.js ├── main.js └── package.json ├── example.html ├── img ├── audiodevice.png ├── audiodevicechange.png ├── callscreen.png ├── feedback.png ├── login.png ├── login_jwt.png ├── metrics.png ├── plivobrowserSdKLogin.png ├── settings.png └── volume.png ├── package-lock.json ├── package.json ├── server.js └── webApp-plivo ├── gulpfile.js ├── public ├── .DS_Store ├── css │ ├── intlTelInput.css │ ├── newstyle.css │ └── notify.css ├── img │ ├── PlivoIcon.png │ ├── background.svg │ ├── favicon.png │ ├── flags.png │ ├── flags@2x.png │ ├── micdenied.png │ ├── plivo-logo-new.png │ └── plivo-logo.png ├── js │ ├── customclient.js │ ├── plivowebsdk.js │ ├── processor.js │ └── utils.js ├── lib │ ├── intlTelInput.min.js │ ├── jquery.min.js │ └── notify.js ├── media │ └── us-ring.mp3 └── patches │ └── intlTelInput.patch └── views └── index.ejs /.github/workflows/job.yml: -------------------------------------------------------------------------------- 1 | name: Test npm install 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - beta 8 | pull_request: 9 | branches: 10 | - master 11 | - beta 12 | 13 | jobs: 14 | test: 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [11, 12, 14, 16, 18, 'node'] 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v3 24 | 25 | - name: Setup Node.js 26 | uses: actions/setup-node@v3 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | 30 | - name: Install dependencies 31 | run: npm install 32 | 33 | - name: Verify npm install success 34 | run: echo "npm install succeeded for Node.js version ${{ matrix.node-version }}" 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!groovy 2 | 3 | @Library('plivo_standard_libs@support-ecs-tasks') _ 4 | 5 | deliveryPipeline ([ 6 | disableQAStages: true 7 | ]) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Plivo Browser SDK v2.1 Example 2 | *This Plivo example shows how to use all the features in Plivo Browser SDK 2.1 using a simple webphone demo. This demo helps in making phone calls from web browser to both sip addresses and PSTN phone numbers without installing any plugins.* 3 | 4 | ![plivo-websdk-2.0-example](img/callscreen.png) 5 | 6 | --- 7 | *To use the [live web phone demo](https://s3.amazonaws.com/plivobrowsersdk/v2/example.html)* 8 | 9 | *a. Sign up for a Plivo account here: https://console.plivo.com/accounts/register/* 10 | 11 | *b. Create a Plivo Endpoint here: https://console.plivo.com/voice/endpoints/add/* 12 | 13 | *c. Use this Plivo endpoint to login after deploying the application* 14 | 15 | --- 16 | 17 | ### Automatically Deploy to Heroku 18 | 19 | - Create a [Plivo account](https://console.plivo.com/accounts/register/) 20 | - Create and **verify** a Heroku account if you don't have one then click the button below. 21 | 22 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 23 | 24 | ### Deploying the application on your local setup 25 | 26 | ``` 27 | git clone https://github.com/plivo/plivo-browser-sdk2-examples.git 28 | npm install 29 | npm start 30 | ``` 31 | 32 | ### Initialization 33 | Include 34 | ```js 35 | 36 | ``` 37 | in the `` tag before you include other javascript files dependent on the SDK. 38 | 39 | Lets create a `customclient.js` file and declare a variable `var plivoBrowserSdk;` 40 | This is where we initialise a new Plivo object by passing `options` as `plivoBrowserSdk = new window.Plivo(options);`. The application can set up listeners for events as shown in the `initPhone` function below. 41 | 42 | ```js 43 | var plivoBrowserSdk; 44 | function initPhone(username, password){ 45 | var options = refreshSettings(); 46 | plivoBrowserSdk = new window.Plivo(options); 47 | 48 | 49 | plivoBrowserSdk.client.on('onWebrtcNotSupported', onWebrtcNotSupported); 50 | plivoBrowserSdk.client.on('onLogin', onLogin); 51 | plivoBrowserSdk.client.on('onLogout', onLogout); 52 | plivoBrowserSdk.client.on('onLoginFailed', onLoginFailed); 53 | plivoBrowserSdk.client.on('onCallRemoteRinging', onCallRemoteRinging); 54 | plivoBrowserSdk.client.on('onIncomingCallCanceled', onIncomingCallCanceled); 55 | plivoBrowserSdk.client.on('onCallFailed', onCallFailed); 56 | plivoBrowserSdk.client.on('onCallAnswered', onCallAnswered); 57 | plivoBrowserSdk.client.on('onCallTerminated', onCallTerminated); 58 | plivoBrowserSdk.client.on('onCalling', onCalling); 59 | plivoBrowserSdk.client.on('onIncomingCall', onIncomingCall); 60 | plivoBrowserSdk.client.on('onMediaPermission', onMediaPermission); 61 | plivoBrowserSdk.client.on('mediaMetrics',mediaMetrics); 62 | plivoBrowserSdk.client.on('audioDeviceChange',audioDeviceChange); 63 | plivoBrowserSdk.client.on('onConnectionChange', onConnectionChange); 64 | plivoBrowserSdk.client.on('volume', volume); 65 | plivoBrowserSdk.client.setRingTone(true); 66 | plivoBrowserSdk.client.setRingToneBack(true); 67 | console.log('initPhone ready!') 68 | } 69 | ``` 70 | In the demo, `options` can be set from UI in the CONFIG menu. Once the CONFIG is updated clicking on LOGIN will boot the phone again. 71 | 72 | ### Document ready state 73 | 74 | >If you're directly calling login on page load, please make sure you do that only after HTML document ready. 75 | 76 | ```html 77 | 84 | ``` 85 | ### Login 86 | ![plivo-websdk-2.0-example](img/plivobrowserSdKLogin.png) 87 | ```js 88 | function login(username, password) { 89 | if(username && password) { 90 | //start UI load spinner 91 | kickStartNow(); 92 | plivoBrowserSdk.client.login(username, password); 93 | } else { 94 | console.error('username/password missing!') 95 | } 96 | } 97 | 98 | $('#clickLogin').click(function(e){ 99 | var userName = $('#loginUser').val(); 100 | var password = $('#loginPwd').val(); 101 | login(userName, password); 102 | }); 103 | ``` 104 | 105 | ### Options 106 | *Options allow to disable tracking, setting codec type, enabling and disabling AEC/AGC etc. The list of all the settings can be found in the documentation page.* 107 | ![plivo-websdk-2.0-example](img/settings.png) 108 | 109 | ```js 110 | var defaultSettings = { "debug":"DEBUG", "permOnClick":true, "codecs":["OPUS","PCMU"], "enableIPV6":false, "audioConstraints":{"optional":[{"googAutoGainControl":false}, {"googEchoCancellation":false}]}, "enableTracking":true, "closeProtection":false, "maxAverageBitrate":48000} 111 | function resetSettings(){ 112 | document.getElementById('loglevelbtn').value = "INFO" 113 | document.getElementById('onpageload').checked = true 114 | document.getElementById('monitorquality').checked = true 115 | document.getElementById('dontcloseprotect').checked = true 116 | document.getElementById('allowdscp').checked = true 117 | document.getElementById('noincoming').checked = true 118 | document.getElementById('msregionbtn').value = "AUTO" 119 | document.getElementById('averagebitrate').value = 48000 120 | localStorage.setItem('plivosettings',JSON.stringify(defaultSettings)); 121 | } 122 | 123 | function updateSettings(val){ 124 | let loglevel = document.getElementById('loglevelbtn').value; 125 | val.debug = loglevel; 126 | changeVal(val, document.getElementById('onpageload').checked, 'permOnClick', true); 127 | changeVal(val, document.getElementById('monitorquality').checked, "enableTracking", false); 128 | changeVal(val, document.getElementById('dontcloseprotect').checked, "closeProtection", true); 129 | changeVal(val, document.getElementById('allowdscp').checked, "dscp", false); 130 | changeVal(val, document.getElementById('noincoming').checked, "allowMultipleIncomingCalls", true); 131 | let clientRegion = document.getElementById('msregionbtn').value; 132 | if(clientRegion!='AUTO') { 133 | val.clientRegion = clientRegion; 134 | } 135 | let averagebitrate = document.getElementById('averagebitrate').value; 136 | val.maxAverageBitrate = parseInt(averagebitrate); 137 | localStorage.setItem('plivosettings',JSON.stringify(val)); 138 | console.log('plivosettings updated!') 139 | } 140 | // From UI triggers 141 | $('#updateSettings').click(function(e){ 142 | updateSettings(defaultSettings); 143 | }); 144 | 145 | $('#resetSettings').click(function(e){ 146 | resetSettings(); 147 | }); 148 | ``` 149 | ### Registration 150 | The following snippet shows how to handle registration related events in the application 151 | ```js 152 | function onReady(){ 153 | $('#phonestatus').html('trying to login...'); 154 | console.info('Ready'); 155 | } 156 | 157 | function onLogin(){ 158 | $('#phonestatus').html('online'); 159 | console.info('Logged in'); 160 | $('#makecall').attr('class', 'btn btn-success btn-block flatbtn'); 161 | $('#loginContainer').hide(); 162 | $('#callContainer').show(); 163 | } 164 | 165 | function onLoginFailed(reason){ 166 | console.info('onLoginFailed ',reason); 167 | customAlert('Login failure :',reason, 'warn'); 168 | } 169 | 170 | function onLogout(){ 171 | console.info('onLogout'); 172 | $('#loginContainer').show(); 173 | $('#callContainer').hide(); 174 | } 175 | ``` 176 | ### Outgoing call 177 | Given a number or SIP URI, this snippet shows how to make an outgoing call. The following snippet takes input from the dial pad UI. 178 | ```js 179 | $('#makecall').click(function(e){ 180 | var to = $('#toNumber').val().replace(" ",""); 181 | var callEnabled = $('#makecall').attr('class').match('disabled'); 182 | if(!to || !plivoBrowserSdk || !!callEnabled){return}; 183 | console.info('Click make call : ',to); 184 | plivoBrowserSdk.client.call(to); 185 | $('.phone').hide(); 186 | $('.AfterAnswer').show(); 187 | $('#boundType').html('Outgoing : '+to); 188 | $('#callDuration').html('00:00:00'); 189 | $('.callinfo').show(); 190 | }); 191 | ``` 192 | #### Outgoing call with dynamic caller ID 193 | There are cases where you need to set different caller ID for each campaign or some different reasons, then you can start using extraHeaders in `.call()` method 194 | ```js 195 | $('#makecall').click(function(e){ 196 | var to = $('#toNumber').val(); 197 | // pass caller Id 198 | var extraHeaders={}, 199 | customCallerId = localStorage.getItem('callerId'); // get the dynamic caller id 200 | if(customCallerId) { 201 | extraHeaders = {'X-PH-callerId': customCallerId}; 202 | } 203 | console.info('Click make call : ',to); 204 | plivoBrowserSdk.client.call(to, extraHeaders); 205 | }); 206 | ``` 207 | Capture this extraHeader in application side and use `callerId` attribute to set the callerId in [Dial](https://www.plivo.com/docs/xml/dial/) Element 208 | 209 | 210 | ### Handling Incoming calls 211 | By creating the `onIncomingCall` listener, the `plivoBrowserSdk` object can handle incoming calls to the Plivo Endpoint. 212 | 213 | ```js 214 | function onIncomingCall(callerName, extraHeaders){ 215 | console.info(callerName, extraHeaders); 216 | $('#boundType').html('Incomming :'); 217 | $('#callNum').html(callerName); 218 | $('#callDuration').html('00:00:00'); 219 | $('.callinfo').show(); 220 | $('.callScreen').show(); 221 | $('.inboundBeforeAnswer').show(); 222 | } 223 | function onIncomingCallCanceled(){ 224 | console.info('onIncomingCallCanceled'); 225 | callOff(); 226 | } 227 | ``` 228 | The following snippet shows how to answer an incoming call 229 | ```js 230 | $('.answerIncoming').click(function(){ 231 | console.info('Call accept clicked'); 232 | plivoBrowserSdk.client.answer(); 233 | $('.incomingCallDefault').hide(); 234 | $('.callinfo').show(); 235 | }); 236 | ``` 237 | The following snippet shows how to reject an incoming call 238 | ```js 239 | $('.rejectIncoming').click(function(){ 240 | console.info('Call rejected'); 241 | plivoBrowserSdk.client.reject(); 242 | $('.incomingCallDefault').hide(); 243 | }); 244 | ``` 245 | The following snippet shows how to ignore an incoming call 246 | ```js 247 | $('.ignoreIncoming').click(function(){ 248 | console.info('Call ignored'); 249 | plivoBrowserSdk.client.ignore(); 250 | $('.incomingCallDefault').hide(); 251 | }); 252 | ``` 253 | ### Terminating a call 254 | This code may be used to terminate a call. 255 | ```js 256 | $('.hangup').click(function(){ 257 | console.info('Hangup'); 258 | if(plivoBrowserSdk.client.callSession) { 259 | plivoBrowserSdk.client.hangup(); 260 | }else { 261 | callOff(); 262 | } 263 | }); 264 | ``` 265 | ### Implementing MediaMetrics 266 | 267 | This snippet shows how to handle network or media related events from the SDK. A simple dynamic UI to show notifications when some warning events get emitted from Plivo SDK 268 | 269 | ![plivo-websdk-2.0-example](img/metrics.png) 270 | 271 | Please check Chrome or Firefox console to see the complete info of the event. 272 | ```js 273 | function mediaMetrics(obj){ 274 | console.table([obj]); 275 | $(".alertmsg").prepend( 276 | '
' + 277 | ''+obj.level+' | ' + 278 | ''+obj.group+' | ' + 279 | ''+message+' - '+obj.desc+' : '+obj.value+''+ 280 | '' + 281 | '
' 282 | ); 283 | } 284 | ``` 285 | 286 | ### Audio Device API 287 | 288 | The Audio Device API in this SDK allows developers to select input, output and ring devices for the calls. 289 | ![plivo-websdk-2.0-example](img/audiodevice.png) 290 | 291 | The following snippet uses this API to demonstrate how to handle device selection from the UI  292 | 293 | ```js 294 | // Audio device selection 295 | $('#micDev').change(function(){ 296 | var selectDev = $('#micDev').val(); 297 | plivoBrowserSdk.client.audio.microphoneDevices.set(selectDev); 298 | console.debug('Microphone device set to : ',selectDev); 299 | }); 300 | 301 | $('#speakerDev').change(function(){ 302 | var selectDev = $('#speakerDev').val(); 303 | plivoBrowserSdk.client.audio.speakerDevices.set(selectDev); 304 | console.debug('Speaker device set to : ',selectDev); 305 | }); 306 | 307 | $('#ringtoneDev').change(function(){ 308 | var selectDev = $('#ringtoneDev').val(); 309 | plivoBrowserSdk.client.audio.ringtoneDevices.set(selectDev); 310 | console.debug('Ringtone dev set to : ',selectDev); 311 | }); 312 | ``` 313 | 314 | The following snippet uses this API and demonstrates the use case of testing audio devices 315 | 316 | ```js 317 | // Ringtone device test 318 | $('#ringtoneDevTest').click(function(){ 319 | let ringtoneVal = document.getElementById('ringtoneDevTest').innerText; 320 | // Toggle Test 321 | if(ringtoneVal=='Test') { 322 | showOuputAudioLevel('ringoutput'); 323 | $('#ringtoneDevTest').html('Stop'); 324 | } else if(ringtoneVal=='Stop') { 325 | stopOutputAudioLevel('ringoutput'); 326 | $('#ringtoneDevTest').html('Test'); 327 | } 328 | }); 329 | 330 | // Speaker device test 331 | $('#speakerDevTest').click(function(){ 332 | let speakerVal = document.getElementById('speakerDevTest').innerText; 333 | // Toggle Test 334 | if(speakerVal=='Test') { 335 | showOuputAudioLevel('speakeroutput'); 336 | $('#speakerDevTest').html('Stop'); 337 | } else if(speakerVal=='Stop') { 338 | stopOutputAudioLevel('speakeroutput'); 339 | $('#speakerDevTest').html('Test'); 340 | } 341 | }); 342 | ``` 343 | 344 | The following snippet uses this API to retrieve available devices and populate them in UI 345 | 346 | ```js 347 | function updateAudioDevices(){ 348 | // Remove existing options if any 349 | document.querySelectorAll('#micDev option').forEach(e=>e.remove()) 350 | document.querySelectorAll('#ringtoneDev option').forEach(e=>e.remove()) 351 | plivoBrowserSdk.client.audio.availableDevices() 352 | .then(function(e){ 353 | e.forEach(function(dev){ 354 | if(dev.label && dev.kind == "audioinput") 355 | $('#micDev').append('') 356 | if(dev.label && dev.kind == "audiooutput"){ 357 | $('#ringtoneDev').append(''); 358 | $('#speakerDev').append('') 359 | } 360 | }); 361 | }) 362 | .catch(function(error){ 363 | console.error(error); 364 | }) 365 | } 366 | 367 | //revealAudioDevices 368 | $('#allowAudioDevices').click(function(){ 369 | refreshAudioDevices(); 370 | }); 371 | 372 | function refreshAudioDevices() { 373 | _forEach.call(document.querySelectorAll('#popAudioDevices option'), e=>e.remove()); 374 | plivoBrowserSdk.client.audio.revealAudioDevices() 375 | .then(function(e){ 376 | updateAudioDevices(); 377 | console.log('Media permission ',e) 378 | }) 379 | .catch(function(error){ 380 | console.error('media permission error :',error); 381 | $('#mediaAccessBlock').modal('show'); 382 | }) 383 | } 384 | ``` 385 | ### Audio Device change 386 | Show users about change in audio device, either added or removed. 387 | When a new device gets added they can select the device for either input or output audio. 388 | 389 | ![plivo-websdk-2.0-example](img/audiodevicechange.png) 390 | 391 | ```js 392 | function audioDeviceChange(e){ 393 | console.log('audioDeviceChange',e); 394 | if(e.change){ 395 | if(e.change == "added") { 396 | customAlert(e.change,e.device.kind +" - "+e.device.label,'info'); 397 | }else { 398 | customAlert(e.change,e.device.kind +" - "+e.device.label,'warn'); 399 | } 400 | }else { 401 | customAlert('info','There is an audioDeviceChange but mediaPermission is not allowed yet'); 402 | } 403 | } 404 | ``` 405 | ### Sending Feedback 406 | The following snippet shows how to collect feedback using the SDK. There is a predefined list of feedback comments that users can select for the score range from 1-3. In this application we are taking “good” and “perfect” as feedback for scores 4 and 5. 407 | 408 | ![plivo-websdk-2.0-example](img/feedback.png) 409 | 410 | ```js 411 | $('#sendFeedback').click(function(){ 412 | var score = $('#stars li.selected').last().data('value'); 413 | score = Number(score); 414 | var lastCallid = plivoBrowserSdk.client.getLastCallUUID(); 415 | var issues=[]; 416 | _forEach.call(document.querySelectorAll('[name="callqualitycheck"]'), e=>{ 417 | if(e.checked) { 418 | issues.push(e.value); 419 | } 420 | }); 421 | var note = sendFeedbackComment.value; 422 | var sendConsoleLogs = document.getElementById("sendConsoleLogs").checked; 423 | // submitCallQualityFeedback takes parameteres callUUId, starRating, issues, note, sendConsoleLogs 424 | plivoBrowserSdk.client.submitCallQualityFeedback(lastCallid, score, issues, note, sendConsoleLogs) 425 | .then((result) => { 426 | $('#feedbackStatus').html('Feedback sent'); 427 | $('#ignoreFeedback').click(); 428 | customAlert('Feedback sent','','info'); 429 | $('.lowQualityRadios').hide(); 430 | }) 431 | .catch((error) => { 432 | $('#feedbackStatus').html(error); 433 | customAlert('Could not send feedback','','warn'); 434 | }); 435 | }); 436 | ``` 437 | ### Real-time volume indicator on UI 438 | Display user real-time volume of mic and speaker. 439 | 'volume' event handler will be invoked 60 times per second. The handler receives inputVolume and outputVolume as percentages of maximum volume represented by a floating point number between 0.0 and 1.0, inclusive. This value represents a range of relative decibel values between -100dB and -30dB. 440 | 441 | ![plivo-websdk-2.0-example](img/volume.png) 442 | 443 | ```js 444 | function volume(audioStats){ 445 | inputVolume = audioStats.inputVolume; 446 | outputVolume = audioStats.outputVolume; 447 | colorPids(Math.floor(inputVolume * 325), 'localaudio'); 448 | colorPids(Math.floor(outputVolume * 325), 'remoteaudio'); 449 | } 450 | ``` 451 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"Plivo Browser SDK", 3 | "description":"Example app for the Plivo Browser SDK v2", 4 | "keywords":[ 5 | "plivo", 6 | "browser SDK", 7 | "webrtc", 8 | "telephony" 9 | ], 10 | "website":"https://www.plivo.com/", 11 | "repository":"https://github.com/plivo/plivo-browser-sdk2-examples", 12 | "image":"heroku/node", 13 | "logo":"https://www.plivo.com/assets/dist/new-design/branding/plivo-icon.svg" 14 | } 15 | -------------------------------------------------------------------------------- /chromeExten-plivo/README.md: -------------------------------------------------------------------------------- 1 | # PlivoBrowserSdk for Chrome-Extension/Packaged app 2 | 3 | ### Setup 4 | Got to chrome extension in a new tab 5 | ``` 6 | chrome://extensions/ 7 | 8 | Enable "developer mode" at top right 9 | 10 | click on "load unpacked extension" menu 11 | Select the folder "chromeExtension-plivo" that you cloned. 12 | 13 | Now open a new tab in chrome, look for a Chrome "App" menu icon under address bar and select 'Plivo' 14 | ``` 15 | -------------------------------------------------------------------------------- /chromeExten-plivo/background.js: -------------------------------------------------------------------------------- 1 | chrome.app.runtime.onLaunched.addListener(function() { 2 | chrome.app.window.create('index.html', { 3 | 'outerBounds': { 4 | 'width': 1233, 5 | 'height': 707 6 | } 7 | }); 8 | }); -------------------------------------------------------------------------------- /chromeExten-plivo/css/newstyle.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background: url() no-repeat center center fixed; 3 | -webkit-background-size: cover; 4 | -moz-background-size: cover; 5 | -o-background-size: cover; 6 | background-size: cover; 7 | } 8 | body 9 | { 10 | margin: 0; 11 | padding: 0; 12 | font-family: 'Lato' , sans-serif; 13 | color: #333; 14 | background-size: 100%; 15 | -webkit-font-smoothing: antialiased; 16 | -webkit-text-size-adjust: none; 17 | background-color: black; 18 | } 19 | p 20 | { 21 | margin: 0; 22 | padding: 0 0 10px 0; 23 | line-height: 20px; 24 | } 25 | .phone-panel{ 26 | margin-bottom: 20px; 27 | border: 1px solid transparent; 28 | border-radius: 4px; 29 | -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05); 30 | box-shadow: 0 1px 1px rgba(0,0,0,.05); 31 | border-color: white; 32 | } 33 | .span4 34 | { 35 | width: 80px; 36 | float: left; 37 | margin: 0 8px 10px 8px; 38 | } 39 | 40 | .phone 41 | { 42 | margin-top: 15px; 43 | background: rgba(150, 209, 150, 0.09); 44 | } 45 | .tel 46 | { 47 | margin-bottom: 10px; 48 | margin-top: 10px; 49 | background-color: rgba(0, 0, 0, 0); 50 | color: white; 51 | font-weight: 600; 52 | } 53 | .num-pad 54 | { 55 | padding-left: 15px; 56 | } 57 | 58 | 59 | .num 60 | { 61 | /*border: 1px solid #9e9e9e;*/ 62 | -webkit-border-radius: 999px; 63 | border-radius: 999px; 64 | -moz-border-radius: 999px; 65 | height: 80px; 66 | /*background-color: #fff;*/ 67 | cursor: pointer; 68 | } 69 | .num:hover 70 | { 71 | background-color: #5cb85c; 72 | color: #fff; 73 | transition-property: background-color .2s linear 0s; 74 | -moz-transition: background-color .2s linear 0s; 75 | -webkit-transition: background-color .2s linear 0s; 76 | -o-transition: background-color .2s linear 0s; 77 | } 78 | .txt 79 | { 80 | font-size: 30px; 81 | text-align: center; 82 | /*margin-top: 15px;*/ 83 | font-family: 'Lato' , sans-serif; 84 | line-height: 30px; 85 | color: white; 86 | } 87 | .small 88 | { 89 | font-size: 15px; 90 | } 91 | 92 | .btn 93 | { 94 | font-weight: bold; 95 | -webkit-transition: .1s ease-in background-color; 96 | -webkit-font-smoothing: antialiased; 97 | letter-spacing: 1px; 98 | } 99 | .btn:hover 100 | { 101 | transition-property: background-color .2s linear 0s; 102 | -moz-transition: background-color .2s linear 0s; 103 | -webkit-transition: background-color .2s linear 0s; 104 | -o-transition: background-color .2s linear 0s; 105 | } 106 | .spanicons 107 | { 108 | width: 72px; 109 | float: left; 110 | text-align: center; 111 | margin-top: 40px; 112 | font-size: 30px; 113 | cursor: pointer; 114 | } 115 | .spanicons:hover 116 | { 117 | color: #3498db; 118 | transition-property: color .2s linear 0s; 119 | -moz-transition: color .2s linear 0s; 120 | -webkit-transition: color .2s linear 0s; 121 | -o-transition: color .2s linear 0s; 122 | } 123 | .active 124 | { 125 | color: #3498db; 126 | } 127 | .metrics{ 128 | margin-bottom: 10px; 129 | padding: 10px; 130 | /*z-index: 10000;*/ 131 | /*display: inline-block;*/ 132 | /*background: rgba(0,153,204,0.93);*/ 133 | background: rgba(244, 67, 54, 0.75); 134 | /*border: 1px solid #006b8f;*/ 135 | color: #fff; 136 | font-size: 13px; 137 | text-align: center; 138 | border-radius: 3px; 139 | padding-top: 8px; 140 | padding-bottom: 8px; 141 | outline: 0; 142 | /*position: fixed;*/ 143 | top: 0; 144 | /*left: 0;*/ 145 | right:0; 146 | font-family: monospace; 147 | } 148 | .alertmsg{ 149 | position: fixed; 150 | top: 10px; 151 | right: 10px; 152 | /*width: 20%;*/ 153 | z-index: 100000; 154 | } 155 | #recPlayerLayout, .hangup,.inboundBeforeAnswer, .outboundBeforeAnswer, .AfterAnswer, .callinfo, #uiLogout, .lowQualityRadios, .feedback, .loader, .fadein-effect{ 156 | display: none; 157 | } 158 | 159 | .customAlert{ 160 | margin-bottom: 10px; 161 | padding: 10px; 162 | z-index: 10000; 163 | background: rgb(14, 14, 14); 164 | border: 1px solid #03A9F4; 165 | font-size: 13px; 166 | text-align: center; 167 | border-radius: 3px; 168 | padding-top: 8px; 169 | padding-bottom: 8px; 170 | outline: 0; 171 | top: 0; 172 | right: 0; 173 | font-family: monospace; 174 | color: red; 175 | } 176 | 177 | .white{ 178 | color: white; 179 | font-size: 20px; 180 | font-weight: 600; 181 | } 182 | .white-icon { 183 | color: white; 184 | font-size: 20px; 185 | font-weight: 600; 186 | margin-left: 20px; 187 | cursor: pointer; 188 | } 189 | .feedback{ 190 | transform: rotate(90deg); 191 | position: absolute; 192 | top: 50%; 193 | left: -2%; 194 | } 195 | .audioDevices{ 196 | position: absolute; 197 | top: 20%; 198 | right: 0%; 199 | } 200 | .monospace{ 201 | font-family: monospace; 202 | } 203 | .keypad { 204 | background-color: deepskyblue; 205 | border-radius: 0%; 206 | color: #fff; 207 | display: inline-block; 208 | font-size: 12px; 209 | height: 20px; 210 | line-height: 20px; 211 | padding: 5px; 212 | margin: 1px; 213 | text-align: center; 214 | width: 20px; 215 | opacity: .8; 216 | cursor:pointer; 217 | } 218 | .dialpad { 219 | margin-left: 2%; 220 | } 221 | .googleLogin { 222 | background: url(signin_button.png) no-repeat 6px center; 223 | /*width: 100px;*/ 224 | height: 100px; 225 | display: block; 226 | } 227 | .center-div 228 | { 229 | position: absolute; 230 | margin: auto; 231 | top: 0; 232 | right: 0; 233 | bottom: 0; 234 | left: 0; 235 | width: 15%; 236 | height: 100px; 237 | border-radius: 3px; 238 | } 239 | .white-shadow{ 240 | box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 241 | } 242 | .client-name{ 243 | margin-left: 28%; 244 | position: absolute; 245 | /*font-size: 30px;*/ 246 | /*font-weight: 600;*/ 247 | color: gray; 248 | } 249 | .lead{ 250 | font-weight: 600; 251 | } 252 | .loader { 253 | position: absolute; 254 | left: 50%; 255 | top: 50%; 256 | z-index: 1; 257 | width: 150px; 258 | height: 150px; 259 | margin: -75px 0 0 -75px; 260 | border: 16px solid #f3f3f3; 261 | border-radius: 50%; 262 | border-top: 16px solid #00a848; 263 | width: 120px; 264 | height: 120px; 265 | -webkit-animation: spin 2s linear infinite; 266 | animation: spin 2s linear infinite; 267 | } 268 | 269 | @-webkit-keyframes spin { 270 | 0% { -webkit-transform: rotate(0deg); } 271 | 100% { -webkit-transform: rotate(360deg); } 272 | } 273 | 274 | @keyframes spin { 275 | 0% { transform: rotate(0deg); } 276 | 100% { transform: rotate(360deg); } 277 | } 278 | .btn-success{ 279 | background-color: #00a848; 280 | border-color: rgba(0,0,0,.0001); 281 | } 282 | .dropdown{ 283 | margin-top: 6%; 284 | } 285 | .log-out{ 286 | font-size: 25px; 287 | color: orange; 288 | } 289 | .log-in{ 290 | font-size: 25px; 291 | color: green; 292 | } 293 | .log-missed{ 294 | font-size: 25px; 295 | color: red; 296 | } 297 | .log-call{ 298 | font-size: 25px; 299 | color: green; 300 | } 301 | .log-call:hover{ 302 | text-shadow: 7px 2px 10px; 303 | cursor: pointer; 304 | } -------------------------------------------------------------------------------- /chromeExten-plivo/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/chromeExten-plivo/icon.png -------------------------------------------------------------------------------- /chromeExten-plivo/img/plivo-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/chromeExten-plivo/img/plivo-logo.png -------------------------------------------------------------------------------- /chromeExten-plivo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | plivo webphone 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 28 |
29 |
30 |
31 | - phone status: 32 | Not ready... 33 |
34 |
35 | - call status: 36 | idle 37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 45 |
46 |
47 |
48 |
49 | 1 50 |
51 |
52 |
53 |
54 |
55 |
56 | 2 57 |

58 | ABC

59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | 3 67 |

68 | DEF

69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | 4 77 |

78 | GHI

79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | 5 87 |

88 | JKL

89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | 6 97 |

98 | MNO

99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | 7 107 |

108 | PQRS

109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | 8 117 |

118 | TUV

119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | 9 127 |

128 | WXYZ

129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | * 137 |
138 |
139 |
140 |
141 |
142 |
143 | 0 144 |

145 | +

146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | # 154 |
155 |
156 |
157 |
158 |
159 |
160 | 161 | 162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |

Fetching...

170 |

Fetching...

171 |

00:00

172 |
173 |
174 |
175 |
176 |
177 | 178 |

179 | Answer

180 |
181 |
182 |
183 | 184 |

185 | Reject

186 |
187 |
188 |
189 | 190 |

191 | Hangup

192 |
193 |
194 |
195 | 196 |

197 | Hangup

198 |
199 |
200 |
201 | 202 |

203 | Microphone

204 |
205 |
206 |
207 |
208 |
209 | 210 |
211 | 212 | Download 213 | Ignore 214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | 223 | 242 | 243 | 244 | 245 | 275 | 276 | 277 | 313 | 314 | 358 | 359 | 362 |
363 |
364 | 365 |
366 |
367 | 368 |
369 | 370 | 371 | 372 | -------------------------------------------------------------------------------- /chromeExten-plivo/js/customclient.js: -------------------------------------------------------------------------------- 1 | /* 2 | Chrome extension tweaks 3 | 1. support localstorage 4 | 2. load external URL 5 | */ 6 | var localStorage = (typeof chrome != 'undefined' && chrome.storage) ? chrome.storage.local : window.localStorage; 7 | (function(){ 8 | var xhr = new XMLHttpRequest(); 9 | xhr.onreadystatechange = function(){ 10 | // console.log('Plivo xhr.readyState',xhr.readyState,' xhr.status: ',xhr.status, " document.readyState: ",document.readyState); 11 | if(xhr.readyState == 4 && xhr.status == 200){ 12 | if(document.readyState == "complete"){ 13 | setTimeout(PlivoJsReady,50); 14 | }else{ 15 | document.onreadystatechange = function(e){ 16 | if(document.readyState == "complete"){ 17 | PlivoJsReady(); 18 | } 19 | } 20 | } 21 | } 22 | } 23 | xhr.open('GET', 'https://s3.amazonaws.com/plivosdk-backup/sdk/browser/v2/plivo-2.0.9-beta.min.js', true); 24 | xhr.responseType = 'blob'; 25 | xhr.onload = function(e) { 26 | var ps = document.createElement('script'); 27 | ps.type = 'text/javascript'; 28 | ps.src= window.URL.createObjectURL(this.response); 29 | ps.async=true; 30 | var s = document.getElementsByTagName('script')[0]; 31 | s.parentNode.insertBefore(ps, s); 32 | }; 33 | xhr.send(); 34 | })(); 35 | 36 | var callStorage = {}, timer = "00:00:00"; 37 | // UI tweaks 38 | $('#makecall').attr('class', 'btn btn-success btn-block flatbtn disabled'); 39 | 40 | function date(){ 41 | return (new Date()).toISOString().substring(0, 10)+" "+Date().split(" ")[4]; 42 | } 43 | function kickStartNow(){ 44 | $('.callScreen').hide(); 45 | $('.loader').show(); 46 | $('.fadein-effect').fadeIn(5000); 47 | } 48 | function login(username, password) { 49 | if(username && password){ 50 | //start UI load spinner 51 | kickStartNow(); 52 | plivoBrowserSdk.client.login(username, password); 53 | $('#sipUserName').html('sip:'+username+'@'+plivoBrowserSdk.client.phone.configuration.hostport_params); 54 | document.querySelector('title').innerHTML=username; 55 | }else{ 56 | console.error('username/password missing!') 57 | } 58 | } 59 | function onWebrtcNotSupported() { 60 | console.warn('no webRTC support'); 61 | alert('Webrtc is not supported in this broswer, Please use latest version of chrome/firefox/opera/IE Edge'); 62 | } 63 | function mediaMetrics(obj){ 64 | /** 65 | * Set a trigger for Quality FB popup when there is an warning druing call using sessionStorage 66 | * During `onCallTerminated` event check for `triggerFB` flag 67 | */ 68 | sessionStorage.setItem('triggerFB',true); 69 | console.table([obj]); 70 | var message = obj.type; 71 | var classExist = document.querySelector('.-'+obj.type); 72 | 73 | /** 74 | * If there is a same audio level for 3 samples then we will get a trigger 75 | * If audio level is greater than 30 then it could be some continuous echo or user is not speaking 76 | * Set message "same level" for audio greater than 30. Less than 30 could be a possible mute 77 | */ 78 | if(obj.type.match('audio') && obj.value > 30){ 79 | message = "same level"; 80 | } 81 | if(obj.active){ 82 | classExist? classExist.remove() : null; 83 | $(".alertmsg").prepend( 84 | '
' + 85 | ''+obj.level+' | ' + 86 | ''+obj.group+' | ' + 87 | ''+message+' - '+obj.desc+' : '+obj.value+''+ 88 | '' + 89 | '
' 90 | ); 91 | $('.closeMediaMetrics').click(function(){ 92 | $('.metrics').remove(); 93 | }); 94 | } 95 | if(!obj.active && classExist){ 96 | document.querySelector('.-'+obj.type).remove(); 97 | } 98 | // Handle no mic input even after mic access 99 | if(obj.desc == "no access to your microphone"){ 100 | $('#micAccessBlock').modal({ show: true }) 101 | } 102 | } 103 | function onReady(){ 104 | $('#phonestatus').html('trying to login...'); 105 | console.info('Ready'); 106 | } 107 | function onLogin(){ 108 | $('#phonestatus').html('online'); 109 | console.info('Logged in'); 110 | $('#makecall').attr('class', 'btn btn-success btn-block flatbtn'); 111 | $('#uiLogin').hide(); 112 | $('#uiLogout').show(); 113 | $('.feedback').show(); 114 | $('.loader').remove(); 115 | } 116 | function onLoginFailed(reason){ 117 | $('#phonestatus').html('login failed'); 118 | console.info('onLoginFailed ',reason); 119 | customAlert('Login failure :',reason); 120 | $('.loader').remove() 121 | } 122 | function onLogout(){ 123 | $('#phonestatus').html('Offline'); 124 | console.info('onLogout'); 125 | } 126 | function onCalling(){ 127 | $('#callstatus').html('Progress...'); 128 | console.info('onCalling'); 129 | } 130 | function onCallRemoteRinging(){ 131 | $('#callstatus').html('Ringing...'); 132 | console.info('onCallRemoteRinging'); 133 | } 134 | function onCallConnected(){ 135 | $('#callstatus').html('Connected...'); 136 | console.info('onCallConnected'); 137 | } 138 | function onCallAnswered(){ 139 | console.info('onCallAnswered'); 140 | $('#callstatus').html('Answered'); 141 | $('.hangup').show(); 142 | timer = 0; 143 | window.calltimer = setInterval(function(){ 144 | timer = timer +1; 145 | $('#callDuration').html(timer.toString().calltimer()); 146 | },1000); 147 | } 148 | function onCallTerminated(){ 149 | $('#callstatus').html('Call Ended'); 150 | console.info('onCallTerminated'); 151 | if(sessionStorage.getItem('triggerFB')){ 152 | $('#clickFeedback').trigger('click'); 153 | // clear at end of every call 154 | sessionStorage.removeItem('triggerFB'); 155 | } 156 | callOff(); 157 | } 158 | function onCallFailed(reason){ 159 | $('#callstatus').html('call failed'); 160 | console.info('onCallFailed',reason); 161 | if(reason && /Denied Media/i.test(reason)){ 162 | $('#mediaAccessBlock').modal('show'); 163 | }; 164 | callOff(); 165 | } 166 | function onMediaPermission(evt){ 167 | console.info('onMediaPermission',evt); 168 | if(evt.error){ 169 | customAlert('Media permission error',evt.error); 170 | $('#mediaAccessBlock').modal('show'); 171 | } 172 | } 173 | function onIncomingCall(callerName, extraHeaders){ 174 | console.info(callerName, extraHeaders); 175 | callStorage.startTime = date(); 176 | callStorage.mode = 'in'; 177 | callStorage.num = callerName; 178 | $('#boundType').html('Incomming :'); 179 | $('#callNum').html(callerName); 180 | $('#callDuration').html('00:00:00'); 181 | $('.callinfo').show(); 182 | $('.callScreen').show(); 183 | $('.inboundBeforeAnswer').show(); 184 | $('#makecall').hide(); 185 | } 186 | function onIncomingCallCanceled(){ 187 | console.info('onIncomingCallCanceled'); 188 | callOff(); 189 | } 190 | 191 | function callOff(){ 192 | $('.callScreen').hide(); 193 | $('.inboundBeforeAnswer').hide(); 194 | $('.AfterAnswer').hide(); 195 | $('.outboundBeforeAnswer').hide(); 196 | $('.hangup').hide(); 197 | $('#makecall').show(); 198 | window.calltimer? clearInterval(window.calltimer) : false; 199 | callStorage.dur = timer.toString().calltimer(); 200 | if(timer == "00:00:00" && callStorage.mode == "in"){ 201 | callStorage.mode = "missed"; 202 | } 203 | $('#callstatus').html('Idle'); 204 | $('.callinfo').hide(); 205 | callStorage={}; // reset callStorage 206 | timer = "00:00:00"; //reset the timer 207 | } 208 | 209 | String.prototype.calltimer = function () { 210 | var sec_num = parseInt(this, 10); 211 | var hours = Math.floor(sec_num / 3600); 212 | var minutes = Math.floor((sec_num - (hours * 3600)) / 60); 213 | var seconds = sec_num - (hours * 3600) - (minutes * 60); 214 | if (hours < 10) {hours = "0"+hours;} 215 | if (minutes < 10) {minutes = "0"+minutes;} 216 | if (seconds < 10) {seconds = "0"+seconds;} 217 | return hours+':'+minutes+':'+seconds; 218 | } 219 | 220 | function resetSettings(source){ 221 | // You can use all your default settings to go in as options during sdk init 222 | var defaultSettings = {"debug":"DEBUG","permOnClick":true,"codecs":["OPUS","PCMU"],"enableIPV6":false,"audioConstraints":{"optional":[{"googAutoGainControl":false},{"googEchoCancellation":false}]},"dscp":true,"enableTracking":true} 223 | var uiSettings = document.querySelector('#appSettings'); 224 | uiSettings.value = JSON.stringify(defaultSettings); 225 | if(source == 'clickTrigger') 226 | localStorage.plivosettings=""; 227 | } 228 | 229 | function refreshSettings(){ 230 | var getSettings = localStorage.plivosettings; 231 | var uiSettings = document.querySelector('#appSettings'); 232 | if(getSettings){ 233 | uiSettings.value = getSettings; 234 | return JSON.parse(getSettings); 235 | }else{ 236 | return JSON.parse(uiSettings.value); 237 | } 238 | } 239 | function updateSettings(val){ 240 | localStorage.plivosettings= val; 241 | console.log('plivosettings updated!') 242 | } 243 | function customAlert(alertType,alertMessage){ 244 | $(".alertmsg").prepend( 245 | '
' + 246 | ''+alertType+' | ' + 247 | ''+alertMessage+' '+ 248 | '' + 249 | '
' 250 | ); 251 | $('.closeMetrics').click(function(){ 252 | $('.customAlert').remove(); 253 | }); 254 | } 255 | 256 | function updateAudioDevices(){ 257 | // Remove existing options if any 258 | document.querySelectorAll('#micDev option').forEach(e=>e.remove()) 259 | document.querySelectorAll('#ringtoneDev option').forEach(e=>e.remove()) 260 | 261 | plivoBrowserSdk.client.audio.availableDevices() 262 | .then(function(e){ 263 | e.forEach(function(dev){ 264 | if(dev.label && dev.kind == "audioinput") 265 | $('#micDev').append('') 266 | if(dev.label && dev.kind == "audiooutput"){ 267 | $('#ringtoneDev').append(''); 268 | $('#speakerDev').append('') 269 | } 270 | }); 271 | }) 272 | .catch(function(error){ 273 | console.error(error); 274 | }) 275 | } 276 | 277 | function checkBrowserComplaince(client){ 278 | if(client.browserDetails.browser != "chrome"){ 279 | document.querySelector('[data-target="#popAudioDevices"]').remove(); 280 | } 281 | } 282 | 283 | function trimSpace(e){ 284 | e.value = e.value.replace(/[- ()]/g,''); 285 | } 286 | 287 | /* 288 | Capture UI onclick triggers 289 | */ 290 | $('#inboundAccept').click(function(){ 291 | console.info('Call accept clicked'); 292 | plivoBrowserSdk.client.answer(); 293 | $('.inboundBeforeAnswer').hide(); 294 | $('.AfterAnswer').show(); 295 | }); 296 | $('#inboundReject').click(function(){ 297 | console.info('callReject'); 298 | plivoBrowserSdk.client.reject(); 299 | }); 300 | $('#outboundHangup').click(function(){ 301 | console.info('outboundHangup'); 302 | plivoBrowserSdk.client.hangup(); 303 | }); 304 | $('.hangup').click(function(){ 305 | console.info('Hangup'); 306 | if(plivoBrowserSdk.client.callSession){ 307 | plivoBrowserSdk.client.hangup(); 308 | }else{ 309 | callOff(); 310 | } 311 | }); 312 | 313 | $('#tmute').click(function(e){ 314 | var event = e.currentTarget.getAttribute('data-toggle'); 315 | if(event == "mute"){ 316 | plivoBrowserSdk.client.mute(); 317 | e.currentTarget.setAttribute('data-toggle','unmute'); 318 | $('.tmute').attr('class', 'fa tmute fa-microphone-slash') 319 | customAlert('info','Muted'); 320 | }else{ 321 | plivoBrowserSdk.client.unmute(); 322 | e.currentTarget.setAttribute('data-toggle','mute'); 323 | $('.tmute').attr('class', 'fa tmute fa-microphone') 324 | customAlert('info','UnMuted'); 325 | } 326 | }); 327 | $('#makecall').click(function(e){ 328 | var to = $('#toNumber').val().replace(" ",""), 329 | extraHeaders; 330 | // Prevent click on makecall disabled button 331 | var callEnabled = $('#makecall').attr('class').match('disabled'); 332 | if(!to || !plivoBrowserSdk || !!callEnabled){return}; 333 | plivoBrowserSdk.client.call(to,extraHeaders); 334 | console.info('Click make call : ',to); 335 | callStorage.mode = "out"; 336 | callStorage.startTime = date(); 337 | callStorage.num = to; 338 | $('.callScreen').show(); 339 | $('.AfterAnswer').show(); 340 | $('#boundType').html('Outgoing :'); 341 | $('#callNum').html(to); 342 | $('#callDuration').html('00:00:00'); 343 | $('.callinfo').show(); 344 | $('.hangup').show(); 345 | $('#makecall').hide(); 346 | }); 347 | 348 | $('#updateSettings').click(function(e){ 349 | var appSettings = document.querySelector('#appSettings'); 350 | appSettings = appSettings.value; 351 | updateSettings(appSettings); 352 | }); 353 | 354 | $('#resetSettings').click(function(e){ 355 | resetSettings('clickTrigger'); 356 | }); 357 | 358 | $('#qualityRange').click(function(e){ 359 | var value = e.currentTarget.value; 360 | $('#qualityNumber').html('Rating: '+value); 361 | // Show quality issue reasons only if rating is less then 4 362 | if(value < 4){ 363 | $('.lowQualityRadios').show(); 364 | }else{ 365 | $('.lowQualityRadios').hide(); 366 | } 367 | }); 368 | 369 | $('#sendFeedback').click(function(){ 370 | var score = $('#qualityRange').val(); 371 | var lastCallid = plivoBrowserSdk.client.getLastCallUUID(); 372 | var comment = $("input[type=radio][name=callqualityradio]:checked").val() || "good"; 373 | score = Number(score); 374 | plivoBrowserSdk.client.sendQualityFeedback(lastCallid,score,comment); 375 | customAlert('Quality feedback','success'); 376 | }); 377 | 378 | $('#clickLogin').click(function(e){ 379 | var userName = $('#loginUser').val(); 380 | var password = $('#loginPwd').val(); 381 | login(userName, password); 382 | }); 383 | 384 | // Audio device selection 385 | $('#micDev').change(function(){ 386 | var selectDev = $('#micDev').val(); 387 | plivoBrowserSdk.client.audio.microphoneDevices.set(selectDev); 388 | console.debug('Microphone device set to : ',selectDev); 389 | }); 390 | $('#speakerDev').change(function(){ 391 | var selectDev = $('#speakerDev').val(); 392 | plivoBrowserSdk.client.audio.speakerDevices.set(selectDev); 393 | console.debug('Speaker device set to : ',selectDev); 394 | }); 395 | $('#ringtoneDev').change(function(){ 396 | var selectDev = $('#ringtoneDev').val(); 397 | plivoBrowserSdk.client.audio.ringtoneDevices.set(selectDev); 398 | console.debug('Ringtone dev set to : ',selectDev); 399 | }); 400 | 401 | // Ringtone device test 402 | $('#ringtoneDevTest').click(function(){ 403 | var ringAudio = plivoBrowserSdk.client.audio.ringtoneDevices.media(); 404 | // Toggle play 405 | if(ringAudio.paused){ 406 | ringAudio.play(); 407 | $('#ringtoneDevTest').html('Pause'); 408 | }else{ 409 | ringAudio.pause(); 410 | $('#ringtoneDevTest').html('Play'); 411 | } 412 | }); 413 | // Speaker device test 414 | $('#speakerDevTest').click(function(){ 415 | var speakerAudio = plivoBrowserSdk.client.audio.speakerDevices.media(); 416 | // Toggle play 417 | if(speakerAudio.paused){ 418 | speakerAudio.play(); 419 | $('#speakerDevTest').html('Pause'); 420 | }else{ 421 | speakerAudio.pause(); 422 | $('#speakerDevTest').html('Play'); 423 | } 424 | }); 425 | //revealAudioDevices 426 | $('#allowAudioDevices').click(function(){ 427 | document.querySelectorAll('#popAudioDevices option').forEach(e=>e.remove()); 428 | plivoBrowserSdk.client.audio.revealAudioDevices() 429 | .then(function(e){ 430 | updateAudioDevices(); 431 | console.log('Media permission ',e) 432 | }) 433 | .catch(function(error){ 434 | console.error('media permission error :',error); 435 | $('#mediaAccessBlock').modal('show'); 436 | }) 437 | }); 438 | 439 | $('.num').click(function () { 440 | var num = $(this); 441 | var text = $.trim(num.find('.txt').clone().children().remove().end().text()); 442 | var telNumber = $('#toNumber'); 443 | $(telNumber).val(telNumber.val() + text); 444 | if(plivoBrowserSdk && plivoBrowserSdk.client.callSession){ 445 | plivoBrowserSdk.client.sendDtmf(text); 446 | } 447 | }); 448 | 449 | loginUser.onblur = function(){ 450 | trimSpace(loginUser); 451 | } 452 | 453 | showPass.onclick = function(){ 454 | if($('#showPass input').prop("checked")){ 455 | loginPwd.type="text"; 456 | }else{ 457 | loginPwd.type="password"; 458 | } 459 | } 460 | // variables to declare 461 | 462 | var plivoBrowserSdk; // this will be retrived from settings in UI 463 | 464 | function initPhone(username, password){ 465 | var options = refreshSettings(); 466 | plivoBrowserSdk = new window.Plivo(options); 467 | plivoBrowserSdk.client.on('onWebrtcNotSupported', onWebrtcNotSupported); 468 | plivoBrowserSdk.client.on('onLogin', onLogin); 469 | plivoBrowserSdk.client.on('onLogout', onLogout); 470 | plivoBrowserSdk.client.on('onLoginFailed', onLoginFailed); 471 | plivoBrowserSdk.client.on('onCallRemoteRinging', onCallRemoteRinging); 472 | plivoBrowserSdk.client.on('onCallConnected', onCallConnected); 473 | plivoBrowserSdk.client.on('onIncomingCallCanceled', onIncomingCallCanceled); 474 | plivoBrowserSdk.client.on('onCallFailed', onCallFailed); 475 | plivoBrowserSdk.client.on('onCallAnswered', onCallAnswered); 476 | plivoBrowserSdk.client.on('onCallTerminated', onCallTerminated); 477 | plivoBrowserSdk.client.on('onCalling', onCalling); 478 | plivoBrowserSdk.client.on('onIncomingCall', onIncomingCall); 479 | plivoBrowserSdk.client.on('onMediaPermission', onMediaPermission); 480 | plivoBrowserSdk.client.on('mediaMetrics',mediaMetrics); 481 | plivoBrowserSdk.client.setRingTone(true); 482 | plivoBrowserSdk.client.setRingToneBack(true); 483 | /** Handle browser issues 484 | * Sound devices won't work in firefox 485 | */ 486 | checkBrowserComplaince(plivoBrowserSdk.client); 487 | updateAudioDevices(); 488 | console.log('initPhone ready!') 489 | } 490 | 491 | function PlivoJsReady(){ 492 | if(document.readyState == "complete"){ 493 | console.log( "PlivoJs ready!" ); 494 | $('[data-toggle="tooltip"]').tooltip(); 495 | resetSettings(); 496 | initPhone(); 497 | } 498 | } 499 | -------------------------------------------------------------------------------- /chromeExten-plivo/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "plivo", 4 | "description": "plivo websdk", 5 | "version": "2.0", 6 | "app": { 7 | "background": { 8 | "scripts": [ "background.js" ] 9 | } 10 | }, 11 | "permissions": [ "storage", "notifications", "", "videoCapture", "audioCapture" ] 12 | } -------------------------------------------------------------------------------- /ci/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | parent: csdk 3 | serviceName: csdk-browser-example 4 | language: nodejs 5 | build: 6 | nodejs: 7 | outputDistDir: csdk 8 | command: | 9 | mkdir csdk 10 | mkdir csdk/assets 11 | cp example.html csdk/ 12 | cp -r webApp-plivo/public/img csdk/assets/ 13 | cp -r webApp-plivo/public/js csdk/assets/ 14 | cp -r webApp-plivo/public/lib csdk/assets/ 15 | cp -r webApp-plivo/public/css csdk/assets/ 16 | -------------------------------------------------------------------------------- /electronApp-plivo/LICENSE.md: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | ================== 3 | 4 | Statement of Purpose 5 | --------------------- 6 | 7 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). 8 | 9 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. 10 | 11 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 12 | 13 | 1. Copyright and Related Rights. 14 | -------------------------------- 15 | A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 16 | 17 | i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; 18 | ii. moral rights retained by the original author(s) and/or performer(s); 19 | iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; 20 | iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; 21 | v. rights protecting the extraction, dissemination, use and reuse of data in a Work; 22 | vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and 23 | vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 24 | 25 | 2. Waiver. 26 | ----------- 27 | To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 28 | 29 | 3. Public License Fallback. 30 | ---------------------------- 31 | Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 32 | 33 | 4. Limitations and Disclaimers. 34 | -------------------------------- 35 | 36 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. 37 | b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. 38 | c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. 39 | d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. 40 | -------------------------------------------------------------------------------- /electronApp-plivo/README.md: -------------------------------------------------------------------------------- 1 | # Plivo-electron-quickstart 2 | 3 | A basic Plivo Electron application needs just these files: 4 | 5 | - `package.json` - Points to the app's main file and lists its details and dependencies. 6 | - `main.js` - Starts the app and creates a browser window to render HTML. This is the app's **main process**. 7 | - `index.html` - A web page to render. This is the app's **renderer process** 8 | 9 | ## To Use 10 | 11 | To clone and run this repository you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer. From your command line: 12 | 13 | ```bash 14 | # Clone this repository 15 | git clone https://github.com/plivo/plivo-websdk-2.0-example 16 | # Go into the repository 17 | cd electronApp-plivo 18 | # Install dependencies 19 | npm install 20 | # Run the app 21 | npm start 22 | ``` 23 | This app runs in developer mode so you can use same shortcut key that you use in chrome browser to open console mode 24 | 25 | Note: If you're using Linux Bash for Windows, [see this guide](https://www.howtogeek.com/261575/how-to-run-graphical-linux-desktop-applications-from-windows-10s-bash-shell/) or use `node` from the command prompt. 26 | -------------------------------------------------------------------------------- /electronApp-plivo/css/despic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/electronApp-plivo/css/despic.png -------------------------------------------------------------------------------- /electronApp-plivo/css/newstyle.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Lato:300); 2 | @import url(https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css); 3 | body{ 4 | background: url(despic.png) no-repeat center center fixed; 5 | -webkit-background-size: cover; 6 | -moz-background-size: cover; 7 | -o-background-size: cover; 8 | background-size: cover; 9 | } 10 | body 11 | { 12 | margin: 0; 13 | padding: 0; 14 | font-family: 'Lato' , sans-serif; 15 | color: #333; 16 | background-size: 100%; 17 | -webkit-font-smoothing: antialiased; 18 | -webkit-text-size-adjust: none; 19 | background-color: black; 20 | } 21 | p 22 | { 23 | margin: 0; 24 | padding: 0 0 10px 0; 25 | line-height: 20px; 26 | } 27 | .phone-panel{ 28 | margin-bottom: 20px; 29 | border: 1px solid transparent; 30 | border-radius: 4px; 31 | -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05); 32 | box-shadow: 0 1px 1px rgba(0,0,0,.05); 33 | border-color: white; 34 | } 35 | .span4 36 | { 37 | width: 80px; 38 | float: left; 39 | margin: 0 8px 10px 8px; 40 | } 41 | 42 | .phone 43 | { 44 | margin-top: 15px; 45 | background: rgba(150, 209, 150, 0.09); 46 | } 47 | .tel 48 | { 49 | margin-bottom: 10px; 50 | margin-top: 10px; 51 | background-color: rgba(0, 0, 0, 0); 52 | color: white; 53 | font-weight: 600; 54 | } 55 | .num-pad 56 | { 57 | padding-left: 15px; 58 | } 59 | 60 | 61 | .num 62 | { 63 | /*border: 1px solid #9e9e9e;*/ 64 | -webkit-border-radius: 999px; 65 | border-radius: 999px; 66 | -moz-border-radius: 999px; 67 | height: 80px; 68 | /*background-color: #fff;*/ 69 | cursor: pointer; 70 | } 71 | .num:hover 72 | { 73 | background-color: #5cb85c; 74 | color: #fff; 75 | transition-property: background-color .2s linear 0s; 76 | -moz-transition: background-color .2s linear 0s; 77 | -webkit-transition: background-color .2s linear 0s; 78 | -o-transition: background-color .2s linear 0s; 79 | } 80 | .txt 81 | { 82 | font-size: 30px; 83 | text-align: center; 84 | /*margin-top: 15px;*/ 85 | font-family: 'Lato' , sans-serif; 86 | line-height: 30px; 87 | color: white; 88 | } 89 | .small 90 | { 91 | font-size: 15px; 92 | } 93 | 94 | .btn 95 | { 96 | font-weight: bold; 97 | -webkit-transition: .1s ease-in background-color; 98 | -webkit-font-smoothing: antialiased; 99 | letter-spacing: 1px; 100 | } 101 | .btn:hover 102 | { 103 | transition-property: background-color .2s linear 0s; 104 | -moz-transition: background-color .2s linear 0s; 105 | -webkit-transition: background-color .2s linear 0s; 106 | -o-transition: background-color .2s linear 0s; 107 | } 108 | .spanicons 109 | { 110 | width: 72px; 111 | float: left; 112 | text-align: center; 113 | margin-top: 40px; 114 | font-size: 30px; 115 | cursor: pointer; 116 | } 117 | .spanicons:hover 118 | { 119 | color: #3498db; 120 | transition-property: color .2s linear 0s; 121 | -moz-transition: color .2s linear 0s; 122 | -webkit-transition: color .2s linear 0s; 123 | -o-transition: color .2s linear 0s; 124 | } 125 | .active 126 | { 127 | color: #3498db; 128 | } 129 | .metrics{ 130 | margin-bottom: 10px; 131 | padding: 10px; 132 | /*z-index: 10000;*/ 133 | /*display: inline-block;*/ 134 | /*background: rgba(0,153,204,0.93);*/ 135 | background: rgba(244, 67, 54, 0.75); 136 | /*border: 1px solid #006b8f;*/ 137 | color: #fff; 138 | font-size: 13px; 139 | text-align: center; 140 | border-radius: 3px; 141 | padding-top: 8px; 142 | padding-bottom: 8px; 143 | outline: 0; 144 | /*position: fixed;*/ 145 | top: 0; 146 | /*left: 0;*/ 147 | right:0; 148 | font-family: monospace; 149 | } 150 | .alertmsg{ 151 | position: fixed; 152 | top: 10px; 153 | right: 10px; 154 | /*width: 20%;*/ 155 | z-index: 100000; 156 | } 157 | #recPlayerLayout, .hangup,.inboundBeforeAnswer, .outboundBeforeAnswer, .AfterAnswer, .callinfo, #uiLogout, .lowQualityRadios, .feedback, .loader, .fadein-effect{ 158 | display: none; 159 | } 160 | 161 | .customAlert{ 162 | margin-bottom: 10px; 163 | padding: 10px; 164 | z-index: 10000; 165 | background: rgb(14, 14, 14); 166 | /*border: 1px solid #03A9F4;*/ 167 | font-size: 13px; 168 | text-align: center; 169 | border-radius: 3px; 170 | padding-top: 8px; 171 | padding-bottom: 8px; 172 | outline: 0; 173 | top: 0; 174 | right: 0; 175 | font-family: monospace; 176 | color: red; 177 | } 178 | .alertwarn{ 179 | color: red; 180 | } 181 | .alertinfo{ 182 | color: rgb(25, 255, 34); 183 | } 184 | 185 | .white{ 186 | color: white; 187 | font-size: 20px; 188 | font-weight: 600; 189 | } 190 | .white-icon { 191 | color: white; 192 | font-size: 20px; 193 | font-weight: 600; 194 | margin-left: 20px; 195 | cursor: pointer; 196 | } 197 | .feedback{ 198 | transform: rotate(90deg); 199 | position: absolute; 200 | top: 50%; 201 | left: -2%; 202 | } 203 | .audioDevices{ 204 | position: absolute; 205 | top: 20%; 206 | right: 0%; 207 | } 208 | .monospace{ 209 | font-family: monospace; 210 | } 211 | .keypad { 212 | background-color: deepskyblue; 213 | border-radius: 0%; 214 | color: #fff; 215 | display: inline-block; 216 | font-size: 12px; 217 | height: 20px; 218 | line-height: 20px; 219 | padding: 5px; 220 | margin: 1px; 221 | text-align: center; 222 | width: 20px; 223 | opacity: .8; 224 | cursor:pointer; 225 | } 226 | .dialpad { 227 | margin-left: 2%; 228 | } 229 | .googleLogin { 230 | background: url(signin_button.png) no-repeat 6px center; 231 | /*width: 100px;*/ 232 | height: 100px; 233 | display: block; 234 | } 235 | .center-div 236 | { 237 | position: absolute; 238 | margin: auto; 239 | top: 0; 240 | right: 0; 241 | bottom: 0; 242 | left: 0; 243 | width: 15%; 244 | height: 100px; 245 | border-radius: 3px; 246 | } 247 | .white-shadow{ 248 | box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 249 | } 250 | .client-name{ 251 | margin-left: 28%; 252 | position: absolute; 253 | /*font-size: 30px;*/ 254 | /*font-weight: 600;*/ 255 | color: gray; 256 | } 257 | .lead{ 258 | font-weight: 600; 259 | } 260 | .loader { 261 | position: absolute; 262 | left: 50%; 263 | top: 50%; 264 | z-index: 1; 265 | width: 150px; 266 | height: 150px; 267 | margin: -75px 0 0 -75px; 268 | border: 16px solid #f3f3f3; 269 | border-radius: 50%; 270 | border-top: 16px solid #00a848; 271 | width: 120px; 272 | height: 120px; 273 | -webkit-animation: spin 2s linear infinite; 274 | animation: spin 2s linear infinite; 275 | } 276 | 277 | @-webkit-keyframes spin { 278 | 0% { -webkit-transform: rotate(0deg); } 279 | 100% { -webkit-transform: rotate(360deg); } 280 | } 281 | 282 | @keyframes spin { 283 | 0% { transform: rotate(0deg); } 284 | 100% { transform: rotate(360deg); } 285 | } 286 | .btn-success{ 287 | background-color: #00a848; 288 | border-color: rgba(0,0,0,.0001); 289 | } 290 | .dropdown{ 291 | margin-top: 6%; 292 | } 293 | .log-out{ 294 | font-size: 25px; 295 | color: orange; 296 | } 297 | .log-in{ 298 | font-size: 25px; 299 | color: green; 300 | } 301 | .log-missed{ 302 | font-size: 25px; 303 | color: red; 304 | } 305 | .log-call{ 306 | font-size: 25px; 307 | color: green; 308 | } 309 | .log-call:hover{ 310 | text-shadow: 7px 2px 10px; 311 | cursor: pointer; 312 | } 313 | 314 | 315 | /* Rating Star Widgets Style */ 316 | .rating-stars ul { 317 | list-style-type:none; 318 | padding:0; 319 | 320 | -moz-user-select:none; 321 | -webkit-user-select:none; 322 | } 323 | .rating-stars ul > li.star { 324 | display:inline-block; 325 | 326 | } 327 | 328 | /* Idle State of the stars */ 329 | .rating-stars ul > li.star > i.fa { 330 | font-size:2.5em; /* Change the size of the stars */ 331 | color:#ccc; /* Color on idle state */ 332 | } 333 | /* Hover state of the stars */ 334 | .rating-stars ul > li.star.hover > i.fa { 335 | color:#FFCC36; 336 | } 337 | /* Selected state of the stars */ 338 | .rating-stars ul > li.star.selected > i.fa { 339 | color:#FF912C; 340 | } 341 | -------------------------------------------------------------------------------- /electronApp-plivo/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/electronApp-plivo/img/favicon.png -------------------------------------------------------------------------------- /electronApp-plivo/img/micdenied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/electronApp-plivo/img/micdenied.png -------------------------------------------------------------------------------- /electronApp-plivo/img/plivo-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/electronApp-plivo/img/plivo-logo.png -------------------------------------------------------------------------------- /electronApp-plivo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | plivo webphone 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 32 |
33 |
34 |
35 | - phone status: 36 | Not ready... 37 |
38 |
39 | - call status: 40 | idle 41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | 49 |
50 |
51 |
52 |
53 | 1 54 |
55 |
56 |
57 |
58 |
59 |
60 | 2 61 |

62 | ABC

63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | 3 71 |

72 | DEF

73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | 4 81 |

82 | GHI

83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | 5 91 |

92 | JKL

93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | 6 101 |

102 | MNO

103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | 7 111 |

112 | PQRS

113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | 8 121 |

122 | TUV

123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | 9 131 |

132 | WXYZ

133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | * 141 |
142 |
143 |
144 |
145 |
146 |
147 | 0 148 |

149 | +

150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | # 158 |
159 |
160 |
161 |
162 |
163 |
164 | 165 | 166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |

Fetching...

174 |

Fetching...

175 |

00:00

176 |
177 |
178 |
179 |
180 |
181 | 182 |

183 | Answer

184 |
185 |
186 |
187 | 188 |

189 | Reject

190 |
191 |
192 |
193 | 194 |

195 | Hangup

196 |
197 |
198 |
199 | 200 |

201 | Hangup

202 |
203 |
204 |
205 | 206 |

207 | Microphone

208 |
209 |
210 |
211 |
212 |
213 | 214 |
215 | 216 | Download 217 | Ignore 218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 | 227 | 246 | 247 | 248 | 249 | 279 | 280 | 281 | 317 | 318 | 319 | 337 | 338 | 353 | 354 | 373 | 374 | 441 | 442 | 445 |
446 |
447 | 448 |
449 |
450 | 451 |
452 | 453 | 454 | 455 | 456 | 457 | 465 | 466 | -------------------------------------------------------------------------------- /electronApp-plivo/js/customclient.js: -------------------------------------------------------------------------------- 1 | var callStorage = {}, timer = "00:00:00"; 2 | // UI tweaks 3 | $('#makecall').attr('class', 'btn btn-success btn-block flatbtn disabled'); 4 | 5 | function date(){ 6 | return (new Date()).toISOString().substring(0, 10)+" "+Date().split(" ")[4]; 7 | } 8 | function kickStartNow(){ 9 | $('.callScreen').hide(); 10 | $('.loader').show(); 11 | $('.fadein-effect').fadeIn(5000); 12 | } 13 | function login(username, password) { 14 | if(username && password){ 15 | //start UI load spinner 16 | kickStartNow(); 17 | plivoBrowserSdk.client.login(username, password); 18 | $('#sipUserName').html(username); 19 | document.querySelector('title').innerHTML=username; 20 | }else{ 21 | console.error('username/password missing!') 22 | } 23 | } 24 | function audioDeviceChange(e){ 25 | console.log('audioDeviceChange',e); 26 | if(e.change){ 27 | if(e.change == "added"){ 28 | customAlert(e.change,e.device.kind +" - "+e.device.label,'info'); 29 | }else{ 30 | customAlert(e.change,e.device.kind +" - "+e.device.label,'warn'); 31 | } 32 | }else{ 33 | customAlert('info','There is an audioDeviceChange but mediaPermission is not allowed yet'); 34 | } 35 | } 36 | function onWebrtcNotSupported() { 37 | console.warn('no webRTC support'); 38 | alert('Webrtc is not supported in this broswer, Please use latest version of chrome/firefox/opera/IE Edge'); 39 | } 40 | function mediaMetrics(obj){ 41 | /** 42 | * Set a trigger for Quality FB popup when there is an warning druing call using sessionStorage 43 | * During `onCallTerminated` event check for `triggerFB` flag 44 | */ 45 | sessionStorage.setItem('triggerFB',true); 46 | console.table([obj]); 47 | var classExist = document.querySelector('.-'+obj.type); 48 | var message = obj.type; 49 | /** 50 | * If there is a same audio level for 3 samples then we will get a trigger 51 | * If audio level is greater than 30 then it could be some continuous echo or user is not speaking 52 | * Set message "same level" for audio greater than 30. Less than 30 could be a possible mute 53 | */ 54 | if(obj.type.match('audio') && obj.value > 30){ 55 | message = "same level"; 56 | } 57 | if(obj.active){ 58 | classExist? classExist.remove() : null; 59 | $(".alertmsg").prepend( 60 | '
' + 61 | ''+obj.level+' | ' + 62 | ''+obj.group+' | ' + 63 | ''+message+' - '+obj.value+' : '+obj.desc+''+ 64 | '' + 65 | '
' 66 | ); 67 | } 68 | if(!obj.active && classExist){ 69 | document.querySelector('.-'+obj.type).remove(); 70 | } 71 | // Handle no mic input even after mic access 72 | if(obj.desc == "no access to your microphone"){ 73 | $('#micAccessBlock').modal({ show: true }) 74 | } 75 | } 76 | 77 | function onReady(){ 78 | $('#phonestatus').html('trying to login...'); 79 | console.info('Ready'); 80 | } 81 | function onLogin(){ 82 | $('#phonestatus').html('online'); 83 | console.info('Logged in'); 84 | $('#makecall').attr('class', 'btn btn-success btn-block flatbtn'); 85 | $('#uiLogin').hide(); 86 | $('#uiLogout').show(); 87 | $('.feedback').show(); 88 | $('.loader').remove(); 89 | } 90 | function onLoginFailed(reason){ 91 | $('#phonestatus').html('login failed'); 92 | console.info('onLoginFailed ',reason); 93 | customAlert('Login failure :',reason); 94 | $('.loader').remove() 95 | } 96 | function onLogout(){ 97 | $('#phonestatus').html('Offline'); 98 | console.info('onLogout'); 99 | } 100 | function onCalling(){ 101 | $('#callstatus').html('Progress...'); 102 | console.info('onCalling'); 103 | } 104 | function onCallRemoteRinging(){ 105 | $('#callstatus').html('Ringing...'); 106 | console.info('onCallRemoteRinging'); 107 | } 108 | function onCallConnected(){ 109 | $('#callstatus').html('Connected...'); 110 | console.info('onCallConnected'); 111 | } 112 | function onCallAnswered(){ 113 | console.info('onCallAnswered'); 114 | $('#callstatus').html('Answered'); 115 | $('.hangup').show(); 116 | // plivoBrowserSdk.client.logout(); 117 | timer = 0; 118 | window.calltimer = setInterval(function(){ 119 | timer = timer +1; 120 | $('#callDuration').html(timer.toString().calltimer()); 121 | },1000); 122 | 123 | } 124 | function onCallTerminated(evt){ 125 | $('#callstatus').html('Call Ended'); 126 | console.info('onCallTerminated'); 127 | if(sessionStorage.getItem('triggerFB')){ 128 | clearStars(); 129 | $('#clickFeedback').trigger('click'); 130 | // clear at end of every call 131 | sessionStorage.removeItem('triggerFB'); 132 | } 133 | callOff(evt); 134 | } 135 | function onCallFailed(reason){ 136 | $('#callstatus').html('call failed'); 137 | console.info('onCallFailed',reason); 138 | if(reason && /Denied Media/i.test(reason)){ 139 | $('#mediaAccessBlock').modal('show'); 140 | }; 141 | callOff(reason); 142 | } 143 | function onMediaPermission(evt){ 144 | console.info('onMediaPermission',evt); 145 | if(evt.error){ 146 | customAlert('Media permission error',evt.error); 147 | $('#mediaAccessBlock').modal('show'); 148 | } 149 | } 150 | function onIncomingCall(callerName, extraHeaders){ 151 | 152 | console.info('onIncomingCall : ', callerName, extraHeaders); 153 | callStorage.startTime = date(); 154 | callStorage.mode = 'in'; 155 | callStorage.num = callerName; 156 | $('#boundType').html('Incomming :'); 157 | $('#callNum').html(callerName); 158 | $('#callDuration').html('00:00:00'); 159 | $('.callinfo').show(); 160 | $('.callScreen').show(); 161 | $('.inboundBeforeAnswer').show(); 162 | $('#makecall').hide(); 163 | } 164 | function onIncomingCallCanceled(){ 165 | console.info('onIncomingCallCanceled'); 166 | callOff(); 167 | } 168 | 169 | function callOff(reason){ 170 | if(typeof reason == "object"){ 171 | customAlert('Hangup',JSON.stringify(reason) ); 172 | }else if(typeof reason == "string"){ 173 | customAlert('Hangup',reason); 174 | } 175 | $('.callScreen').hide(); 176 | $('.inboundBeforeAnswer').hide(); 177 | $('.AfterAnswer').hide(); 178 | $('.outboundBeforeAnswer').hide(); 179 | $('.hangup').hide(); 180 | $('#makecall').show(); 181 | window.calltimer? clearInterval(window.calltimer) : false; 182 | callStorage.dur = timer.toString().calltimer(); 183 | if(timer == "00:00:00" && callStorage.mode == "in"){ 184 | callStorage.mode = "missed"; 185 | } 186 | saveCallLog(callStorage); 187 | $('#callstatus').html('Idle'); 188 | $('.callinfo').hide(); 189 | callStorage={}; // reset callStorage 190 | timer = "00:00:00"; //reset the timer 191 | } 192 | 193 | String.prototype.calltimer = function () { 194 | var sec_num = parseInt(this, 10); 195 | var hours = Math.floor(sec_num / 3600); 196 | var minutes = Math.floor((sec_num - (hours * 3600)) / 60); 197 | var seconds = sec_num - (hours * 3600) - (minutes * 60); 198 | if (hours < 10) {hours = "0"+hours;} 199 | if (minutes < 10) {minutes = "0"+minutes;} 200 | if (seconds < 10) {seconds = "0"+seconds;} 201 | return hours+':'+minutes+':'+seconds; 202 | } 203 | function closeMetrics(e){ 204 | e.parentElement.remove(); 205 | } 206 | 207 | function resetSettings(source){ 208 | // You can use all your default settings to go in as options during sdk init 209 | var defaultSettings = {"debug":"ALL","permOnClick":true,"codecs":["OPUS","PCMU"],"enableIPV6":false,"audioConstraints":{"optional":[{"googAutoGainControl":false}]},"dscp":true,"enableTracking":true} 210 | var uiSettings = document.querySelector('#appSettings'); 211 | uiSettings.value = JSON.stringify(defaultSettings); 212 | if(source == 'clickTrigger') 213 | localStorage.removeItem('plivosettings'); 214 | } 215 | 216 | function refreshSettings(){ 217 | var getSettings = localStorage.getItem('plivosettings'); 218 | var uiSettings = document.querySelector('#appSettings'); 219 | if(getSettings){ 220 | uiSettings.value = getSettings; 221 | return JSON.parse(getSettings); 222 | }else{ 223 | return JSON.parse(uiSettings.value); 224 | } 225 | } 226 | function updateSettings(val){ 227 | localStorage.setItem('plivosettings',val); 228 | console.log('plivosettings updated!') 229 | } 230 | function customAlert(header,alertMessage,type){ 231 | var typeClass=""; 232 | if(type == "info"){ 233 | typeClass = "alertinfo"; 234 | }else if(type == "warn"){ 235 | typeClass = "alertwarn"; 236 | } 237 | $(".alertmsg").prepend( 238 | '
' + 239 | ''+header+' | ' + 240 | ''+alertMessage+' '+ 241 | '' + 242 | '
' 243 | ); 244 | } 245 | 246 | function updateAudioDevices(){ 247 | // Remove existing options if any 248 | document.querySelectorAll('#micDev option').forEach(e=>e.remove()) 249 | document.querySelectorAll('#ringtoneDev option').forEach(e=>e.remove()) 250 | 251 | plivoBrowserSdk.client.audio.availableDevices() 252 | .then(function(e){ 253 | e.forEach(function(dev){ 254 | if(dev.label && dev.kind == "audioinput") 255 | $('#micDev').append('') 256 | if(dev.label && dev.kind == "audiooutput"){ 257 | $('#ringtoneDev').append(''); 258 | $('#speakerDev').append('') 259 | } 260 | }); 261 | }) 262 | .catch(function(error){ 263 | console.error(error); 264 | }) 265 | } 266 | 267 | function clearStars(){ 268 | var stars = document.querySelectorAll('.star'); 269 | for (i = 0; i < stars.length; i++) { 270 | $(stars[i]).removeClass('selected'); 271 | } 272 | document.querySelectorAll('[name="callqualitycheck"]').forEach(e=>{ 273 | e.checked? (e.checked=false): null; 274 | }); 275 | sendFeedbackComment.value=""; 276 | } 277 | 278 | function checkBrowserComplaince(client){ 279 | if(client.browserDetails.browser != "chrome"){ 280 | document.querySelector('[data-target="#popAudioDevices"]').remove(); 281 | } 282 | } 283 | 284 | function trimSpace(e){ 285 | e.value = e.value.replace(/[- ()]/g,''); 286 | } 287 | 288 | function callLogDiv(e){ 289 | var mapper = { 290 | "in" : "arrow-down log-in", 291 | "out" : "share-alt log-out", 292 | "missed": "arrow-down log-missed" 293 | } 294 | $('#callHistoryTable').prepend( 295 | ''+ 296 | ''+ 297 | ''+e.num+''+ 298 | ''+e.dur+''+ 299 | ''+e.startTime+''+ 300 | ''+ 301 | '' 302 | ); 303 | return; 304 | } 305 | 306 | function saveCallLog(e){ 307 | var callLog = localStorage.getItem('pli_callHis'); 308 | var formatCallLog = JSON.parse(callLog); 309 | var callLogStr; 310 | callLogDiv(e); 311 | if(formatCallLog.length > 50){ 312 | formatCallLog.shift();// Pops first element 313 | console.info('Call log exceeded 50 rows, removing oldest log') 314 | } 315 | formatCallLog.push({"mode":e.mode,"num":e.num,"dur":e.dur,"startTime":e.startTime}); 316 | callLogStr = JSON.stringify(formatCallLog); 317 | localStorage.setItem('pli_callHis',callLogStr); 318 | } 319 | 320 | function displayCallHistory(){ 321 | var callLog = localStorage.getItem('pli_callHis'); 322 | if(callLog){ 323 | var formatCallLog = JSON.parse(callLog); 324 | var mapper = { 325 | "in" : "right log-in", 326 | "out" : "left log-out", 327 | "missed": "down log-missed" 328 | } 329 | for(var i=0; i < formatCallLog.length; i++){ 330 | callLogDiv(formatCallLog[i]); 331 | } 332 | }else{ 333 | localStorage.setItem('pli_callHis','[]'); 334 | } 335 | } 336 | function makecallCallLog(e){ 337 | var to = e.parentNode.parentNode.childNodes[1].innerHTML; 338 | toNumber.value = to; // update the dial input 339 | makecall.click(); // trigger call 340 | } 341 | /** 342 | * Hangup calls on page reload / close 343 | * This is will prevent the other end still listening for dead call 344 | */ 345 | window.onbeforeunload = function () { 346 | plivoBrowserSdk.client && plivoBrowserSdk.client.logout(); 347 | }; 348 | 349 | /* 350 | Capture UI onclick triggers 351 | */ 352 | $('#inboundAccept').click(function(){ 353 | console.info('Call accept clicked'); 354 | plivoBrowserSdk.client.answer(); 355 | $('.inboundBeforeAnswer').hide(); 356 | $('.AfterAnswer').show(); 357 | }); 358 | $('#inboundReject').click(function(){ 359 | console.info('callReject'); 360 | plivoBrowserSdk.client.reject(); 361 | }); 362 | $('#outboundHangup').click(function(){ 363 | console.info('outboundHangup'); 364 | plivoBrowserSdk.client.hangup(); 365 | }); 366 | $('.hangup').click(function(){ 367 | console.info('Hangup'); 368 | if(plivoBrowserSdk.client.callSession){ 369 | plivoBrowserSdk.client.hangup(); 370 | }else{ 371 | callOff(); 372 | } 373 | }); 374 | 375 | $('#tmute').click(function(e){ 376 | var event = e.currentTarget.getAttribute('data-toggle'); 377 | if(event == "mute"){ 378 | plivoBrowserSdk.client.mute(); 379 | e.currentTarget.setAttribute('data-toggle','unmute'); 380 | $('.tmute').attr('class', 'fa tmute fa-microphone-slash') 381 | }else{ 382 | plivoBrowserSdk.client.unmute(); 383 | e.currentTarget.setAttribute('data-toggle','mute'); 384 | $('.tmute').attr('class', 'fa tmute fa-microphone') 385 | } 386 | }); 387 | $('#makecall').click(function(e){ 388 | var to = $('#toNumber').val().replace(" ",""), 389 | extraHeaders, 390 | customCallerId= localStorage.getItem('setCallerId'), 391 | customCallerIdEnabled = localStorage.getItem('setCallerIdCheck'); 392 | if(customCallerIdEnabled && customCallerId){ 393 | customCallerId = customCallerId.replace("+",""); 394 | extraHeaders = {'X-PH-callerId': customCallerId}; 395 | } 396 | var callEnabled = $('#makecall').attr('class').match('disabled'); 397 | if(!to || !plivoBrowserSdk || !!callEnabled){return}; 398 | if(!plivoBrowserSdk.client.isLoggedIn){alert('You\'re not Logged in!')} 399 | plivoBrowserSdk.client.call(to,extraHeaders); 400 | console.info('Click make call : ',to); 401 | callStorage.mode = "out"; 402 | callStorage.startTime = date(); 403 | callStorage.num = to; 404 | $('.callScreen').show(); 405 | $('.AfterAnswer').show(); 406 | $('#boundType').html('Outgoing :'); 407 | $('#callNum').html(to); 408 | $('#callDuration').html('00:00:00'); 409 | $('.callinfo').show(); 410 | $('.hangup').show(); 411 | $('#makecall').hide(); 412 | }); 413 | 414 | $('#updateSettings').click(function(e){ 415 | var appSettings = document.querySelector('#appSettings'); 416 | appSettings = appSettings.value; 417 | updateSettings(appSettings); 418 | }); 419 | 420 | $('#resetSettings').click(function(e){ 421 | resetSettings('clickTrigger'); 422 | }); 423 | 424 | $('#sendFeedback').click(function(){ 425 | var score = $('#stars li.selected').last().data('value'); 426 | score = Number(score); 427 | var lastCallid = plivoBrowserSdk.client.getLastCallUUID(); 428 | // var comment = $("input[type=radio][name=callqualitycheck]:checked").val() || "good"; 429 | var comment = ""; 430 | if(score == 5){ 431 | comment = "good"; 432 | } 433 | document.querySelectorAll('[name="callqualitycheck"]').forEach(e=>{ 434 | if(e.checked){ 435 | comment = comment + "," + e.value; 436 | } 437 | }); 438 | if(sendFeedbackComment.value){ 439 | comment = comment + "," + sendFeedbackComment.value; 440 | } 441 | comment = comment.slice(1); 442 | if(!comment){ 443 | customAlert('feedback','Please select any comment'); 444 | return; 445 | } 446 | if(!score){ 447 | customAlert('feedback','Please select star'); 448 | return; 449 | } 450 | plivoBrowserSdk.client.sendQualityFeedback(lastCallid,score,comment); 451 | customAlert('Quality feedback ',lastCallid); 452 | }); 453 | 454 | $('#clickLogin').click(function(e){ 455 | var userName = $('#loginUser').val(); 456 | var password = $('#loginPwd').val(); 457 | login(userName, password); 458 | }); 459 | 460 | // Audio device selection 461 | $('#micDev').change(function(){ 462 | var selectDev = $('#micDev').val(); 463 | plivoBrowserSdk.client.audio.microphoneDevices.set(selectDev); 464 | console.debug('Microphone device set to : ',selectDev); 465 | }); 466 | $('#speakerDev').change(function(){ 467 | var selectDev = $('#speakerDev').val(); 468 | plivoBrowserSdk.client.audio.speakerDevices.set(selectDev); 469 | console.debug('Speaker device set to : ',selectDev); 470 | }); 471 | $('#ringtoneDev').change(function(){ 472 | var selectDev = $('#ringtoneDev').val(); 473 | plivoBrowserSdk.client.audio.ringtoneDevices.set(selectDev); 474 | console.debug('Ringtone dev set to : ',selectDev); 475 | }); 476 | 477 | // Ringtone device test 478 | $('#ringtoneDevTest').click(function(){ 479 | var ringAudio = plivoBrowserSdk.client.audio.ringtoneDevices.media(); 480 | // Toggle play 481 | if(ringAudio.paused){ 482 | ringAudio.play(); 483 | $('#ringtoneDevTest').html('Pause'); 484 | }else{ 485 | ringAudio.pause(); 486 | $('#ringtoneDevTest').html('Play'); 487 | } 488 | }); 489 | // Speaker device test 490 | $('#speakerDevTest').click(function(){ 491 | var speakerAudio = plivoBrowserSdk.client.audio.speakerDevices.media(); 492 | // Toggle play 493 | if(speakerAudio.paused){ 494 | speakerAudio.play(); 495 | $('#speakerDevTest').html('Pause'); 496 | }else{ 497 | speakerAudio.pause(); 498 | $('#speakerDevTest').html('Play'); 499 | } 500 | }); 501 | //revealAudioDevices 502 | $('#allowAudioDevices').click(function(){ 503 | document.querySelectorAll('#popAudioDevices option').forEach(e=>e.remove()); 504 | plivoBrowserSdk.client.audio.revealAudioDevices() 505 | .then(function(e){ 506 | updateAudioDevices(); 507 | console.log('Media permission ',e) 508 | }) 509 | .catch(function(error){ 510 | console.error('media permission error :',error); 511 | $('#mediaAccessBlock').modal('show'); 512 | }) 513 | }); 514 | 515 | $('.num').click(function () { 516 | var num = $(this); 517 | var text = $.trim(num.find('.txt').clone().children().remove().end().text()); 518 | var telNumber = $('#toNumber'); 519 | $(telNumber).val(telNumber.val() + text); 520 | if(plivoBrowserSdk && plivoBrowserSdk.client.callSession){ 521 | plivoBrowserSdk.client.sendDtmf(text); 522 | } 523 | }); 524 | 525 | clearLogs.onclick = function(){ 526 | localStorage.setItem('pli_callHis','[]'); 527 | callHistoryTable.innerHTML="" 528 | } 529 | showPass.onclick = function(){ 530 | if($('#showPass input').prop("checked")){ 531 | loginPwd.type="text"; 532 | }else{ 533 | loginPwd.type="password"; 534 | } 535 | } 536 | 537 | function starFeedback(){ 538 | $('#stars li').on('mouseover', function(){ 539 | var onStar = parseInt($(this).data('value'), 10); 540 | 541 | $(this).parent().children('li.star').each(function(e){ 542 | if (e < onStar) { 543 | $(this).addClass('hover'); 544 | } 545 | else { 546 | $(this).removeClass('hover'); 547 | } 548 | }); 549 | }).on('mouseout', function(){ 550 | $(this).parent().children('li.star').each(function(e){ 551 | $(this).removeClass('hover'); 552 | }); 553 | }); 554 | 555 | //Action to perform on click */ 556 | $('#stars li').on('click', function(){ 557 | var onStar = parseInt($(this).data('value'), 10); 558 | var stars = $(this).parent().children('li.star'); 559 | 560 | for (i = 0; i < stars.length; i++) { 561 | $(stars[i]).removeClass('selected'); 562 | } 563 | 564 | for (i = 0; i < onStar; i++) { 565 | $(stars[i]).addClass('selected'); 566 | } 567 | 568 | var value = parseInt($('#stars li.selected').last().data('value'), 10); 569 | if(value < 5){ 570 | $('.lowQualityRadios').show(); 571 | }else{ 572 | $('.lowQualityRadios').hide(); 573 | } 574 | 575 | }); 576 | } 577 | // variables to declare 578 | 579 | var plivoBrowserSdk; // this will be retrived from settings in UI 580 | 581 | function initPhone(username, password){ 582 | var options = refreshSettings(); 583 | plivoBrowserSdk = new window.Plivo(options); 584 | plivoBrowserSdk.client.on('onWebrtcNotSupported', onWebrtcNotSupported); 585 | plivoBrowserSdk.client.on('onLogin', onLogin); 586 | plivoBrowserSdk.client.on('onLogout', onLogout); 587 | plivoBrowserSdk.client.on('onLoginFailed', onLoginFailed); 588 | plivoBrowserSdk.client.on('onCallRemoteRinging', onCallRemoteRinging); 589 | plivoBrowserSdk.client.on('onCallConnected', onCallConnected); 590 | plivoBrowserSdk.client.on('onIncomingCallCanceled', onIncomingCallCanceled); 591 | plivoBrowserSdk.client.on('onCallFailed', onCallFailed); 592 | plivoBrowserSdk.client.on('onCallAnswered', onCallAnswered); 593 | plivoBrowserSdk.client.on('onCallTerminated', onCallTerminated); 594 | plivoBrowserSdk.client.on('onCalling', onCalling); 595 | plivoBrowserSdk.client.on('onIncomingCall', onIncomingCall); 596 | plivoBrowserSdk.client.on('onMediaPermission', onMediaPermission); 597 | plivoBrowserSdk.client.on('mediaMetrics',mediaMetrics); 598 | plivoBrowserSdk.client.on('audioDeviceChange',audioDeviceChange); 599 | plivoBrowserSdk.client.setRingTone(true); 600 | plivoBrowserSdk.client.setRingToneBack(true); 601 | // plivoBrowserSdk.client.setConnectTone(false); 602 | /** Handle browser issues 603 | * Sound devices won't work in firefox 604 | */ 605 | checkBrowserComplaince(plivoBrowserSdk.client); 606 | updateAudioDevices(); 607 | displayCallHistory(); 608 | starFeedback(); 609 | console.log('initPhone ready!') 610 | } 611 | -------------------------------------------------------------------------------- /electronApp-plivo/main.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron') 2 | // Module to control application life. 3 | const app = electron.app 4 | // Module to create native browser window. 5 | const BrowserWindow = electron.BrowserWindow 6 | 7 | const path = require('path') 8 | const url = require('url') 9 | 10 | // Keep a global reference of the window object, if you don't, the window will 11 | // be closed automatically when the JavaScript object is garbage collected. 12 | let mainWindow 13 | 14 | function createWindow () { 15 | // Create the browser window. 16 | mainWindow = new BrowserWindow({width: 1280, height: 800}) 17 | 18 | // and load the index.html of the app. 19 | mainWindow.loadURL(url.format({ 20 | pathname: path.join(__dirname, 'index.html'), 21 | protocol: 'file:', 22 | slashes: true 23 | })) 24 | 25 | // Open the DevTools. 26 | mainWindow.webContents.openDevTools() 27 | 28 | // Emitted when the window is closed. 29 | mainWindow.on('closed', function () { 30 | // Dereference the window object, usually you would store windows 31 | // in an array if your app supports multi windows, this is the time 32 | // when you should delete the corresponding element. 33 | mainWindow = null 34 | }) 35 | } 36 | 37 | // This method will be called when Electron has finished 38 | // initialization and is ready to create browser windows. 39 | // Some APIs can only be used after this event occurs. 40 | app.on('ready', createWindow) 41 | 42 | // Quit when all windows are closed. 43 | app.on('window-all-closed', function () { 44 | // On OS X it is common for applications and their menu bar 45 | // to stay active until the user quits explicitly with Cmd + Q 46 | if (process.platform !== 'darwin') { 47 | app.quit() 48 | } 49 | }) 50 | 51 | app.on('activate', function () { 52 | // On OS X it's common to re-create a window in the app when the 53 | // dock icon is clicked and there are no other windows open. 54 | if (mainWindow === null) { 55 | createWindow() 56 | } 57 | }) 58 | 59 | // In this file you can include the rest of your app's specific main process 60 | // code. You can also put them in separate files and require them here. 61 | -------------------------------------------------------------------------------- /electronApp-plivo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-plivo-quick-start", 3 | "version": "1.0.0", 4 | "description": "A minimal Electron application with plivo js", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "electron ." 8 | }, 9 | "author": "plivo", 10 | "license": "CC0-1.0", 11 | "devDependencies": { 12 | "electron": "^22.0.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /img/audiodevice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/audiodevice.png -------------------------------------------------------------------------------- /img/audiodevicechange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/audiodevicechange.png -------------------------------------------------------------------------------- /img/callscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/callscreen.png -------------------------------------------------------------------------------- /img/feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/feedback.png -------------------------------------------------------------------------------- /img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/login.png -------------------------------------------------------------------------------- /img/login_jwt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/login_jwt.png -------------------------------------------------------------------------------- /img/metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/metrics.png -------------------------------------------------------------------------------- /img/plivobrowserSdKLogin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/plivobrowserSdKLogin.png -------------------------------------------------------------------------------- /img/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/settings.png -------------------------------------------------------------------------------- /img/volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/img/volume.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plivo-sample-app", 3 | "description": "Example application demonstrating the use of Plivo SDK", 4 | "version": "2.2.12-beta.0", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js", 8 | "beta-version-patch": "npm version $(semver $npm_package_version -i prerelease --preid beta)", 9 | "beta-version-minor": "npm version $(semver $npm_package_version -i preminor --preid beta)", 10 | "beta-version-major": "npm version $(semver $npm_package_version -i premajor --preid beta)", 11 | "rc-version": "npm version $(semver $npm_package_version -i prerelease --preid rc)", 12 | "final-release": "npm version $(semver $npm_package_version -i)", 13 | "semver": "npm version $(semver $npm_package_version -i $release --preid $preid)" 14 | }, 15 | "dependencies": { 16 | "ejs": "~3.1.7", 17 | "express": "^4.9.8" 18 | }, 19 | "devDependencies": { 20 | "gulp": "^4.0.2", 21 | "gulp-express": "^0.3.5" 22 | } 23 | } -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var app = express(); 4 | 5 | // set the port of our application 6 | // process.env.PORT lets the port be set by Heroku 7 | var port = process.env.PORT || 8080; 8 | 9 | app.set('views', path.join(__dirname, '/webApp-plivo/views')); 10 | 11 | // set the view engine to ejs 12 | app.set('view engine', 'ejs'); 13 | 14 | // make express look in the public directory for assets (css/js/img) 15 | console.log(__dirname); 16 | app.use(express.static(__dirname + '/webApp-plivo/public')); 17 | 18 | // set the home page route 19 | app.get('/', function(req, res) { 20 | // ejs render automatically looks in the views folder 21 | res.render('index'); 22 | }); 23 | 24 | app.listen(port, function() { 25 | console.log('Our app is running on http://localhost:' + port); 26 | }); -------------------------------------------------------------------------------- /webApp-plivo/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var server = require('gulp-express'); 5 | 6 | gulp.task('default', function() { 7 | server.run(['server.js']); 8 | 9 | // Restart the server when file changes 10 | gulp.watch(['public/**/*.js'], server.notify); 11 | }); -------------------------------------------------------------------------------- /webApp-plivo/public/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/.DS_Store -------------------------------------------------------------------------------- /webApp-plivo/public/css/intlTelInput.css: -------------------------------------------------------------------------------- 1 | .iti { 2 | position: relative; 3 | display: inline-block; } 4 | .iti * { 5 | box-sizing: border-box; 6 | -moz-box-sizing: border-box; } 7 | .iti__hide { 8 | display: none; } 9 | .iti__v-hide { 10 | visibility: hidden; } 11 | .iti input, .iti input[type=text], .iti input[type=tel] { 12 | position: relative; 13 | z-index: 0; 14 | margin-top: 0 !important; 15 | margin-bottom: 0 !important; 16 | padding-right: 36px; 17 | margin-right: 0; } 18 | .iti__flag-container { 19 | position: absolute; 20 | top: 0; 21 | bottom: 0; 22 | right: 0; 23 | padding: 1px; } 24 | .iti__selected-flag { 25 | z-index: 1; 26 | position: relative; 27 | display: flex; 28 | align-items: center; 29 | height: 100%; 30 | padding: 0 6px 0 8px; } 31 | .iti__arrow { 32 | margin-left: 6px; 33 | width: 0; 34 | height: 0; 35 | border-left: 3px solid transparent; 36 | border-right: 3px solid transparent; 37 | border-top: 4px solid #555; } 38 | .iti__arrow--up { 39 | border-top: none; 40 | border-bottom: 4px solid #555; } 41 | .iti__country-list { 42 | position: absolute; 43 | z-index: 2; 44 | list-style: none; 45 | text-align: left; 46 | padding: 0; 47 | margin: 0 0 0 -1px; 48 | box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2); 49 | background-color: white; 50 | border: 1px solid #CCC; 51 | white-space: nowrap; 52 | max-height: 200px; 53 | overflow-y: scroll; 54 | -webkit-overflow-scrolling: touch; } 55 | .iti__country-list--dropup { 56 | bottom: 100%; 57 | margin-bottom: -1px; } 58 | @media (max-width: 500px) { 59 | .iti__country-list { 60 | white-space: normal; } } 61 | .iti__flag-box { 62 | display: inline-block; 63 | width: 20px; } 64 | .iti__divider { 65 | padding-bottom: 5px; 66 | margin-bottom: 5px; 67 | border-bottom: 1px solid #CCC; } 68 | .iti__country { 69 | padding: 5px 10px; 70 | outline: none; } 71 | .iti__dial-code { 72 | color: #999; } 73 | .iti__country.iti__highlight { 74 | background-color: rgba(0, 0, 0, 0.05); } 75 | .iti__flag-box, .iti__country-name, .iti__dial-code { 76 | vertical-align: middle; } 77 | .iti__flag-box, .iti__country-name { 78 | margin-right: 6px; } 79 | .iti--allow-dropdown input, .iti--allow-dropdown input[type=text], .iti--allow-dropdown input[type=tel], .iti--separate-dial-code input, .iti--separate-dial-code input[type=text], .iti--separate-dial-code input[type=tel] { 80 | padding-right: 6px; 81 | padding-left: 52px; 82 | margin-left: 0; } 83 | .iti--allow-dropdown .iti__flag-container, .iti--separate-dial-code .iti__flag-container { 84 | right: auto; 85 | left: 0; } 86 | .iti--allow-dropdown .iti__flag-container:hover { 87 | cursor: pointer; } 88 | .iti--allow-dropdown .iti__flag-container:hover .iti__selected-flag { 89 | background-color: rgba(0, 0, 0, 0.05); } 90 | .iti--allow-dropdown input[disabled] + .iti__flag-container:hover, 91 | .iti--allow-dropdown input[readonly] + .iti__flag-container:hover { 92 | cursor: default; } 93 | .iti--allow-dropdown input[disabled] + .iti__flag-container:hover .iti__selected-flag, 94 | .iti--allow-dropdown input[readonly] + .iti__flag-container:hover .iti__selected-flag { 95 | background-color: transparent; } 96 | .iti--separate-dial-code .iti__selected-flag { 97 | background-color: rgba(0, 0, 0, 0.05); } 98 | .iti--separate-dial-code .iti__selected-dial-code { 99 | margin-left: 6px; } 100 | .iti--container { 101 | position: absolute; 102 | top: -1000px; 103 | left: -1000px; 104 | z-index: 1060; 105 | padding: 1px; } 106 | .iti--container:hover { 107 | cursor: pointer; } 108 | 109 | .iti-mobile .iti--container { 110 | top: 30px; 111 | bottom: 30px; 112 | left: 30px; 113 | right: 30px; 114 | position: fixed; } 115 | 116 | .iti-mobile .iti__country-list { 117 | max-height: 100%; 118 | width: 100%; } 119 | 120 | .iti-mobile .iti__country { 121 | padding: 10px 10px; 122 | line-height: 1.5em; } 123 | 124 | .iti__flag { 125 | width: 20px; } 126 | .iti__flag.iti__be { 127 | width: 18px; } 128 | .iti__flag.iti__ch { 129 | width: 15px; } 130 | .iti__flag.iti__mc { 131 | width: 19px; } 132 | .iti__flag.iti__ne { 133 | width: 18px; } 134 | .iti__flag.iti__np { 135 | width: 13px; } 136 | .iti__flag.iti__va { 137 | width: 15px; } 138 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { 139 | .iti__flag { 140 | background-size: 5652px 15px; } } 141 | .iti__flag.iti__ac { 142 | height: 10px; 143 | background-position: 0px 0px; } 144 | .iti__flag.iti__ad { 145 | height: 14px; 146 | background-position: -22px 0px; } 147 | .iti__flag.iti__ae { 148 | height: 10px; 149 | background-position: -44px 0px; } 150 | .iti__flag.iti__af { 151 | height: 14px; 152 | background-position: -66px 0px; } 153 | .iti__flag.iti__ag { 154 | height: 14px; 155 | background-position: -88px 0px; } 156 | .iti__flag.iti__ai { 157 | height: 10px; 158 | background-position: -110px 0px; } 159 | .iti__flag.iti__al { 160 | height: 15px; 161 | background-position: -132px 0px; } 162 | .iti__flag.iti__am { 163 | height: 10px; 164 | background-position: -154px 0px; } 165 | .iti__flag.iti__ao { 166 | height: 14px; 167 | background-position: -176px 0px; } 168 | .iti__flag.iti__aq { 169 | height: 14px; 170 | background-position: -198px 0px; } 171 | .iti__flag.iti__ar { 172 | height: 13px; 173 | background-position: -220px 0px; } 174 | .iti__flag.iti__as { 175 | height: 10px; 176 | background-position: -242px 0px; } 177 | .iti__flag.iti__at { 178 | height: 14px; 179 | background-position: -264px 0px; } 180 | .iti__flag.iti__au { 181 | height: 10px; 182 | background-position: -286px 0px; } 183 | .iti__flag.iti__aw { 184 | height: 14px; 185 | background-position: -308px 0px; } 186 | .iti__flag.iti__ax { 187 | height: 13px; 188 | background-position: -330px 0px; } 189 | .iti__flag.iti__az { 190 | height: 10px; 191 | background-position: -352px 0px; } 192 | .iti__flag.iti__ba { 193 | height: 10px; 194 | background-position: -374px 0px; } 195 | .iti__flag.iti__bb { 196 | height: 14px; 197 | background-position: -396px 0px; } 198 | .iti__flag.iti__bd { 199 | height: 12px; 200 | background-position: -418px 0px; } 201 | .iti__flag.iti__be { 202 | height: 15px; 203 | background-position: -440px 0px; } 204 | .iti__flag.iti__bf { 205 | height: 14px; 206 | background-position: -460px 0px; } 207 | .iti__flag.iti__bg { 208 | height: 12px; 209 | background-position: -482px 0px; } 210 | .iti__flag.iti__bh { 211 | height: 12px; 212 | background-position: -504px 0px; } 213 | .iti__flag.iti__bi { 214 | height: 12px; 215 | background-position: -526px 0px; } 216 | .iti__flag.iti__bj { 217 | height: 14px; 218 | background-position: -548px 0px; } 219 | .iti__flag.iti__bl { 220 | height: 14px; 221 | background-position: -570px 0px; } 222 | .iti__flag.iti__bm { 223 | height: 10px; 224 | background-position: -592px 0px; } 225 | .iti__flag.iti__bn { 226 | height: 10px; 227 | background-position: -614px 0px; } 228 | .iti__flag.iti__bo { 229 | height: 14px; 230 | background-position: -636px 0px; } 231 | .iti__flag.iti__bq { 232 | height: 14px; 233 | background-position: -658px 0px; } 234 | .iti__flag.iti__br { 235 | height: 14px; 236 | background-position: -680px 0px; } 237 | .iti__flag.iti__bs { 238 | height: 10px; 239 | background-position: -702px 0px; } 240 | .iti__flag.iti__bt { 241 | height: 14px; 242 | background-position: -724px 0px; } 243 | .iti__flag.iti__bv { 244 | height: 15px; 245 | background-position: -746px 0px; } 246 | .iti__flag.iti__bw { 247 | height: 14px; 248 | background-position: -768px 0px; } 249 | .iti__flag.iti__by { 250 | height: 10px; 251 | background-position: -790px 0px; } 252 | .iti__flag.iti__bz { 253 | height: 14px; 254 | background-position: -812px 0px; } 255 | .iti__flag.iti__ca { 256 | height: 10px; 257 | background-position: -834px 0px; } 258 | .iti__flag.iti__cc { 259 | height: 10px; 260 | background-position: -856px 0px; } 261 | .iti__flag.iti__cd { 262 | height: 15px; 263 | background-position: -878px 0px; } 264 | .iti__flag.iti__cf { 265 | height: 14px; 266 | background-position: -900px 0px; } 267 | .iti__flag.iti__cg { 268 | height: 14px; 269 | background-position: -922px 0px; } 270 | .iti__flag.iti__ch { 271 | height: 15px; 272 | background-position: -944px 0px; } 273 | .iti__flag.iti__ci { 274 | height: 14px; 275 | background-position: -961px 0px; } 276 | .iti__flag.iti__ck { 277 | height: 10px; 278 | background-position: -983px 0px; } 279 | .iti__flag.iti__cl { 280 | height: 14px; 281 | background-position: -1005px 0px; } 282 | .iti__flag.iti__cm { 283 | height: 14px; 284 | background-position: -1027px 0px; } 285 | .iti__flag.iti__cn { 286 | height: 14px; 287 | background-position: -1049px 0px; } 288 | .iti__flag.iti__co { 289 | height: 14px; 290 | background-position: -1071px 0px; } 291 | .iti__flag.iti__cp { 292 | height: 14px; 293 | background-position: -1093px 0px; } 294 | .iti__flag.iti__cr { 295 | height: 12px; 296 | background-position: -1115px 0px; } 297 | .iti__flag.iti__cu { 298 | height: 10px; 299 | background-position: -1137px 0px; } 300 | .iti__flag.iti__cv { 301 | height: 12px; 302 | background-position: -1159px 0px; } 303 | .iti__flag.iti__cw { 304 | height: 14px; 305 | background-position: -1181px 0px; } 306 | .iti__flag.iti__cx { 307 | height: 10px; 308 | background-position: -1203px 0px; } 309 | .iti__flag.iti__cy { 310 | height: 14px; 311 | background-position: -1225px 0px; } 312 | .iti__flag.iti__cz { 313 | height: 14px; 314 | background-position: -1247px 0px; } 315 | .iti__flag.iti__de { 316 | height: 12px; 317 | background-position: -1269px 0px; } 318 | .iti__flag.iti__dg { 319 | height: 10px; 320 | background-position: -1291px 0px; } 321 | .iti__flag.iti__dj { 322 | height: 14px; 323 | background-position: -1313px 0px; } 324 | .iti__flag.iti__dk { 325 | height: 15px; 326 | background-position: -1335px 0px; } 327 | .iti__flag.iti__dm { 328 | height: 10px; 329 | background-position: -1357px 0px; } 330 | .iti__flag.iti__do { 331 | height: 14px; 332 | background-position: -1379px 0px; } 333 | .iti__flag.iti__dz { 334 | height: 14px; 335 | background-position: -1401px 0px; } 336 | .iti__flag.iti__ea { 337 | height: 14px; 338 | background-position: -1423px 0px; } 339 | .iti__flag.iti__ec { 340 | height: 14px; 341 | background-position: -1445px 0px; } 342 | .iti__flag.iti__ee { 343 | height: 13px; 344 | background-position: -1467px 0px; } 345 | .iti__flag.iti__eg { 346 | height: 14px; 347 | background-position: -1489px 0px; } 348 | .iti__flag.iti__eh { 349 | height: 10px; 350 | background-position: -1511px 0px; } 351 | .iti__flag.iti__er { 352 | height: 10px; 353 | background-position: -1533px 0px; } 354 | .iti__flag.iti__es { 355 | height: 14px; 356 | background-position: -1555px 0px; } 357 | .iti__flag.iti__et { 358 | height: 10px; 359 | background-position: -1577px 0px; } 360 | .iti__flag.iti__eu { 361 | height: 14px; 362 | background-position: -1599px 0px; } 363 | .iti__flag.iti__fi { 364 | height: 12px; 365 | background-position: -1621px 0px; } 366 | .iti__flag.iti__fj { 367 | height: 10px; 368 | background-position: -1643px 0px; } 369 | .iti__flag.iti__fk { 370 | height: 10px; 371 | background-position: -1665px 0px; } 372 | .iti__flag.iti__fm { 373 | height: 11px; 374 | background-position: -1687px 0px; } 375 | .iti__flag.iti__fo { 376 | height: 15px; 377 | background-position: -1709px 0px; } 378 | .iti__flag.iti__fr { 379 | height: 14px; 380 | background-position: -1731px 0px; } 381 | .iti__flag.iti__ga { 382 | height: 15px; 383 | background-position: -1753px 0px; } 384 | .iti__flag.iti__gb { 385 | height: 10px; 386 | background-position: -1775px 0px; } 387 | .iti__flag.iti__gd { 388 | height: 12px; 389 | background-position: -1797px 0px; } 390 | .iti__flag.iti__ge { 391 | height: 14px; 392 | background-position: -1819px 0px; } 393 | .iti__flag.iti__gf { 394 | height: 14px; 395 | background-position: -1841px 0px; } 396 | .iti__flag.iti__gg { 397 | height: 14px; 398 | background-position: -1863px 0px; } 399 | .iti__flag.iti__gh { 400 | height: 14px; 401 | background-position: -1885px 0px; } 402 | .iti__flag.iti__gi { 403 | height: 10px; 404 | background-position: -1907px 0px; } 405 | .iti__flag.iti__gl { 406 | height: 14px; 407 | background-position: -1929px 0px; } 408 | .iti__flag.iti__gm { 409 | height: 14px; 410 | background-position: -1951px 0px; } 411 | .iti__flag.iti__gn { 412 | height: 14px; 413 | background-position: -1973px 0px; } 414 | .iti__flag.iti__gp { 415 | height: 14px; 416 | background-position: -1995px 0px; } 417 | .iti__flag.iti__gq { 418 | height: 14px; 419 | background-position: -2017px 0px; } 420 | .iti__flag.iti__gr { 421 | height: 14px; 422 | background-position: -2039px 0px; } 423 | .iti__flag.iti__gs { 424 | height: 10px; 425 | background-position: -2061px 0px; } 426 | .iti__flag.iti__gt { 427 | height: 13px; 428 | background-position: -2083px 0px; } 429 | .iti__flag.iti__gu { 430 | height: 11px; 431 | background-position: -2105px 0px; } 432 | .iti__flag.iti__gw { 433 | height: 10px; 434 | background-position: -2127px 0px; } 435 | .iti__flag.iti__gy { 436 | height: 12px; 437 | background-position: -2149px 0px; } 438 | .iti__flag.iti__hk { 439 | height: 14px; 440 | background-position: -2171px 0px; } 441 | .iti__flag.iti__hm { 442 | height: 10px; 443 | background-position: -2193px 0px; } 444 | .iti__flag.iti__hn { 445 | height: 10px; 446 | background-position: -2215px 0px; } 447 | .iti__flag.iti__hr { 448 | height: 10px; 449 | background-position: -2237px 0px; } 450 | .iti__flag.iti__ht { 451 | height: 12px; 452 | background-position: -2259px 0px; } 453 | .iti__flag.iti__hu { 454 | height: 10px; 455 | background-position: -2281px 0px; } 456 | .iti__flag.iti__ic { 457 | height: 14px; 458 | background-position: -2303px 0px; } 459 | .iti__flag.iti__id { 460 | height: 14px; 461 | background-position: -2325px 0px; } 462 | .iti__flag.iti__ie { 463 | height: 10px; 464 | background-position: -2347px 0px; } 465 | .iti__flag.iti__il { 466 | height: 15px; 467 | background-position: -2369px 0px; } 468 | .iti__flag.iti__im { 469 | height: 10px; 470 | background-position: -2391px 0px; } 471 | .iti__flag.iti__in { 472 | height: 14px; 473 | background-position: -2413px 0px; } 474 | .iti__flag.iti__io { 475 | height: 10px; 476 | background-position: -2435px 0px; } 477 | .iti__flag.iti__iq { 478 | height: 14px; 479 | background-position: -2457px 0px; } 480 | .iti__flag.iti__ir { 481 | height: 12px; 482 | background-position: -2479px 0px; } 483 | .iti__flag.iti__is { 484 | height: 15px; 485 | background-position: -2501px 0px; } 486 | .iti__flag.iti__it { 487 | height: 14px; 488 | background-position: -2523px 0px; } 489 | .iti__flag.iti__je { 490 | height: 12px; 491 | background-position: -2545px 0px; } 492 | .iti__flag.iti__jm { 493 | height: 10px; 494 | background-position: -2567px 0px; } 495 | .iti__flag.iti__jo { 496 | height: 10px; 497 | background-position: -2589px 0px; } 498 | .iti__flag.iti__jp { 499 | height: 14px; 500 | background-position: -2611px 0px; } 501 | .iti__flag.iti__ke { 502 | height: 14px; 503 | background-position: -2633px 0px; } 504 | .iti__flag.iti__kg { 505 | height: 12px; 506 | background-position: -2655px 0px; } 507 | .iti__flag.iti__kh { 508 | height: 13px; 509 | background-position: -2677px 0px; } 510 | .iti__flag.iti__ki { 511 | height: 10px; 512 | background-position: -2699px 0px; } 513 | .iti__flag.iti__km { 514 | height: 12px; 515 | background-position: -2721px 0px; } 516 | .iti__flag.iti__kn { 517 | height: 14px; 518 | background-position: -2743px 0px; } 519 | .iti__flag.iti__kp { 520 | height: 10px; 521 | background-position: -2765px 0px; } 522 | .iti__flag.iti__kr { 523 | height: 14px; 524 | background-position: -2787px 0px; } 525 | .iti__flag.iti__kw { 526 | height: 10px; 527 | background-position: -2809px 0px; } 528 | .iti__flag.iti__ky { 529 | height: 10px; 530 | background-position: -2831px 0px; } 531 | .iti__flag.iti__kz { 532 | height: 10px; 533 | background-position: -2853px 0px; } 534 | .iti__flag.iti__la { 535 | height: 14px; 536 | background-position: -2875px 0px; } 537 | .iti__flag.iti__lb { 538 | height: 14px; 539 | background-position: -2897px 0px; } 540 | .iti__flag.iti__lc { 541 | height: 10px; 542 | background-position: -2919px 0px; } 543 | .iti__flag.iti__li { 544 | height: 12px; 545 | background-position: -2941px 0px; } 546 | .iti__flag.iti__lk { 547 | height: 10px; 548 | background-position: -2963px 0px; } 549 | .iti__flag.iti__lr { 550 | height: 11px; 551 | background-position: -2985px 0px; } 552 | .iti__flag.iti__ls { 553 | height: 14px; 554 | background-position: -3007px 0px; } 555 | .iti__flag.iti__lt { 556 | height: 12px; 557 | background-position: -3029px 0px; } 558 | .iti__flag.iti__lu { 559 | height: 12px; 560 | background-position: -3051px 0px; } 561 | .iti__flag.iti__lv { 562 | height: 10px; 563 | background-position: -3073px 0px; } 564 | .iti__flag.iti__ly { 565 | height: 10px; 566 | background-position: -3095px 0px; } 567 | .iti__flag.iti__ma { 568 | height: 14px; 569 | background-position: -3117px 0px; } 570 | .iti__flag.iti__mc { 571 | height: 15px; 572 | background-position: -3139px 0px; } 573 | .iti__flag.iti__md { 574 | height: 10px; 575 | background-position: -3160px 0px; } 576 | .iti__flag.iti__me { 577 | height: 10px; 578 | background-position: -3182px 0px; } 579 | .iti__flag.iti__mf { 580 | height: 14px; 581 | background-position: -3204px 0px; } 582 | .iti__flag.iti__mg { 583 | height: 14px; 584 | background-position: -3226px 0px; } 585 | .iti__flag.iti__mh { 586 | height: 11px; 587 | background-position: -3248px 0px; } 588 | .iti__flag.iti__mk { 589 | height: 10px; 590 | background-position: -3270px 0px; } 591 | .iti__flag.iti__ml { 592 | height: 14px; 593 | background-position: -3292px 0px; } 594 | .iti__flag.iti__mm { 595 | height: 14px; 596 | background-position: -3314px 0px; } 597 | .iti__flag.iti__mn { 598 | height: 10px; 599 | background-position: -3336px 0px; } 600 | .iti__flag.iti__mo { 601 | height: 14px; 602 | background-position: -3358px 0px; } 603 | .iti__flag.iti__mp { 604 | height: 10px; 605 | background-position: -3380px 0px; } 606 | .iti__flag.iti__mq { 607 | height: 14px; 608 | background-position: -3402px 0px; } 609 | .iti__flag.iti__mr { 610 | height: 14px; 611 | background-position: -3424px 0px; } 612 | .iti__flag.iti__ms { 613 | height: 10px; 614 | background-position: -3446px 0px; } 615 | .iti__flag.iti__mt { 616 | height: 14px; 617 | background-position: -3468px 0px; } 618 | .iti__flag.iti__mu { 619 | height: 14px; 620 | background-position: -3490px 0px; } 621 | .iti__flag.iti__mv { 622 | height: 14px; 623 | background-position: -3512px 0px; } 624 | .iti__flag.iti__mw { 625 | height: 14px; 626 | background-position: -3534px 0px; } 627 | .iti__flag.iti__mx { 628 | height: 12px; 629 | background-position: -3556px 0px; } 630 | .iti__flag.iti__my { 631 | height: 10px; 632 | background-position: -3578px 0px; } 633 | .iti__flag.iti__mz { 634 | height: 14px; 635 | background-position: -3600px 0px; } 636 | .iti__flag.iti__na { 637 | height: 14px; 638 | background-position: -3622px 0px; } 639 | .iti__flag.iti__nc { 640 | height: 10px; 641 | background-position: -3644px 0px; } 642 | .iti__flag.iti__ne { 643 | height: 15px; 644 | background-position: -3666px 0px; } 645 | .iti__flag.iti__nf { 646 | height: 10px; 647 | background-position: -3686px 0px; } 648 | .iti__flag.iti__ng { 649 | height: 10px; 650 | background-position: -3708px 0px; } 651 | .iti__flag.iti__ni { 652 | height: 12px; 653 | background-position: -3730px 0px; } 654 | .iti__flag.iti__nl { 655 | height: 14px; 656 | background-position: -3752px 0px; } 657 | .iti__flag.iti__no { 658 | height: 15px; 659 | background-position: -3774px 0px; } 660 | .iti__flag.iti__np { 661 | height: 15px; 662 | background-position: -3796px 0px; } 663 | .iti__flag.iti__nr { 664 | height: 10px; 665 | background-position: -3811px 0px; } 666 | .iti__flag.iti__nu { 667 | height: 10px; 668 | background-position: -3833px 0px; } 669 | .iti__flag.iti__nz { 670 | height: 10px; 671 | background-position: -3855px 0px; } 672 | .iti__flag.iti__om { 673 | height: 10px; 674 | background-position: -3877px 0px; } 675 | .iti__flag.iti__pa { 676 | height: 14px; 677 | background-position: -3899px 0px; } 678 | .iti__flag.iti__pe { 679 | height: 14px; 680 | background-position: -3921px 0px; } 681 | .iti__flag.iti__pf { 682 | height: 14px; 683 | background-position: -3943px 0px; } 684 | .iti__flag.iti__pg { 685 | height: 15px; 686 | background-position: -3965px 0px; } 687 | .iti__flag.iti__ph { 688 | height: 10px; 689 | background-position: -3987px 0px; } 690 | .iti__flag.iti__pk { 691 | height: 14px; 692 | background-position: -4009px 0px; } 693 | .iti__flag.iti__pl { 694 | height: 13px; 695 | background-position: -4031px 0px; } 696 | .iti__flag.iti__pm { 697 | height: 14px; 698 | background-position: -4053px 0px; } 699 | .iti__flag.iti__pn { 700 | height: 10px; 701 | background-position: -4075px 0px; } 702 | .iti__flag.iti__pr { 703 | height: 14px; 704 | background-position: -4097px 0px; } 705 | .iti__flag.iti__ps { 706 | height: 10px; 707 | background-position: -4119px 0px; } 708 | .iti__flag.iti__pt { 709 | height: 14px; 710 | background-position: -4141px 0px; } 711 | .iti__flag.iti__pw { 712 | height: 13px; 713 | background-position: -4163px 0px; } 714 | .iti__flag.iti__py { 715 | height: 11px; 716 | background-position: -4185px 0px; } 717 | .iti__flag.iti__qa { 718 | height: 8px; 719 | background-position: -4207px 0px; } 720 | .iti__flag.iti__re { 721 | height: 14px; 722 | background-position: -4229px 0px; } 723 | .iti__flag.iti__ro { 724 | height: 14px; 725 | background-position: -4251px 0px; } 726 | .iti__flag.iti__rs { 727 | height: 14px; 728 | background-position: -4273px 0px; } 729 | .iti__flag.iti__ru { 730 | height: 14px; 731 | background-position: -4295px 0px; } 732 | .iti__flag.iti__rw { 733 | height: 14px; 734 | background-position: -4317px 0px; } 735 | .iti__flag.iti__sa { 736 | height: 14px; 737 | background-position: -4339px 0px; } 738 | .iti__flag.iti__sb { 739 | height: 10px; 740 | background-position: -4361px 0px; } 741 | .iti__flag.iti__sc { 742 | height: 10px; 743 | background-position: -4383px 0px; } 744 | .iti__flag.iti__sd { 745 | height: 10px; 746 | background-position: -4405px 0px; } 747 | .iti__flag.iti__se { 748 | height: 13px; 749 | background-position: -4427px 0px; } 750 | .iti__flag.iti__sg { 751 | height: 14px; 752 | background-position: -4449px 0px; } 753 | .iti__flag.iti__sh { 754 | height: 10px; 755 | background-position: -4471px 0px; } 756 | .iti__flag.iti__si { 757 | height: 10px; 758 | background-position: -4493px 0px; } 759 | .iti__flag.iti__sj { 760 | height: 15px; 761 | background-position: -4515px 0px; } 762 | .iti__flag.iti__sk { 763 | height: 14px; 764 | background-position: -4537px 0px; } 765 | .iti__flag.iti__sl { 766 | height: 14px; 767 | background-position: -4559px 0px; } 768 | .iti__flag.iti__sm { 769 | height: 15px; 770 | background-position: -4581px 0px; } 771 | .iti__flag.iti__sn { 772 | height: 14px; 773 | background-position: -4603px 0px; } 774 | .iti__flag.iti__so { 775 | height: 14px; 776 | background-position: -4625px 0px; } 777 | .iti__flag.iti__sr { 778 | height: 14px; 779 | background-position: -4647px 0px; } 780 | .iti__flag.iti__ss { 781 | height: 10px; 782 | background-position: -4669px 0px; } 783 | .iti__flag.iti__st { 784 | height: 10px; 785 | background-position: -4691px 0px; } 786 | .iti__flag.iti__sv { 787 | height: 12px; 788 | background-position: -4713px 0px; } 789 | .iti__flag.iti__sx { 790 | height: 14px; 791 | background-position: -4735px 0px; } 792 | .iti__flag.iti__sy { 793 | height: 14px; 794 | background-position: -4757px 0px; } 795 | .iti__flag.iti__sz { 796 | height: 14px; 797 | background-position: -4779px 0px; } 798 | .iti__flag.iti__ta { 799 | height: 10px; 800 | background-position: -4801px 0px; } 801 | .iti__flag.iti__tc { 802 | height: 10px; 803 | background-position: -4823px 0px; } 804 | .iti__flag.iti__td { 805 | height: 14px; 806 | background-position: -4845px 0px; } 807 | .iti__flag.iti__tf { 808 | height: 14px; 809 | background-position: -4867px 0px; } 810 | .iti__flag.iti__tg { 811 | height: 13px; 812 | background-position: -4889px 0px; } 813 | .iti__flag.iti__th { 814 | height: 14px; 815 | background-position: -4911px 0px; } 816 | .iti__flag.iti__tj { 817 | height: 10px; 818 | background-position: -4933px 0px; } 819 | .iti__flag.iti__tk { 820 | height: 10px; 821 | background-position: -4955px 0px; } 822 | .iti__flag.iti__tl { 823 | height: 10px; 824 | background-position: -4977px 0px; } 825 | .iti__flag.iti__tm { 826 | height: 14px; 827 | background-position: -4999px 0px; } 828 | .iti__flag.iti__tn { 829 | height: 14px; 830 | background-position: -5021px 0px; } 831 | .iti__flag.iti__to { 832 | height: 10px; 833 | background-position: -5043px 0px; } 834 | .iti__flag.iti__tr { 835 | height: 14px; 836 | background-position: -5065px 0px; } 837 | .iti__flag.iti__tt { 838 | height: 12px; 839 | background-position: -5087px 0px; } 840 | .iti__flag.iti__tv { 841 | height: 10px; 842 | background-position: -5109px 0px; } 843 | .iti__flag.iti__tw { 844 | height: 14px; 845 | background-position: -5131px 0px; } 846 | .iti__flag.iti__tz { 847 | height: 14px; 848 | background-position: -5153px 0px; } 849 | .iti__flag.iti__ua { 850 | height: 14px; 851 | background-position: -5175px 0px; } 852 | .iti__flag.iti__ug { 853 | height: 14px; 854 | background-position: -5197px 0px; } 855 | .iti__flag.iti__um { 856 | height: 11px; 857 | background-position: -5219px 0px; } 858 | .iti__flag.iti__un { 859 | height: 14px; 860 | background-position: -5241px 0px; } 861 | .iti__flag.iti__us { 862 | height: 11px; 863 | background-position: -5263px 0px; } 864 | .iti__flag.iti__uy { 865 | height: 14px; 866 | background-position: -5285px 0px; } 867 | .iti__flag.iti__uz { 868 | height: 10px; 869 | background-position: -5307px 0px; } 870 | .iti__flag.iti__va { 871 | height: 15px; 872 | background-position: -5329px 0px; } 873 | .iti__flag.iti__vc { 874 | height: 14px; 875 | background-position: -5346px 0px; } 876 | .iti__flag.iti__ve { 877 | height: 14px; 878 | background-position: -5368px 0px; } 879 | .iti__flag.iti__vg { 880 | height: 10px; 881 | background-position: -5390px 0px; } 882 | .iti__flag.iti__vi { 883 | height: 14px; 884 | background-position: -5412px 0px; } 885 | .iti__flag.iti__vn { 886 | height: 14px; 887 | background-position: -5434px 0px; } 888 | .iti__flag.iti__vu { 889 | height: 12px; 890 | background-position: -5456px 0px; } 891 | .iti__flag.iti__wf { 892 | height: 14px; 893 | background-position: -5478px 0px; } 894 | .iti__flag.iti__ws { 895 | height: 10px; 896 | background-position: -5500px 0px; } 897 | .iti__flag.iti__xk { 898 | height: 15px; 899 | background-position: -5522px 0px; } 900 | .iti__flag.iti__ye { 901 | height: 14px; 902 | background-position: -5544px 0px; } 903 | .iti__flag.iti__yt { 904 | height: 14px; 905 | background-position: -5566px 0px; } 906 | .iti__flag.iti__za { 907 | height: 14px; 908 | background-position: -5588px 0px; } 909 | .iti__flag.iti__zm { 910 | height: 14px; 911 | background-position: -5610px 0px; } 912 | .iti__flag.iti__zw { 913 | height: 10px; 914 | background-position: -5632px 0px; } 915 | 916 | .iti__flag { 917 | height: 15px; 918 | box-shadow: 0px 0px 1px 0px #888; 919 | background-image: url("../img/flags.png"); 920 | background-repeat: no-repeat; 921 | background-color: #DBDBDB; 922 | background-position: 20px 0; } 923 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { 924 | .iti__flag { 925 | background-image: url("../img/flags@2x.png"); } } 926 | 927 | .iti__flag.iti__np { 928 | background-color: transparent; } 929 | -------------------------------------------------------------------------------- /webApp-plivo/public/css/newstyle.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Lato:300); 2 | @import url(https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css); 3 | 4 | body{ 5 | background: no-repeat center center; 6 | background-image: url(../img/background.svg); 7 | -webkit-background-size: cover; 8 | -moz-background-size: cover; 9 | -o-background-size: cover; 10 | background-size: cover; 11 | } 12 | body 13 | { 14 | margin: 0; 15 | padding: 0; 16 | font-family: soleil,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; 17 | background-size: 100%; 18 | -webkit-font-smoothing: antialiased; 19 | -webkit-text-size-adjust: none; 20 | color: #212933; 21 | background-color: #f8f9fa; 22 | } 23 | 24 | p 25 | { 26 | margin: 0; 27 | padding: 0 0 10px 0; 28 | line-height: 20px; 29 | } 30 | 31 | 32 | 33 | /* .borderline{ 34 | border-bottom: 1px solid black; 35 | } */ 36 | 37 | .loginscreen{ 38 | position: relative; 39 | background: #fff; 40 | border-radius: 2px; 41 | box-shadow: 0 0 14px 0 #dee5eb; 42 | border: solid 1px #d7e1ec; 43 | display: inline-block; 44 | padding-left: 80px; 45 | padding-right: 80px; 46 | margin-top:5%; 47 | margin-bottom: 120px; 48 | } 49 | 50 | .span4 51 | { 52 | width: 80px; 53 | float: left; 54 | margin: 0 8px 10px 8px; 55 | } 56 | 57 | @media (min-width: 768px) 58 | { 59 | .phone, .row2 { 60 | width: 380px; 61 | } 62 | 63 | .row1 { 64 | width: 550px; 65 | } 66 | } 67 | 68 | .phone 69 | { 70 | margin-top: 24px; 71 | /* background: rgba(150, 209, 150, 0.09); */ 72 | } 73 | 74 | .callanswerpad{ 75 | width:100%; 76 | } 77 | 78 | .callinfo 79 | { 80 | margin-top: 15px; 81 | /* background: rgba(150, 209, 150, 0.09); */ 82 | width: 50%; 83 | } 84 | 85 | .callinfoIcon{ 86 | font-size: 2em !important; 87 | } 88 | 89 | input[type="radio"] { 90 | accent-color: black; 91 | } 92 | 93 | .callinfoPid{ 94 | margin-left: 20px !important; 95 | } 96 | 97 | .incomingCallDefault { 98 | margin-top: 15px; 99 | /* background: rgba(150, 209, 150, 0.09); */ 100 | width: 40%; 101 | } 102 | 103 | .incomingCallBtnSecondary{ 104 | width: 50%; 105 | } 106 | 107 | .tel 108 | { 109 | margin-bottom: 10px; 110 | margin-top: 10px; 111 | color: black; 112 | font-weight: 600; 113 | } 114 | .num-pad 115 | { 116 | padding-left: 15px; 117 | } 118 | 119 | .num 120 | { 121 | /*border: 1px solid #9e9e9e;*/ 122 | -webkit-border-radius: 999px; 123 | border-radius: 999px; 124 | -moz-border-radius: 999px; 125 | height: 80px; 126 | /*background-color: #fff;*/ 127 | cursor: pointer; 128 | } 129 | 130 | .num:hover 131 | { 132 | background-color: #d9edf7; 133 | transition-property: background-color .2s linear 0s; 134 | -moz-transition: background-color .2s linear 0s; 135 | -webkit-transition: background-color .2s linear 0s; 136 | -o-transition: background-color .2s linear 0s; 137 | } 138 | 139 | .num-star{ 140 | font-size:55px !important; 141 | margin-top:-5px; 142 | } 143 | 144 | .txt 145 | { 146 | font-size: 30px; 147 | text-align: center; 148 | font-family: 'Lato' , sans-serif; 149 | } 150 | 151 | .small 152 | { 153 | font-size: 13px; 154 | } 155 | 156 | .btn 157 | { 158 | font-weight: bold; 159 | -webkit-transition: .1s ease-in background-color; 160 | -webkit-font-smoothing: antialiased; 161 | letter-spacing: 1px; 162 | } 163 | 164 | .btn-lg{ 165 | width: 80%; 166 | } 167 | 168 | .btn:hover 169 | { 170 | transition-property: background-color .2s linear 0s; 171 | -moz-transition: background-color .2s linear 0s; 172 | -webkit-transition: background-color .2s linear 0s; 173 | -o-transition: background-color .2s linear 0s; 174 | } 175 | 176 | .active 177 | { 178 | color: #3498db; 179 | } 180 | 181 | .metrics{ 182 | margin-bottom: 7px; 183 | padding: 10px; 184 | background: rgba(244, 67, 54, 0.75); 185 | color: #fff; 186 | font-size: 13px; 187 | text-align: center; 188 | border-radius: 3px; 189 | padding-top: 8px; 190 | padding-bottom: 8px; 191 | outline: 0; 192 | top: 0; 193 | right:0; 194 | font-family: monospace; 195 | } 196 | 197 | .oncallalertmsg{ 198 | position: absolute !important; 199 | top: 30% !important; 200 | right: 10% !important; 201 | z-index: 100000 !important; 202 | left: 60% !important; 203 | } 204 | 205 | .mediaalertmsg{ 206 | position: absolute; 207 | top: 30%; 208 | right: 10%; 209 | z-index: 100000; 210 | } 211 | 212 | .alertmsg{ 213 | position: fixed; 214 | top: 10px; 215 | right: 10px; 216 | z-index: 100000; 217 | } 218 | 219 | .AfterAnswer, .callinfo, .lowQualityRadios, .feedback, .loader, .fadein-effect{ 220 | display: none; 221 | } 222 | 223 | .customAlert{ 224 | margin-bottom: 10px; 225 | padding: 10px; 226 | z-index: 10000; 227 | font-size: 14px; 228 | text-align: center; 229 | border-radius: 3px; 230 | padding-top: 8px; 231 | padding-bottom: 8px; 232 | outline: 0; 233 | top: 0; 234 | right: 0; 235 | font-family: monospace; 236 | } 237 | 238 | .alertwarn{ 239 | color: red; 240 | border: 1px solid red; 241 | } 242 | 243 | .alertinfo{ 244 | color: #0F172A; 245 | border: 1px solid #0F172A; 246 | } 247 | 248 | .black{ 249 | font-size: 20px; 250 | font-weight: 500; 251 | } 252 | 253 | .caption{ 254 | font-size: 20px; 255 | font-weight: 400; 256 | } 257 | 258 | .loginUser, .loginPwd{ 259 | font-size: initial; 260 | } 261 | 262 | .middleLabel{ 263 | margin-top: 5px; 264 | } 265 | 266 | #answerkeypad{ 267 | font-weight: 600; 268 | margin-top: 20px; 269 | } 270 | 271 | .feedback{ 272 | transform: rotate(90deg); 273 | position: absolute; 274 | top: 50%; 275 | left: -2%; 276 | } 277 | 278 | .monospace{ 279 | font-family: monospace; 280 | } 281 | 282 | #clickLogin{ 283 | width:30%; 284 | } 285 | 286 | .white-shadow{ 287 | box-shadow: 0 6px 20px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 288 | } 289 | 290 | .lead{ 291 | font-weight: 400; 292 | font-size: 18px; 293 | } 294 | 295 | .text-success{ 296 | color: #0F172A; 297 | } 298 | 299 | .label-value{ 300 | font-size: 18px; 301 | } 302 | 303 | .loader { 304 | position: absolute; 305 | left: 50%; 306 | top: 50%; 307 | z-index: 1; 308 | width: 150px; 309 | height: 150px; 310 | margin: -75px 0 0 -75px; 311 | border: 16px solid #D4D4D4; 312 | border-radius: 50%; 313 | border-top: 16px solid #0F172A; 314 | width: 120px; 315 | height: 120px; 316 | background-color: transparent; 317 | -webkit-animation: spin 2s linear infinite; 318 | animation: spin 2s linear infinite; 319 | } 320 | 321 | @-webkit-keyframes spin { 322 | 0% { -webkit-transform: rotate(0deg); } 323 | 100% { -webkit-transform: rotate(360deg); } 324 | } 325 | 326 | @keyframes spin { 327 | 0% { transform: rotate(0deg); } 328 | 100% { transform: rotate(360deg); } 329 | } 330 | 331 | .btn-success, .btn-primary{ 332 | background-color: #0F172A !important; 333 | border-color: rgba(0,0,0,.0001) !important; 334 | } 335 | 336 | .btn-success:hover, .btn-success:active, .btn-success:focus, .btn-success:visited, .btn-primary:hover, .btn-primary:active, .btn-primary:focus, .btn-primary:visited{ 337 | background-color: #0F172A !important; 338 | border-color: rgba(0,0,0,.0001) !important; 339 | } 340 | 341 | .btn-primary{ 342 | padding: 8px 16px; 343 | } 344 | 345 | .btn-outline-primary{ 346 | border: solid 1px #0F172A; 347 | padding: 8px 15px; 348 | color: #0F172A; 349 | border-radius: 4px; 350 | } 351 | 352 | .navbar-text{ 353 | color: black; 354 | font-weight: 400; 355 | } 356 | 357 | .modal-footer{ 358 | text-align: center; 359 | } 360 | 361 | .iti__flag{ 362 | background-image: url("../img/flags.png"); 363 | } 364 | 365 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { 366 | .iti__flag {background-image: url("../img/flags@2x.png");} 367 | } 368 | 369 | .iti{ 370 | width: 100%; 371 | margin-top: 10px; 372 | margin-bottom: 20px; 373 | } 374 | 375 | #callerid { 376 | background: transparent; 377 | border: none; 378 | border-bottom: 1px solid #000000; 379 | outline:none; 380 | box-shadow:none; 381 | text-align: center; 382 | margin-bottom: 10px; 383 | color: black; 384 | width: 190px; 385 | } 386 | 387 | .calleridRemove{ 388 | cursor:pointer; 389 | margin-left:3px; 390 | } 391 | 392 | .micsettingslink{ 393 | margin-bottom: 10px; 394 | margin-top: 10px; 395 | text-decoration: underline; 396 | } 397 | 398 | .micsettingsLabel{ 399 | font-size: 15px !important; 400 | } 401 | 402 | .micLabel{ 403 | font-weight: 200; 404 | } 405 | 406 | .toggleLabel{ 407 | margin-left:10px; 408 | } 409 | 410 | a, a:focus, a:hover, a:visited { 411 | color: black; 412 | font-weight: 600; 413 | } 414 | 415 | .pidinput{ 416 | width: calc(10% - 60px); 417 | height: 10px; 418 | display: inline-block; 419 | margin: 5px; 420 | color: #0F172A; 421 | } 422 | 423 | .pidspeakeroutput, .pidringoutput{ 424 | width: calc(10% - 60px); 425 | height: 10px; 426 | display: inline-block; 427 | margin: 5px; 428 | background-color: #e6e7e8; 429 | } 430 | 431 | .pidlocalaudio, .pidremoteaudio{ 432 | width: calc(10% - 20px); 433 | height: 10px; 434 | display: inline-block; 435 | margin: 5px; 436 | background-color: #e6e7e8; 437 | } 438 | 439 | .miclink, .speakerlink{ 440 | margin-left: 20px; 441 | font-size: 15px; 442 | position: absolute; 443 | text-decoration: underline; 444 | } 445 | 446 | .audio-btn{ 447 | margin-right: 15px; 448 | width: 104px; 449 | margin-bottom: 25px; 450 | } 451 | 452 | .audio-text { 453 | margin-right: 15px; 454 | margin-bottom: 15px; 455 | font-size: 15px; 456 | } 457 | 458 | .hangup{ 459 | width: 60%; 460 | margin-bottom: 10px; 461 | margin-top: 15px; 462 | } 463 | 464 | .rejectIncoming, .ignoreIncoming{ 465 | width:100%; 466 | margin-top:5px; 467 | } 468 | 469 | .answerIncoming, .makecall{ 470 | width: 100%; 471 | background-color: #0F172A !important; 472 | border-color: #0F172A !important; 473 | } 474 | 475 | .answerIncoming:hover, .answerIncoming:active, .answerIncoming:focus, .answerIncoming:visited, .makecall:hover, .makecall:active, .makecall:focus, .makecall:visited{ 476 | background-color: #0F172A !important; 477 | border-color: #0F172A !important; 478 | } 479 | 480 | .answerIncoming{ 481 | margin-top: 40px; 482 | } 483 | 484 | .btn-default, .btn-default:active, .btn-default:focus { 485 | background-color: #0F172A !important; 486 | border-color: #0F172A !important; 487 | } 488 | 489 | 490 | .logout, .config{ 491 | font-size: large; 492 | cursor: pointer; 493 | color: #0F172A; 494 | font-weight: 500; 495 | margin-right: 2px; 496 | } 497 | 498 | .config-cog{ 499 | cursor: pointer; 500 | color: #0F172A; 501 | font-weight: 500; 502 | margin-right: 2px; 503 | font-size: 1.4em !important; 504 | line-height: 1.1em !important; 505 | } 506 | 507 | .config-login{ 508 | cursor: pointer; 509 | margin-bottom: 10px; 510 | } 511 | 512 | .config-div{ 513 | margin-left: 95px; 514 | font-size: 16px; 515 | } 516 | 517 | .config-update{ 518 | width:15%; 519 | } 520 | 521 | .config-reset{ 522 | width:15%; 523 | margin-left:10px; 524 | } 525 | 526 | .feedbackTextArea{ 527 | width: 100%; 528 | } 529 | 530 | .feedbackComment{ 531 | width: 50%; 532 | } 533 | 534 | .feedbackIssue{ 535 | width: 45%; 536 | margin-top: -15px; 537 | margin-left: 10px; 538 | } 539 | 540 | #sendFeedback, #ignoreFeedback { 541 | width: 15%; 542 | } 543 | 544 | /* Rating Star Widgets Style */ 545 | .rating-stars ul { 546 | list-style-type:none; 547 | padding:0; 548 | -moz-user-select:none; 549 | -webkit-user-select:none; 550 | } 551 | .rating-stars ul > li.star { 552 | display:inline-block; 553 | } 554 | 555 | /* Idle State of the stars */ 556 | .rating-stars ul > li.star > i.fa { 557 | font-size:2.5em; /* Change the size of the stars */ 558 | color:#ccc; /* Color on idle state */ 559 | } 560 | 561 | /* Hover state of the stars */ 562 | .rating-stars ul > li.star.hover > i.fa { 563 | color:#FFCC36; 564 | } 565 | 566 | /* Selected state of the stars */ 567 | .rating-stars ul > li.star.selected > i.fa { 568 | color:#FF912C; 569 | } 570 | 571 | .feedback-status{ 572 | color: #afaf00; 573 | font-weight: 600; 574 | font-family: sans-serif; 575 | text-align: center; 576 | margin-right: 25%; 577 | } 578 | 579 | 580 | .container { 581 | margin-right: 40px; 582 | margin-left: 40px; 583 | padding-left: 0px; 584 | padding-right: 0px; 585 | } 586 | 587 | .panel-body { 588 | padding: 0px; 589 | } -------------------------------------------------------------------------------- /webApp-plivo/public/css/notify.css: -------------------------------------------------------------------------------- 1 | .messg { 2 | z-index: 9999; 3 | left: 10px; 4 | right: 10px; 5 | border: 0 none; 6 | -webkit-border-radius: 2px; 7 | -moz-border-radius: 2px; 8 | -ms-border-radius: 2px; 9 | -o-border-radius: 2px; 10 | border-radius: 2px; 11 | -webkit-box-shadow: inset 0 -1px rgba(0,0,0,0.25); 12 | -moz-box-shadow: inset 0 -1px rgba(0,0,0,0.25); 13 | box-shadow: inset 0 -1px rgba(0,0,0,0.25); 14 | font-size: 14px; 15 | line-height: 1.4286; 16 | text-align: left; 17 | cursor: pointer; 18 | } 19 | 20 | @media (min-width: 768px) { 21 | .messg { 22 | left: 23%; 23 | right: 23%; 24 | } 25 | 26 | .messg--left { 27 | left: 10px !important; 28 | right: 45%; 29 | } 30 | 31 | .messg--right { 32 | left: 45%; 33 | right: 10px !important; 34 | } 35 | } 36 | 37 | @media (min-width: 992px) { 38 | .messg { 39 | left: 28%; 40 | right: 28%; 41 | } 42 | 43 | .messg--left { 44 | right: 55%; 45 | } 46 | 47 | .messg--right { 48 | left: 55%; 49 | } 50 | } 51 | 52 | @media (min-width: 1200px) { 53 | .messg { 54 | left: 33%; 55 | right: 33%; 56 | } 57 | 58 | .messg--left { 59 | right: 65%; 60 | } 61 | 62 | .messg--right { 63 | left: 65%; 64 | } 65 | } 66 | 67 | .messg--default { 68 | background-color: #323232; 69 | } 70 | 71 | .messg--success { 72 | background-color: #182441; 73 | } 74 | 75 | .messg--info { 76 | background-color: #00bcd4; 77 | } 78 | 79 | .messg--warning { 80 | background-color: #ff9800; 81 | } 82 | 83 | .messg--error { 84 | background-color: #f44336; 85 | } 86 | 87 | .messg__text { 88 | padding: 10px 14px; 89 | } 90 | 91 | .messg__buttons { 92 | float: right; 93 | padding: 10px; 94 | } 95 | 96 | .messg, 97 | .messg__button { 98 | color: #f5f5f5; 99 | font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; 100 | } 101 | 102 | .messg__button { 103 | display: inline-block; 104 | border: 0 none; 105 | -webkit-border-radius: 1px; 106 | -moz-border-radius: 1px; 107 | -ms-border-radius: 1px; 108 | -o-border-radius: 1px; 109 | border-radius: 1px; 110 | margin: 0 0 0 5px; 111 | padding: 0 6px; 112 | background: none; 113 | cursor: pointer; 114 | } 115 | 116 | .messg--default .messg__button { 117 | background-color: #212121; 118 | } 119 | 120 | .messg--default .messg__button:hover { 121 | background-color: #000; 122 | } 123 | 124 | .messg--success .messg__button { 125 | background-color: #0F172A; 126 | } 127 | 128 | .messg--success .messg__button:hover { 129 | background-color: #0F172A; 130 | } 131 | 132 | .messg--info .messg__button { 133 | background-color: #00acc1; 134 | } 135 | 136 | .messg--info .messg__button:hover { 137 | background-color: #0097a7; 138 | } 139 | 140 | .messg--warning .messg__button { 141 | background-color: #fb8c00; 142 | } 143 | 144 | .messg--warning .messg__button:hover { 145 | background-color: #f57c00; 146 | } 147 | 148 | .messg--error .messg__button { 149 | background-color: #e53935; 150 | } 151 | 152 | .messg--error .messg__button:hover { 153 | background-color: #d32f2f; 154 | } -------------------------------------------------------------------------------- /webApp-plivo/public/img/PlivoIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/img/PlivoIcon.png -------------------------------------------------------------------------------- /webApp-plivo/public/img/background.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /webApp-plivo/public/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/img/favicon.png -------------------------------------------------------------------------------- /webApp-plivo/public/img/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/img/flags.png -------------------------------------------------------------------------------- /webApp-plivo/public/img/flags@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/img/flags@2x.png -------------------------------------------------------------------------------- /webApp-plivo/public/img/micdenied.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/img/micdenied.png -------------------------------------------------------------------------------- /webApp-plivo/public/img/plivo-logo-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/img/plivo-logo-new.png -------------------------------------------------------------------------------- /webApp-plivo/public/img/plivo-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/img/plivo-logo.png -------------------------------------------------------------------------------- /webApp-plivo/public/lib/intlTelInput.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * International Telephone Input v17.0.3 3 | * https://github.com/jackocnr/intl-tel-input.git 4 | * Licensed under the MIT license 5 | */ 6 | 7 | !function(a){"object"==typeof module&&module.exports?module.exports=a():window.intlTelInput=a()}(function(a){"use strict";return function(){function b(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}function c(a,b){for(var c=0;cthis.countryCodeMaxLen&&(this.countryCodeMaxLen=c.length),this.q.hasOwnProperty(c)||(this.q[c]=[]);for(var e=0;e-1})}else if(this.d.excludeCountries.length){var b=this.d.excludeCountries.map(function(a){return a.toLowerCase()});this.p=e.filter(function(a){return-1===b.indexOf(a.iso2)})}else this.p=e}},{key:"_d0",value:function(){for(var a=0;a"),d+="
"),d+="".concat(f.name,""),d+="+".concat(f.dialCode,""),d+=""}this.m.insertAdjacentHTML("beforeend",d)}},{key:"_h",value:function(){var a=this.a.value,b=this._5(a),c=this._w(a),d=this.d,e=d.initialCountry,f=d.nationalMode,g=d.autoHideDialCode,h=d.separateDialCode;b&&!c?this._v(a):"auto"!==e&&(e?this._z(e.toLowerCase()):b&&c?this._z("us"):(this.j=this.preferredCountries.length?this.preferredCountries[0].iso2:this.p[0].iso2,a||this._z(this.j)),a||f||g||h||(this.a.value="+".concat(this.s.dialCode))),a&&this._u(a)}},{key:"_i",value:function(){this._j(),this.d.autoHideDialCode&&this._l(),this.d.allowDropdown&&this._i2(),this.hiddenInput&&this._i0()}},{key:"_i0",value:function(){var a=this;this._a14=function(){a.hiddenInput.value=a.getNumber()},this.a.form&&this.a.form.addEventListener("submit",this._a14)}},{key:"_i1",value:function(){for(var a=this.a;a&&"LABEL"!==a.tagName;)a=a.parentNode;return a}},{key:"_i2",value:function(){var a=this;this._a9=function(b){a.m.classList.contains("iti__hide")?a.a.focus():b.preventDefault()};var b=this._i1();b&&b.addEventListener("click",this._a9),this._a10=function(){!a.m.classList.contains("iti__hide")||a.a.disabled||a.a.readOnly||a._n()},this.selectedFlag.addEventListener("click",this._a10),this._a11=function(b){a.m.classList.contains("iti__hide")&&-1!==["ArrowUp","Up","ArrowDown","Down"," ","Enter"].indexOf(b.key)&&(b.preventDefault(),b.stopPropagation(),a._n()),"Tab"===b.key&&a._2()},this.k.addEventListener("keydown",this._a11)}},{key:"_i3",value:function(){var a=this;this.d.utilsScript&&!window.intlTelInputUtils?window.intlTelInputGlobals.windowLoaded?window.intlTelInputGlobals.loadUtils(this.d.utilsScript):window.addEventListener("load",function(){window.intlTelInputGlobals.loadUtils(a.d.utilsScript)}):this.i0(),"auto"===this.d.initialCountry?this._i4():this.h()}},{key:"_i4",value:function(){window.intlTelInputGlobals.autoCountry?this.handleAutoCountry():window.intlTelInputGlobals.startedLoadingAutoCountry||(window.intlTelInputGlobals.startedLoadingAutoCountry=!0,"function"==typeof this.d.geoIpLookup&&this.d.geoIpLookup(function(a){window.intlTelInputGlobals.autoCountry=a.toLowerCase(),setTimeout(function(){return m("handleAutoCountry")})},function(){return m("rejectAutoCountryPromise")}))}},{key:"_j",value:function(){var a=this;this._a12=function(){a._v(a.a.value)&&a._8()},this.a.addEventListener("keyup",this._a12),this._a13=function(){setTimeout(a._a12)},this.a.addEventListener("cut",this._a13),this.a.addEventListener("paste",this._a13)}},{key:"_j2",value:function(a){var b=this.a.getAttribute("maxlength");return b&&a.length>b?a.substr(0,b):a}},{key:"_l",value:function(){var a=this;this._a8=function(){a._l2()},this.a.form&&this.a.form.addEventListener("submit",this._a8),this.a.addEventListener("blur",this._a8)}},{key:"_l2",value:function(){if("+"===this.a.value.charAt(0)){var a=this._m(this.a.value);a&&this.s.dialCode!==a||(this.a.value="")}}},{key:"_m",value:function(a){return a.replace(/\D/g,"")}},{key:"_m2",value:function(a){var b=document.createEvent("Event");b.initEvent(a,!0,!0),this.a.dispatchEvent(b)}},{key:"_n",value:function(){this.m.classList.remove("iti__hide"),this.selectedFlag.setAttribute("aria-expanded","true"),this._o(),this.b&&(this._x(this.b,!1),this._3(this.b,!0)),this._p(),this.u.classList.add("iti__arrow--up"),this._m2("open:countrydropdown")}},{key:"_n2",value:function(a,b,c){c&&!a.classList.contains(b)?a.classList.add(b):!c&&a.classList.contains(b)&&a.classList.remove(b)}},{key:"_o",value:function(){var a=this;if(this.d.dropdownContainer&&this.d.dropdownContainer.appendChild(this.dropdown),!this.g){var b=this.a.getBoundingClientRect(),c=window.pageYOffset||document.documentElement.scrollTop,d=b.top+c,e=this.m.offsetHeight,f=d+this.a.offsetHeight+ec;if(this._n2(this.m,"iti__country-list--dropup",!f&&g),this.d.dropdownContainer){var h=!f&&g?0:this.a.offsetHeight;this.dropdown.style.top="".concat(d+h,"px"),this.dropdown.style.left="".concat(b.left+document.body.scrollLeft,"px"),this._a4=function(){return a._2()},window.addEventListener("scroll",this._a4)}}}},{key:"_o2",value:function(a){for(var b=a;b&&b!==this.m&&!b.classList.contains("iti__country");)b=b.parentNode;return b===this.m?null:b}},{key:"_p",value:function(){var a=this;this._a0=function(b){var c=a._o2(b.target);c&&a._x(c,!1)},this.m.addEventListener("mouseover",this._a0),this._a1=function(b){var c=a._o2(b.target);c&&a._1(c)},this.m.addEventListener("click",this._a1);var b=!0;this._a2=function(){b||a._2(),b=!1},document.documentElement.addEventListener("click",this._a2);var c="",d=null;this._a3=function(b){b.preventDefault(),"ArrowUp"===b.key||"Up"===b.key||"ArrowDown"===b.key||"Down"===b.key?a._q(b.key):"Enter"===b.key?a._r():"Escape"===b.key?a._2():/^[a-zA-ZÀ-ÿа-яА-Я ]$/.test(b.key)&&(d&&clearTimeout(d),c+=b.key.toLowerCase(),a._s(c),d=setTimeout(function(){c=""},1e3))},document.addEventListener("keydown",this._a3)}},{key:"_q",value:function(a){var b="ArrowUp"===a||"Up"===a?this.c.previousElementSibling:this.c.nextElementSibling;b&&(b.classList.contains("iti__divider")&&(b="ArrowUp"===a||"Up"===a?b.previousElementSibling:b.nextElementSibling),this._x(b,!0))}},{key:"_r",value:function(){this.c&&this._1(this.c)}},{key:"_s",value:function(a){for(var b=0;bg){b&&(k+=l);var m=e-h;c.scrollTop=k-m}}},{key:"_4",value:function(a,b){var c,d=this.a.value,e="+".concat(a);if("+"===d.charAt(0)){var f=this._5(d);c=f?d.replace(f,e):e}else{if(this.d.nationalMode||this.d.separateDialCode)return;if(d)c=e+d;else{if(!b&&this.d.autoHideDialCode)return;c=e}}this.a.value=c}},{key:"_5",value:function(a,b){var c="";if("+"===a.charAt(0))for(var d="",e=0;e (https://andrepolischuk.com) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | // Github: https://github.com/andrepolischuk/messg 26 | 27 | 'use strict' 28 | var flow = [] 29 | var margin = 30 30 | var prefix = 'messg' 31 | 32 | var template = '
' + 33 | '
' + 34 | '
' + 35 | '
' 36 | 37 | window.Notify = {}; 38 | window.Notify.Message = Message 39 | window.Notify.default = getMessageByType('default') 40 | window.Notify.success = getMessageByType('success') 41 | window.Notify.info = getMessageByType('info') 42 | window.Notify.warning = getMessageByType('warning') 43 | window.Notify.error = getMessageByType('error') 44 | 45 | Message.speed = 250 46 | Message.position = 'top' 47 | Message.flow = true 48 | Message.max = null 49 | Message.delay = null 50 | 51 | function Message (text, type, delay) { 52 | if (!text) return 53 | if (!(this instanceof Message)) return new Message(text, type, delay) 54 | this.delay = (typeof type === 'number' ? type : delay) || Message.delay 55 | this.type = typeof type === 'string' ? type : 'default' 56 | this.text = text.replace(/(.*<\/script>)/gim, '') 57 | this.element = document.createElement('div') 58 | this.element.innerHTML = template 59 | this.element = this.element.children[0] 60 | this.element.className += ' ' + prefix + '--' + this.type 61 | 62 | if (/-/.test(Message.position)) { 63 | this.element.className += ' ' + prefix + '--' + Message.position.split(/-/)[1] 64 | } 65 | 66 | this.element.setAttribute('role', this.type) 67 | this.element.children[1].innerHTML = this.text 68 | var metrics = document.getElementsByClassName("metrics")[0]; 69 | if(metrics != null) { 70 | document.getElementById('oncallalertmsg').insertBefore(this.element, metrics); 71 | } else { 72 | document.getElementById('oncallalertmsg').appendChild(this.element); 73 | } 74 | this.element.style.opacity = '0.0' 75 | this.element.style.transition = 'all ' + Message.speed + 'ms ease-in-out' 76 | this.element.offsetWidth // eslint-disable-line no-unused-expressions 77 | 78 | if (!Message.flow || Message.max) { 79 | flow.forEach(function (message, i) { 80 | if (!Message.max || i <= flow.length - Message.max) message.hide() 81 | }) 82 | } 83 | 84 | flow.unshift(this) 85 | this.hide = this.hide.bind(this) 86 | this.element.addEventListener('click', this.hide, false) 87 | this.show() 88 | } 89 | 90 | Message.prototype.show = function () { 91 | this.element.style.opacity = '1.0' 92 | this.element.style.marginBottom = '7px' 93 | Message.reposition() 94 | 95 | if (this.delay) { 96 | setTimeout(this.hide, this.delay + Message.speed) 97 | } 98 | 99 | return this 100 | } 101 | 102 | Message.prototype.hide = function (fn) { 103 | if (typeof fn === 'function') { 104 | this.fn = fn 105 | return this 106 | } 107 | 108 | if (this.isHidden()) return 109 | this.element.style.opacity = '0.0' 110 | if (this.fn) this.fn() 111 | flow.splice(flow.indexOf(this), 1) 112 | Message.reposition() 113 | 114 | setTimeout(function () { 115 | this.element.parentNode.removeChild(this.element) 116 | }.bind(this), Message.speed) 117 | } 118 | 119 | Message.prototype.button = function (name, fn) { 120 | var button = document.createElement('button') 121 | button.innerHTML = name 122 | button.className = prefix + '__button' 123 | this.element.children[0].appendChild(button) 124 | this.element.removeEventListener('click', this.hide, false) 125 | 126 | button.addEventListener('click', function () { 127 | if (this.isHidden()) return 128 | if (typeof fn === 'function') fn(name.toLowerCase()) 129 | this.hide() 130 | }.bind(this), false) 131 | 132 | return this 133 | } 134 | 135 | Message.prototype.isHidden = function () { 136 | return flow.indexOf(this) < 0 137 | } 138 | 139 | Message.reposition = function () { 140 | var top = margin 141 | var verticalPosition = Message.position.split(/-/)[0] 142 | 143 | flow.forEach(function (message) { 144 | message.element.style[verticalPosition] = top + 'px' 145 | top += message.element.offsetHeight + margin 146 | }) 147 | } 148 | 149 | Message.clean = function () { 150 | flow.forEach(function (message) { 151 | message.hide() 152 | }) 153 | } 154 | 155 | function getMessageByType (type) { 156 | return function (text, delay) { 157 | if (!text) return 158 | return new Message(text, type, delay) 159 | } 160 | } -------------------------------------------------------------------------------- /webApp-plivo/public/media/us-ring.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/plivo/plivo-browser-sdk2-examples/189f44835964cc6b49f2b7c62c338edbf3ef9149/webApp-plivo/public/media/us-ring.mp3 --------------------------------------------------------------------------------