@coze/realtime-api 1.3.1 → 1.3.2-alpha.f7fe14
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/cjs/event-names/index.js +220 -214
- package/dist/cjs/index.js +758 -627
- package/dist/cjs/live/index.js +141 -144
- package/dist/esm/event-names/index.js +216 -173
- package/dist/esm/index.js +753 -594
- package/dist/esm/live/index.js +139 -102
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/event-names/event-names.d.ts +2 -1
- package/dist/types/index.d.ts +329 -9
- package/dist/types/live/live/index.d.ts +9 -4
- package/package.json +16 -6
- package/dist/types/client.d.ts +0 -49
- package/dist/types/error.d.ts +0 -25
- package/dist/types/event-handler.d.ts +0 -12
- package/dist/types/event-names/client.d.ts +0 -49
- package/dist/types/event-names/error.d.ts +0 -25
- package/dist/types/event-names/event-handler.d.ts +0 -12
- package/dist/types/event-names/index.d.ts +0 -164
- package/dist/types/event-names/live/index.d.ts +0 -86
- package/dist/types/event-names/utils.d.ts +0 -49
- package/dist/types/event-names.d.ts +0 -213
- package/dist/types/live/client.d.ts +0 -49
- package/dist/types/live/error.d.ts +0 -25
- package/dist/types/live/event-handler.d.ts +0 -12
- package/dist/types/live/event-names.d.ts +0 -213
- package/dist/types/live/index.d.ts +0 -86
- package/dist/types/live/utils.d.ts +0 -49
- package/dist/types/utils.d.ts +0 -49
- package/dist/umd/index.js +0 -994
package/dist/cjs/live/index.js
CHANGED
|
@@ -1,103 +1,97 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
(()=>{
|
|
6
|
-
__webpack_require__.d = function(exports1, definition) {
|
|
7
|
-
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
8
|
-
enumerable: true,
|
|
9
|
-
get: definition[key]
|
|
10
|
-
});
|
|
11
|
-
};
|
|
12
|
-
})();
|
|
13
|
-
// webpack/runtime/has_own_property
|
|
14
|
-
(()=>{
|
|
15
|
-
__webpack_require__.o = function(obj, prop) {
|
|
16
|
-
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
-
};
|
|
18
|
-
})();
|
|
19
|
-
// webpack/runtime/make_namespace_object
|
|
20
|
-
(()=>{
|
|
21
|
-
// define __esModule on exports
|
|
22
|
-
__webpack_require__.r = function(exports1) {
|
|
23
|
-
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
24
|
-
value: 'Module'
|
|
25
|
-
});
|
|
26
|
-
Object.defineProperty(exports1, '__esModule', {
|
|
27
|
-
value: true
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
})();
|
|
31
|
-
/************************************************************************/ var __webpack_exports__ = {};
|
|
32
|
-
// ESM COMPAT FLAG
|
|
33
|
-
__webpack_require__.r(__webpack_exports__);
|
|
34
|
-
// EXPORTS
|
|
35
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
36
|
-
WebLiveClient: ()=>/* binding */ WebLiveClient,
|
|
37
|
-
ResourceStatus: ()=>/* binding */ live_ResourceStatus
|
|
38
|
-
});
|
|
39
|
-
const api_namespaceObject = require("@coze/api");
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var api = require('@coze/api');
|
|
4
|
+
|
|
40
5
|
// WTN服务基础URL
|
|
41
6
|
const WTN_BASE_URL = 'https://wtn.volcvideo.com';
|
|
42
7
|
/**
|
|
43
8
|
* WebRTC资源状态
|
|
44
|
-
*/
|
|
9
|
+
*/
|
|
10
|
+
exports.ResourceStatus = void 0;
|
|
11
|
+
(function (ResourceStatus) {
|
|
45
12
|
ResourceStatus["IDLE"] = "idle";
|
|
46
13
|
ResourceStatus["CONNECTING"] = "connecting";
|
|
47
14
|
ResourceStatus["CONNECTED"] = "connected";
|
|
48
15
|
ResourceStatus["FAILED"] = "failed";
|
|
49
16
|
ResourceStatus["CLOSING"] = "closing";
|
|
50
17
|
ResourceStatus["CLOSED"] = "closed";
|
|
51
|
-
|
|
52
|
-
}({});
|
|
18
|
+
})(exports.ResourceStatus || (exports.ResourceStatus = {}));
|
|
53
19
|
/**
|
|
54
20
|
* 同声传译客户端
|
|
55
|
-
*/
|
|
21
|
+
*/
|
|
22
|
+
class WebLiveClient {
|
|
23
|
+
constructor(liveId) {
|
|
24
|
+
this.peerConnection = null;
|
|
25
|
+
this.resourceUrl = '';
|
|
26
|
+
this.status = exports.ResourceStatus.IDLE;
|
|
27
|
+
this.statusListeners = [];
|
|
28
|
+
/**
|
|
29
|
+
* 获取直播信息
|
|
30
|
+
*/
|
|
31
|
+
this.getLiveData = async () => {
|
|
32
|
+
const api$1 = new api.CozeAPI({
|
|
33
|
+
baseURL: api.COZE_CN_BASE_URL,
|
|
34
|
+
token: '', // 免登录
|
|
35
|
+
});
|
|
36
|
+
return await api$1.audio.live.retrieve(this.liveId);
|
|
37
|
+
};
|
|
38
|
+
this.setupPeerConnectionListeners();
|
|
39
|
+
this.player = document.createElement('audio');
|
|
40
|
+
this.liveId = liveId;
|
|
41
|
+
}
|
|
56
42
|
/**
|
|
57
|
-
|
|
58
|
-
|
|
43
|
+
* 获取当前连接状态
|
|
44
|
+
*/
|
|
45
|
+
getStatus() {
|
|
59
46
|
return this.status;
|
|
60
47
|
}
|
|
61
48
|
/**
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
* 添加状态变化监听器
|
|
50
|
+
* @param callback 状态变化回调函数
|
|
51
|
+
*/
|
|
52
|
+
onStatusChange(callback) {
|
|
65
53
|
this.statusListeners.push(callback);
|
|
66
54
|
}
|
|
67
55
|
/**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
* 移除状态变化监听器
|
|
57
|
+
* @param callback 要移除的回调函数
|
|
58
|
+
*/
|
|
59
|
+
offStatusChange(callback) {
|
|
71
60
|
this.removeStatusListener(callback);
|
|
72
61
|
}
|
|
73
62
|
/**
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
* 移除状态变化监听器
|
|
64
|
+
* @param callback 要移除的回调函数
|
|
65
|
+
*/
|
|
66
|
+
removeStatusListener(callback) {
|
|
77
67
|
const index = this.statusListeners.indexOf(callback);
|
|
78
|
-
if (
|
|
68
|
+
if (index !== -1) {
|
|
69
|
+
this.statusListeners.splice(index, 1);
|
|
70
|
+
}
|
|
79
71
|
}
|
|
80
72
|
/**
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
73
|
+
* 订阅音频资源
|
|
74
|
+
* @param appId 应用ID
|
|
75
|
+
* @param streamId 流ID
|
|
76
|
+
* @param clientId 客户端ID
|
|
77
|
+
*/
|
|
78
|
+
async subscribe(appId, streamId, clientId = '') {
|
|
79
|
+
var _a;
|
|
87
80
|
try {
|
|
88
|
-
var _pc_localDescription;
|
|
89
81
|
// 先清理现有连接
|
|
90
82
|
if (this.peerConnection) {
|
|
91
83
|
this.peerConnection.close();
|
|
92
84
|
this.peerConnection = null;
|
|
93
85
|
}
|
|
94
|
-
this.setStatus(
|
|
86
|
+
this.setStatus(exports.ResourceStatus.CONNECTING);
|
|
95
87
|
// 1. 创建RTCPeerConnection
|
|
96
|
-
const rtcConfig = {
|
|
88
|
+
const rtcConfig = {
|
|
89
|
+
// iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
|
|
90
|
+
};
|
|
97
91
|
const pc = new RTCPeerConnection(rtcConfig);
|
|
98
|
-
pc.ontrack = (event)=>{
|
|
92
|
+
pc.ontrack = (event) => {
|
|
99
93
|
// 音频流
|
|
100
|
-
this.player.onloadeddata = ()=>{
|
|
94
|
+
this.player.onloadeddata = () => {
|
|
101
95
|
this.player.play();
|
|
102
96
|
};
|
|
103
97
|
this.player.srcObject = event.streams[0];
|
|
@@ -105,7 +99,7 @@ const WTN_BASE_URL = 'https://wtn.volcvideo.com';
|
|
|
105
99
|
this.peerConnection = pc;
|
|
106
100
|
this.setupPeerConnectionListeners();
|
|
107
101
|
pc.addTransceiver('audio', {
|
|
108
|
-
direction: 'recvonly'
|
|
102
|
+
direction: 'recvonly',
|
|
109
103
|
});
|
|
110
104
|
// 2. 创建Offer (SDP)
|
|
111
105
|
const offer = await pc.createOffer();
|
|
@@ -113,18 +107,24 @@ const WTN_BASE_URL = 'https://wtn.volcvideo.com';
|
|
|
113
107
|
await pc.setLocalDescription(offer);
|
|
114
108
|
// 等待ICE收集完成再继续
|
|
115
109
|
await this.waitForIceGathering(pc);
|
|
116
|
-
if (!(
|
|
110
|
+
if (!((_a = pc.localDescription) === null || _a === void 0 ? void 0 : _a.sdp)) {
|
|
111
|
+
throw new Error('Failed to create SDP offer');
|
|
112
|
+
}
|
|
117
113
|
// 3. 发送Offer到WTN服务订阅资源
|
|
118
114
|
let subscribeUrl = `${WTN_BASE_URL}/sub/${appId}/${streamId}?MuteVideo=true`;
|
|
119
|
-
if (clientId)
|
|
115
|
+
if (clientId) {
|
|
116
|
+
subscribeUrl += `&clientid=${clientId}`;
|
|
117
|
+
}
|
|
120
118
|
const response = await fetch(subscribeUrl, {
|
|
121
119
|
method: 'POST',
|
|
122
120
|
headers: {
|
|
123
|
-
'Content-Type': 'application/sdp'
|
|
121
|
+
'Content-Type': 'application/sdp',
|
|
124
122
|
},
|
|
125
|
-
body: offer.sdp
|
|
123
|
+
body: offer.sdp,
|
|
126
124
|
});
|
|
127
|
-
if (!response.ok)
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
127
|
+
}
|
|
128
128
|
// 4. 保存资源URL (用于销毁资源)
|
|
129
129
|
this.resourceUrl = response.headers.get('location') || '';
|
|
130
130
|
// 5. 设置远程SDP (Answer)
|
|
@@ -132,54 +132,63 @@ const WTN_BASE_URL = 'https://wtn.volcvideo.com';
|
|
|
132
132
|
const answerSdp = await response.text();
|
|
133
133
|
const answer = new RTCSessionDescription({
|
|
134
134
|
type: 'answer',
|
|
135
|
-
sdp: answerSdp
|
|
135
|
+
sdp: answerSdp,
|
|
136
136
|
});
|
|
137
137
|
await this.peerConnection.setRemoteDescription(answer);
|
|
138
138
|
// 7. 返回结果
|
|
139
139
|
return {
|
|
140
140
|
status: this.status,
|
|
141
|
-
peerConnection: this.peerConnection
|
|
141
|
+
peerConnection: this.peerConnection, // 返回连接对象,以便客户端可以监听媒体事件
|
|
142
142
|
};
|
|
143
|
-
}
|
|
144
|
-
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
this.status = exports.ResourceStatus.FAILED;
|
|
145
146
|
console.error('Failed to subscribe WebRTC stream:', error);
|
|
146
147
|
return Promise.reject(error);
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
150
|
/**
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
* 销毁订阅资源
|
|
152
|
+
*/
|
|
153
|
+
async unsubscribe() {
|
|
152
154
|
try {
|
|
153
155
|
// 销毁订阅资源
|
|
154
|
-
if (!this.resourceUrl)
|
|
155
|
-
|
|
156
|
+
if (!this.resourceUrl) {
|
|
157
|
+
throw new Error('No valid subscription resource URL to unsubscribe');
|
|
158
|
+
}
|
|
159
|
+
this.setStatus(exports.ResourceStatus.CLOSING);
|
|
156
160
|
const response = await fetch(this.resourceUrl, {
|
|
157
|
-
method: 'DELETE'
|
|
161
|
+
method: 'DELETE',
|
|
158
162
|
});
|
|
159
|
-
if (!response.ok)
|
|
163
|
+
if (!response.ok) {
|
|
164
|
+
throw new Error(`Failed to unsubscribe: ${response.status} ${response.statusText}`);
|
|
165
|
+
}
|
|
160
166
|
// 关闭RTC连接
|
|
161
167
|
if (this.peerConnection) {
|
|
162
168
|
this.peerConnection.close();
|
|
163
169
|
this.peerConnection = null;
|
|
164
170
|
}
|
|
165
171
|
this.resourceUrl = '';
|
|
166
|
-
this.status =
|
|
172
|
+
this.status = exports.ResourceStatus.CLOSED;
|
|
167
173
|
return true;
|
|
168
|
-
}
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
169
176
|
console.error('Error unsubscribing resource:', error);
|
|
170
|
-
this.status =
|
|
177
|
+
this.status = exports.ResourceStatus.FAILED;
|
|
171
178
|
return Promise.reject(error);
|
|
172
179
|
}
|
|
173
180
|
}
|
|
174
181
|
/**
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
* 静音/取消静音
|
|
183
|
+
* @param muted 是否静音
|
|
184
|
+
*/
|
|
185
|
+
setMuted(muted) {
|
|
178
186
|
this.player.muted = muted;
|
|
179
187
|
}
|
|
180
188
|
/**
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
* 关闭并清理资源
|
|
190
|
+
*/
|
|
191
|
+
close() {
|
|
183
192
|
// 关闭PeerConnection
|
|
184
193
|
this.closePeerConnection();
|
|
185
194
|
// Clean up audio element
|
|
@@ -190,21 +199,22 @@ const WTN_BASE_URL = 'https://wtn.volcvideo.com';
|
|
|
190
199
|
}
|
|
191
200
|
// 重置状态
|
|
192
201
|
this.resourceUrl = '';
|
|
193
|
-
this.setStatus(
|
|
202
|
+
this.setStatus(exports.ResourceStatus.IDLE);
|
|
194
203
|
}
|
|
195
204
|
/**
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
205
|
+
* 等待ICE收集完成
|
|
206
|
+
* @param pc RTCPeerConnection实例
|
|
207
|
+
*/
|
|
208
|
+
waitForIceGathering(pc) {
|
|
209
|
+
return new Promise(resolve => {
|
|
200
210
|
// 如果已经收集完成,直接返回
|
|
201
|
-
if ('complete'
|
|
211
|
+
if (pc.iceGatheringState === 'complete') {
|
|
202
212
|
resolve();
|
|
203
213
|
return;
|
|
204
214
|
}
|
|
205
215
|
// 设置收集完成时的回调
|
|
206
|
-
const checkState = ()=>{
|
|
207
|
-
if ('complete'
|
|
216
|
+
const checkState = () => {
|
|
217
|
+
if (pc.iceGatheringState === 'complete') {
|
|
208
218
|
pc.removeEventListener('icegatheringstatechange', checkState);
|
|
209
219
|
resolve();
|
|
210
220
|
}
|
|
@@ -212,81 +222,68 @@ const WTN_BASE_URL = 'https://wtn.volcvideo.com';
|
|
|
212
222
|
// 监听收集状态变化
|
|
213
223
|
pc.addEventListener('icegatheringstatechange', checkState);
|
|
214
224
|
// 添加超时处理,防止永远等待
|
|
215
|
-
setTimeout(()=>resolve(), 5000);
|
|
225
|
+
setTimeout(() => resolve(), 5000);
|
|
216
226
|
});
|
|
217
227
|
}
|
|
218
228
|
setupPeerConnectionListeners() {
|
|
219
|
-
if (!this.peerConnection)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
if (!this.peerConnection) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.peerConnection.oniceconnectionstatechange = () => {
|
|
233
|
+
var _a, _b, _c;
|
|
234
|
+
console.log('ICE connection state changed:', (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.iceConnectionState);
|
|
235
|
+
switch ((_b = this.peerConnection) === null || _b === void 0 ? void 0 : _b.iceConnectionState) {
|
|
224
236
|
case 'connected':
|
|
225
237
|
case 'completed':
|
|
226
|
-
this.setStatus(
|
|
238
|
+
this.setStatus(exports.ResourceStatus.CONNECTED);
|
|
227
239
|
break;
|
|
228
240
|
case 'failed':
|
|
229
241
|
case 'disconnected':
|
|
230
|
-
this.setStatus(
|
|
242
|
+
this.setStatus(exports.ResourceStatus.FAILED);
|
|
231
243
|
break;
|
|
232
244
|
case 'closed':
|
|
233
|
-
this.setStatus(
|
|
245
|
+
this.setStatus(exports.ResourceStatus.CLOSED);
|
|
234
246
|
break;
|
|
235
247
|
default:
|
|
236
|
-
|
|
237
|
-
console.log('ICE connection state changed:', null === (_this_peerConnection2 = this.peerConnection) || void 0 === _this_peerConnection2 ? void 0 : _this_peerConnection2.iceConnectionState);
|
|
248
|
+
console.log('ICE connection state changed:', (_c = this.peerConnection) === null || _c === void 0 ? void 0 : _c.iceConnectionState);
|
|
238
249
|
break;
|
|
239
250
|
}
|
|
240
251
|
};
|
|
241
|
-
this.peerConnection.onicecandidate =
|
|
242
|
-
if (event.candidate)
|
|
252
|
+
this.peerConnection.onicecandidate = event => {
|
|
253
|
+
if (event.candidate) {
|
|
254
|
+
console.log('New ICE candidate:', event.candidate);
|
|
255
|
+
}
|
|
243
256
|
};
|
|
244
257
|
}
|
|
245
258
|
/**
|
|
246
|
-
|
|
247
|
-
|
|
259
|
+
* 关闭PeerConnection
|
|
260
|
+
*/
|
|
261
|
+
closePeerConnection() {
|
|
248
262
|
if (this.peerConnection) {
|
|
249
263
|
this.peerConnection.close();
|
|
250
264
|
this.peerConnection = null;
|
|
251
265
|
}
|
|
252
266
|
}
|
|
253
267
|
/**
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
268
|
+
* 设置状态并触发监听回调
|
|
269
|
+
* @param newStatus 新状态
|
|
270
|
+
* @private 私有方法,仅内部使用
|
|
271
|
+
*/
|
|
272
|
+
setStatus(newStatus) {
|
|
258
273
|
const oldStatus = this.status;
|
|
259
274
|
if (oldStatus !== newStatus) {
|
|
260
275
|
this.status = newStatus;
|
|
261
276
|
// 触发所有监听器
|
|
262
|
-
for (const listener of this.statusListeners)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
277
|
+
for (const listener of this.statusListeners) {
|
|
278
|
+
try {
|
|
279
|
+
listener(newStatus);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
console.error('Error in status listener:', error);
|
|
283
|
+
}
|
|
266
284
|
}
|
|
267
285
|
}
|
|
268
286
|
}
|
|
269
|
-
constructor(liveId){
|
|
270
|
-
this.peerConnection = null;
|
|
271
|
-
this.resourceUrl = '';
|
|
272
|
-
this.status = "idle";
|
|
273
|
-
this.statusListeners = [];
|
|
274
|
-
/**
|
|
275
|
-
* 获取直播信息
|
|
276
|
-
*/ this.getLiveData = async ()=>{
|
|
277
|
-
const api = new api_namespaceObject.CozeAPI({
|
|
278
|
-
baseURL: api_namespaceObject.COZE_CN_BASE_URL,
|
|
279
|
-
token: ''
|
|
280
|
-
});
|
|
281
|
-
return await api.audio.live.retrieve(this.liveId);
|
|
282
|
-
};
|
|
283
|
-
this.setupPeerConnectionListeners();
|
|
284
|
-
this.player = document.createElement('audio');
|
|
285
|
-
this.liveId = liveId;
|
|
286
|
-
}
|
|
287
287
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, '__esModule', {
|
|
291
|
-
value: true
|
|
292
|
-
});
|
|
288
|
+
|
|
289
|
+
exports.WebLiveClient = WebLiveClient;
|