botium-connector-voip 0.0.6 → 0.0.7

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.
@@ -57,7 +57,13 @@ const Capabilities = {
57
57
  VOIP_ICE_TURN_SERVER: 'VOIP_ICE_TURN_SERVER',
58
58
  VOIP_ICE_TURN_USER: 'VOIP_ICE_TURN_USER',
59
59
  VOIP_ICE_TURN_PASSWORD: 'VOIP_ICE_TURN_PASSWORD',
60
- VOIP_ICE_TURN_PROTOCOL: 'VOIP_ICE_TURN_PROTOCOL'
60
+ VOIP_ICE_TURN_PROTOCOL: 'VOIP_ICE_TURN_PROTOCOL',
61
+ VOIP_WEBSOCKET_CONNECT_MAXRETRIES: 'VOIP_WEBSOCKET_CONNECT_MAXRETRIES',
62
+ VOIP_WEBSOCKET_CONNECT_TIMEOUT: 'VOIP_WEBSOCKET_CONNECT_TIMEOUT',
63
+ VOIP_SILENCE_DURATION_TIMEOUT_ENABLE: 'VOIP_SILENCE_DURATION_TIMEOUT_ENABLE',
64
+ VOIP_SILENCE_DURATION_TIMEOUT: 'VOIP_SILENCE_DURATION_TIMEOUT',
65
+ VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE: 'VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE',
66
+ VOIP_SILENCE_DURATION_TIMEOUT_START: 'VOIP_SILENCE_DURATION_TIMEOUT_START'
61
67
  };
62
68
  const Defaults = {
63
69
  VOIP_STT_METHOD: 'POST',
@@ -65,9 +71,15 @@ const Defaults = {
65
71
  VOIP_TTS_METHOD: 'GET',
66
72
  VOIP_TTS_TIMEOUT: 10000,
67
73
  VOIP_STT_MESSAGE_HANDLING: 'ORIGINAL',
68
- VOIP_STT_MESSAGE_HANDLING_TIMEOUT: 5000,
74
+ VOIP_STT_MESSAGE_HANDLING_TIMEOUT: 500,
69
75
  VOIP_STT_MESSAGE_HANDLING_DELIMITER: '. ',
70
- VOIP_STT_MESSAGE_HANDLING_PUNCTUATION: '.!?'
76
+ VOIP_STT_MESSAGE_HANDLING_PUNCTUATION: '.!?',
77
+ VOIP_WEBSOCKET_CONNECT_TIMEOUT: 4000,
78
+ VOIP_WEBSOCKET_CONNECT_MAXRETRIES: 20,
79
+ VOIP_SILENCE_DURATION_TIMEOUT: 2500,
80
+ VOIP_SILENCE_DURATION_TIMEOUT_ENABLE: false,
81
+ VOIP_SILENCE_DURATION_TIMEOUT_START: 1000,
82
+ VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE: false
71
83
  };
72
84
 
73
85
  class BotiumConnectorVoip {
@@ -133,20 +145,29 @@ class BotiumConnectorVoip {
133
145
  this.stopCalled = false;
134
146
  this.fullRecord = '';
135
147
  this.end = false;
148
+ this.connected = false;
136
149
 
137
150
  const sendBotMsg = botMsg => {
138
151
  setTimeout(() => this.queueBotSays(botMsg), 0);
139
152
  };
140
153
 
141
- const buildBotMsg = botMsgs => {
142
- if (botMsgs.length === 1) return botMsgs[0];
154
+ const joinBotMsg = (botMsgs, joinLastPrevMsg) => {
143
155
  const botMsg = {};
144
156
  botMsg.messageText = botMsgs.map(m => m.messageText).join(this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_DELIMITER]);
145
157
  botMsg.sourceData = botMsgs.map(m => m.sourceData);
158
+
159
+ if (lodash__default["default"].isNil(joinLastPrevMsg)) {
160
+ botMsg.sourceData[0].silenceDuration = botMsgs[0].sourceData.data.start;
161
+ botMsg.sourceData[0].voiceDuration = botMsgs[botMsgs.length - 1].sourceData.data.end - botMsgs[0].sourceData.data.start;
162
+ } else {
163
+ botMsg.sourceData[0].silenceDuration = botMsgs[0].sourceData.data.start - joinLastPrevMsg.sourceData.data.end;
164
+ botMsg.sourceData[0].voiceDuration = botMsgs[botMsgs.length - 1].sourceData.data.end - botMsgs[0].sourceData.data.start;
165
+ }
166
+
146
167
  return botMsg;
147
168
  };
148
169
 
149
- const expandBotMsgs = botMsgs => {
170
+ const splitBotMsgs = botMsgs => {
150
171
  const splitSentences = s => s.match(new RegExp(`[^${this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_PUNCTUATION]}]+[${this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_PUNCTUATION]}]+`, 'g'));
151
172
 
152
173
  const botMsgsFinal = [];
@@ -157,11 +178,14 @@ class BotiumConnectorVoip {
157
178
  if (lodash__default["default"].isNil(sentences)) {
158
179
  botMsgsFinal.push(botMsg);
159
180
  } else {
181
+ let botMsgCount = 0;
182
+
160
183
  for (const sentence of sentences) {
161
184
  botMsgsFinal.push({
162
185
  messageText: sentence,
163
- sourceData: botMsg.sourceData
186
+ sourceData: botMsgCount === 0 ? botMsg.sourceData : lodash__default["default"].omit(botMsg.sourceData, ['silenceDuration'])
164
187
  });
188
+ botMsgCount++;
165
189
  }
166
190
  }
167
191
  }
@@ -169,37 +193,66 @@ class BotiumConnectorVoip {
169
193
  return botMsgsFinal;
170
194
  };
171
195
 
172
- const {
173
- data
174
- } = await axios__default["default"]({
175
- method: 'post',
176
- data: {
177
- API_KEY: this.caps[Capabilities.VOIP_WORKER_APIKEY]
178
- },
179
- url: new URL(path__default["default"].join(`${this.caps[Capabilities.VOIP_WORKER_URL].replace('wss', 'https').replace('ws', 'http')}`, 'initCall')).toString()
180
- });
181
- await new Promise(resolve => {
182
- setTimeout(resolve, 2000);
183
- });
196
+ let data = null;
197
+ let headers = null;
198
+
199
+ try {
200
+ const res = await axios__default["default"]({
201
+ method: 'post',
202
+ data: {
203
+ API_KEY: this.caps[Capabilities.VOIP_WORKER_APIKEY]
204
+ },
205
+ url: new URL(path__default["default"].join(`${this.caps[Capabilities.VOIP_WORKER_URL].replace('wss', 'https').replace('ws', 'http')}`, 'initCall')).toString()
206
+ });
207
+ data = res.data;
208
+ headers = res.headers;
209
+ } catch (err) {
210
+ return Promise.reject(new Error(`Connecting to VOIP Worker failed: ${err.response.data.message || 'Not reachable'}`));
211
+ }
212
+
184
213
  return new Promise((resolve, reject) => {
185
- if (data.status === 'error') {
186
- reject(new Error(`Error connecting to VOIP Worker: ${data.message}`));
187
- }
214
+ const wsEndpoint = `${this.caps[Capabilities.VOIP_WORKER_URL]}/ws/${data.port}`;
215
+
216
+ const connect = retryIndex => {
217
+ retryIndex = retryIndex || 0;
218
+ return new Promise((resolve, reject) => {
219
+ if ('set-cookie' in headers) {
220
+ this.ws = new ws__default["default"](wsEndpoint, {
221
+ headers: {
222
+ Cookie: headers['set-cookie']
223
+ }
224
+ });
225
+ } else {
226
+ this.ws = new ws__default["default"](wsEndpoint);
227
+ }
188
228
 
189
- this.ws = new ws__default["default"](this.caps[Capabilities.VOIP_WORKER_URL].replace('8765', data.port));
229
+ this.ws.on('open', () => {
230
+ resolve();
231
+ });
232
+ this.ws.on('error', () => {
233
+ if (retryIndex === this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_MAXRETRIES]) {
234
+ reject(new Error(`Websocket connection failed to ${wsEndpoint}`));
235
+ }
190
236
 
191
- if (!lodash__default["default"].isArray(this.caps[Capabilities.VOIP_ICE_STUN_SERVERS])) {
192
- if (this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] === '') {
193
- this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] = [];
194
- } else {
195
- this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] = this.caps[Capabilities.VOIP_ICE_STUN_SERVERS].split(',');
237
+ setTimeout(() => connect(retryIndex + 1).then(resolve).catch(reject), this.caps[Capabilities.VOIP_WEBSOCKET_CONNECT_TIMEOUT]);
238
+ });
239
+ });
240
+ };
241
+
242
+ connect().then(() => {
243
+ if (!lodash__default["default"].isArray(this.caps[Capabilities.VOIP_ICE_STUN_SERVERS])) {
244
+ if (this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] === '') {
245
+ this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] = [];
246
+ } else {
247
+ this.caps[Capabilities.VOIP_ICE_STUN_SERVERS] = this.caps[Capabilities.VOIP_ICE_STUN_SERVERS].split(',');
248
+ }
196
249
  }
197
- }
198
250
 
199
- this.wsOpened = false;
200
- this.ws.on('open', () => {
251
+ this.silence = null;
252
+ this.msgCount = 0;
253
+ this.firstMsg = true;
201
254
  this.wsOpened = true;
202
- debug(`Websocket connection to ${this.caps[Capabilities.VOIP_WORKER_ENDPOINT]} opened.`);
255
+ debug(`Websocket connection to ${wsEndpoint} opened.`);
203
256
  const request = {
204
257
  METHOD: 'initCall',
205
258
  SIP_CALLER_AUTO: this.caps[Capabilities.VOIP_SIP_POOL_CALLER_ENABLE],
@@ -218,6 +271,7 @@ class BotiumConnectorVoip {
218
271
  ICE_TURN_USERNAME: this.caps[Capabilities.VOIP_ICE_TURN_USER],
219
272
  ICE_TURN_PASSWORD: this.caps[Capabilities.VOIP_ICE_TURN_PASSWORD],
220
273
  ICE_TURN_PROTOCOL: this.caps[Capabilities.VOIP_ICE_TURN_PROTOCOL] || 'TCP',
274
+ MIN_SILENCE_DURATION: this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT_ENABLE] ? this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT] : null,
221
275
  STT_CONFIG: {
222
276
  stt_url: this.caps[Capabilities.VOIP_STT_URL_STREAM],
223
277
  stt_params: this.caps[Capabilities.VOIP_STT_PARAMS_STREAM],
@@ -231,110 +285,162 @@ class BotiumConnectorVoip {
231
285
  };
232
286
  debug(JSON.stringify(request, null, 2));
233
287
  this.ws.send(JSON.stringify(request));
234
- });
235
- this.ws.on('close', async () => {
236
- debug(`${this.sessionId} - Websocket connection to ${this.caps[Capabilities.VOIP_WORKER_URL]} closed.`);
237
- });
238
- this.ws.on('error', err => {
239
- debug(err);
288
+ this.ws.on('error', err => {
289
+ debug(err);
240
290
 
241
- if (!this.wsOpened) {
242
- this.end = true;
243
- reject(new Error(`${this.sessionId} - Websocket connection to ${this.caps[Capabilities.VOIP_WORKER_URL]} error: ${err.message || err}`));
244
- }
245
- });
246
- this.ws.on('message', async data => {
247
- const parsedData = JSON.parse(data);
291
+ if (!this.wsOpened) {
292
+ this.end = true;
293
+ reject(new Error(`${this.sessionId} - Websocket connection to ${wsEndpoint} error: ${err.message || err}`));
294
+ }
295
+ });
296
+ this.ws.on('message', async data => {
297
+ const parsedData = JSON.parse(data);
248
298
 
249
- const parsedDataLog = lodash__default["default"].cloneDeep(parsedData);
299
+ const parsedDataLog = lodash__default["default"].cloneDeep(parsedData);
250
300
 
251
- parsedDataLog.fullRecord = '<full_record_buffer>';
252
- debug(JSON.stringify(parsedDataLog, null, 2));
301
+ parsedDataLog.fullRecord = '<full_record_buffer>';
302
+ debug(JSON.stringify(parsedDataLog, null, 2));
253
303
 
254
- if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'initialized') {
255
- this.sessionId = parsedData.voipConfig.sessionId;
256
- }
304
+ if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'initialized') {
305
+ this.sessionId = parsedData.voipConfig.sessionId;
306
+ }
257
307
 
258
- if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'unauthorized') {
259
- reject(new Error('Error: Cannot open a call: SIP Authorization failed'));
260
- }
308
+ if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'unauthorized') {
309
+ reject(new Error('Error: Cannot open a call: SIP Authorization failed'));
310
+ }
261
311
 
262
- if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'forbidden' && parsedData.event === 'onCallRegState') {
263
- reject(new Error('Error: Sip Registration failed'));
264
- }
312
+ if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'forbidden' && parsedData.event === 'onCallRegState') {
313
+ reject(new Error('Error: Sip Registration failed'));
314
+ }
265
315
 
266
- if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'connected') {
267
- resolve();
268
- }
316
+ if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'connected') {
317
+ resolve();
318
+ }
269
319
 
270
- if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'disconnected') {
271
- const apiKey = this._extractApiKey(this._getBody(Capabilities.VOIP_STT_BODY));
320
+ if (parsedData && parsedData.type === 'callinfo' && parsedData.status === 'disconnected') {
321
+ const apiKey = this._extractApiKey(this._getBody(Capabilities.VOIP_STT_BODY));
272
322
 
273
- if (parsedData.connectDuration && parsedData.connectDuration > 0) {
274
- this.eventEmitter.emit('CONSUMPTION_METADATA', this.container, {
275
- type: lodash__default["default"].isNil(apiKey) ? 'INBUILT' : 'THIRD_PARTY',
276
- metricName: 'consumption.e2e.voip.stt.seconds',
277
- credits: parsedData.connectDuration,
278
- apiKey
279
- });
323
+ if (parsedData.connectDuration && parsedData.connectDuration > 0) {
324
+ this.eventEmitter.emit('CONSUMPTION_METADATA', this, {
325
+ type: lodash__default["default"].isNil(apiKey) ? 'INBUILT' : 'THIRD_PARTY',
326
+ metricName: 'consumption.e2e.voip.stt.seconds',
327
+ credits: parsedData.connectDuration,
328
+ apiKey
329
+ });
330
+ }
280
331
  }
281
- }
282
332
 
283
- if (parsedData && parsedData.type === 'error') {
284
- this.end = true;
285
- this.Stop();
286
- reject(new Error(`Error: ${parsedData.message}`));
287
- }
333
+ if (parsedData && parsedData.type === 'error') {
334
+ this.end = true;
335
+ reject(new Error(`Error: ${parsedData.message}`));
336
+ sendBotMsg(new Error(`Error: ${parsedData.message}`));
337
+ }
288
338
 
289
- if (parsedData && parsedData.type === 'fullRecord') {
290
- this.end = true;
291
- this.eventEmitter.emit('MESSAGE_ATTACHMENT', this.container, {
292
- name: 'full_record.wav',
293
- mimeType: 'audio/wav',
294
- base64: parsedData.fullRecord
295
- });
296
- this.Stop();
297
- }
339
+ if (parsedData && parsedData.type === 'silence') {
340
+ this.end = true;
298
341
 
299
- if (parsedData && parsedData.data && parsedData.data.final === false) {
300
- if (!this.sentenceBuilding) {
301
- this.sentenceBuilding = true;
302
- this.sentencesBuilding++;
342
+ if (parsedData.data.silence.length > 0) {
343
+ sendBotMsg(new Error(`Silence Duration of ${parsedData.data.silence[0][2].toFixed(2)}s exceeded General Silence Duration Timeout of ${this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT] / 1000}s`));
344
+ this.Stop();
345
+ }
303
346
  }
304
- }
305
347
 
306
- if (parsedData && parsedData.data && parsedData.data.final) {
307
- const botMsg = {
308
- messageText: parsedData.data.message,
309
- sourceData: parsedData
310
- };
311
- this.botMsgs.push(botMsg);
312
-
313
- if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'ORIGINAL') {
314
- this.botMsgs.forEach(botMsg => sendBotMsg(botMsg));
315
- this.botMsgs = [];
348
+ if (parsedData && parsedData.type === 'fullRecord') {
349
+ this.eventEmitter.emit('MESSAGE_ATTACHMENT', this.container, {
350
+ name: 'full_record.wav',
351
+ mimeType: 'audio/wav',
352
+ base64: parsedData.fullRecord
353
+ });
316
354
  }
317
355
 
318
- if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'EXPAND') {
319
- const botMsgsExpanded = expandBotMsgs(this.botMsgs);
320
- botMsgsExpanded.forEach(botMsg => sendBotMsg(botMsg));
321
- this.botMsgs = [];
356
+ if (parsedData && parsedData.data && parsedData.data.final === false) {
357
+ if (this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT_START_ENABLE] && parsedData.data.start && parsedData.data.start * 1000 > this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT_START]) {
358
+ sendBotMsg(new Error(`Silence Duration of ${parsedData.data.start}s exceeded Start Silence Duration Timeout of ${this.caps[Capabilities.VOIP_SILENCE_DURATION_TIMEOUT_START] / 1000}s`));
359
+ this.Stop();
360
+ }
361
+
362
+ if (this.prevData) {
363
+ if (!lodash__default["default"].isNil(parsedData.data.start) && parsedData.data.start - this.prevData.data.end > parseInt(this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_TIMEOUT]) / 1000) {
364
+ if (this.botMsgs.length > 0) {
365
+ sendBotMsg(joinBotMsg(this.botMsgs, this.joinLastPrevMsg));
366
+ this.firstMsg = false;
367
+ this.joinLastPrevMsg = this.botMsgs[this.botMsgs.length - 1];
368
+ this.botMsgs = [];
369
+ }
370
+ }
371
+ }
322
372
  }
323
373
 
324
- if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'CONCAT') {
325
- this.sentenceBuilding = false;
326
- this.sentencesFinal++;
327
- clearTimeout(this.sendMessageTimeout);
328
- this.sendMessageTimeout = setTimeout(() => {
329
- if (this.sentenceBuilding === false && this.sentencesBuilding === this.sentencesFinal) {
330
- sendBotMsg(buildBotMsg(this.botMsgs));
331
- this.botMsgs = [];
332
- this.sentencesBuilding = 0;
333
- this.sentencesFinal = 0;
374
+ if (parsedData && parsedData.data && parsedData.data.type === 'stt' && parsedData.data.final) {
375
+ if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'ORIGINAL') {
376
+ let botMsg = {
377
+ messageText: parsedData.data.message
378
+ };
379
+
380
+ if (this.firstMsg) {
381
+ const sourceData = parsedData;
382
+ sourceData.silenceDuration = parsedData.data.start;
383
+ sourceData.voiceDuration = parsedData.data.end - parsedData.data.start;
384
+ botMsg = Object.assign({}, botMsg, {
385
+ sourceData
386
+ });
387
+ this.firstMsg = false;
388
+ } else {
389
+ const sourceData = parsedData;
390
+ sourceData.silenceDuration = parsedData.data.start - this.prevData.data.end;
391
+ sourceData.voiceDuration = parsedData.data.end - parsedData.data.start;
392
+ botMsg = Object.assign({}, botMsg, {
393
+ sourceData
394
+ });
395
+ }
396
+
397
+ this.prevData = parsedData;
398
+ this.botMsgs.push(botMsg);
399
+ this.botMsgs.forEach(botMsg => sendBotMsg(botMsg));
400
+ this.botMsgs = [];
401
+ }
402
+
403
+ if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'SPLIT' || this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'EXPAND') {
404
+ let botMsg = {
405
+ messageText: parsedData.data.message
406
+ };
407
+
408
+ if (this.firstMsg) {
409
+ const sourceData = parsedData;
410
+ sourceData.silenceDuration = parsedData.data.start;
411
+ sourceData.voiceDuration = parsedData.data.end - parsedData.data.start;
412
+ botMsg = Object.assign({}, botMsg, {
413
+ sourceData
414
+ });
415
+ this.firstMsg = false;
416
+ } else {
417
+ const sourceData = parsedData;
418
+ sourceData.silenceDuration = parsedData.data.start - this.prevData.data.end;
419
+ sourceData.voiceDuration = parsedData.data.end - parsedData.data.start;
420
+ botMsg = Object.assign({}, botMsg, {
421
+ sourceData
422
+ });
334
423
  }
335
- }, this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING_TIMEOUT]);
424
+
425
+ this.prevData = parsedData;
426
+ this.botMsgs.push(botMsg);
427
+ const botMsgsExpanded = splitBotMsgs(this.botMsgs);
428
+ botMsgsExpanded.forEach(botMsg => sendBotMsg(botMsg));
429
+ this.botMsgs = [];
430
+ }
431
+
432
+ if (this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'JOIN' || this.caps[Capabilities.VOIP_STT_MESSAGE_HANDLING] === 'CONCAT') {
433
+ const botMsg = {
434
+ messageText: parsedData.data.message,
435
+ sourceData: parsedData
436
+ };
437
+ this.botMsgs.push(botMsg);
438
+ this.prevData = parsedData;
439
+ }
336
440
  }
337
- }
441
+ });
442
+ }).catch(err => {
443
+ reject(new Error('Error: ' + err));
338
444
  });
339
445
  });
340
446
  }
@@ -447,35 +553,29 @@ class BotiumConnectorVoip {
447
553
  }
448
554
 
449
555
  async Stop() {
450
- if (!this.stopCalled) {
451
- this.stopCalled = true;
452
- debug(`${this.sessionId} - Stop called`);
453
-
454
- if (this.ws && this.ws.readyState !== ws__default["default"].CLOSED) {
455
- const request = JSON.stringify({
456
- METHOD: 'stopCall',
457
- sessionId: this.sessionId
458
- });
459
- this.ws.send(request);
460
- await new Promise(resolve => {
461
- setTimeout(resolve, 50000);
462
- setInterval(() => {
463
- if (this.end) {
464
- this.wsOpened = false;
465
- this.ws = null;
466
- this.view = {};
467
- resolve();
468
- }
469
- }, 1000);
470
- });
471
- /* if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {
472
- this.ws.close()
473
- } */
474
- } else {
475
- this.wsOpened = false;
476
- this.ws = null;
477
- this.view = {};
478
- }
556
+ debug(`${this.sessionId} - Stop called`);
557
+
558
+ if (this.ws && this.ws.readyState !== ws__default["default"].CLOSED) {
559
+ const request = JSON.stringify({
560
+ METHOD: 'stopCall',
561
+ sessionId: this.sessionId
562
+ });
563
+ this.ws.send(request);
564
+ await new Promise(resolve => {
565
+ setTimeout(resolve, 10000);
566
+ setInterval(() => {
567
+ if (this.end) {
568
+ this.wsOpened = false;
569
+ this.ws = null;
570
+ this.view = {};
571
+ resolve();
572
+ }
573
+ }, 1000);
574
+ });
575
+ } else {
576
+ this.wsOpened = false;
577
+ this.ws = null;
578
+ this.view = {};
479
579
  }
480
580
  }
481
581