@phonghq/go-chat 1.0.11 → 1.0.14
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/dist/assets/icons/IconAiCheck.vue.d.ts +2 -0
- package/dist/assets/icons/call/IconClose.vue.d.ts +2 -0
- package/dist/assets/icons/call/IconSoundDownload.vue.d.ts +2 -0
- package/dist/chat/App.vue.d.ts +7 -2
- package/dist/chat/page/customer-detail/CustomerDetail.vue.d.ts +1 -1
- package/dist/chat/page/home/ChatList.vue.d.ts +29 -1
- package/dist/chat/page/home/ChatMessage.vue.d.ts +2 -1
- package/dist/chat/page/home/Home.vue.d.ts +1 -1
- package/dist/components/chat/ScrollEvent/ScrollEvent.vue.d.ts +1 -0
- package/dist/components/chat/call/Calling.vue.d.ts +8 -2
- package/dist/components/chat/common/input/InputSearch.vue.d.ts +1 -1
- package/dist/components/chat/select/SelectBase.vue.d.ts +22 -0
- package/dist/components/common/drawer/DrawerBase.vue.d.ts +1 -1
- package/dist/components/common/modal/ModalBase.vue.d.ts +1 -1
- package/dist/composable/useCallHelper.d.ts +7 -2
- package/dist/composable/useInitData.d.ts +2 -4
- package/dist/composable/usePlivo.d.ts +9 -0
- package/dist/go-chat.es.js +14676 -12322
- package/dist/go-chat.umd.js +44 -14
- package/dist/plugins/websocket.d.ts +12 -2
- package/dist/router/index.d.ts +2 -0
- package/dist/style.css +1 -1
- package/dist/test/assets/icons/IconAiCheck.vue.js +28 -0
- package/dist/test/assets/icons/call/IconClose.vue.js +26 -0
- package/dist/test/assets/icons/call/IconMic.vue.js +9 -9
- package/dist/test/assets/icons/call/IconSoundDownload.vue.js +50 -0
- package/dist/test/chat/App.vue.js +144 -90
- package/dist/test/chat/page/customer-detail/CustomerDetail.vue.js +6 -5
- package/dist/test/chat/page/home/ChatList.vue.js +30 -9
- package/dist/test/chat/page/home/ChatMessage.vue.js +23 -12
- package/dist/test/chat/page/home/Home.vue.js +4 -3
- package/dist/test/chat/page/home/NewCustomer.vue.js +0 -12
- package/dist/test/components/chat/ScrollEvent/ScrollEvent.vue.js +7 -1
- package/dist/test/components/chat/call/Calling.vue.js +277 -111
- package/dist/test/components/chat/common/input/InputSearch.vue.js +2 -2
- package/dist/test/components/chat/select/SelectBase.vue.js +98 -0
- package/dist/test/components/common/drawer/DrawerBaseCustom.vue.js +0 -1
- package/dist/test/composable/data.json +32 -0
- package/dist/test/composable/useCallHelper.js +146 -33
- package/dist/test/composable/useDigibot.js +1 -1
- package/dist/test/composable/useInitData.js +17 -12
- package/dist/test/composable/usePlivo.js +138 -0
- package/dist/test/constant/color.js +1 -1
- package/dist/test/plugins/axios.js +2 -1
- package/dist/test/plugins/mqtt.js +11 -8
- package/dist/test/plugins/websocket.js +108 -19
- package/dist/test/router/index.js +39 -0
- package/dist/test/types/call.js +10 -1
- package/dist/test/utils/chat/auth.js +10 -2
- package/dist/test/utils/chat/call.js +48 -8
- package/dist/test/utils/chat/phone-string.js +4 -0
- package/dist/test/utils/chat/user.js +7 -2
- package/dist/test/views/NotFound.vue.js +47 -0
- package/dist/test/views/TenantPhone.vue.js +270 -0
- package/dist/types/call.d.ts +9 -0
- package/dist/types/chat/global.d.ts +4 -0
- package/dist/utils/chat/auth.d.ts +5 -1
- package/dist/utils/chat/call.d.ts +6 -2
- package/dist/utils/chat/phone-string.d.ts +1 -0
- package/dist/utils/chat/user.d.ts +4 -0
- package/dist/views/NotFound.vue.d.ts +2 -0
- package/dist/views/TenantPhone.vue.d.ts +2 -0
- package/package.json +2 -1
- package/dist/composable/TestSound.d.ts +0 -64
- package/dist/test/composable/TestSound.js +0 -196
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "audio_chunk",
|
|
4
|
+
"size_bytes": 160,
|
|
5
|
+
"hex_preview": "36 25 39 bb c0 41 48 bc c3 32 27 3f c7 f6 ee aa 9f ae b3 9e",
|
|
6
|
+
"samples_count": 160
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"type": "audio_chunk",
|
|
10
|
+
"size_bytes": 160,
|
|
11
|
+
"hex_preview": "3f d9 ac b3 3d 3b b9 a8 ac b4 b3 ac af bc ae 9e 9b a5 ac a9",
|
|
12
|
+
"samples_count": 160
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"type": "audio_chunk",
|
|
16
|
+
"size_bytes": 160,
|
|
17
|
+
"hex_preview": "b1 a3 b3 a9 a8 a8 ae a3 a7 a6 a6 a8 a7 ab a9 ad af ae aa a6 ab",
|
|
18
|
+
"samples_count": 160
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"type": "audio_chunk",
|
|
22
|
+
"size_bytes": 160,
|
|
23
|
+
"hex_preview": "b3 b1 b2 b0 ae ae b0 b2 b3 b1 b1 b0 b0 af af ae ae ae ad ac ac",
|
|
24
|
+
"samples_count": 160
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "audio_chunk",
|
|
28
|
+
"size_bytes": 160,
|
|
29
|
+
"hex_preview": "ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad ad",
|
|
30
|
+
"samples_count": 160
|
|
31
|
+
}
|
|
32
|
+
]
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { plivoCall, plivoEndCall } from '../utils/chat/call';
|
|
1
|
+
import { callClient, plivoCall, plivoEndCall } from '../utils/chat/call';
|
|
2
|
+
import { dataProfile } from '../utils/chat/auth';
|
|
2
3
|
import { ref } from 'vue';
|
|
3
|
-
import {
|
|
4
|
+
import { WebSocketClient } from '../plugins/websocket';
|
|
5
|
+
import dataJson from './data.json';
|
|
4
6
|
export function useCallHelper() {
|
|
5
|
-
function _getAudioContext() {
|
|
7
|
+
function _getAudioContext(sampleRate) {
|
|
6
8
|
return new (window.AudioContext || window.webkitAudioContext)({
|
|
7
|
-
sampleRate:
|
|
9
|
+
sampleRate: sampleRate ?? PLIVO_SAMPLE_RATE
|
|
8
10
|
});
|
|
9
11
|
}
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
+
const PLIVO_SAMPLE_RATE = 8000;
|
|
13
|
+
const SAMPLE_RATE = 48000;
|
|
14
|
+
const CHUNK_LENGTH = 160;
|
|
15
|
+
const uuid = ref('');
|
|
12
16
|
let audioCtxListen = _getAudioContext();
|
|
13
17
|
let audioCtxCall = _getAudioContext();
|
|
14
18
|
let prebuffer = [];
|
|
@@ -17,7 +21,10 @@ export function useCallHelper() {
|
|
|
17
21
|
let sourceCall;
|
|
18
22
|
let loopTimer = null;
|
|
19
23
|
let running = false;
|
|
24
|
+
let loopId = null;
|
|
20
25
|
const userRemoter = ref(null);
|
|
26
|
+
let websocket = null;
|
|
27
|
+
let stream;
|
|
21
28
|
function _int16ToFloat32(int16Array) {
|
|
22
29
|
const float32 = new Float32Array(int16Array.length);
|
|
23
30
|
for (let i = 0; i < int16Array.length; i++) {
|
|
@@ -114,34 +121,59 @@ export function useCallHelper() {
|
|
|
114
121
|
}
|
|
115
122
|
return int16Array;
|
|
116
123
|
}
|
|
124
|
+
function _resample8kTo48k(float8k) {
|
|
125
|
+
const ratio = 48000 / 8000;
|
|
126
|
+
const float48k = new Float32Array(float8k.length * ratio);
|
|
127
|
+
for (let i = 0; i < float48k.length; i++) {
|
|
128
|
+
float48k[i] = float8k[Math.floor(i / ratio)] || 0;
|
|
129
|
+
}
|
|
130
|
+
return float48k;
|
|
131
|
+
}
|
|
117
132
|
const call = async (user) => {
|
|
118
133
|
userRemoter.value = user;
|
|
119
|
-
uuid = '';
|
|
134
|
+
uuid.value = '';
|
|
120
135
|
const res = await plivoCall(user);
|
|
121
|
-
|
|
122
|
-
uuid = res?.call?.requestUuid;
|
|
136
|
+
uuid.value = res?.call?.requestUuid;
|
|
123
137
|
};
|
|
124
|
-
const end = async (
|
|
138
|
+
const end = async () => {
|
|
125
139
|
processorCall?.disconnect?.();
|
|
126
140
|
sourceCall?.disconnect?.(processorCall);
|
|
127
141
|
stopQueue();
|
|
128
|
-
|
|
142
|
+
websocket?.disconnect();
|
|
143
|
+
stream?.getAudioTracks?.()?.forEach((track) => track?.stop());
|
|
129
144
|
if (!uuid)
|
|
130
145
|
return;
|
|
131
|
-
await plivoEndCall(uuid);
|
|
146
|
+
await plivoEndCall(uuid.value);
|
|
132
147
|
return;
|
|
133
148
|
};
|
|
134
149
|
const startPeerConnection = async () => {
|
|
135
150
|
try {
|
|
136
|
-
|
|
151
|
+
if (!audioCtxCall) {
|
|
152
|
+
audioCtxCall = _getAudioContext();
|
|
153
|
+
}
|
|
154
|
+
if (audioCtxCall.state === 'suspended')
|
|
155
|
+
await audioCtxCall.resume();
|
|
156
|
+
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
137
157
|
sourceCall = audioCtxCall.createMediaStreamSource(stream);
|
|
138
|
-
processorCall
|
|
158
|
+
processorCall = audioCtxCall.createScriptProcessor(256, 1, 1);
|
|
139
159
|
processorCall.onaudioprocess = (e) => {
|
|
140
160
|
const input = e.inputBuffer.getChannelData(0);
|
|
141
|
-
for (let i = 0; i < input.length; i +=
|
|
142
|
-
const slice = input.slice(i, i +
|
|
161
|
+
for (let i = 0; i < input.length; i += CHUNK_LENGTH) {
|
|
162
|
+
const slice = input.slice(i, i + CHUNK_LENGTH);
|
|
143
163
|
const binaryChunk = _float32ToMuLaw8(slice);
|
|
144
|
-
socketSend(binaryChunk)
|
|
164
|
+
// socketSend(binaryChunk)
|
|
165
|
+
// const data = {
|
|
166
|
+
// event: 'testPlaySound',
|
|
167
|
+
// media: {
|
|
168
|
+
// payload: binaryChunk
|
|
169
|
+
// }
|
|
170
|
+
// }
|
|
171
|
+
// console.log(data)
|
|
172
|
+
// addQueueListen(binaryChunk)
|
|
173
|
+
// socketSend(binaryChunk)
|
|
174
|
+
// websocket.binaryType = "arraybuffer";
|
|
175
|
+
// console.log(binaryChunk)
|
|
176
|
+
// websocket.sendDefault(binaryChunk)
|
|
145
177
|
}
|
|
146
178
|
};
|
|
147
179
|
sourceCall.connect(processorCall);
|
|
@@ -160,59 +192,135 @@ export function useCallHelper() {
|
|
|
160
192
|
// const float32Data = int16ToFloat32(int16View)
|
|
161
193
|
const floatData = _muLawToFloat32(ulawBytes);
|
|
162
194
|
prebuffer.push(floatData);
|
|
195
|
+
if (prebuffer.length > 3) {
|
|
196
|
+
prebuffer.shift(); // bỏ gói cũ
|
|
197
|
+
}
|
|
163
198
|
};
|
|
164
199
|
async function scheduleNext() {
|
|
165
200
|
try {
|
|
166
201
|
const chunk = prebuffer.shift();
|
|
167
202
|
if (chunk) {
|
|
168
|
-
const
|
|
203
|
+
const float48k = _resample8kTo48k(chunk);
|
|
204
|
+
const audioBuffer = audioCtxListen.createBuffer(1, chunk.length, PLIVO_SAMPLE_RATE);
|
|
169
205
|
audioBuffer.getChannelData(0).set(chunk);
|
|
170
206
|
const source = audioCtxListen.createBufferSource();
|
|
171
207
|
source.buffer = audioBuffer;
|
|
172
208
|
source.connect(audioCtxListen.destination);
|
|
209
|
+
// console.log(
|
|
210
|
+
// 'Scheduling chunk',
|
|
211
|
+
// 'nextPlayTime:', nextPlayTime,
|
|
212
|
+
// 'currentTime:', audioCtxListen.currentTime
|
|
213
|
+
// );
|
|
214
|
+
if (nextPlayTime < audioCtxListen.currentTime + (CHUNK_LENGTH / PLIVO_SAMPLE_RATE)) {
|
|
215
|
+
nextPlayTime = audioCtxListen.currentTime + (CHUNK_LENGTH / PLIVO_SAMPLE_RATE);
|
|
216
|
+
}
|
|
173
217
|
source.start(nextPlayTime);
|
|
174
|
-
|
|
218
|
+
// console.log(
|
|
219
|
+
// 'Started chunk',
|
|
220
|
+
// 'sourceStartTime:', nextPlayTime,
|
|
221
|
+
// 'audioCtxCurrentTime:', audioCtxListen.currentTime
|
|
222
|
+
// );
|
|
223
|
+
// nextPlayTime += audioBuffer.duration
|
|
224
|
+
nextPlayTime += audioBuffer.duration;
|
|
175
225
|
}
|
|
176
226
|
}
|
|
177
227
|
catch (e) {
|
|
178
228
|
console.log(e);
|
|
179
229
|
}
|
|
180
230
|
}
|
|
231
|
+
let startTime = 0;
|
|
181
232
|
const playQueueLoop = () => {
|
|
182
233
|
if (!running)
|
|
183
234
|
return;
|
|
184
235
|
while (prebuffer.length > 0 && nextPlayTime < audioCtxListen.currentTime + 0.1) {
|
|
185
236
|
scheduleNext();
|
|
186
237
|
}
|
|
187
|
-
|
|
238
|
+
loopId = requestAnimationFrame(playQueueLoop);
|
|
188
239
|
};
|
|
240
|
+
async function processSpeakerQueue() {
|
|
241
|
+
try {
|
|
242
|
+
// console.log(prebuffer)
|
|
243
|
+
if (prebuffer.length > 0) {
|
|
244
|
+
const chunk = prebuffer.shift();
|
|
245
|
+
if (chunk) {
|
|
246
|
+
// console.log(chunk.length)
|
|
247
|
+
const audioBuffer = audioCtxListen.createBuffer(1, chunk.length, 8000);
|
|
248
|
+
audioBuffer.getChannelData(0).set(chunk);
|
|
249
|
+
const source = audioCtxListen.createBufferSource();
|
|
250
|
+
source.buffer = audioBuffer;
|
|
251
|
+
source.connect(audioCtxListen.destination);
|
|
252
|
+
if (nextPlayTime < audioCtxListen.currentTime + audioBuffer.duration) {
|
|
253
|
+
nextPlayTime = audioCtxListen.currentTime + audioBuffer.duration;
|
|
254
|
+
}
|
|
255
|
+
source.start(nextPlayTime);
|
|
256
|
+
// console.log(`🎧 Played samples (${audioBuffer.duration.toFixed(3)}s)`);
|
|
257
|
+
nextPlayTime += audioBuffer.duration;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
console.log(e);
|
|
263
|
+
}
|
|
264
|
+
requestAnimationFrame(processSpeakerQueue);
|
|
265
|
+
}
|
|
189
266
|
function stopQueue() {
|
|
190
267
|
running = false;
|
|
191
268
|
if (loopTimer)
|
|
192
269
|
clearTimeout(loopTimer);
|
|
270
|
+
if (loopId !== null) {
|
|
271
|
+
cancelAnimationFrame(loopId);
|
|
272
|
+
loopId = null;
|
|
273
|
+
}
|
|
193
274
|
prebuffer.length = 0;
|
|
194
275
|
}
|
|
195
276
|
const handleMedia = async (message) => {
|
|
196
277
|
addQueueListen(message);
|
|
197
278
|
};
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
279
|
+
const handleMqttMessage = async (message) => {
|
|
280
|
+
handleMedia(message);
|
|
281
|
+
};
|
|
282
|
+
const startIncomingCall = async (uuid_request) => {
|
|
283
|
+
try {
|
|
284
|
+
if (uuid_request && uuid_request != uuid.value) {
|
|
285
|
+
throw new Error('This call isn’t yours');
|
|
286
|
+
}
|
|
287
|
+
websocket = new WebSocketClient(uuid_request, handleMqttMessage);
|
|
288
|
+
await websocket?.init();
|
|
289
|
+
if (running)
|
|
290
|
+
return;
|
|
291
|
+
running = true;
|
|
292
|
+
if (!audioCtxListen) {
|
|
293
|
+
audioCtxListen = _getAudioContext();
|
|
294
|
+
}
|
|
295
|
+
if (audioCtxListen.state === 'suspended')
|
|
296
|
+
await audioCtxListen.resume();
|
|
297
|
+
nextPlayTime = audioCtxListen.currentTime;
|
|
298
|
+
playQueueLoop();
|
|
299
|
+
// processSpeakerQueue()
|
|
300
|
+
}
|
|
301
|
+
catch (e) {
|
|
302
|
+
end();
|
|
303
|
+
throw new Error(e);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
const testPlay = () => {
|
|
307
|
+
for (let i = 0; i < dataJson.length; i++) {
|
|
308
|
+
addQueueListen(dataJson[i]);
|
|
201
309
|
}
|
|
202
|
-
if (audioCtxCall.state === 'suspended')
|
|
203
|
-
await audioCtxCall.resume();
|
|
204
|
-
await startPeerConnection();
|
|
205
310
|
if (running)
|
|
206
311
|
return;
|
|
207
312
|
running = true;
|
|
208
|
-
if (!audioCtxListen) {
|
|
209
|
-
audioCtxListen = _getAudioContext();
|
|
210
|
-
}
|
|
211
|
-
if (audioCtxListen.state === 'suspended')
|
|
212
|
-
await audioCtxListen.resume();
|
|
213
|
-
nextPlayTime = audioCtxListen.currentTime;
|
|
214
313
|
playQueueLoop();
|
|
215
314
|
};
|
|
315
|
+
const handleCallAnswer = (data) => {
|
|
316
|
+
uuid.value = data?.data?.call_uuid ?? '';
|
|
317
|
+
};
|
|
318
|
+
const callAnswer = async (uuid_request) => {
|
|
319
|
+
if (uuid_request && uuid_request != uuid.value) {
|
|
320
|
+
throw new Error('This call isn’t yours');
|
|
321
|
+
}
|
|
322
|
+
await callClient({ call_uuid: uuid.value, clientId: dataProfile.value?.tenant_id ?? '' });
|
|
323
|
+
};
|
|
216
324
|
return {
|
|
217
325
|
call,
|
|
218
326
|
end,
|
|
@@ -221,6 +329,11 @@ export function useCallHelper() {
|
|
|
221
329
|
sendOfferOk,
|
|
222
330
|
handleMedia,
|
|
223
331
|
userRemoter,
|
|
224
|
-
|
|
332
|
+
testPlay,
|
|
333
|
+
handleCallAnswer,
|
|
334
|
+
callAnswer,
|
|
335
|
+
startPeerConnection,
|
|
336
|
+
startIncomingCall,
|
|
337
|
+
uuid
|
|
225
338
|
};
|
|
226
339
|
}
|
|
@@ -5,7 +5,8 @@ import { routerPush } from '../utils/chat/chat-router';
|
|
|
5
5
|
import { PAGE } from '../constant/general';
|
|
6
6
|
import { subscribeToTopic, unsubscribeFromTopic } from '../plugins/mqtt';
|
|
7
7
|
import { TOPIC_DETAIL_CALL } from '../constant/mqtt';
|
|
8
|
-
import { getWebSocket } from '../plugins/websocket';
|
|
8
|
+
import { getWebSocket, initWebSocket } from '../plugins/websocket';
|
|
9
|
+
import router from '../router';
|
|
9
10
|
//PINIA
|
|
10
11
|
export const isRouterReady = ref(false);
|
|
11
12
|
export function useInitData() {
|
|
@@ -13,7 +14,7 @@ export function useInitData() {
|
|
|
13
14
|
const initPage = async (data) => {
|
|
14
15
|
try {
|
|
15
16
|
isRouterReady.value = false;
|
|
16
|
-
const sdk_res = await sdkInit(
|
|
17
|
+
const sdk_res = await sdkInit(data.props);
|
|
17
18
|
if (sdk_res.tenant_error) {
|
|
18
19
|
const api_link_res = await loginApiLink();
|
|
19
20
|
// if (api_link_res.client_error) {
|
|
@@ -22,13 +23,7 @@ export function useInitData() {
|
|
|
22
23
|
// }
|
|
23
24
|
}
|
|
24
25
|
// connectMqtt()
|
|
25
|
-
await initData();
|
|
26
|
-
if (data.response == 'mobile') {
|
|
27
|
-
routerPush(PAGE.CHAT_LIST);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
routerPush(PAGE.HOME);
|
|
31
|
-
}
|
|
26
|
+
await initData(data.props, data.response);
|
|
32
27
|
}
|
|
33
28
|
catch (error) {
|
|
34
29
|
console.log(error);
|
|
@@ -37,11 +32,21 @@ export function useInitData() {
|
|
|
37
32
|
isRouterReady.value = true;
|
|
38
33
|
}
|
|
39
34
|
};
|
|
40
|
-
const initData = async () => {
|
|
41
|
-
await getProfile();
|
|
42
|
-
getWebSocket();
|
|
35
|
+
const initData = async (props, response) => {
|
|
36
|
+
const res = await getProfile();
|
|
37
|
+
await getWebSocket();
|
|
38
|
+
initWebSocket();
|
|
43
39
|
unsubscribeFromTopic(TOPIC_DETAIL_CALL + dataProfile.value?.id);
|
|
44
40
|
subscribeToTopic(TOPIC_DETAIL_CALL + dataProfile.value?.id);
|
|
41
|
+
if ((!res?.phone && res.tenant_id && !props.isLib)) {
|
|
42
|
+
router.push({ name: 'tenant-phone' });
|
|
43
|
+
}
|
|
44
|
+
else if (response == 'mobile') {
|
|
45
|
+
routerPush(PAGE.CHAT_LIST);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
routerPush(PAGE.HOME);
|
|
49
|
+
}
|
|
45
50
|
};
|
|
46
51
|
const loginApiLink = async () => {
|
|
47
52
|
try {
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PLIVO_CALL_STATUS } from '../types/call';
|
|
2
|
+
export function usePlivo(callback) {
|
|
3
|
+
var options = {
|
|
4
|
+
debug: 'ALL',
|
|
5
|
+
permOnClick: true,
|
|
6
|
+
deviceParams: {
|
|
7
|
+
micEnabled: true,
|
|
8
|
+
audioConstraints: { audio: true, video: false }
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var plivoBrowserSdk = null;
|
|
12
|
+
let CallUuid = '';
|
|
13
|
+
let custom_resolve = null;
|
|
14
|
+
let custom_reject = null;
|
|
15
|
+
const plivoLogin = async (token) => {
|
|
16
|
+
token =
|
|
17
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6InBsaXZvO3Y9MSJ9.eyJqdGkiOiJ0ZXN0MSIsImlzcyI6IlNBTjJZMFpERTRNSkFUTVpZNU5DIiwic3ViIjoid2ViY2FsbDAwMzA3OTY3MzQ1NDg5MTgyNyIsIm5iZiI6MTc2MzY5MzUyNSwiZXhwIjoxNzYzNzc5OTI1LCJncmFudHMiOnsidm9pY2UiOnsiaW5jb21pbmdfYWxsb3ciOnRydWUsIm91dGdvaW5nX2FsbG93Ijp0cnVlfX19.9p4O_xTb4kNhKyDVfK3EemSKBQiHtbKNUZ5iwnSdX1I';
|
|
18
|
+
try {
|
|
19
|
+
if (!plivoBrowserSdk)
|
|
20
|
+
plivoBrowserSdk = new window.Plivo(options);
|
|
21
|
+
plivoBrowserSdk?.client?.on?.('onCallAnswered', (callInfo) => {
|
|
22
|
+
handleCallAnswered(callInfo);
|
|
23
|
+
});
|
|
24
|
+
plivoBrowserSdk?.client?.on?.('onCallTerminated', (hangupInfo, callInfo) => handleCallTerminated(hangupInfo, callInfo));
|
|
25
|
+
plivoBrowserSdk.client.on('onCallFailed', (data, callInfo) => {
|
|
26
|
+
handleCallFailed(data, callInfo);
|
|
27
|
+
});
|
|
28
|
+
plivoBrowserSdk.client.on('onCalling', (data) => console.log('onCallFailed', data));
|
|
29
|
+
plivoBrowserSdk?.client?.on?.('onIncomingCall', (callerID, extraHeaders, callInfo) => {
|
|
30
|
+
handleIncomingCall(callInfo);
|
|
31
|
+
});
|
|
32
|
+
plivoBrowserSdk.client.on('onCallRemoteRinging', (data) => handleCallRemoteRinging(data));
|
|
33
|
+
// plivoBrowserSdk?.client?.on?.('onReady', () => console.log('Ready'))
|
|
34
|
+
// plivoBrowserSdk?.client?.on?.('onLoginFailed', () => console.log('Login failed'))
|
|
35
|
+
// plivoBrowserSdk?.client?.on?.('remoteAudioStatus', () => console.log('remoteAudioStatus'))
|
|
36
|
+
await plivoBrowserSdk?.client?.login('webcall003079673454891827', '123456abcA!');
|
|
37
|
+
const speaker = document.getElementById("go-chat-remote-audio");
|
|
38
|
+
if (speaker)
|
|
39
|
+
plivoBrowserSdk?.client?.setAudioElement(speaker);
|
|
40
|
+
console.log('Registered with token');
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.log('Login error: ' + err);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const handleIncomingCall = (call) => {
|
|
47
|
+
const data = {
|
|
48
|
+
phone: _getPhone(call.src)
|
|
49
|
+
};
|
|
50
|
+
console.log(call);
|
|
51
|
+
callback(PLIVO_CALL_STATUS.RINGING, data);
|
|
52
|
+
CallUuid = call?.callUUID;
|
|
53
|
+
};
|
|
54
|
+
const handleCallRemoteRinging = (callInfo) => {
|
|
55
|
+
CallUuid = callInfo.callUUID;
|
|
56
|
+
callback(PLIVO_CALL_STATUS.CALLING);
|
|
57
|
+
custom_resolve?.();
|
|
58
|
+
};
|
|
59
|
+
const handleCallAnswered = (call) => {
|
|
60
|
+
if (call.callUUID == CallUuid) {
|
|
61
|
+
custom_resolve?.();
|
|
62
|
+
callback(PLIVO_CALL_STATUS.CALL_START);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const handleCallTerminated = (data, callInfo) => {
|
|
66
|
+
if (CallUuid === callInfo.callUUID) {
|
|
67
|
+
callback(PLIVO_CALL_STATUS.CALL_END, { message: data?.reason });
|
|
68
|
+
CallUuid = '';
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const _getPhone = (text, dial = '1') => {
|
|
72
|
+
let result = text.replace(/[^0-9]/g, '');
|
|
73
|
+
return result?.startsWith(dial) ? result.slice(dial.toString().length) : result;
|
|
74
|
+
};
|
|
75
|
+
const _waitEventOrTimeout = (timeoutMs = 3000) => {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
custom_resolve = null;
|
|
78
|
+
const timer = setTimeout(() => {
|
|
79
|
+
reject('Time out error!');
|
|
80
|
+
custom_resolve = null;
|
|
81
|
+
custom_reject = null;
|
|
82
|
+
}, timeoutMs);
|
|
83
|
+
custom_resolve = () => {
|
|
84
|
+
resolve(true);
|
|
85
|
+
custom_resolve = null;
|
|
86
|
+
clearTimeout(timer);
|
|
87
|
+
};
|
|
88
|
+
custom_reject = (data) => {
|
|
89
|
+
reject(data);
|
|
90
|
+
custom_reject = null;
|
|
91
|
+
clearTimeout(timer);
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
const plivoCallAnswer = async () => {
|
|
96
|
+
plivoBrowserSdk?.client?.answer?.(CallUuid);
|
|
97
|
+
await _waitEventOrTimeout(3000);
|
|
98
|
+
};
|
|
99
|
+
const plivoCallReject = () => {
|
|
100
|
+
plivoBrowserSdk?.client?.reject?.(CallUuid);
|
|
101
|
+
};
|
|
102
|
+
const plivoCallIgnore = () => {
|
|
103
|
+
if (CallUuid)
|
|
104
|
+
plivoBrowserSdk?.client?.ignore?.(CallUuid);
|
|
105
|
+
};
|
|
106
|
+
const plivoCallSwishMute = (isMute) => {
|
|
107
|
+
plivoBrowserSdk?.client?.mute();
|
|
108
|
+
if (isMute)
|
|
109
|
+
plivoBrowserSdk?.client?.mute?.();
|
|
110
|
+
else
|
|
111
|
+
plivoBrowserSdk?.client?.unmute?.();
|
|
112
|
+
};
|
|
113
|
+
const plivoCall = async (phone) => {
|
|
114
|
+
plivoBrowserSdk.client.call('+' + phone, { number_phone: phone });
|
|
115
|
+
await _waitEventOrTimeout(5000);
|
|
116
|
+
};
|
|
117
|
+
const plivoEndCall = (status) => {
|
|
118
|
+
if (status == PLIVO_CALL_STATUS.RINGING) {
|
|
119
|
+
plivoBrowserSdk?.client?.reject?.(CallUuid);
|
|
120
|
+
}
|
|
121
|
+
else if (status == PLIVO_CALL_STATUS.CALL_START || status == PLIVO_CALL_STATUS.CALLING) {
|
|
122
|
+
plivoBrowserSdk?.client?.hangup?.();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const handleCallFailed = (data, callInfo) => {
|
|
126
|
+
if (custom_reject)
|
|
127
|
+
custom_reject?.(data);
|
|
128
|
+
callback(PLIVO_CALL_STATUS.CALL_END, { message: data });
|
|
129
|
+
};
|
|
130
|
+
return {
|
|
131
|
+
plivoLogin,
|
|
132
|
+
plivoCallAnswer,
|
|
133
|
+
plivoCallReject,
|
|
134
|
+
plivoCall,
|
|
135
|
+
plivoEndCall,
|
|
136
|
+
plivoCallSwishMute
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -27,7 +27,7 @@ export function defineRootColor() {
|
|
|
27
27
|
root.style?.setProperty('--chat-color-primary', Color.Primary);
|
|
28
28
|
// root.style?.setProperty('--chat-color-primary_hover', Color.Primary_Hover)
|
|
29
29
|
// root.style?.setProperty('--chat-color-primary_rgb', Color.Primary_RGB)
|
|
30
|
-
|
|
30
|
+
root.style?.setProperty('--chat-color-error', Color.Error);
|
|
31
31
|
// root.style?.setProperty('--chat-color-error_hover', Color.Error_Hover)
|
|
32
32
|
root.style?.setProperty('--chat-color-success', Color.Success);
|
|
33
33
|
// root.style?.setProperty('--chat-color-success-bg', Color.Success_Bg)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
const baseURL = 'https://go-chat.dev01.dtsmart.dev/';
|
|
3
|
-
// const baseURL = '
|
|
3
|
+
// const baseURL = 'https://go-chat-test.dev01.dtsmart.dev'
|
|
4
|
+
// const baseURL = '192.168.1.162:3000'
|
|
4
5
|
const instance = axios.create({
|
|
5
6
|
baseURL,
|
|
6
7
|
timeout: 20000,
|
|
@@ -4,11 +4,12 @@ const mqttOptions = { qos: 1, retain: false };
|
|
|
4
4
|
let mqttClient = null;
|
|
5
5
|
const subscribedTopics = new Set();
|
|
6
6
|
let dataCallBack = [];
|
|
7
|
+
let reconnectCount = 0;
|
|
8
|
+
const MAX_RECONNECT = 5;
|
|
7
9
|
export const connectMqtt = () => {
|
|
8
10
|
return new Promise((resolve, reject) => {
|
|
9
|
-
|
|
11
|
+
reconnectCount = 0;
|
|
10
12
|
if (mqttClient && mqttClient?.connected) {
|
|
11
|
-
console.log('MQTT already connected');
|
|
12
13
|
return resolve();
|
|
13
14
|
}
|
|
14
15
|
const userInfo = JSON.parse(localStorage.getItem('user') || '{}');
|
|
@@ -28,7 +29,6 @@ export const connectMqtt = () => {
|
|
|
28
29
|
const connectUrl = `wss://${host}:${port}${path}`;
|
|
29
30
|
mqttClient = mqtt.connect(connectUrl, options);
|
|
30
31
|
mqttClient?.on('connect', () => {
|
|
31
|
-
console.log('MQTT Connected Successfully');
|
|
32
32
|
subscribedTopics.forEach((topic) => mqttClient?.subscribe(topic));
|
|
33
33
|
mqttClient?.on('message', (topic, message) => {
|
|
34
34
|
try {
|
|
@@ -49,11 +49,17 @@ export const connectMqtt = () => {
|
|
|
49
49
|
});
|
|
50
50
|
resolve();
|
|
51
51
|
});
|
|
52
|
+
mqttClient?.on('reconnect', () => {
|
|
53
|
+
reconnectCount++;
|
|
54
|
+
if (reconnectCount >= MAX_RECONNECT) {
|
|
55
|
+
mqttClient?.end(true); // true = force close
|
|
56
|
+
mqttClient = null;
|
|
57
|
+
resolve();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
52
60
|
mqttClient?.on('close', () => {
|
|
53
|
-
console.log('MQTT Disconnected');
|
|
54
61
|
});
|
|
55
62
|
mqttClient?.on('error', (err) => {
|
|
56
|
-
console.error('MQTT Error:', err);
|
|
57
63
|
reject(err);
|
|
58
64
|
});
|
|
59
65
|
});
|
|
@@ -61,14 +67,12 @@ export const connectMqtt = () => {
|
|
|
61
67
|
export const disconnectMqtt = () => {
|
|
62
68
|
if (mqttClient) {
|
|
63
69
|
mqttClient?.end(false, {}, () => {
|
|
64
|
-
console.log('MQTT Disconnected');
|
|
65
70
|
mqttClient = null;
|
|
66
71
|
});
|
|
67
72
|
}
|
|
68
73
|
};
|
|
69
74
|
export const subscribeToTopic = (topic) => {
|
|
70
75
|
if (subscribedTopics.has(topic)) {
|
|
71
|
-
console.log(`Already subscribed to ${topic}`);
|
|
72
76
|
return;
|
|
73
77
|
}
|
|
74
78
|
if (mqttClient?.connected || true) {
|
|
@@ -104,7 +108,6 @@ export const publishMessage = (topic, payload) => {
|
|
|
104
108
|
const message = typeof payload !== 'string' ? JSON.stringify(payload) : payload;
|
|
105
109
|
mqttClient?.publish(topic, message, { qos: 1, retain: false }, (err) => {
|
|
106
110
|
if (!err) {
|
|
107
|
-
// console.log(`Published message to ${topic}`)
|
|
108
111
|
}
|
|
109
112
|
else {
|
|
110
113
|
console.error(`Failed to publish message to ${topic}`, err);
|