@voicemaster/core 1.0.3 → 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();
@@ -69,6 +58,7 @@ var VoiceClient = class {
69
58
  async connect() {
70
59
  try {
71
60
  await this.initMicrophone();
61
+ this.initPeerConnection();
72
62
  this.initWebSocket();
73
63
  } catch (error) {
74
64
  this.emit("error", error);
@@ -84,75 +74,89 @@ var VoiceClient = class {
84
74
  });
85
75
  this.emit("localStream", this.localStream);
86
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
+ }
87
99
  initWebSocket() {
88
100
  const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
89
101
  this.ws = new WebSocket(url);
90
102
  this.ws.onopen = () => {
91
103
  this.send({ type: "join", roomId: this.roomId, userId: this.userId });
92
104
  };
93
- this.ws.onmessage = (event) => {
105
+ this.ws.onmessage = async (event) => {
94
106
  const message = JSON.parse(event.data);
95
- this.handleSignalingMessage(message);
107
+ await this.handleSignalingMessage(message);
96
108
  };
97
109
  this.ws.onclose = () => {
98
110
  this.emit("disconnected");
99
111
  };
100
112
  }
101
- handleSignalingMessage(message) {
113
+ async handleSignalingMessage(message) {
102
114
  switch (message.type) {
103
115
  case "user-joined":
104
116
  if (message.userId !== this.userId) {
105
- this.initPeer(true);
117
+ await this.createOffer();
106
118
  this.emit("userJoined", message.userId);
107
119
  }
108
120
  break;
109
- case "signal":
110
- 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);
111
129
  break;
112
130
  case "user-left":
113
131
  this.emit("userLeft", message.userId);
114
132
  break;
115
133
  }
116
134
  }
117
- initPeer(initiator) {
118
- if (this.peer) return;
119
- this.peer = new import_simple_peer.default({
120
- initiator,
121
- trickle: true,
122
- stream: this.localStream || void 0,
123
- config: { iceServers: this.iceServers }
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
124
141
  });
125
- this.peer.on("signal", (data) => {
126
- this.send({
127
- type: "signal",
128
- userId: this.userId,
129
- roomId: this.roomId,
130
- payload: data
131
- });
132
- });
133
- this.peer.on("stream", (stream) => {
134
- this.remoteStream = stream;
135
- this.emit("remoteStream", stream);
136
- if (!this.isConnectedFlag) {
137
- this.isConnectedFlag = true;
138
- this.emit("connected");
139
- }
140
- });
141
- this.peer.on("connect", () => {
142
- if (!this.isConnectedFlag) {
143
- this.isConnectedFlag = true;
144
- this.emit("connected");
145
- }
146
- });
147
- this.peer.on("error", (err) => {
148
- 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
149
151
  });
150
152
  }
151
- handlePeerSignal(targetUserId, signal) {
152
- if (!this.peer) {
153
- this.initPeer(false);
154
- }
155
- 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);
156
160
  }
157
161
  send(data) {
158
162
  if (this.ws?.readyState === WebSocket.OPEN) {
@@ -164,10 +168,8 @@ var VoiceClient = class {
164
168
  this.send({ type: "leave", roomId: this.roomId, userId: this.userId });
165
169
  this.ws.close();
166
170
  }
167
- this.peer?.destroy();
168
- if (this.localStream) {
169
- this.localStream.getTracks().forEach((track) => track.stop());
170
- }
171
+ this.pc?.close();
172
+ this.localStream?.getTracks().forEach((track) => track.stop());
171
173
  this.isConnectedFlag = false;
172
174
  this.emit("disconnected");
173
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();
@@ -33,6 +32,7 @@ var VoiceClient = class {
33
32
  async connect() {
34
33
  try {
35
34
  await this.initMicrophone();
35
+ this.initPeerConnection();
36
36
  this.initWebSocket();
37
37
  } catch (error) {
38
38
  this.emit("error", error);
@@ -48,75 +48,89 @@ var VoiceClient = class {
48
48
  });
49
49
  this.emit("localStream", this.localStream);
50
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
+ }
51
73
  initWebSocket() {
52
74
  const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
53
75
  this.ws = new WebSocket(url);
54
76
  this.ws.onopen = () => {
55
77
  this.send({ type: "join", roomId: this.roomId, userId: this.userId });
56
78
  };
57
- this.ws.onmessage = (event) => {
79
+ this.ws.onmessage = async (event) => {
58
80
  const message = JSON.parse(event.data);
59
- this.handleSignalingMessage(message);
81
+ await this.handleSignalingMessage(message);
60
82
  };
61
83
  this.ws.onclose = () => {
62
84
  this.emit("disconnected");
63
85
  };
64
86
  }
65
- handleSignalingMessage(message) {
87
+ async handleSignalingMessage(message) {
66
88
  switch (message.type) {
67
89
  case "user-joined":
68
90
  if (message.userId !== this.userId) {
69
- this.initPeer(true);
91
+ await this.createOffer();
70
92
  this.emit("userJoined", message.userId);
71
93
  }
72
94
  break;
73
- case "signal":
74
- 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);
75
103
  break;
76
104
  case "user-left":
77
105
  this.emit("userLeft", message.userId);
78
106
  break;
79
107
  }
80
108
  }
81
- initPeer(initiator) {
82
- if (this.peer) return;
83
- this.peer = new Peer({
84
- initiator,
85
- trickle: true,
86
- stream: this.localStream || void 0,
87
- config: { iceServers: this.iceServers }
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
88
115
  });
89
- this.peer.on("signal", (data) => {
90
- this.send({
91
- type: "signal",
92
- userId: this.userId,
93
- roomId: this.roomId,
94
- payload: data
95
- });
96
- });
97
- this.peer.on("stream", (stream) => {
98
- this.remoteStream = stream;
99
- this.emit("remoteStream", stream);
100
- if (!this.isConnectedFlag) {
101
- this.isConnectedFlag = true;
102
- this.emit("connected");
103
- }
104
- });
105
- this.peer.on("connect", () => {
106
- if (!this.isConnectedFlag) {
107
- this.isConnectedFlag = true;
108
- this.emit("connected");
109
- }
110
- });
111
- this.peer.on("error", (err) => {
112
- 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
113
125
  });
114
126
  }
115
- handlePeerSignal(targetUserId, signal) {
116
- if (!this.peer) {
117
- this.initPeer(false);
118
- }
119
- 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);
120
134
  }
121
135
  send(data) {
122
136
  if (this.ws?.readyState === WebSocket.OPEN) {
@@ -128,10 +142,8 @@ var VoiceClient = class {
128
142
  this.send({ type: "leave", roomId: this.roomId, userId: this.userId });
129
143
  this.ws.close();
130
144
  }
131
- this.peer?.destroy();
132
- if (this.localStream) {
133
- this.localStream.getTracks().forEach((track) => track.stop());
134
- }
145
+ this.pc?.close();
146
+ this.localStream?.getTracks().forEach((track) => track.stop());
135
147
  this.isConnectedFlag = false;
136
148
  this.emit("disconnected");
137
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voicemaster/core",
3
- "version": "1.0.3",
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();
@@ -50,6 +48,7 @@ export class VoiceClient {
50
48
  async connect(): Promise<void> {
51
49
  try {
52
50
  await this.initMicrophone();
51
+ this.initPeerConnection();
53
52
  this.initWebSocket();
54
53
  } catch (error) {
55
54
  this.emit('error', error);
@@ -67,6 +66,32 @@ export class VoiceClient {
67
66
  this.emit('localStream', this.localStream);
68
67
  }
69
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
+
70
95
  private initWebSocket(): void {
71
96
  const url = `${this.signalingUrl}?userId=${this.userId}&roomId=${this.roomId}`;
72
97
  this.ws = new WebSocket(url);
@@ -75,9 +100,9 @@ export class VoiceClient {
75
100
  this.send({ type: 'join', roomId: this.roomId, userId: this.userId });
76
101
  };
77
102
 
78
- this.ws.onmessage = (event) => {
103
+ this.ws.onmessage = async (event) => {
79
104
  const message = JSON.parse(event.data);
80
- this.handleSignalingMessage(message);
105
+ await this.handleSignalingMessage(message);
81
106
  };
82
107
 
83
108
  this.ws.onclose = () => {
@@ -85,16 +110,22 @@ export class VoiceClient {
85
110
  };
86
111
  }
87
112
 
88
- private handleSignalingMessage(message: any): void {
113
+ private async handleSignalingMessage(message: any): Promise<void> {
89
114
  switch (message.type) {
90
115
  case 'user-joined':
91
116
  if (message.userId !== this.userId) {
92
- this.initPeer(true);
117
+ await this.createOffer();
93
118
  this.emit('userJoined', message.userId);
94
119
  }
95
120
  break;
96
- case 'signal':
97
- 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);
98
129
  break;
99
130
  case 'user-left':
100
131
  this.emit('userLeft', message.userId);
@@ -102,52 +133,34 @@ export class VoiceClient {
102
133
  }
103
134
  }
104
135
 
105
- private initPeer(initiator: boolean): void {
106
- if (this.peer) return;
107
-
108
- this.peer = new Peer({
109
- initiator,
110
- trickle: true,
111
- stream: this.localStream || undefined,
112
- config: { iceServers: this.iceServers }
113
- });
114
-
115
- this.peer.on('signal', (data) => {
116
- this.send({
117
- type: 'signal',
118
- userId: this.userId,
119
- roomId: this.roomId,
120
- payload: data
121
- });
122
- });
123
-
124
- this.peer.on('stream', (stream) => {
125
- this.remoteStream = stream;
126
- this.emit('remoteStream', stream);
127
- // Когда получили удалённый поток — значит соединение установлено
128
- if (!this.isConnectedFlag) {
129
- this.isConnectedFlag = true;
130
- this.emit('connected');
131
- }
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
132
142
  });
143
+ }
133
144
 
134
- this.peer.on('connect', () => {
135
- if (!this.isConnectedFlag) {
136
- this.isConnectedFlag = true;
137
- this.emit('connected');
138
- }
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
139
153
  });
154
+ }
140
155
 
141
- this.peer.on('error', (err) => {
142
- console.error('Peer error:', err);
143
- });
156
+ private async handleAnswer(message: any): Promise<void> {
157
+ const answer = new RTCSessionDescription(message.sdp);
158
+ await this.pc!.setRemoteDescription(answer);
144
159
  }
145
160
 
146
- private handlePeerSignal(targetUserId: string, signal: any): void {
147
- if (!this.peer) {
148
- this.initPeer(false);
149
- }
150
- 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);
151
164
  }
152
165
 
153
166
  private send(data: any): void {
@@ -161,10 +174,8 @@ export class VoiceClient {
161
174
  this.send({ type: 'leave', roomId: this.roomId, userId: this.userId });
162
175
  this.ws.close();
163
176
  }
164
- this.peer?.destroy();
165
- if (this.localStream) {
166
- this.localStream.getTracks().forEach(track => track.stop());
167
- }
177
+ this.pc?.close();
178
+ this.localStream?.getTracks().forEach(track => track.stop());
168
179
  this.isConnectedFlag = false;
169
180
  this.emit('disconnected');
170
181
  }
@@ -186,7 +197,6 @@ export class VoiceClient {
186
197
  return this.userId;
187
198
  }
188
199
  }
189
-
190
200
  export interface VoiceEvents {
191
201
  connected: () => void;
192
202
  disconnected: () => void;