@voicemaster/core 1.0.10 → 1.0.11
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/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +35 -8
- package/dist/index.mjs +35 -8
- package/package.json +1 -1
- package/src/VoiceClient.ts +39 -8
package/dist/index.d.mts
CHANGED
|
@@ -17,6 +17,8 @@ declare class VoiceClient {
|
|
|
17
17
|
private iceServers;
|
|
18
18
|
private isConnectedFlag;
|
|
19
19
|
private targetUserId;
|
|
20
|
+
private connectingPromise;
|
|
21
|
+
private peers;
|
|
20
22
|
constructor(config: VoiceClientConfig);
|
|
21
23
|
on(event: string, callback: Function): void;
|
|
22
24
|
private emit;
|
|
@@ -31,6 +33,7 @@ declare class VoiceClient {
|
|
|
31
33
|
private handleCandidate;
|
|
32
34
|
private send;
|
|
33
35
|
disconnect(): void;
|
|
36
|
+
getPeers(): string[];
|
|
34
37
|
toggleMute(): void;
|
|
35
38
|
isMuted(): boolean;
|
|
36
39
|
getUserId(): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ declare class VoiceClient {
|
|
|
17
17
|
private iceServers;
|
|
18
18
|
private isConnectedFlag;
|
|
19
19
|
private targetUserId;
|
|
20
|
+
private connectingPromise;
|
|
21
|
+
private peers;
|
|
20
22
|
constructor(config: VoiceClientConfig);
|
|
21
23
|
on(event: string, callback: Function): void;
|
|
22
24
|
private emit;
|
|
@@ -31,6 +33,7 @@ declare class VoiceClient {
|
|
|
31
33
|
private handleCandidate;
|
|
32
34
|
private send;
|
|
33
35
|
disconnect(): void;
|
|
36
|
+
getPeers(): string[];
|
|
34
37
|
toggleMute(): void;
|
|
35
38
|
isMuted(): boolean;
|
|
36
39
|
getUserId(): string;
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,8 @@ var VoiceClient = class {
|
|
|
34
34
|
this.eventHandlers = /* @__PURE__ */ new Map();
|
|
35
35
|
this.isConnectedFlag = false;
|
|
36
36
|
this.targetUserId = null;
|
|
37
|
+
this.connectingPromise = null;
|
|
38
|
+
this.peers = /* @__PURE__ */ new Set();
|
|
37
39
|
this.signalingUrl = config.signalingUrl;
|
|
38
40
|
this.roomId = config.roomId;
|
|
39
41
|
this.userId = config.userId;
|
|
@@ -41,7 +43,7 @@ var VoiceClient = class {
|
|
|
41
43
|
{ urls: "stun:stun.l.google.com:19302" }
|
|
42
44
|
];
|
|
43
45
|
if (config.autoConnect !== false) {
|
|
44
|
-
this.connect();
|
|
46
|
+
Promise.resolve().then(() => this.connect());
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
on(event, callback) {
|
|
@@ -57,13 +59,22 @@ var VoiceClient = class {
|
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
async connect() {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.initPeerConnection();
|
|
63
|
-
this.initWebSocket();
|
|
64
|
-
} catch (error) {
|
|
65
|
-
this.emit("error", error);
|
|
62
|
+
if (this.connectingPromise) {
|
|
63
|
+
return this.connectingPromise;
|
|
66
64
|
}
|
|
65
|
+
this.connectingPromise = (async () => {
|
|
66
|
+
try {
|
|
67
|
+
await this.initMicrophone();
|
|
68
|
+
this.initPeerConnection();
|
|
69
|
+
this.initWebSocket();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
this.emit("error", error);
|
|
72
|
+
throw error;
|
|
73
|
+
} finally {
|
|
74
|
+
this.connectingPromise = null;
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
return this.connectingPromise;
|
|
67
78
|
}
|
|
68
79
|
async initMicrophone() {
|
|
69
80
|
this.localStream = await navigator.mediaDevices.getUserMedia({
|
|
@@ -81,7 +92,9 @@ var VoiceClient = class {
|
|
|
81
92
|
this.pc.addTrack(track, this.localStream);
|
|
82
93
|
});
|
|
83
94
|
this.pc.ontrack = (event) => {
|
|
84
|
-
|
|
95
|
+
const stream = event.streams?.[0] || new MediaStream([event.track]);
|
|
96
|
+
this.remoteStream = stream;
|
|
97
|
+
console.log("[VoiceClient] Remote track received", { track: event.track, stream });
|
|
85
98
|
this.emit("remoteStream", this.remoteStream);
|
|
86
99
|
};
|
|
87
100
|
this.pc.onicecandidate = (event) => {
|
|
@@ -105,13 +118,19 @@ var VoiceClient = class {
|
|
|
105
118
|
const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
|
|
106
119
|
this.ws = new WebSocket(url);
|
|
107
120
|
this.ws.onopen = () => {
|
|
121
|
+
console.log("[VoiceClient] WebSocket connected");
|
|
108
122
|
this.send({ type: "join", roomId: this.roomId, userId: this.userId });
|
|
109
123
|
};
|
|
110
124
|
this.ws.onmessage = async (event) => {
|
|
111
125
|
const message = JSON.parse(event.data);
|
|
112
126
|
await this.handleSignalingMessage(message);
|
|
113
127
|
};
|
|
128
|
+
this.ws.onerror = (event) => {
|
|
129
|
+
console.error("[VoiceClient] WebSocket error", event);
|
|
130
|
+
this.emit("error", new Error("WebSocket error"));
|
|
131
|
+
};
|
|
114
132
|
this.ws.onclose = () => {
|
|
133
|
+
console.log("[VoiceClient] WebSocket closed");
|
|
115
134
|
this.emit("disconnected");
|
|
116
135
|
};
|
|
117
136
|
}
|
|
@@ -121,6 +140,7 @@ var VoiceClient = class {
|
|
|
121
140
|
case "user-joined":
|
|
122
141
|
console.log("[VoiceClient] User joined, myId:", this.userId, "theirId:", message.userId);
|
|
123
142
|
if (message.userId !== this.userId) {
|
|
143
|
+
this.peers.add(message.userId);
|
|
124
144
|
console.log("[VoiceClient] Creating offer...");
|
|
125
145
|
this.targetUserId = message.userId;
|
|
126
146
|
await this.createOffer();
|
|
@@ -143,6 +163,7 @@ var VoiceClient = class {
|
|
|
143
163
|
await this.handleCandidate(message);
|
|
144
164
|
break;
|
|
145
165
|
case "user-left":
|
|
166
|
+
this.peers.delete(message.userId);
|
|
146
167
|
this.emit("userLeft", message.userId);
|
|
147
168
|
break;
|
|
148
169
|
default:
|
|
@@ -193,9 +214,12 @@ var VoiceClient = class {
|
|
|
193
214
|
send(data) {
|
|
194
215
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
195
216
|
this.ws.send(JSON.stringify(data));
|
|
217
|
+
} else {
|
|
218
|
+
console.warn("[VoiceClient] WebSocket is not open, cannot send message", data);
|
|
196
219
|
}
|
|
197
220
|
}
|
|
198
221
|
disconnect() {
|
|
222
|
+
this.peers.clear();
|
|
199
223
|
if (this.ws) {
|
|
200
224
|
this.send({ type: "leave", roomId: this.roomId, userId: this.userId });
|
|
201
225
|
this.ws.close();
|
|
@@ -207,6 +231,9 @@ var VoiceClient = class {
|
|
|
207
231
|
this.isConnectedFlag = false;
|
|
208
232
|
this.emit("disconnected");
|
|
209
233
|
}
|
|
234
|
+
getPeers() {
|
|
235
|
+
return Array.from(this.peers);
|
|
236
|
+
}
|
|
210
237
|
toggleMute() {
|
|
211
238
|
if (this.localStream) {
|
|
212
239
|
const audioTrack = this.localStream.getAudioTracks()[0];
|
package/dist/index.mjs
CHANGED
|
@@ -8,6 +8,8 @@ var VoiceClient = class {
|
|
|
8
8
|
this.eventHandlers = /* @__PURE__ */ new Map();
|
|
9
9
|
this.isConnectedFlag = false;
|
|
10
10
|
this.targetUserId = null;
|
|
11
|
+
this.connectingPromise = null;
|
|
12
|
+
this.peers = /* @__PURE__ */ new Set();
|
|
11
13
|
this.signalingUrl = config.signalingUrl;
|
|
12
14
|
this.roomId = config.roomId;
|
|
13
15
|
this.userId = config.userId;
|
|
@@ -15,7 +17,7 @@ var VoiceClient = class {
|
|
|
15
17
|
{ urls: "stun:stun.l.google.com:19302" }
|
|
16
18
|
];
|
|
17
19
|
if (config.autoConnect !== false) {
|
|
18
|
-
this.connect();
|
|
20
|
+
Promise.resolve().then(() => this.connect());
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
on(event, callback) {
|
|
@@ -31,13 +33,22 @@ var VoiceClient = class {
|
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
async connect() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
this.initPeerConnection();
|
|
37
|
-
this.initWebSocket();
|
|
38
|
-
} catch (error) {
|
|
39
|
-
this.emit("error", error);
|
|
36
|
+
if (this.connectingPromise) {
|
|
37
|
+
return this.connectingPromise;
|
|
40
38
|
}
|
|
39
|
+
this.connectingPromise = (async () => {
|
|
40
|
+
try {
|
|
41
|
+
await this.initMicrophone();
|
|
42
|
+
this.initPeerConnection();
|
|
43
|
+
this.initWebSocket();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
this.emit("error", error);
|
|
46
|
+
throw error;
|
|
47
|
+
} finally {
|
|
48
|
+
this.connectingPromise = null;
|
|
49
|
+
}
|
|
50
|
+
})();
|
|
51
|
+
return this.connectingPromise;
|
|
41
52
|
}
|
|
42
53
|
async initMicrophone() {
|
|
43
54
|
this.localStream = await navigator.mediaDevices.getUserMedia({
|
|
@@ -55,7 +66,9 @@ var VoiceClient = class {
|
|
|
55
66
|
this.pc.addTrack(track, this.localStream);
|
|
56
67
|
});
|
|
57
68
|
this.pc.ontrack = (event) => {
|
|
58
|
-
|
|
69
|
+
const stream = event.streams?.[0] || new MediaStream([event.track]);
|
|
70
|
+
this.remoteStream = stream;
|
|
71
|
+
console.log("[VoiceClient] Remote track received", { track: event.track, stream });
|
|
59
72
|
this.emit("remoteStream", this.remoteStream);
|
|
60
73
|
};
|
|
61
74
|
this.pc.onicecandidate = (event) => {
|
|
@@ -79,13 +92,19 @@ var VoiceClient = class {
|
|
|
79
92
|
const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
|
|
80
93
|
this.ws = new WebSocket(url);
|
|
81
94
|
this.ws.onopen = () => {
|
|
95
|
+
console.log("[VoiceClient] WebSocket connected");
|
|
82
96
|
this.send({ type: "join", roomId: this.roomId, userId: this.userId });
|
|
83
97
|
};
|
|
84
98
|
this.ws.onmessage = async (event) => {
|
|
85
99
|
const message = JSON.parse(event.data);
|
|
86
100
|
await this.handleSignalingMessage(message);
|
|
87
101
|
};
|
|
102
|
+
this.ws.onerror = (event) => {
|
|
103
|
+
console.error("[VoiceClient] WebSocket error", event);
|
|
104
|
+
this.emit("error", new Error("WebSocket error"));
|
|
105
|
+
};
|
|
88
106
|
this.ws.onclose = () => {
|
|
107
|
+
console.log("[VoiceClient] WebSocket closed");
|
|
89
108
|
this.emit("disconnected");
|
|
90
109
|
};
|
|
91
110
|
}
|
|
@@ -95,6 +114,7 @@ var VoiceClient = class {
|
|
|
95
114
|
case "user-joined":
|
|
96
115
|
console.log("[VoiceClient] User joined, myId:", this.userId, "theirId:", message.userId);
|
|
97
116
|
if (message.userId !== this.userId) {
|
|
117
|
+
this.peers.add(message.userId);
|
|
98
118
|
console.log("[VoiceClient] Creating offer...");
|
|
99
119
|
this.targetUserId = message.userId;
|
|
100
120
|
await this.createOffer();
|
|
@@ -117,6 +137,7 @@ var VoiceClient = class {
|
|
|
117
137
|
await this.handleCandidate(message);
|
|
118
138
|
break;
|
|
119
139
|
case "user-left":
|
|
140
|
+
this.peers.delete(message.userId);
|
|
120
141
|
this.emit("userLeft", message.userId);
|
|
121
142
|
break;
|
|
122
143
|
default:
|
|
@@ -167,9 +188,12 @@ var VoiceClient = class {
|
|
|
167
188
|
send(data) {
|
|
168
189
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
169
190
|
this.ws.send(JSON.stringify(data));
|
|
191
|
+
} else {
|
|
192
|
+
console.warn("[VoiceClient] WebSocket is not open, cannot send message", data);
|
|
170
193
|
}
|
|
171
194
|
}
|
|
172
195
|
disconnect() {
|
|
196
|
+
this.peers.clear();
|
|
173
197
|
if (this.ws) {
|
|
174
198
|
this.send({ type: "leave", roomId: this.roomId, userId: this.userId });
|
|
175
199
|
this.ws.close();
|
|
@@ -181,6 +205,9 @@ var VoiceClient = class {
|
|
|
181
205
|
this.isConnectedFlag = false;
|
|
182
206
|
this.emit("disconnected");
|
|
183
207
|
}
|
|
208
|
+
getPeers() {
|
|
209
|
+
return Array.from(this.peers);
|
|
210
|
+
}
|
|
184
211
|
toggleMute() {
|
|
185
212
|
if (this.localStream) {
|
|
186
213
|
const audioTrack = this.localStream.getAudioTracks()[0];
|
package/package.json
CHANGED
package/src/VoiceClient.ts
CHANGED
|
@@ -18,6 +18,8 @@ export class VoiceClient {
|
|
|
18
18
|
private iceServers: RTCIceServer[];
|
|
19
19
|
private isConnectedFlag = false;
|
|
20
20
|
private targetUserId: string | null = null;
|
|
21
|
+
private connectingPromise: Promise<void> | null = null;
|
|
22
|
+
private peers: Set<string> = new Set();
|
|
21
23
|
|
|
22
24
|
constructor(config: VoiceClientConfig) {
|
|
23
25
|
this.signalingUrl = config.signalingUrl;
|
|
@@ -28,7 +30,7 @@ export class VoiceClient {
|
|
|
28
30
|
];
|
|
29
31
|
|
|
30
32
|
if (config.autoConnect !== false) {
|
|
31
|
-
this.connect();
|
|
33
|
+
Promise.resolve().then(() => this.connect());
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -49,13 +51,24 @@ export class VoiceClient {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
async connect(): Promise<void> {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.initPeerConnection();
|
|
55
|
-
this.initWebSocket();
|
|
56
|
-
} catch (error) {
|
|
57
|
-
this.emit('error', error);
|
|
54
|
+
if (this.connectingPromise) {
|
|
55
|
+
return this.connectingPromise;
|
|
58
56
|
}
|
|
57
|
+
|
|
58
|
+
this.connectingPromise = (async () => {
|
|
59
|
+
try {
|
|
60
|
+
await this.initMicrophone();
|
|
61
|
+
this.initPeerConnection();
|
|
62
|
+
this.initWebSocket();
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.emit('error', error);
|
|
65
|
+
throw error;
|
|
66
|
+
} finally {
|
|
67
|
+
this.connectingPromise = null;
|
|
68
|
+
}
|
|
69
|
+
})();
|
|
70
|
+
|
|
71
|
+
return this.connectingPromise;
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
private async initMicrophone(): Promise<void> {
|
|
@@ -77,7 +90,9 @@ export class VoiceClient {
|
|
|
77
90
|
});
|
|
78
91
|
|
|
79
92
|
this.pc.ontrack = (event) => {
|
|
80
|
-
|
|
93
|
+
const stream = event.streams?.[0] || new MediaStream([event.track]);
|
|
94
|
+
this.remoteStream = stream;
|
|
95
|
+
console.log('[VoiceClient] Remote track received', { track: event.track, stream });
|
|
81
96
|
this.emit('remoteStream', this.remoteStream);
|
|
82
97
|
};
|
|
83
98
|
|
|
@@ -105,6 +120,7 @@ export class VoiceClient {
|
|
|
105
120
|
this.ws = new WebSocket(url);
|
|
106
121
|
|
|
107
122
|
this.ws.onopen = () => {
|
|
123
|
+
console.log('[VoiceClient] WebSocket connected');
|
|
108
124
|
this.send({ type: 'join', roomId: this.roomId, userId: this.userId });
|
|
109
125
|
};
|
|
110
126
|
|
|
@@ -113,7 +129,13 @@ export class VoiceClient {
|
|
|
113
129
|
await this.handleSignalingMessage(message);
|
|
114
130
|
};
|
|
115
131
|
|
|
132
|
+
this.ws.onerror = (event) => {
|
|
133
|
+
console.error('[VoiceClient] WebSocket error', event);
|
|
134
|
+
this.emit('error', new Error('WebSocket error'));
|
|
135
|
+
};
|
|
136
|
+
|
|
116
137
|
this.ws.onclose = () => {
|
|
138
|
+
console.log('[VoiceClient] WebSocket closed');
|
|
117
139
|
this.emit('disconnected');
|
|
118
140
|
};
|
|
119
141
|
}
|
|
@@ -125,6 +147,7 @@ export class VoiceClient {
|
|
|
125
147
|
case 'user-joined':
|
|
126
148
|
console.log('[VoiceClient] User joined, myId:', this.userId, 'theirId:', message.userId);
|
|
127
149
|
if (message.userId !== this.userId) {
|
|
150
|
+
this.peers.add(message.userId);
|
|
128
151
|
console.log('[VoiceClient] Creating offer...');
|
|
129
152
|
this.targetUserId = message.userId;
|
|
130
153
|
await this.createOffer();
|
|
@@ -147,6 +170,7 @@ export class VoiceClient {
|
|
|
147
170
|
await this.handleCandidate(message);
|
|
148
171
|
break;
|
|
149
172
|
case 'user-left':
|
|
173
|
+
this.peers.delete(message.userId);
|
|
150
174
|
this.emit('userLeft', message.userId);
|
|
151
175
|
break;
|
|
152
176
|
default:
|
|
@@ -205,10 +229,13 @@ export class VoiceClient {
|
|
|
205
229
|
private send(data: any): void {
|
|
206
230
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
207
231
|
this.ws.send(JSON.stringify(data));
|
|
232
|
+
} else {
|
|
233
|
+
console.warn('[VoiceClient] WebSocket is not open, cannot send message', data);
|
|
208
234
|
}
|
|
209
235
|
}
|
|
210
236
|
|
|
211
237
|
disconnect(): void {
|
|
238
|
+
this.peers.clear();
|
|
212
239
|
if (this.ws) {
|
|
213
240
|
this.send({ type: 'leave', roomId: this.roomId, userId: this.userId });
|
|
214
241
|
this.ws.close();
|
|
@@ -221,6 +248,10 @@ export class VoiceClient {
|
|
|
221
248
|
this.emit('disconnected');
|
|
222
249
|
}
|
|
223
250
|
|
|
251
|
+
getPeers(): string[] {
|
|
252
|
+
return Array.from(this.peers);
|
|
253
|
+
}
|
|
254
|
+
|
|
224
255
|
toggleMute(): void {
|
|
225
256
|
if (this.localStream) {
|
|
226
257
|
const audioTrack = this.localStream.getAudioTracks()[0];
|