module-develop-kit 1.0.4 → 1.0.5
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.
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { J as
|
|
1
|
+
import { J as f } from "../../commonjs-virtual-dir/JsSIP.js";
|
|
2
2
|
import { C as h } from "../../commonjs-virtual-dir/Constants.js";
|
|
3
|
-
import { ECallStatus as a, EMIT_EVENT_NAME as
|
|
4
|
-
import { CallLogger as e, getIceServersByCallConfig as
|
|
3
|
+
import { ECallStatus as a, EMIT_EVENT_NAME as T } from "./constants.js";
|
|
4
|
+
import { CallLogger as e, getIceServersByCallConfig as E, formatSdp as y } from "./utils.js";
|
|
5
5
|
import { EventBus as I } from "../utils/eventBus.js";
|
|
6
|
-
class
|
|
6
|
+
class _ {
|
|
7
7
|
ua = null;
|
|
8
8
|
session = null;
|
|
9
9
|
eventBus;
|
|
@@ -13,15 +13,16 @@ class $ {
|
|
|
13
13
|
};
|
|
14
14
|
// 有可能会出现 音频还未加载成功,但是会话已经结束的情况
|
|
15
15
|
isStop = !1;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
checkTimer = null;
|
|
17
|
+
constructor(i, t) {
|
|
18
|
+
this.eventBus = new I(), this.playTipAudio(t.tipAudioUrl), this.initUa(i, t);
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* 监听状态更新
|
|
21
22
|
* @param callback
|
|
22
23
|
*/
|
|
23
|
-
onStatusUpdate(
|
|
24
|
-
this.eventBus.$on(
|
|
24
|
+
onStatusUpdate(i) {
|
|
25
|
+
this.eventBus.$on(T.UPDATE_STATUS, i, !0);
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
28
|
* 更新状态,触发状态更新
|
|
@@ -29,8 +30,8 @@ class $ {
|
|
|
29
30
|
* @param cause
|
|
30
31
|
* @param statusCode
|
|
31
32
|
*/
|
|
32
|
-
updateStatus(
|
|
33
|
-
this.callStatus =
|
|
33
|
+
updateStatus(i, t, s) {
|
|
34
|
+
this.callStatus = i, this.eventBus.$emit(T.UPDATE_STATUS, i, t, s);
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
37
|
* 初始化sip和websocket的链接
|
|
@@ -38,11 +39,11 @@ class $ {
|
|
|
38
39
|
* @param config
|
|
39
40
|
* @private
|
|
40
41
|
*/
|
|
41
|
-
initUa(
|
|
42
|
+
initUa(i, t) {
|
|
42
43
|
try {
|
|
43
44
|
e.log("wssUrl", t.wssUrl), e.log("当前作席", t.extension);
|
|
44
|
-
const s = new
|
|
45
|
-
this.ua = new
|
|
45
|
+
const s = new f.WebSocketInterface(t.wssUrl);
|
|
46
|
+
this.ua = new f.UA({
|
|
46
47
|
sockets: [s],
|
|
47
48
|
uri: `sip:${t.extension}@${t.sipIp}`,
|
|
48
49
|
password: t.password,
|
|
@@ -50,11 +51,11 @@ class $ {
|
|
|
50
51
|
register_expires: 300,
|
|
51
52
|
session_timers_expires: 120,
|
|
52
53
|
pcConfig: {
|
|
53
|
-
iceServers:
|
|
54
|
+
iceServers: E(t)
|
|
54
55
|
},
|
|
55
56
|
extra_headers: [`X-Call-ID: ${t.callId}`]
|
|
56
57
|
}), this.ua.on("registered", () => {
|
|
57
|
-
e.log("SIP 注册成功"), this.initSession(
|
|
58
|
+
e.log("SIP 注册成功"), this.initSession(i, t);
|
|
58
59
|
}), this.ua.on("connected", () => {
|
|
59
60
|
e.log("WebSocket已连接");
|
|
60
61
|
}), this.ua.on("disconnected", () => {
|
|
@@ -67,12 +68,12 @@ class $ {
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
70
|
-
* 用于优化通话,倒计时
|
|
71
|
+
* 用于优化通话,倒计时60s,如果超过60s还未接通,则挂断;并提示无法接听
|
|
71
72
|
*/
|
|
72
73
|
optimizationCall() {
|
|
73
|
-
const
|
|
74
|
-
e.log("开始接听倒计时:",
|
|
75
|
-
const t =
|
|
74
|
+
const i = Date.now();
|
|
75
|
+
e.log("开始接听倒计时:", i);
|
|
76
|
+
const t = 60 * 1e3 + i, s = () => {
|
|
76
77
|
requestAnimationFrame(() => {
|
|
77
78
|
a.PENDING === this.callStatus && (Date.now() > t ? (e.error("接听超时", Date.now()), this.updateStatus(a.FAILED, h.causes.NO_ANSWER), this.stop()) : s());
|
|
78
79
|
});
|
|
@@ -82,14 +83,15 @@ class $ {
|
|
|
82
83
|
/**
|
|
83
84
|
* 音频检测,存在有早期媒体但是并无声音的情况,所以增加音频分析检测;
|
|
84
85
|
*/
|
|
85
|
-
audioCheck(
|
|
86
|
+
audioCheck(i) {
|
|
86
87
|
try {
|
|
87
|
-
|
|
88
|
+
e.log("开始进行音频检测");
|
|
89
|
+
const t = new (Reflect.get(window, "AudioContext") || Reflect.get(window, "webkitAudioContext"))(), s = t.createAnalyser(), n = t.createMediaStreamSource(i.streams[0]);
|
|
88
90
|
n.connect(s), s.fftSize = 256;
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
const u = s.frequencyBinCount, l = new Uint8Array(u);
|
|
92
|
+
this.checkTimer = setInterval(() => {
|
|
93
|
+
s.getByteTimeDomainData(l), l.some((p) => Math.abs(p - 128) > 2) && (e.log("【音频分析】检测到有效声音"), n.disconnect(), this.stopPlayTipAudio(), this.checkTimer && clearInterval(this.checkTimer), this.checkTimer = null);
|
|
94
|
+
}, 100);
|
|
93
95
|
} catch (t) {
|
|
94
96
|
e.error("音频分析模块初始化失败", t?.message);
|
|
95
97
|
}
|
|
@@ -100,37 +102,37 @@ class $ {
|
|
|
100
102
|
* @param config
|
|
101
103
|
* @private
|
|
102
104
|
*/
|
|
103
|
-
getSessionEventHandlers(
|
|
105
|
+
getSessionEventHandlers(i, t) {
|
|
104
106
|
let s = !1;
|
|
105
|
-
const n =
|
|
107
|
+
const n = i.call.split("").slice(-4).join("");
|
|
106
108
|
e.log("开始呼叫(尾号):", `sip:${n}@${t.sipIp}`);
|
|
107
|
-
const
|
|
108
|
-
let
|
|
109
|
-
const
|
|
110
|
-
|
|
109
|
+
const u = t.iceTransportPolicy === "relay";
|
|
110
|
+
let l = null;
|
|
111
|
+
const d = () => {
|
|
112
|
+
l && clearTimeout(l), l = null;
|
|
111
113
|
}, { iceCandidateTimeout: p = 2e3 } = t;
|
|
112
114
|
return {
|
|
113
|
-
sdp: (
|
|
114
|
-
|
|
115
|
+
sdp: (o) => {
|
|
116
|
+
o.sdp = y(o.sdp);
|
|
115
117
|
},
|
|
116
118
|
connecting: () => {
|
|
117
119
|
a.PENDING !== this.callStatus && this.updateStatus(a.PENDING), e.log("正在连接...");
|
|
118
120
|
},
|
|
119
|
-
progress: (
|
|
120
|
-
if (e.log("呼叫进行中..."), this.optimizationCall(),
|
|
121
|
-
const r =
|
|
122
|
-
r === 183 && c ?
|
|
121
|
+
progress: (o) => {
|
|
122
|
+
if (e.log("呼叫进行中..."), this.optimizationCall(), o.response) {
|
|
123
|
+
const r = o.response.status_code, c = o.response.body;
|
|
124
|
+
r === 183 && c ? e.log("收到 183 (带SDP),确认有早期媒体,停止本地提示音。") : (r === 180 || r === 183 && !c) && e.log(`收到 ${r} (无SDP),继续播放本地提示音。`);
|
|
123
125
|
}
|
|
124
126
|
},
|
|
125
|
-
ended: (
|
|
127
|
+
ended: (o) => {
|
|
126
128
|
if (a.FAILED !== this.callStatus) {
|
|
127
|
-
const r = s ?
|
|
129
|
+
const r = s ? o?.cause : h.causes.REJECTED;
|
|
128
130
|
this.updateStatus(a.ENDED, r), e.log("通话已结束 cause: ", r);
|
|
129
131
|
}
|
|
130
132
|
this.stop();
|
|
131
133
|
},
|
|
132
|
-
failed: (
|
|
133
|
-
const { cause: r, message: c = {} } =
|
|
134
|
+
failed: (o) => {
|
|
135
|
+
const { cause: r, message: c = {} } = o, S = r === "Canceled";
|
|
134
136
|
this.updateStatus(
|
|
135
137
|
S ? a.CANCELLED : a.FAILED,
|
|
136
138
|
r,
|
|
@@ -146,32 +148,30 @@ class $ {
|
|
|
146
148
|
},
|
|
147
149
|
confirmed: () => {
|
|
148
150
|
this.updateStatus(a.ANSWERED), e.log("通话已确认");
|
|
149
|
-
const
|
|
150
|
-
s = !0, clearTimeout(
|
|
151
|
+
const o = setTimeout(() => {
|
|
152
|
+
s = !0, clearTimeout(o);
|
|
151
153
|
}, 1500);
|
|
152
154
|
},
|
|
153
|
-
peerconnection: (
|
|
154
|
-
const r =
|
|
155
|
+
peerconnection: (o) => {
|
|
156
|
+
const r = o.peerconnection;
|
|
155
157
|
e.log("RTCPeerConnection 已创建或更新,正在设置 ontrack 监听器"), r.ontrack = (c) => {
|
|
156
158
|
if (c.track.kind === "audio" && c.streams[0]) {
|
|
157
|
-
e.log(c.track, "track"), e.log(`接收到远程媒体轨道 (track): ${c.track.kind}`);
|
|
158
|
-
const S = c.streams[0];
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
e.error("播放远程音频失败 (来自 ontrack)", A);
|
|
163
|
-
})) : e.error("无法播放远程音频,播放元素不存在", `${t.playAudioId}`), this.audioCheck(c);
|
|
159
|
+
e.log(c.track, "track"), e.log(`接收到远程媒体轨道 (track): ${c.track.kind}`), this.audioCheck(c);
|
|
160
|
+
const S = c.streams[0], m = document.getElementById(t.playAudioId);
|
|
161
|
+
m ? (m.srcObject = S, m.play().catch((C) => {
|
|
162
|
+
e.error("播放远程音频失败 (来自 ontrack)", C);
|
|
163
|
+
})) : e.error("无法播放远程音频,播放元素不存在", `${t.playAudioId}`);
|
|
164
164
|
}
|
|
165
165
|
}, r.addEventListener("iceconnectionstatechange", () => {
|
|
166
166
|
e.log(`ICE状态: ${r.iceConnectionState}`), r.iceConnectionState === "disconnected" && (e.error("ICE连接断开"), this.updateStatus(a.FAILED, h.causes.CONNECTION_ERROR), this.stop());
|
|
167
167
|
});
|
|
168
168
|
},
|
|
169
|
-
icecandidate:
|
|
170
|
-
e.log("relay 模式 ice 候选:",
|
|
171
|
-
} : (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}, p),
|
|
169
|
+
icecandidate: u ? (o) => {
|
|
170
|
+
e.log("relay 模式 ice 候选:", o.candidate), o.ready();
|
|
171
|
+
} : (o) => {
|
|
172
|
+
d(), l = setTimeout(() => {
|
|
173
|
+
o.ready(), d(), e.log(`ice 候选候选${p}ms 后获取结束`);
|
|
174
|
+
}, p), o.candidate ? e.log("ice 候选:", o.candidate) : (d(), e.log("ice 候选结束"), o.ready());
|
|
175
175
|
}
|
|
176
176
|
};
|
|
177
177
|
}
|
|
@@ -179,28 +179,28 @@ class $ {
|
|
|
179
179
|
* 初始化rtc会话
|
|
180
180
|
* @private
|
|
181
181
|
*/
|
|
182
|
-
initSession(
|
|
182
|
+
initSession(i, t) {
|
|
183
183
|
if (!this.ua) {
|
|
184
184
|
this.updateStatus(a.FAILED, h.causes.SIP_FAILURE_CODE), e.error("SIP 未初始化");
|
|
185
185
|
return;
|
|
186
186
|
}
|
|
187
187
|
try {
|
|
188
188
|
const n = {
|
|
189
|
-
eventHandlers: this.getSessionEventHandlers(
|
|
189
|
+
eventHandlers: this.getSessionEventHandlers(i, t),
|
|
190
190
|
mediaConstraints: { audio: !0, video: !1 },
|
|
191
191
|
rtcOfferConstraints: {
|
|
192
192
|
offerToReceiveAudio: !0,
|
|
193
193
|
offerToReceiveVideo: !1
|
|
194
194
|
},
|
|
195
195
|
rtcConfiguration: {
|
|
196
|
-
iceServers:
|
|
196
|
+
iceServers: E(t)
|
|
197
197
|
},
|
|
198
198
|
sessionTimersExpires: 180,
|
|
199
199
|
pcConfig: {
|
|
200
|
-
iceServers:
|
|
200
|
+
iceServers: E(t)
|
|
201
201
|
}
|
|
202
202
|
};
|
|
203
|
-
t.iceTransportPolicy && n.pcConfig && (e.log("iceTransportPolicy", t.iceTransportPolicy), n.pcConfig.iceTransportPolicy = t.iceTransportPolicy), this.session = this.ua.call(`sip:${
|
|
203
|
+
t.iceTransportPolicy && n.pcConfig && (e.log("iceTransportPolicy", t.iceTransportPolicy), n.pcConfig.iceTransportPolicy = t.iceTransportPolicy), this.session = this.ua.call(`sip:${i.call}@${t.sipIp}`, n);
|
|
204
204
|
} catch (s) {
|
|
205
205
|
e.error("SIP 会话创建失败", s?.message), this.stop();
|
|
206
206
|
}
|
|
@@ -209,27 +209,27 @@ class $ {
|
|
|
209
209
|
* 播放提示音
|
|
210
210
|
* @private
|
|
211
211
|
*/
|
|
212
|
-
async playTipAudio(
|
|
212
|
+
async playTipAudio(i) {
|
|
213
213
|
let t, s;
|
|
214
214
|
try {
|
|
215
215
|
e.log("开始播放提示音");
|
|
216
|
-
const
|
|
216
|
+
const l = await (await fetch(i || `https://store.zxfqf.com/file/uMgvB0wt9f.mp3?t=${Date.now()}`)).arrayBuffer();
|
|
217
217
|
t = new (window.AudioContext || Reflect.get(window, "webkitAudioContext"))(), await t.suspend();
|
|
218
|
-
const
|
|
219
|
-
s = t.createBufferSource(), s.buffer =
|
|
218
|
+
const d = await t.decodeAudioData(l);
|
|
219
|
+
s = t.createBufferSource(), s.buffer = d, s.connect(t.destination), s.loop = !0, s.loopStart = 0, s.loopEnd = d.duration;
|
|
220
220
|
const p = t.currentTime;
|
|
221
221
|
e.log("音频播放开始时间:", p), await t.resume(), s.start(p);
|
|
222
|
-
} catch (
|
|
223
|
-
e.error("播放音频失败",
|
|
222
|
+
} catch (u) {
|
|
223
|
+
e.error("播放音频失败", u?.message);
|
|
224
224
|
}
|
|
225
225
|
let n = !1;
|
|
226
226
|
this.stopPlayTipAudio = () => {
|
|
227
|
-
n
|
|
227
|
+
this.checkTimer && clearInterval(this.checkTimer), !n && (e.log("停止播放提示音"), n = !0, s.stop(), s.disconnect(), t.close().finally(() => {
|
|
228
228
|
s = null, t = null, this.stopPlayTipAudio = () => {
|
|
229
229
|
};
|
|
230
230
|
}));
|
|
231
|
-
}, this.onStatusUpdate((
|
|
232
|
-
a.ANSWERED ===
|
|
231
|
+
}, this.onStatusUpdate((u) => {
|
|
232
|
+
a.ANSWERED === u && this.stopPlayTipAudio();
|
|
233
233
|
}), this.isStop && this.stopPlayTipAudio();
|
|
234
234
|
}
|
|
235
235
|
/**
|
|
@@ -239,10 +239,10 @@ class $ {
|
|
|
239
239
|
stop() {
|
|
240
240
|
try {
|
|
241
241
|
this.ua?.stop?.(), !this.session?.isEnded?.() && this.session?.terminate();
|
|
242
|
-
} catch (
|
|
243
|
-
e.error("挂断失败",
|
|
242
|
+
} catch (i) {
|
|
243
|
+
e.error("挂断失败", i?.message);
|
|
244
244
|
} finally {
|
|
245
|
-
this.isStop = !0, this.stopPlayTipAudio();
|
|
245
|
+
this.isStop = !0, this.stopPlayTipAudio(), this.checkTimer && clearInterval(this.checkTimer);
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
248
|
/**
|
|
@@ -259,5 +259,5 @@ class $ {
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
export {
|
|
262
|
-
|
|
262
|
+
_ as CallManagement
|
|
263
263
|
};
|