@exotel-npm-dev/webrtc-client-sdk 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Changelog CHANGED
@@ -1,5 +1,14 @@
1
1
  Change Log
2
2
 
3
+ ## v2.0.2 21 July, 2025
4
+ -[VST-1038] make auto audio device change handling configurable and fixing Missing sent_request event in registerCallback
5
+
6
+ ## v2.0.1 19 June, 2025
7
+ -[VST-1031] Maintaining v1.0.23
8
+
9
+ ## v1.0.24 19 June, 2025
10
+ -[VST-1031] Deprecated, v1.0.21 for customers using CRM SDK with old SDK
11
+
3
12
  ## v1.0.23 10 June, 2025
4
13
  -[VST-1011] Increasing Registration Expiry from 60s to 300s
5
14
 
package/Makefile CHANGED
@@ -12,7 +12,7 @@ build-local:
12
12
 
13
13
  dep:
14
14
  npm uninstall @exotel-npm-dev/webrtc-core-sdk
15
- npm install @exotel-npm-dev/webrtc-core-sdk@latest
15
+ npm install @exotel-npm-dev/webrtc-core-sdk@1.0.21
16
16
 
17
17
  publish: build
18
- npm publish
18
+ npm publish --tag legacy
package/dist/exotelsdk.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  *
3
- * WebRTC CLient SIP version 2.0.1
3
+ * WebRTC CLient SIP version 2.0.2
4
4
  *
5
5
  */
6
6
  (function webpackUniversalModuleDefinition(root, factory) {
@@ -48,6 +48,7 @@ __webpack_require__.r(__webpack_exports__);
48
48
 
49
49
 
50
50
  const logger = _coreSDKLogger__WEBPACK_IMPORTED_MODULE_0__["default"];
51
+ let enableAutoAudioDeviceChangeHandling = false;
51
52
  const audioDeviceManager = {
52
53
  resetInputDevice: false,
53
54
  resetOutputDevice: false,
@@ -65,21 +66,23 @@ const audioDeviceManager = {
65
66
  this.resetOutputDevice = value;
66
67
  },
67
68
 
68
- async changeAudioInputDevice(deviceId, onSuccess, onError) {
69
+ async changeAudioInputDevice(deviceId, onSuccess, onError, forceDeviceChange) {
69
70
  logger.log(`SIPJSPhone:changeAudioInputDevice entry`);
70
71
  try {
71
- if (deviceId == audioDeviceManager.currentAudioInputDeviceId) {
72
- logger.log(`SIPJSPhone:changeAudioInputDevice current input device is same as ${deviceId} hence not changing`);
73
- if (onError) onError("current input device is same as " + deviceId + " hence not changing");
74
- return;
75
- }
76
- const inputDevice = audioDeviceManager.mediaDevices.find(device => device.deviceId === deviceId && device.kind === 'audioinput');
77
- if (!inputDevice) {
78
- logger.error("input device id " + deviceId + "not found");
79
- if (onError) onError("deviceIdNotFound");
80
- return;
72
+ if (enableAutoAudioDeviceChangeHandling && !forceDeviceChange) {
73
+ if (deviceId == audioDeviceManager.currentAudioInputDeviceId) {
74
+ logger.log(`SIPJSPhone:changeAudioInputDevice current input device is same as ${deviceId} hence not changing`);
75
+ if (onError) onError("current input device is same as " + deviceId + " hence not changing");
76
+ return;
77
+ }
78
+ const inputDevice = audioDeviceManager.mediaDevices.find(device => device.deviceId === deviceId && device.kind === 'audioinput');
79
+ if (!inputDevice) {
80
+ logger.error("input device id " + deviceId + "not found");
81
+ if (onError) onError("deviceIdNotFound");
82
+ return;
83
+ }
84
+ logger.log(`SIPJSPhone:changeAudioInputDevice acquiring input device ${deviceId} : ${inputDevice.label}`);
81
85
  }
82
- logger.log(`SIPJSPhone:changeAudioInputDevice acquiring input device ${deviceId} : ${inputDevice.label}`);
83
86
  const stream = await navigator.mediaDevices.getUserMedia({
84
87
  audio: { deviceId: { exact: deviceId } }
85
88
  });
@@ -90,30 +93,31 @@ const audioDeviceManager = {
90
93
  }
91
94
  },
92
95
 
93
- async changeAudioOutputDevice(audioRemote, deviceId, onSuccess, onError) {
94
- logger.log(`audioDeviceManager:changeAudioOutputDevice : entry`);
95
- if (deviceId == audioDeviceManager.currentAudioOutputDeviceId) {
96
- logger.log(`SIPJSPhone:changeAudioOutputDevice current output device is same as ${deviceId}`);
97
- if (onError) onError("current output device is same as " + deviceId);
98
- return;
99
- }
96
+ async changeAudioOutputDevice(audioRemote, deviceId, onSuccess, onError, forceDeviceChange) {
97
+ logger.log(`audioDeviceManager:changeAudioOutputDevice : entry`);
100
98
  const audioElement = audioRemote;
101
99
  if (typeof audioElement.sinkId !== 'undefined') {
102
100
  try {
103
-
104
- if (!audioDeviceManager.mediaDevices || audioDeviceManager.mediaDevices.length == 0) {
105
- logger.error("audioDeviceManager:changeAudioOutputDevice mediaDeviceList is empty ");
106
- if (onError) logger.error(deviceId + "not found in mediaDeviceList in audioManager");
107
- return;
108
- }
109
- const outputDevice = audioDeviceManager.mediaDevices.find(device => device.deviceId === deviceId && device.kind === 'audiooutput');
110
- if (!outputDevice) {
111
- logger.error("audioDeviceManager:changeAudioOutputDevice output device id " + deviceId + "not found");
112
- if (onError) onError("deviceIdNotFound");
113
- return;
101
+ if (enableAutoAudioDeviceChangeHandling && !forceDeviceChange) {
102
+ if (deviceId == audioDeviceManager.currentAudioOutputDeviceId) {
103
+ logger.log(`SIPJSPhone:changeAudioOutputDevice current output device is same as ${deviceId}`);
104
+ if (onError) onError("current output device is same as " + deviceId);
105
+ return;
106
+ }
107
+ if (!audioDeviceManager.mediaDevices || audioDeviceManager.mediaDevices.length == 0) {
108
+ logger.error("audioDeviceManager:changeAudioOutputDevice mediaDeviceList is empty ");
109
+ if (onError) onError(deviceId + "not found in mediaDeviceList in audioManager");
110
+ return;
111
+ }
112
+ const outputDevice = audioDeviceManager.mediaDevices.find(device => device.deviceId === deviceId && device.kind === 'audiooutput');
113
+ if (!outputDevice) {
114
+ logger.error("audioDeviceManager:changeAudioOutputDevice output device id " + deviceId + "not found");
115
+ if (onError) onError("deviceIdNotFound");
116
+ return;
117
+ }
118
+ logger.log(`audioDeviceManager:changeAudioOutputDevice acquiring output device ${deviceId} : ${outputDevice.label}`);
119
+ // audioElement.load();
114
120
  }
115
- logger.log(`audioDeviceManager:changeAudioOutputDevice acquiring output device ${deviceId} : ${outputDevice.label}`);
116
- // audioElement.load();
117
121
  await audioElement.setSinkId(deviceId);
118
122
  audioDeviceManager.currentAudioOutputDeviceId = deviceId;
119
123
  logger.log(`audioDeviceManager:changeAudioOutputDevice Output device changed to: ${deviceId}`);
@@ -178,6 +182,10 @@ const audioDeviceManager = {
178
182
  if (callback) callback();
179
183
  },
180
184
 
185
+ setEnableAutoAudioDeviceChangeHandling(flag) {
186
+ enableAutoAudioDeviceChangeHandling = flag;
187
+ },
188
+
181
189
  };
182
190
 
183
191
  audioDeviceManager.enumerateDevices();
@@ -20843,6 +20851,7 @@ var SIP = __webpack_require__(/*! ./sip-0.20.0.js */ "./node_modules/@exotel-npm
20843
20851
 
20844
20852
 
20845
20853
 
20854
+ let enableAutoAudioDeviceChangeHandling = false;
20846
20855
  var lastTransportState = "";
20847
20856
  var lastRegistererState = "";
20848
20857
  var initializeComplete = false;
@@ -21724,8 +21733,8 @@ function handleWebSocketMessageContent(content, direction) {
21724
21733
  switch (direction) {
21725
21734
  case "sent":
21726
21735
 
21727
- if (sipMessage.method == "CONNECTION")
21728
- _webrtcSIPPhoneEventDelegate__WEBPACK_IMPORTED_MODULE_2__["default"].sendWebRTCEventsToFSM("sent_request", sipMessage.method);
21736
+ if (sipMessage.method == "REGISTER")
21737
+ _webrtcSIPPhoneEventDelegate__WEBPACK_IMPORTED_MODULE_2__["default"].sendWebRTCEventsToFSM("sent_request", "CONNECTION");
21729
21738
 
21730
21739
  _webrtcSIPPhoneEventDelegate__WEBPACK_IMPORTED_MODULE_2__["default"].onCallStatSipSendCallback(newtext, "sipjs");
21731
21740
 
@@ -22151,7 +22160,8 @@ const SIPJSPhone = {
22151
22160
  return lastRegistererState;
22152
22161
  },
22153
22162
 
22154
- changeAudioInputDevice(deviceId, onSuccess, onError) {
22163
+ changeAudioInputDevice(deviceId, onSuccess, onError, forceDeviceChange) {
22164
+ logger.log(`SIPJSPhone: changeAudioInputDevice called with deviceId=${deviceId}, forceDeviceChange=${forceDeviceChange}, enableAutoAudioDeviceChangeHandling=${enableAutoAudioDeviceChangeHandling}`);
22155
22165
  _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.changeAudioInputDevice(deviceId, function (stream) {
22156
22166
  const trackChanged = SIPJSPhone.replaceSenderTrack(stream, deviceId);
22157
22167
  if (trackChanged) {
@@ -22163,7 +22173,7 @@ const SIPJSPhone = {
22163
22173
  logger.error("sipjsphone: changeAudioInputDevice: failed");
22164
22174
  onError("replaceSenderTrack failed for webrtc");
22165
22175
  }
22166
- }, onError);
22176
+ }, onError, forceDeviceChange);
22167
22177
  },
22168
22178
  changeAudioOutputDeviceForAdditionalAudioElement(deviceId) {
22169
22179
  const additionalAudioElements = [ringtone, beeptone, ringbacktone, dtmftone];
@@ -22179,14 +22189,15 @@ const SIPJSPhone = {
22179
22189
  logger.error("sipjsphone:changeAudioOutputDeviceForAdditionalAudioElement failed to setSink for additonal AudioElements", e);
22180
22190
  }
22181
22191
  },
22182
- changeAudioOutputDevice(deviceId, onSuccess, onError) {
22192
+ changeAudioOutputDevice(deviceId, onSuccess, onError, forceDeviceChange) {
22193
+ logger.log(`SIPJSPhone: changeAudioOutputDevice called with deviceId=${deviceId}, forceDeviceChange=${forceDeviceChange}, enableAutoAudioDeviceChangeHandling=${enableAutoAudioDeviceChangeHandling}`);
22183
22194
  if (!ctxSip.callActiveID) {
22184
22195
  audioRemote = document.createElement("audio");
22185
22196
  }
22186
22197
  _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.changeAudioOutputDevice(audioRemote, deviceId, function () {
22187
22198
  SIPJSPhone.changeAudioOutputDeviceForAdditionalAudioElement(deviceId);
22188
22199
  onSuccess();
22189
- }, onError);
22200
+ }, onError, forceDeviceChange);
22190
22201
  },
22191
22202
 
22192
22203
  stopStreamTracks(stream) {
@@ -22242,45 +22253,52 @@ const SIPJSPhone = {
22242
22253
  SIPJSPhone.audioInputDeviceChangeCallback = audioInputDeviceChangeCallback;
22243
22254
  SIPJSPhone.audioOutputDeviceChangeCallback = audioOutputDeviceChangeCallback;
22244
22255
  SIPJSPhone.onDeviceChangeCallback = onDeviceChangeCallback;
22245
- }
22246
-
22247
- };
22248
-
22249
-
22250
- navigator.mediaDevices.addEventListener('devicechange', function (event) {
22251
- try {
22252
- if (!ctxSip.callActiveID) {
22253
- audioRemote = document.createElement("audio");
22254
- }
22255
- _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.enumerateDevices(function () {
22256
-
22257
- if (SIPJSPhone.onDeviceChangeCallback) {
22258
- logger.info("SIPJSPhone:ondevicechange relaying event to callback");
22259
- SIPJSPhone.onDeviceChangeCallback(event);
22260
- return;
22261
- }
22262
- _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.onAudioDeviceChange(audioRemote,
22263
- function (stream, deviceId) {
22264
- const trackChanged = SIPJSPhone.replaceSenderTrack(stream, deviceId);
22265
- if (trackChanged) {
22266
- _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.currentAudioInputDeviceId = deviceId;
22267
- if (SIPJSPhone.audioInputDeviceChangeCallback) {
22268
- SIPJSPhone.audioInputDeviceChangeCallback(deviceId);
22269
- }
22270
- }
22271
- }, function (deviceId) {
22272
- SIPJSPhone.changeAudioOutputDeviceForAdditionalAudioElement(deviceId);
22273
- _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.currentAudioOutputDeviceId = deviceId;
22274
- if (SIPJSPhone.audioOutputDeviceChangeCallback) {
22275
- SIPJSPhone.audioOutputDeviceChangeCallback(deviceId);
22256
+ },
22257
+ attachGlobalDeviceChangeListener() {
22258
+ logger.log("SIPJSPhone: Attaching global devicechange event listener (enableAutoAudioDeviceChangeHandling is true)");
22259
+ navigator.mediaDevices.addEventListener('devicechange', (event) => {
22260
+ try {
22261
+ if (!ctxSip.callActiveID) {
22262
+ audioRemote = document.createElement("audio");
22263
+ }
22264
+ _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.enumerateDevices(() => {
22265
+ if (SIPJSPhone.onDeviceChangeCallback) {
22266
+ logger.info("SIPJSPhone:ondevicechange relaying event to callback");
22267
+ SIPJSPhone.onDeviceChangeCallback(event);
22276
22268
  }
22269
+ _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.onAudioDeviceChange(
22270
+ audioRemote,
22271
+ (stream, deviceId) => {
22272
+ const trackChanged = SIPJSPhone.replaceSenderTrack(stream, deviceId);
22273
+ if (trackChanged) {
22274
+ _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.currentAudioInputDeviceId = deviceId;
22275
+ if (SIPJSPhone.audioInputDeviceChangeCallback) {
22276
+ SIPJSPhone.audioInputDeviceChangeCallback(deviceId);
22277
+ }
22278
+ }
22279
+ },
22280
+ (deviceId) => {
22281
+ SIPJSPhone.changeAudioOutputDeviceForAdditionalAudioElement(deviceId);
22282
+ _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.currentAudioOutputDeviceId = deviceId;
22283
+ if (SIPJSPhone.audioOutputDeviceChangeCallback) {
22284
+ SIPJSPhone.audioOutputDeviceChangeCallback(deviceId);
22285
+ }
22286
+ }
22287
+ );
22277
22288
  });
22289
+ } catch (e) {
22290
+ logger.error("SIPJSPhone:ondevicechange something went wrong during device change", e);
22291
+ }
22278
22292
  });
22293
+ },
22294
+ setEnableAutoAudioDeviceChangeHandling(flag) {
22295
+ logger.log("sipjsphone: setEnableAutoAudioDeviceChangeHandling: entry, enableAutoAudioDeviceChangeHandling = ",flag);
22296
+ enableAutoAudioDeviceChangeHandling = flag;
22297
+ _audioDeviceManager_js__WEBPACK_IMPORTED_MODULE_0__.audioDeviceManager.setEnableAutoAudioDeviceChangeHandling(flag);
22298
+ }
22299
+ };
22300
+
22279
22301
 
22280
- } catch (e) {
22281
- logger.error("SIPJSPhone:ondevicechange something went wrong during device change", e);
22282
- }
22283
- });
22284
22302
 
22285
22303
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SIPJSPhone);
22286
22304
 
@@ -22310,7 +22328,6 @@ __webpack_require__.r(__webpack_exports__);
22310
22328
 
22311
22329
 
22312
22330
 
22313
-
22314
22331
  var phone = null;
22315
22332
  let webrtcSIPEngine = null;
22316
22333
  const logger = _coreSDKLogger__WEBPACK_IMPORTED_MODULE_0__["default"];
@@ -22444,8 +22461,8 @@ const webrtcSIPPhone = {
22444
22461
 
22445
22462
 
22446
22463
 
22447
- registerPhone: (engine, delegate) => {
22448
- logger.log("webrtcSIPPhone: registerPhone : ",engine);
22464
+ registerPhone: (engine, delegate, enableAutoAudioDeviceChangeHandling = false) => {
22465
+ logger.log("webrtcSIPPhone: registerPhone : ",engine, "enableAutoAudioDeviceChangeHandling:", enableAutoAudioDeviceChangeHandling);
22449
22466
  webrtcSIPEngine = engine;
22450
22467
  switch (engine) {
22451
22468
  case "sipjs":
@@ -22456,8 +22473,10 @@ const webrtcSIPPhone = {
22456
22473
  }
22457
22474
  _webrtcSIPPhoneEventDelegate__WEBPACK_IMPORTED_MODULE_2__["default"].registerDelegate(delegate);
22458
22475
  _webrtcSIPPhoneEventDelegate__WEBPACK_IMPORTED_MODULE_2__["default"].onRegisterWebRTCSIPEngine(engine);
22459
-
22460
-
22476
+ phone.setEnableAutoAudioDeviceChangeHandling(enableAutoAudioDeviceChangeHandling);
22477
+ if (enableAutoAudioDeviceChangeHandling) {
22478
+ phone.attachGlobalDeviceChangeListener();
22479
+ }
22461
22480
  },
22462
22481
 
22463
22482
  getWebRTCStatus: () => {
@@ -22527,14 +22546,14 @@ const webrtcSIPPhone = {
22527
22546
  }
22528
22547
  },
22529
22548
 
22530
- changeAudioInputDevice(deviceId, onSuccess, onError) {
22549
+ changeAudioInputDevice(deviceId, onSuccess, onError, forceDeviceChange=false) {
22531
22550
  logger.log("webrtcSIPPhone: changeAudioInputDevice : ", deviceId, onSuccess, onError);
22532
- _sipjsphone__WEBPACK_IMPORTED_MODULE_1__["default"].changeAudioInputDevice(deviceId, onSuccess, onError);
22551
+ _sipjsphone__WEBPACK_IMPORTED_MODULE_1__["default"].changeAudioInputDevice(deviceId, onSuccess, onError, forceDeviceChange);
22533
22552
  },
22534
22553
 
22535
- changeAudioOutputDevice(deviceId, onSuccess, onError) {
22554
+ changeAudioOutputDevice(deviceId, onSuccess, onError, forceDeviceChange=false) {
22536
22555
  logger.log("webrtcSIPPhone: changeAudioOutputDevice : ", deviceId, onSuccess, onError);
22537
- _sipjsphone__WEBPACK_IMPORTED_MODULE_1__["default"].changeAudioOutputDevice(deviceId, onSuccess, onError);
22556
+ _sipjsphone__WEBPACK_IMPORTED_MODULE_1__["default"].changeAudioOutputDevice(deviceId, onSuccess, onError, forceDeviceChange);
22538
22557
  },
22539
22558
  setPreferredCodec(codecName) {
22540
22559
  logger.log("webrtcSIPPhone: setPreferredCodec : ", codecName);
@@ -24240,7 +24259,7 @@ class ExotelWebClient {
24240
24259
  if (this.clientSDKLoggerCallback) this.clientSDKLoggerCallback("log", arg1, args);
24241
24260
  });
24242
24261
  }
24243
- initWebrtc = (sipAccountInfo_, RegisterEventCallBack, CallListenerCallback, SessionCallback) => {
24262
+ initWebrtc = (sipAccountInfo_, RegisterEventCallBack, CallListenerCallback, SessionCallback, enableAutoAudioDeviceChangeHandling = false) => {
24244
24263
  if (!this.eventListener) {
24245
24264
  this.eventListener = new _listeners_ExotelVoiceClientListener__WEBPACK_IMPORTED_MODULE_3__.ExotelVoiceClientListener();
24246
24265
  }
@@ -24253,6 +24272,7 @@ class ExotelWebClient {
24253
24272
  if (!this.call) {
24254
24273
  this.call = new _api_callAPI_Call__WEBPACK_IMPORTED_MODULE_0__.Call();
24255
24274
  }
24275
+ sipAccountInfo_.enableAutoAudioDeviceChangeHandling = enableAutoAudioDeviceChangeHandling;
24256
24276
  logger.log("ExWebClient: initWebrtc: Exotel Client Initialised with " + JSON.stringify(sipAccountInfo_));
24257
24277
  this.sipAccountInfo = sipAccountInfo_;
24258
24278
  if (!this.sipAccountInfo["userName"] || !this.sipAccountInfo["sipdomain"] || !this.sipAccountInfo["port"]) {
@@ -24488,7 +24508,7 @@ class ExotelWebClient {
24488
24508
  //webRTCPhones[userName] = webRTC;
24489
24509
 
24490
24510
  /* New-Way */
24491
- _exotel_npm_dev_webrtc_core_sdk__WEBPACK_IMPORTED_MODULE_8__.webrtcSIPPhone.registerPhone("sipjs", delegationHandler);
24511
+ _exotel_npm_dev_webrtc_core_sdk__WEBPACK_IMPORTED_MODULE_8__.webrtcSIPPhone.registerPhone("sipjs", delegationHandler, sipAccountInfo.enableAutoAudioDeviceChangeHandling);
24492
24512
  _exotel_npm_dev_webrtc_core_sdk__WEBPACK_IMPORTED_MODULE_8__.webrtcSIPPhone.registerWebRTCClient(this.sipAccntInfo, synchronousHandler);
24493
24513
 
24494
24514
  /**
@@ -24539,13 +24559,13 @@ class ExotelWebClient {
24539
24559
  callback("media_permission_denied");
24540
24560
  });
24541
24561
  };
24542
- changeAudioInputDevice(deviceId, onSuccess, onError) {
24562
+ changeAudioInputDevice(deviceId, onSuccess, onError, forceDeviceChange = false) {
24543
24563
  logger.log(`ExWebClient: changeAudioInputDevice: Entry`);
24544
- _exotel_npm_dev_webrtc_core_sdk__WEBPACK_IMPORTED_MODULE_8__.webrtcSIPPhone.changeAudioInputDevice(deviceId, onSuccess, onError);
24564
+ _exotel_npm_dev_webrtc_core_sdk__WEBPACK_IMPORTED_MODULE_8__.webrtcSIPPhone.changeAudioInputDevice(deviceId, onSuccess, onError, forceDeviceChange);
24545
24565
  }
24546
- changeAudioOutputDevice(deviceId, onSuccess, onError) {
24566
+ changeAudioOutputDevice(deviceId, onSuccess, onError, forceDeviceChange = false) {
24547
24567
  logger.log(`ExWebClient: changeAudioOutputDevice: Entry`);
24548
- _exotel_npm_dev_webrtc_core_sdk__WEBPACK_IMPORTED_MODULE_8__.webrtcSIPPhone.changeAudioOutputDevice(deviceId, onSuccess, onError);
24568
+ _exotel_npm_dev_webrtc_core_sdk__WEBPACK_IMPORTED_MODULE_8__.webrtcSIPPhone.changeAudioOutputDevice(deviceId, onSuccess, onError, forceDeviceChange);
24549
24569
  }
24550
24570
  downloadLogs() {
24551
24571
  logger.log(`ExWebClient: downloadLogs: Entry`);