videocall-client-socket 0.1.7 → 0.1.8

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 📞 videocall-socket-client
2
2
 
3
- A simple WebRTC client library for peer-to-peer video calls using [simple-peer](https://www.npmjs.com/package/simple-peer) and [socket.io-client](https://www.npmjs.com/package/socket.io-client).
3
+ A WebRTC client library for multi-user video calls (mesh per room) using [simple-peer](https://www.npmjs.com/package/simple-peer) and [socket.io-client](https://www.npmjs.com/package/socket.io-client).
4
4
 
5
5
  > ✅ Designed to work with [videocall-server](https://github.com/EmersonJaraG28/videocall-server)
6
6
 
@@ -30,7 +30,10 @@ This makes SimplePeer available globally in the browser.
30
30
  import * as VideoClient from "videocall-client-socket";
31
31
  import { v4 as uuidv4 } from "uuid";
32
32
 
33
- const userId = uuidv4();
33
+ // Stable user identity (same user across devices/sessions)
34
+ const userId = "user-123";
35
+ // Unique device/session identity
36
+ const userUUID = uuidv4();
34
37
  const channelName = "roomABC";
35
38
 
36
39
  // Step 1: Subscribe to events before anything else
@@ -39,33 +42,30 @@ VideoClient.on("user-published", (data) => {
39
42
  const video = document.createElement("video");
40
43
  video.srcObject = user.videotrack;
41
44
  video.autoplay = true;
42
- video.id = user.uuid;
45
+ video.id = user.userUUID;
43
46
  document.body.appendChild(video);
44
47
  });
45
48
  VideoClient.on("user-unpublished", (data) => {
46
49
  const { user, mediaType } = data;
47
50
  if (mediaType === "video") {
48
- const video = document.getElementById(`${user.uuid}`);
51
+ const video = document.getElementById(`${user.userUUID}`);
49
52
  if (video) {
50
53
  video.remove();
51
54
  }
52
55
  }
53
56
  });
54
57
  VideoClient.on("user-media-toggled", (data) => {
55
- console.log(data.user.uuid, data.type, data.enabled);
58
+ console.log(data.user.userId, data.user.userUUID, data.type, data.enabled);
56
59
  });
57
60
 
58
61
  // Step 2: Create media stream
59
- SocketClient.createMediaStream()
62
+ VideoClient.createMediaStream()
60
63
  .then(() => {
61
64
  // Step 3: Play local stream in <video> tag
62
65
  VideoClient.playVideoTrack("localVideo");
63
- SocketClient.joinChannel(userId, channelName);
64
-
65
- // Step 4: Join the signaling channel
66
- //IMPORTANT: The service repository is located at the bottom.
67
66
  VideoClient.setServerURL("http://localhost:3000");
68
- VideoClient.joinChannel(userId, channelName);
67
+ // Step 4: Join the signaling channel
68
+ VideoClient.joinChannel(userId, userUUID, channelName);
69
69
  })
70
70
  .catch((err) => {
71
71
  console.error(err);
@@ -83,7 +83,7 @@ SocketClient.createMediaStream()
83
83
  | 1️⃣ | `on(...)` | You must subscribe to events **before** joining the channel. |
84
84
  | 2️⃣ | `createMediaStream()` | This requests access to camera and microphone. |
85
85
  | 3️⃣ | `playVideoTrack(videoElementId)` | This shows your local stream in a `<video>` tag. |
86
- | 4️⃣ | `joinChannel(userId, room)` | Finally, join the signaling server and start peer connections. |
86
+ | 4️⃣ | `joinChannel(userId, userUUID, room)` | Finally, join the signaling server and start peer connections. |
87
87
 
88
88
  > 🧠 Skipping or reordering these steps may cause video/audio to not work properly or event listeners to be missed.
89
89
 
@@ -94,7 +94,7 @@ SocketClient.createMediaStream()
94
94
  ### 🔌 Connection
95
95
 
96
96
  - `setServerURL(url: string): void`
97
- - `joinChannel(userId: string, room: string): void`
97
+ - `joinChannel(userId: string, userUUID: string, room: string): void`
98
98
  - `leaveChannel(): void`
99
99
 
100
100
  ### 🎥 Media Controls
@@ -110,9 +110,9 @@ SocketClient.createMediaStream()
110
110
 
111
111
  Use `on(event, callback)` and `off(event, callback)`.
112
112
 
113
- - `user-published`: `{ user: { uuid, videotrack }, mediaType }`
114
- - `user-unpublished`: `{ user: { uuid }, mediaType }`
115
- - `user-media-toggled`: `{ user: { uuid }, type, enabled }`
113
+ - `user-published`: `{ user: { userId, userUUID, videotrack }, mediaType }`
114
+ - `user-unpublished`: `{ user: { userId, userUUID }, mediaType }`
115
+ - `user-media-toggled`: `{ user: { userId, userUUID }, type, enabled }`
116
116
 
117
117
  #### Example:
118
118
 
@@ -121,13 +121,22 @@ VideoClient.on("user-published", ({ user }) => {
121
121
  const video = document.createElement("video");
122
122
  video.srcObject = user.videotrack;
123
123
  video.autoplay = true;
124
- video.id = user.uuid;
124
+ video.id = user.userUUID;
125
125
  document.body.appendChild(video);
126
126
  });
127
127
  ```
128
128
 
129
129
  ---
130
130
 
131
+ ## 🕸 Multi-user Model
132
+
133
+ - Each room supports multiple participants.
134
+ - WebRTC connections are created in mesh mode (one peer connection per remote participant).
135
+ - `userId` identifies the person.
136
+ - `userUUID` identifies a specific device/session for that person.
137
+
138
+ ---
139
+
131
140
  ## 🧩 Backend Integration
132
141
 
133
142
  This library is designed to work with the following signaling server:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "videocall-client-socket",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "main": "src/index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "scripts": {
package/src/index.d.ts CHANGED
@@ -14,6 +14,6 @@ declare module 'videocall-client-socket' {
14
14
 
15
15
  export function playVideoTrack(localVideoId: string): void;
16
16
 
17
- export function joinChannel(userId: string, channelName: string): void;
17
+ export function joinChannel(userId: string, userUUID: string, channelName: string): void;
18
18
  export function leaveChannel(): void;
19
- }
19
+ }
package/src/index.js CHANGED
@@ -5,6 +5,7 @@ var socket = null;
5
5
  var mediastream = null;
6
6
  var localVideoId = "";
7
7
  var userId = "";
8
+ var userUUID = "";
8
9
  var serverURL = 'http://localhost:3000';
9
10
  let events = {};
10
11
 
@@ -90,51 +91,59 @@ export function playVideoTrack(_localVideoId) {
90
91
  /**
91
92
  * Connects to the signaling server and joins a room.
92
93
  * @param {string} _userId - Unique identifier for the user.
94
+ * @param {string} _userUUID - Unique identifier for this device/session.
93
95
  * @param {string} channelName - The name of the room to join.
94
96
  */
95
- export function joinChannel(_userId, channelName) {
97
+ export function joinChannel(_userId, _userUUID, channelName) {
96
98
  userId = _userId;
99
+ userUUID = _userUUID;
97
100
 
98
101
  socket = io(serverURL, {
99
- query: { room: channelName, userId }
102
+ query: { room: channelName, userId, userUUID }
100
103
  });
101
104
 
102
105
  socket.on('all-users', users => {
103
- users.forEach(({ userId: remoteUserId, socketId, }) => {
104
- const peer = createPeer(socket, mediastream, socketId, remoteUserId, true);
105
- peers[remoteUserId] = peer;
106
+ users.forEach(({ userId: remoteUserId, userUUID: remoteUserUUID, socketId, }) => {
107
+ const peer = createPeer(socket, mediastream, socketId, remoteUserId, remoteUserUUID, true);
108
+ peers[remoteUserUUID] = peer;
106
109
  });
107
110
  });
108
111
 
109
- socket.on('user-joined', ({ userId: newUserId, socketId: newSocketId }) => {
110
- console.log("User joined", newUserId, newSocketId);
112
+ socket.on('user-joined', ({ userId: newUserId, userUUID: newUserUUID, socketId: newSocketId }) => {
113
+ // console.log("User joined", newUserId, newUserUUID, newSocketId);
111
114
 
112
- const peer = createPeer(socket, mediastream, newSocketId, newUserId, false);
113
- peers[newUserId] = peer;
115
+ const peer = createPeer(socket, mediastream, newSocketId, newUserId, newUserUUID, false);
116
+ peers[newUserUUID] = peer;
114
117
  });
115
118
 
116
- socket.on('signal', ({ fromUserId, signal }) => {
117
- const peer = peers[fromUserId];
119
+ socket.on('signal', ({ fromUserId, fromUserUUID, signal }) => {
120
+ const peer = peers[fromUserUUID || fromUserId];
118
121
  if (peer) {
119
122
  peer.signal(signal);
120
123
  }
121
124
  });
122
125
 
123
- socket.on('user-left', ({ userId: leftUserId }) => {
124
- if (peers[leftUserId]) {
125
- peers[leftUserId].destroy();
126
- delete peers[leftUserId];
126
+ socket.on('user-left', ({ userId: leftUserId, userUUID: leftUserUUID }) => {
127
+ if (peers[leftUserUUID]) {
128
+ peers[leftUserUUID].destroy();
129
+ delete peers[leftUserUUID];
127
130
  }
128
131
 
129
132
  emit("user-unpublished", {
130
- user: { uuid: leftUserId },
133
+ user: {
134
+ userId: leftUserId,
135
+ userUUID: leftUserUUID
136
+ },
131
137
  mediaType: "video"
132
138
  });
133
139
  });
134
140
 
135
- socket.on('user-media-toggled', ({ userId, type, enabled }) => {
141
+ socket.on('user-media-toggled', ({ userId, userUUID, type, enabled }) => {
136
142
  emit('user-media-toggled', {
137
- user: { uuid: userId },
143
+ user: {
144
+ userId,
145
+ userUUID
146
+ },
138
147
  type,
139
148
  enabled
140
149
  });
@@ -177,10 +186,11 @@ export function leaveChannel() {
177
186
  * @param {MediaStream} localStream - The local media stream.
178
187
  * @param {string} targetSocketId - The socket ID of the remote user.
179
188
  * @param {string} remoteUserId - The ID of the remote user.
189
+ * @param {string} remoteUserUUID - The device/session ID of the remote user.
180
190
  * @param {boolean} initiator - Whether this peer initiates the connection.
181
191
  * @returns {SimplePeer.Instance} - The created peer.
182
192
  */
183
- function createPeer(socket, localStream, targetSocketId, remoteUserId, initiator) {
193
+ function createPeer(socket, localStream, targetSocketId, remoteUserId, remoteUserUUID, initiator) {
184
194
  const peer = new SimplePeer({
185
195
  initiator,
186
196
  trickle: false,
@@ -198,7 +208,8 @@ function createPeer(socket, localStream, targetSocketId, remoteUserId, initiator
198
208
 
199
209
  emit("user-published", {
200
210
  user: {
201
- uuid: remoteUserId,
211
+ userId: remoteUserId,
212
+ userUUID: remoteUserUUID,
202
213
  videotrack: stream
203
214
  },
204
215
  mediaType: "video"
@@ -207,7 +218,6 @@ function createPeer(socket, localStream, targetSocketId, remoteUserId, initiator
207
218
  setTimeout(() => {
208
219
  socket.emit('initial-media-status', {
209
220
  targetId: targetSocketId,
210
- userId: userId,
211
221
  audio: isAudioOn(),
212
222
  video: isCameraOn()
213
223
  });
@@ -231,7 +241,7 @@ export function toggleCamera(on) {
231
241
  track.enabled = on;
232
242
  });
233
243
  if (socket) {
234
- socket.emit('media-toggle', { userId, type: 'video', enabled: on });
244
+ socket.emit('media-toggle', { userId, userUUID, type: 'video', enabled: on });
235
245
  }
236
246
  }
237
247
 
@@ -254,7 +264,7 @@ export function toggleAudio(on) {
254
264
  track.enabled = on;
255
265
  });
256
266
  if (socket) {
257
- socket.emit('media-toggle', { userId, type: 'audio', enabled: on });
267
+ socket.emit('media-toggle', { userId, userUUID, type: 'audio', enabled: on });
258
268
  }
259
269
  }
260
270