@subiz/wsclient 4.0.17 → 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 +17 -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.17",
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.7.1"
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]
@@ -338,7 +341,7 @@ function WebRTCConn(options) {
338
341
  from_number: fromnumber,
339
342
  }
340
343
  dialingRequest[callid] = call
341
- 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
342
345
  return new env.Promise((rs) => {
343
346
  streamPm
344
347
  .then((stream) => {
@@ -346,16 +349,18 @@ function WebRTCConn(options) {
346
349
  if (err) {
347
350
  delete dialingRequest[callid]
348
351
  endRequest[callid] = env.Date.now()
349
- 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}}})
350
353
  return rs({error: err})
351
354
  }
352
355
 
353
- 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}`
354
359
  callAPI('post', url, undefined, (body, code) => {
355
360
  if (code != 200) {
356
361
  delete dialingRequest[callid]
357
362
  endRequest[callid] = env.Date.now()
358
- 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}}})
359
364
  return rs({error: err})
360
365
  }
361
366
  body = parseJSON(body)
@@ -380,7 +385,7 @@ function WebRTCConn(options) {
380
385
  }
381
386
  call.status = 'ended'
382
387
  call.ended = env.Date.now()
383
- 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}}})
384
389
  callAPI('post', `${apiUrl}hangup?x-access-token=${access_token}&call_id=${callid}`)
385
390
  }
386
391
 
@@ -412,13 +417,13 @@ function WebRTCConn(options) {
412
417
  let now = env.Date.now()
413
418
  if (answerRequest[callid]) return Promise.resolve({body: call})
414
419
  answerRequest[callid] = now
415
- 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
416
421
  return new env.Promise((rs) => {
417
422
  this.joinCall(callid, stream, (err, connId) => {
418
423
  if (err) {
419
424
  delete answerRequest[callid]
420
425
  endRequest[callid] = now
421
- 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}}})
422
427
  return rs({error: err})
423
428
  }
424
429
  let url = `${apiUrl}answer?x-access-token=${access_token}&connection_id=${connId}&call_id=${callid}`
@@ -427,7 +432,7 @@ function WebRTCConn(options) {
427
432
  if (code != 200) {
428
433
  delete answerRequest[callid]
429
434
  endRequest[callid] = now
430
- 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}}})
431
436
  return rs({error: body})
432
437
  }
433
438
  return rs({body})
@@ -466,15 +471,4 @@ function WebRTCConn(options) {
466
471
  })
467
472
  }
468
473
 
469
- function randomString(len) {
470
- var str = ''
471
- if (!len || len < 1) len = 10
472
- var asciiKey
473
- for (var i = 0; i < len; i++) {
474
- asciiKey = Math.floor(Math.random() * 25 + 97)
475
- str += String.fromCharCode(asciiKey)
476
- }
477
- return str
478
- }
479
-
480
474
  module.exports = WebRTCConn