@voicemaster/core 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.
package/dist/index.d.mts CHANGED
@@ -7,7 +7,7 @@ interface VoiceClientConfig {
7
7
  }
8
8
  declare class VoiceClient {
9
9
  private ws;
10
- private peer;
10
+ private pc;
11
11
  private localStream;
12
12
  private remoteStream;
13
13
  private eventHandlers;
@@ -21,10 +21,13 @@ declare class VoiceClient {
21
21
  private emit;
22
22
  connect(): Promise<void>;
23
23
  private initMicrophone;
24
+ private initPeerConnection;
24
25
  private initWebSocket;
25
26
  private handleSignalingMessage;
26
- private initPeer;
27
- private handlePeerSignal;
27
+ private createOffer;
28
+ private handleOffer;
29
+ private handleAnswer;
30
+ private handleCandidate;
28
31
  private send;
29
32
  disconnect(): void;
30
33
  toggleMute(): void;
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ interface VoiceClientConfig {
7
7
  }
8
8
  declare class VoiceClient {
9
9
  private ws;
10
- private peer;
10
+ private pc;
11
11
  private localStream;
12
12
  private remoteStream;
13
13
  private eventHandlers;
@@ -21,10 +21,13 @@ declare class VoiceClient {
21
21
  private emit;
22
22
  connect(): Promise<void>;
23
23
  private initMicrophone;
24
+ private initPeerConnection;
24
25
  private initWebSocket;
25
26
  private handleSignalingMessage;
26
- private initPeer;
27
- private handlePeerSignal;
27
+ private createOffer;
28
+ private handleOffer;
29
+ private handleAnswer;
30
+ private handleCandidate;
28
31
  private send;
29
32
  disconnect(): void;
30
33
  toggleMute(): void;
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
@@ -35,11 +25,10 @@ __export(index_exports, {
35
25
  module.exports = __toCommonJS(index_exports);
36
26
 
37
27
  // src/VoiceClient.ts
38
- var import_simple_peer = __toESM(require("simple-peer"));
39
28
  var VoiceClient = class {
40
29
  constructor(config) {
41
30
  this.ws = null;
42
- this.peer = null;
31
+ this.pc = null;
43
32
  this.localStream = null;
44
33
  this.remoteStream = null;
45
34
  this.eventHandlers = /* @__PURE__ */ new Map();
@@ -48,8 +37,7 @@ var VoiceClient = class {
48
37
  this.roomId = config.roomId;
49
38
  this.userId = config.userId;
50
39
  this.iceServers = config.iceServers || [
51
- { urls: "stun:stun.l.google.com:19302" },
52
- { urls: "stun:stun1.l.google.com:19302" }
40
+ { urls: "stun:stun.l.google.com:19302" }
53
41
  ];
54
42
  if (config.autoConnect !== false) {
55
43
  this.connect();
@@ -70,6 +58,7 @@ var VoiceClient = class {
70
58
  async connect() {
71
59
  try {
72
60
  await this.initMicrophone();
61
+ this.initPeerConnection();
73
62
  this.initWebSocket();
74
63
  } catch (error) {
75
64
  this.emit("error", error);
@@ -85,78 +74,89 @@ var VoiceClient = class {
85
74
  });
86
75
  this.emit("localStream", this.localStream);
87
76
  }
77
+ initPeerConnection() {
78
+ this.pc = new RTCPeerConnection({ iceServers: this.iceServers });
79
+ this.localStream?.getTracks().forEach((track) => {
80
+ this.pc.addTrack(track, this.localStream);
81
+ });
82
+ this.pc.ontrack = (event) => {
83
+ this.remoteStream = event.streams[0];
84
+ this.emit("remoteStream", this.remoteStream);
85
+ if (!this.isConnectedFlag) {
86
+ this.isConnectedFlag = true;
87
+ this.emit("connected");
88
+ }
89
+ };
90
+ this.pc.onicecandidate = (event) => {
91
+ if (event.candidate) {
92
+ this.send({
93
+ type: "candidate",
94
+ candidate: event.candidate
95
+ });
96
+ }
97
+ };
98
+ }
88
99
  initWebSocket() {
89
100
  const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
90
101
  this.ws = new WebSocket(url);
91
102
  this.ws.onopen = () => {
92
103
  this.send({ type: "join", roomId: this.roomId, userId: this.userId });
93
104
  };
94
- this.ws.onmessage = (event) => {
105
+ this.ws.onmessage = async (event) => {
95
106
  const message = JSON.parse(event.data);
96
- this.handleSignalingMessage(message);
107
+ await this.handleSignalingMessage(message);
97
108
  };
98
109
  this.ws.onclose = () => {
99
110
  this.emit("disconnected");
100
111
  };
101
112
  }
102
- handleSignalingMessage(message) {
113
+ async handleSignalingMessage(message) {
103
114
  switch (message.type) {
104
115
  case "user-joined":
105
116
  if (message.userId !== this.userId) {
106
- this.initPeer(true);
117
+ await this.createOffer();
107
118
  this.emit("userJoined", message.userId);
108
119
  }
109
120
  break;
110
- case "signal":
111
- this.handlePeerSignal(message.userId, message.payload);
121
+ case "offer":
122
+ await this.handleOffer(message);
123
+ break;
124
+ case "answer":
125
+ await this.handleAnswer(message);
126
+ break;
127
+ case "candidate":
128
+ await this.handleCandidate(message);
112
129
  break;
113
130
  case "user-left":
114
131
  this.emit("userLeft", message.userId);
115
132
  break;
116
133
  }
117
134
  }
118
- initPeer(initiator) {
119
- if (this.peer) return;
120
- const config = {
121
- iceServers: this.iceServers
122
- };
123
- this.peer = new import_simple_peer.default({
124
- initiator,
125
- trickle: true,
126
- stream: this.localStream || void 0,
127
- config
128
- });
129
- this.peer.on("signal", (data) => {
130
- this.send({
131
- type: "signal",
132
- userId: this.userId,
133
- roomId: this.roomId,
134
- payload: data
135
- });
136
- });
137
- this.peer.on("stream", (stream) => {
138
- this.remoteStream = stream;
139
- this.emit("remoteStream", stream);
140
- if (!this.isConnectedFlag) {
141
- this.isConnectedFlag = true;
142
- this.emit("connected");
143
- }
144
- });
145
- this.peer.on("connect", () => {
146
- if (!this.isConnectedFlag) {
147
- this.isConnectedFlag = true;
148
- this.emit("connected");
149
- }
135
+ async createOffer() {
136
+ const offer = await this.pc.createOffer();
137
+ await this.pc.setLocalDescription(offer);
138
+ this.send({
139
+ type: "offer",
140
+ sdp: this.pc.localDescription
150
141
  });
151
- this.peer.on("error", (err) => {
152
- console.error("Peer error:", err);
142
+ }
143
+ async handleOffer(message) {
144
+ const offer = new RTCSessionDescription(message.sdp);
145
+ await this.pc.setRemoteDescription(offer);
146
+ const answer = await this.pc.createAnswer();
147
+ await this.pc.setLocalDescription(answer);
148
+ this.send({
149
+ type: "answer",
150
+ sdp: this.pc.localDescription
153
151
  });
154
152
  }
155
- handlePeerSignal(targetUserId, signal) {
156
- if (!this.peer) {
157
- this.initPeer(false);
158
- }
159
- this.peer?.signal(signal);
153
+ async handleAnswer(message) {
154
+ const answer = new RTCSessionDescription(message.sdp);
155
+ await this.pc.setRemoteDescription(answer);
156
+ }
157
+ async handleCandidate(message) {
158
+ const candidate = new RTCIceCandidate(message.candidate);
159
+ await this.pc.addIceCandidate(candidate);
160
160
  }
161
161
  send(data) {
162
162
  if (this.ws?.readyState === WebSocket.OPEN) {
@@ -168,10 +168,8 @@ var VoiceClient = class {
168
168
  this.send({ type: "leave", roomId: this.roomId, userId: this.userId });
169
169
  this.ws.close();
170
170
  }
171
- this.peer?.destroy();
172
- if (this.localStream) {
173
- this.localStream.getTracks().forEach((track) => track.stop());
174
- }
171
+ this.pc?.close();
172
+ this.localStream?.getTracks().forEach((track) => track.stop());
175
173
  this.isConnectedFlag = false;
176
174
  this.emit("disconnected");
177
175
  }
package/dist/index.mjs CHANGED
@@ -1,9 +1,8 @@
1
1
  // src/VoiceClient.ts
2
- import Peer from "simple-peer";
3
2
  var VoiceClient = class {
4
3
  constructor(config) {
5
4
  this.ws = null;
6
- this.peer = null;
5
+ this.pc = null;
7
6
  this.localStream = null;
8
7
  this.remoteStream = null;
9
8
  this.eventHandlers = /* @__PURE__ */ new Map();
@@ -12,8 +11,7 @@ var VoiceClient = class {
12
11
  this.roomId = config.roomId;
13
12
  this.userId = config.userId;
14
13
  this.iceServers = config.iceServers || [
15
- { urls: "stun:stun.l.google.com:19302" },
16
- { urls: "stun:stun1.l.google.com:19302" }
14
+ { urls: "stun:stun.l.google.com:19302" }
17
15
  ];
18
16
  if (config.autoConnect !== false) {
19
17
  this.connect();
@@ -34,6 +32,7 @@ var VoiceClient = class {
34
32
  async connect() {
35
33
  try {
36
34
  await this.initMicrophone();
35
+ this.initPeerConnection();
37
36
  this.initWebSocket();
38
37
  } catch (error) {
39
38
  this.emit("error", error);
@@ -49,78 +48,89 @@ var VoiceClient = class {
49
48
  });
50
49
  this.emit("localStream", this.localStream);
51
50
  }
51
+ initPeerConnection() {
52
+ this.pc = new RTCPeerConnection({ iceServers: this.iceServers });
53
+ this.localStream?.getTracks().forEach((track) => {
54
+ this.pc.addTrack(track, this.localStream);
55
+ });
56
+ this.pc.ontrack = (event) => {
57
+ this.remoteStream = event.streams[0];
58
+ this.emit("remoteStream", this.remoteStream);
59
+ if (!this.isConnectedFlag) {
60
+ this.isConnectedFlag = true;
61
+ this.emit("connected");
62
+ }
63
+ };
64
+ this.pc.onicecandidate = (event) => {
65
+ if (event.candidate) {
66
+ this.send({
67
+ type: "candidate",
68
+ candidate: event.candidate
69
+ });
70
+ }
71
+ };
72
+ }
52
73
  initWebSocket() {
53
74
  const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
54
75
  this.ws = new WebSocket(url);
55
76
  this.ws.onopen = () => {
56
77
  this.send({ type: "join", roomId: this.roomId, userId: this.userId });
57
78
  };
58
- this.ws.onmessage = (event) => {
79
+ this.ws.onmessage = async (event) => {
59
80
  const message = JSON.parse(event.data);
60
- this.handleSignalingMessage(message);
81
+ await this.handleSignalingMessage(message);
61
82
  };
62
83
  this.ws.onclose = () => {
63
84
  this.emit("disconnected");
64
85
  };
65
86
  }
66
- handleSignalingMessage(message) {
87
+ async handleSignalingMessage(message) {
67
88
  switch (message.type) {
68
89
  case "user-joined":
69
90
  if (message.userId !== this.userId) {
70
- this.initPeer(true);
91
+ await this.createOffer();
71
92
  this.emit("userJoined", message.userId);
72
93
  }
73
94
  break;
74
- case "signal":
75
- this.handlePeerSignal(message.userId, message.payload);
95
+ case "offer":
96
+ await this.handleOffer(message);
97
+ break;
98
+ case "answer":
99
+ await this.handleAnswer(message);
100
+ break;
101
+ case "candidate":
102
+ await this.handleCandidate(message);
76
103
  break;
77
104
  case "user-left":
78
105
  this.emit("userLeft", message.userId);
79
106
  break;
80
107
  }
81
108
  }
82
- initPeer(initiator) {
83
- if (this.peer) return;
84
- const config = {
85
- iceServers: this.iceServers
86
- };
87
- this.peer = new Peer({
88
- initiator,
89
- trickle: true,
90
- stream: this.localStream || void 0,
91
- config
92
- });
93
- this.peer.on("signal", (data) => {
94
- this.send({
95
- type: "signal",
96
- userId: this.userId,
97
- roomId: this.roomId,
98
- payload: data
99
- });
100
- });
101
- this.peer.on("stream", (stream) => {
102
- this.remoteStream = stream;
103
- this.emit("remoteStream", stream);
104
- if (!this.isConnectedFlag) {
105
- this.isConnectedFlag = true;
106
- this.emit("connected");
107
- }
108
- });
109
- this.peer.on("connect", () => {
110
- if (!this.isConnectedFlag) {
111
- this.isConnectedFlag = true;
112
- this.emit("connected");
113
- }
109
+ async createOffer() {
110
+ const offer = await this.pc.createOffer();
111
+ await this.pc.setLocalDescription(offer);
112
+ this.send({
113
+ type: "offer",
114
+ sdp: this.pc.localDescription
114
115
  });
115
- this.peer.on("error", (err) => {
116
- console.error("Peer error:", err);
116
+ }
117
+ async handleOffer(message) {
118
+ const offer = new RTCSessionDescription(message.sdp);
119
+ await this.pc.setRemoteDescription(offer);
120
+ const answer = await this.pc.createAnswer();
121
+ await this.pc.setLocalDescription(answer);
122
+ this.send({
123
+ type: "answer",
124
+ sdp: this.pc.localDescription
117
125
  });
118
126
  }
119
- handlePeerSignal(targetUserId, signal) {
120
- if (!this.peer) {
121
- this.initPeer(false);
122
- }
123
- this.peer?.signal(signal);
127
+ async handleAnswer(message) {
128
+ const answer = new RTCSessionDescription(message.sdp);
129
+ await this.pc.setRemoteDescription(answer);
130
+ }
131
+ async handleCandidate(message) {
132
+ const candidate = new RTCIceCandidate(message.candidate);
133
+ await this.pc.addIceCandidate(candidate);
124
134
  }
125
135
  send(data) {
126
136
  if (this.ws?.readyState === WebSocket.OPEN) {
@@ -132,10 +142,8 @@ var VoiceClient = class {
132
142
  this.send({ type: "leave", roomId: this.roomId, userId: this.userId });
133
143
  this.ws.close();
134
144
  }
135
- this.peer?.destroy();
136
- if (this.localStream) {
137
- this.localStream.getTracks().forEach((track) => track.stop());
138
- }
145
+ this.pc?.close();
146
+ this.localStream?.getTracks().forEach((track) => track.stop());
139
147
  this.isConnectedFlag = false;
140
148
  this.emit("disconnected");
141
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voicemaster/core",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "WebRTC voice communication core library",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -1,5 +1,3 @@
1
- import Peer from 'simple-peer';
2
-
3
1
  export interface VoiceClientConfig {
4
2
  signalingUrl: string;
5
3
  roomId: string;
@@ -10,7 +8,7 @@ export interface VoiceClientConfig {
10
8
 
11
9
  export class VoiceClient {
12
10
  private ws: WebSocket | null = null;
13
- private peer: Peer.Instance | null = null;
11
+ private pc: RTCPeerConnection | null = null;
14
12
  private localStream: MediaStream | null = null;
15
13
  private remoteStream: MediaStream | null = null;
16
14
  private eventHandlers: Map<string, Function[]> = new Map();
@@ -25,8 +23,7 @@ export class VoiceClient {
25
23
  this.roomId = config.roomId;
26
24
  this.userId = config.userId;
27
25
  this.iceServers = config.iceServers || [
28
- { urls: 'stun:stun.l.google.com:19302' },
29
- { urls: 'stun:stun1.l.google.com:19302' }
26
+ { urls: 'stun:stun.l.google.com:19302' }
30
27
  ];
31
28
 
32
29
  if (config.autoConnect !== false) {
@@ -51,6 +48,7 @@ export class VoiceClient {
51
48
  async connect(): Promise<void> {
52
49
  try {
53
50
  await this.initMicrophone();
51
+ this.initPeerConnection();
54
52
  this.initWebSocket();
55
53
  } catch (error) {
56
54
  this.emit('error', error);
@@ -68,6 +66,32 @@ export class VoiceClient {
68
66
  this.emit('localStream', this.localStream);
69
67
  }
70
68
 
69
+ private initPeerConnection(): void {
70
+ this.pc = new RTCPeerConnection({ iceServers: this.iceServers });
71
+
72
+ this.localStream?.getTracks().forEach(track => {
73
+ this.pc!.addTrack(track, this.localStream!);
74
+ });
75
+
76
+ this.pc.ontrack = (event) => {
77
+ this.remoteStream = event.streams[0];
78
+ this.emit('remoteStream', this.remoteStream);
79
+ if (!this.isConnectedFlag) {
80
+ this.isConnectedFlag = true;
81
+ this.emit('connected');
82
+ }
83
+ };
84
+
85
+ this.pc.onicecandidate = (event) => {
86
+ if (event.candidate) {
87
+ this.send({
88
+ type: 'candidate',
89
+ candidate: event.candidate
90
+ });
91
+ }
92
+ };
93
+ }
94
+
71
95
  private initWebSocket(): void {
72
96
  const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
73
97
  this.ws = new WebSocket(url);
@@ -76,9 +100,9 @@ export class VoiceClient {
76
100
  this.send({ type: 'join', roomId: this.roomId, userId: this.userId });
77
101
  };
78
102
 
79
- this.ws.onmessage = (event) => {
103
+ this.ws.onmessage = async (event) => {
80
104
  const message = JSON.parse(event.data);
81
- this.handleSignalingMessage(message);
105
+ await this.handleSignalingMessage(message);
82
106
  };
83
107
 
84
108
  this.ws.onclose = () => {
@@ -86,16 +110,22 @@ export class VoiceClient {
86
110
  };
87
111
  }
88
112
 
89
- private handleSignalingMessage(message: any): void {
113
+ private async handleSignalingMessage(message: any): Promise<void> {
90
114
  switch (message.type) {
91
115
  case 'user-joined':
92
116
  if (message.userId !== this.userId) {
93
- this.initPeer(true);
117
+ await this.createOffer();
94
118
  this.emit('userJoined', message.userId);
95
119
  }
96
120
  break;
97
- case 'signal':
98
- this.handlePeerSignal(message.userId, message.payload);
121
+ case 'offer':
122
+ await this.handleOffer(message);
123
+ break;
124
+ case 'answer':
125
+ await this.handleAnswer(message);
126
+ break;
127
+ case 'candidate':
128
+ await this.handleCandidate(message);
99
129
  break;
100
130
  case 'user-left':
101
131
  this.emit('userLeft', message.userId);
@@ -103,55 +133,34 @@ export class VoiceClient {
103
133
  }
104
134
  }
105
135
 
106
- private initPeer(initiator: boolean): void {
107
- if (this.peer) return;
108
-
109
- const config = {
110
- iceServers: this.iceServers
111
- };
112
-
113
- this.peer = new Peer({
114
- initiator,
115
- trickle: true,
116
- stream: this.localStream || undefined,
117
- config: config
118
- });
119
-
120
- this.peer.on('signal', (data) => {
121
- this.send({
122
- type: 'signal',
123
- userId: this.userId,
124
- roomId: this.roomId,
125
- payload: data
126
- });
127
- });
128
-
129
- this.peer.on('stream', (stream) => {
130
- this.remoteStream = stream;
131
- this.emit('remoteStream', stream);
132
- if (!this.isConnectedFlag) {
133
- this.isConnectedFlag = true;
134
- this.emit('connected');
135
- }
136
+ private async createOffer(): Promise<void> {
137
+ const offer = await this.pc!.createOffer();
138
+ await this.pc!.setLocalDescription(offer);
139
+ this.send({
140
+ type: 'offer',
141
+ sdp: this.pc!.localDescription
136
142
  });
143
+ }
137
144
 
138
- this.peer.on('connect', () => {
139
- if (!this.isConnectedFlag) {
140
- this.isConnectedFlag = true;
141
- this.emit('connected');
142
- }
145
+ private async handleOffer(message: any): Promise<void> {
146
+ const offer = new RTCSessionDescription(message.sdp);
147
+ await this.pc!.setRemoteDescription(offer);
148
+ const answer = await this.pc!.createAnswer();
149
+ await this.pc!.setLocalDescription(answer);
150
+ this.send({
151
+ type: 'answer',
152
+ sdp: this.pc!.localDescription
143
153
  });
154
+ }
144
155
 
145
- this.peer.on('error', (err) => {
146
- console.error('Peer error:', err);
147
- });
156
+ private async handleAnswer(message: any): Promise<void> {
157
+ const answer = new RTCSessionDescription(message.sdp);
158
+ await this.pc!.setRemoteDescription(answer);
148
159
  }
149
160
 
150
- private handlePeerSignal(targetUserId: string, signal: any): void {
151
- if (!this.peer) {
152
- this.initPeer(false);
153
- }
154
- this.peer?.signal(signal);
161
+ private async handleCandidate(message: any): Promise<void> {
162
+ const candidate = new RTCIceCandidate(message.candidate);
163
+ await this.pc!.addIceCandidate(candidate);
155
164
  }
156
165
 
157
166
  private send(data: any): void {
@@ -165,10 +174,8 @@ export class VoiceClient {
165
174
  this.send({ type: 'leave', roomId: this.roomId, userId: this.userId });
166
175
  this.ws.close();
167
176
  }
168
- this.peer?.destroy();
169
- if (this.localStream) {
170
- this.localStream.getTracks().forEach(track => track.stop());
171
- }
177
+ this.pc?.close();
178
+ this.localStream?.getTracks().forEach(track => track.stop());
172
179
  this.isConnectedFlag = false;
173
180
  this.emit('disconnected');
174
181
  }