@subiz/wsclient 4.0.16 → 4.0.18

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.
Files changed (4) hide show
  1. package/common.js +16 -1
  2. package/package.json +2 -2
  3. package/webphone.js +183 -0
  4. package/webrtc.js +18 -23
package/common.js CHANGED
@@ -63,4 +63,19 @@ function Pubsub() {
63
63
  }
64
64
  }
65
65
 
66
- module.exports = {xhrsend, parseJSON, Pubsub}
66
+ function randomString(len, base) {
67
+ var str = ''
68
+ if (!len || len < 1) len = 10
69
+ var asciiKey
70
+ for (var i = 0; i < len; i++) {
71
+ if (base) {
72
+ str += base[Math.floor(Math.random() * base.length)]
73
+ } else {
74
+ asciiKey = Math.floor(Math.random() * 25 + 97)
75
+ str += String.fromCharCode(asciiKey)
76
+ }
77
+ }
78
+ return str
79
+ }
80
+
81
+ module.exports = {xhrsend, parseJSON, Pubsub, randomString}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@subiz/wsclient",
3
- "version": "4.0.16",
3
+ "version": "4.0.18",
4
4
  "main": "realtime.js",
5
5
  "scripts": {
6
6
  "test": "node realtime.test.js"
@@ -14,7 +14,7 @@
14
14
  "homepage": "https://github.com/subiz/wsclient#readme",
15
15
  "description": "",
16
16
  "devDependencies": {
17
- "tape": "^5.6.3"
17
+ "tape": "^5.7.2"
18
18
  },
19
19
  "dependencies": {
20
20
  "@subiz/flow": "^1.1.0",
package/webphone.js ADDED
@@ -0,0 +1,183 @@
1
+ var {xhrsend, parseJSON, Pubsub, randomString} = require('./common.js')
2
+ const WebRTCConn = require('./webrtc.js')
3
+ var Realtime = require('./realtime.js')
4
+
5
+ function WebPhone(access_token, realtime) {
6
+ var pubsub = new Pubsub()
7
+
8
+ var $audio = null
9
+ // chuẩn bị thẻ audio để nghe được
10
+ function createAudioTag() {
11
+ if ($audio) return
12
+ if (!document.createElement) return // mobile
13
+
14
+ $audio = document.createElement('audio')
15
+ $audio.id = 'web_call_audio'
16
+ $audio.style = 'display: none'
17
+ $audio.autoplay = 'autoplay'
18
+ document.body.appendChild($audio)
19
+ }
20
+
21
+ createAudioTag()
22
+
23
+ access_token = access_token || ''
24
+ if (!access_token) throw 'invalid_access_token'
25
+ var accid = access_token.split('_')[0]
26
+ if (!accid.startsWith('ac')) throw 'invalid_access_token'
27
+ var agid = access_token.split('_')[1]
28
+ if (!agid.startsWith('ag')) throw 'invalid_access_token'
29
+
30
+ if (!realtime)
31
+ realtime = new Realtime('https://api.subiz.com.vn/rt/0/', {
32
+ getAccessToken: function () {
33
+ return new Promise(function (rs) {
34
+ rs(access_token)
35
+ })
36
+ },
37
+ })
38
+
39
+ var webrtcconn = new WebRTCConn({
40
+ accid: accid,
41
+ agid: agid,
42
+ access_token: access_token,
43
+ realtime,
44
+ env: window,
45
+ onEvent: function (ev) {
46
+ // publish call status event
47
+ if (!(ev.type || '').startsWith('call')) return
48
+ if (!ev.data || !ev.data.call_info) return
49
+ let callid = ev.data.call_info.call_id
50
+ if (!callid) return
51
+ pubsub.emit('event', ev)
52
+ },
53
+ onTrack: function (event) {
54
+ if (event.track.kind != 'audio') return
55
+ $audio.srcObject = event.streams[0]
56
+ },
57
+ })
58
+
59
+ this.onEvent = function (cb) {
60
+ return pubsub.on('event', cb)
61
+ }
62
+
63
+ this.sendDtmf = function (key, callid) {
64
+ return webrtcconn.sendDtmf(key, callid)
65
+ }
66
+
67
+ this.transferCall = function (number, callid) {
68
+ return webrtcconn.transferCall(number, callid)
69
+ }
70
+
71
+ this.hangupCall = function (callid) {
72
+ if (!callid) callid = current_call_id
73
+ return webrtcconn.hangupCall(callid)
74
+ }
75
+
76
+ var me = this
77
+ this.isMicAllowed = function () {
78
+ return me.checkMic().then(function (out) {
79
+ return out.result
80
+ })
81
+ }
82
+
83
+ var micStream = undefined
84
+ this.getMicroStream = function () {
85
+ return micStream
86
+ }
87
+
88
+ this.checkMic = function () {
89
+ const timeout = new Promise(function (rs, rj) {
90
+ return setTimeout(rs, 500, 'Not_authorized')
91
+ })
92
+ var microPermission = getMicroPermissions()
93
+ return {
94
+ timeout: Promise.race([timeout, microPermission]),
95
+ result: getMicroPermissions(),
96
+ }
97
+ }
98
+
99
+ var getMicroPermissions = function () {
100
+ return new Promise(function (rs) {
101
+ navigator.mediaDevices
102
+ .getUserMedia({audio: true, video: false})
103
+ .then(function (stream) {
104
+ micStream = stream
105
+ rs(micStream)
106
+ })
107
+ .catch(function (err) {
108
+ console.log('REJECT VIDEO PERMISSSIONN', err)
109
+ micStream = undefined
110
+ rs(undefined)
111
+ })
112
+ })
113
+ }
114
+
115
+ this.answerWebCall = function (callid) {
116
+ return new Promise(function (rs) {
117
+ getMicroPermissions().then(function (stream) {
118
+ current_call_id = callid
119
+ webrtcconn.answerCall(callid, stream).then(function (out) {
120
+ if (out.error) return rs({error})
121
+ rs(body)
122
+ })
123
+ })
124
+ })
125
+ }
126
+
127
+ this.getCall = function (callid) {
128
+ return webrtcconn.matchCall(callid)
129
+ }
130
+
131
+ var base = '0123456789abcdef'
132
+ this.makeCall = function (number, fromnumber) {
133
+ // '11edc52b-2918-4d71-9058-f7285e29d894'
134
+ var callid =
135
+ randomString(8, base) +
136
+ '-' +
137
+ randomString(4, base) +
138
+ '-' +
139
+ randomString(4, base) +
140
+ '-' +
141
+ randomString(4, base) +
142
+ '-' +
143
+ randomString(12, base)
144
+
145
+ current_call_id = callid
146
+ return webrtcconn.makeCall(number, fromnumber, getMicroPermissions(), callid)
147
+ }
148
+
149
+ var current_call_id = ''
150
+ this.getCurrentCallId = function () {
151
+ return current_call_id
152
+ }
153
+
154
+ this.getCurrentCall = function () {
155
+ if (current_call_id) {
156
+ var call = webrtcconn.matchCall(current_call_id)
157
+ if (call && call.status != 'ended') return call
158
+ }
159
+
160
+ var myOutgoingCall = Object.values(webrtcconn.matchCall()).find(function (call) {
161
+ var isOutboundCall = call.direction == 'outbound' || call.direction == 'outgoing'
162
+ return (call.status == 'dialing' || call.status == 'active') && isOutboundCall
163
+ })
164
+ if (myOutgoingCall) {
165
+ current_call_id = myOutgoingCall.call_id || ''
166
+ return myOutgoingCall
167
+ }
168
+
169
+ var dialingIncomingCall = Object.values(webrtcconn.matchCall()).find(function (call) {
170
+ return call.status == 'dialing' && (call.direction == 'incoming' || call.direction == 'inbound')
171
+ })
172
+ if (dialingIncomingCall) {
173
+ current_call_id = dialingIncomingCall.call_id || ''
174
+ return dialingIncomingCall
175
+ }
176
+
177
+ current_call_id = ''
178
+ return undefined
179
+ }
180
+ }
181
+
182
+ window.SbzWebPhone1 = WebPhone
183
+ module.exports = WebPhone
package/webrtc.js CHANGED
@@ -1,5 +1,5 @@
1
1
  var flow = require('@subiz/flow')
2
- var {xhrsend} = require('./common.js')
2
+ var {xhrsend, randomString} = require('./common.js')
3
3
  const servers = {
4
4
  iceServers: [{urls: ['stun:stun.l.google.com:19302']}],
5
5
  }
@@ -59,7 +59,6 @@ function WebRTCConn(options) {
59
59
  ])
60
60
  .then((err) => {
61
61
  // create peer connection
62
-
63
62
  cb(err, connId)
64
63
  })
65
64
  }
@@ -109,7 +108,11 @@ function WebRTCConn(options) {
109
108
  if (!call.hangup_code) call.hangup_code = 'cancel'
110
109
  if (call.status != 'ended') {
111
110
  call.status = 'ended'
112
- publish({type: 'call_ended', data: {call_info: {hanup_code: 'outdated', call_id: callid}}})
111
+ publish({
112
+ created: env.Date.now(),
113
+ type: 'call_ended',
114
+ data: {call_info: {hanup_code: 'outdated', call_id: callid}},
115
+ })
113
116
  }
114
117
  })
115
118
 
@@ -255,7 +258,7 @@ function WebRTCConn(options) {
255
258
  }
256
259
 
257
260
  if (ev.type == 'webrtc_negotiation_offered') {
258
- console.log('RT/RECEIVE OFFERED NEGOTIATION', ev)
261
+ // console.log('RT/RECEIVE OFFERED NEGOTIATION', ev)
259
262
  let jsonoffer = ev && ev.data && ev.data.webrtc_message && ev.data.webrtc_message.offer
260
263
  let connId = ev && ev.data && ev.data.webrtc_message && ev.data.webrtc_message.connection_id
261
264
  let peer = peers[connId]
@@ -311,6 +314,7 @@ function WebRTCConn(options) {
311
314
 
312
315
  if (ev.type === 'call_invite_expired') {
313
316
  if (Object.keys(peers).find((cid) => cid == call_info.device_id)) return // this call invitation is expired by us => ignore
317
+ serverCalls[callid] = call_info
314
318
  publish(Object.assign({}, ev, {type: 'call_ended'})) // fake ended call
315
319
  return
316
320
  }
@@ -337,7 +341,7 @@ function WebRTCConn(options) {
337
341
  from_number: fromnumber,
338
342
  }
339
343
  dialingRequest[callid] = call
340
- publish({type: 'call_ringing', data: {call_info: {call_id: callid}}}) // fake dialing
344
+ publish({created: now, type: 'call_ringing', data: {call_info: {call_id: callid}}}) // fake dialing
341
345
  return new env.Promise((rs) => {
342
346
  streamPm
343
347
  .then((stream) => {
@@ -345,16 +349,18 @@ function WebRTCConn(options) {
345
349
  if (err) {
346
350
  delete dialingRequest[callid]
347
351
  endRequest[callid] = env.Date.now()
348
- publish({type: 'call_ended', data: {call_info: {call_id: callid}}})
352
+ publish({created: env.Date.now(), type: 'call_ended', data: {call_info: {call_id: callid}}})
349
353
  return rs({error: err})
350
354
  }
351
355
 
352
- let url = `${apiUrl}call?x-access-token=${access_token}&connection_id=${connId}&call_id=${callid}&number=${number}&from_number=${fromnumber}&campaign_id=${campaignid}&outbound_call_entry_id=${outboundcallentryid}`
356
+ let url = `${apiUrl}call?x-access-token=${access_token}&connection_id=${connId}&call_id=${callid}&number=${number}&from_number=${fromnumber}`
357
+ if (outboundcallentryid) url += `&outbound_call_entry_id=${outboundcallentryid}`
358
+ if (campaignid) url += `&campaign_id=${campaignid}`
353
359
  callAPI('post', url, undefined, (body, code) => {
354
360
  if (code != 200) {
355
361
  delete dialingRequest[callid]
356
362
  endRequest[callid] = env.Date.now()
357
- publish({type: 'call_ended', data: {call_info: {call_id: callid}}})
363
+ publish({created: env.Date.now(), type: 'call_ended', data: {call_info: {call_id: callid}}})
358
364
  return rs({error: err})
359
365
  }
360
366
  body = parseJSON(body)
@@ -379,7 +385,7 @@ function WebRTCConn(options) {
379
385
  }
380
386
  call.status = 'ended'
381
387
  call.ended = env.Date.now()
382
- publish({type: 'call_ended', data: {call_info: {call_id: callid}}})
388
+ publish({created: env.Date.now(), type: 'call_ended', data: {call_info: {call_id: callid}}})
383
389
  callAPI('post', `${apiUrl}hangup?x-access-token=${access_token}&call_id=${callid}`)
384
390
  }
385
391
 
@@ -411,13 +417,13 @@ function WebRTCConn(options) {
411
417
  let now = env.Date.now()
412
418
  if (answerRequest[callid]) return Promise.resolve({body: call})
413
419
  answerRequest[callid] = now
414
- publish({type: 'call_ringing', data: {call_info: {call_id: callid}}}) // fake dialing
420
+ publish({created: env.Date.now(), type: 'call_ringing', data: {call_info: {call_id: callid}}}) // fake dialing
415
421
  return new env.Promise((rs) => {
416
422
  this.joinCall(callid, stream, (err, connId) => {
417
423
  if (err) {
418
424
  delete answerRequest[callid]
419
425
  endRequest[callid] = now
420
- publish({type: 'call_ended', data: {call_info: {call_id: callid}}})
426
+ publish({created: env.Date.now(), type: 'call_ended', data: {call_info: {call_id: callid}}})
421
427
  return rs({error: err})
422
428
  }
423
429
  let url = `${apiUrl}answer?x-access-token=${access_token}&connection_id=${connId}&call_id=${callid}`
@@ -426,7 +432,7 @@ function WebRTCConn(options) {
426
432
  if (code != 200) {
427
433
  delete answerRequest[callid]
428
434
  endRequest[callid] = now
429
- publish({type: 'call_ended', data: {call_info: {call_id: callid}}})
435
+ publish({created: env.Date.now(), type: 'call_ended', data: {call_info: {call_id: callid}}})
430
436
  return rs({error: body})
431
437
  }
432
438
  return rs({body})
@@ -465,15 +471,4 @@ function WebRTCConn(options) {
465
471
  })
466
472
  }
467
473
 
468
- function randomString(len) {
469
- var str = ''
470
- if (!len || len < 1) len = 10
471
- var asciiKey
472
- for (var i = 0; i < len; i++) {
473
- asciiKey = Math.floor(Math.random() * 25 + 97)
474
- str += String.fromCharCode(asciiKey)
475
- }
476
- return str
477
- }
478
-
479
474
  module.exports = WebRTCConn