@afosecure/meetingsdk 1.4.6 → 1.4.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/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +212 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +212 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -128,6 +128,8 @@ declare class VideoSDKCore {
|
|
|
128
128
|
private pubPC;
|
|
129
129
|
private subPC;
|
|
130
130
|
private pendingTracks;
|
|
131
|
+
private subscriberNegotiating;
|
|
132
|
+
private subscriberOfferQueue;
|
|
131
133
|
private iceServers;
|
|
132
134
|
private lastPong;
|
|
133
135
|
private intentionalDisconnect;
|
|
@@ -148,12 +150,14 @@ declare class VideoSDKCore {
|
|
|
148
150
|
private pendingRequestId;
|
|
149
151
|
private iceTransportPolicy;
|
|
150
152
|
constructor(events?: Events, url?: string);
|
|
153
|
+
private acquireLocalMedia;
|
|
151
154
|
initLocal(video: HTMLVideoElement, name: string): Promise<void>;
|
|
152
155
|
joinMeeting(config: MeetingConfig): Promise<void>;
|
|
153
156
|
private setupPublisherPC;
|
|
154
157
|
private setupSubscriberPC;
|
|
155
158
|
connect(roomId: string, name: string): Promise<void>;
|
|
156
159
|
private handle;
|
|
160
|
+
private handleSubscriberOffer;
|
|
157
161
|
private createPublisherOffer;
|
|
158
162
|
toggleMic(): void;
|
|
159
163
|
toggleCam(): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -128,6 +128,8 @@ declare class VideoSDKCore {
|
|
|
128
128
|
private pubPC;
|
|
129
129
|
private subPC;
|
|
130
130
|
private pendingTracks;
|
|
131
|
+
private subscriberNegotiating;
|
|
132
|
+
private subscriberOfferQueue;
|
|
131
133
|
private iceServers;
|
|
132
134
|
private lastPong;
|
|
133
135
|
private intentionalDisconnect;
|
|
@@ -148,12 +150,14 @@ declare class VideoSDKCore {
|
|
|
148
150
|
private pendingRequestId;
|
|
149
151
|
private iceTransportPolicy;
|
|
150
152
|
constructor(events?: Events, url?: string);
|
|
153
|
+
private acquireLocalMedia;
|
|
151
154
|
initLocal(video: HTMLVideoElement, name: string): Promise<void>;
|
|
152
155
|
joinMeeting(config: MeetingConfig): Promise<void>;
|
|
153
156
|
private setupPublisherPC;
|
|
154
157
|
private setupSubscriberPC;
|
|
155
158
|
connect(roomId: string, name: string): Promise<void>;
|
|
156
159
|
private handle;
|
|
160
|
+
private handleSubscriberOffer;
|
|
157
161
|
private createPublisherOffer;
|
|
158
162
|
toggleMic(): void;
|
|
159
163
|
toggleCam(): void;
|
package/dist/index.js
CHANGED
|
@@ -40,8 +40,8 @@ var import_react2 = require("react");
|
|
|
40
40
|
|
|
41
41
|
// src/config/ws.ts
|
|
42
42
|
var SDK_CONFIG = {
|
|
43
|
-
wsUrl: "wss://
|
|
44
|
-
baseUrl: "https://
|
|
43
|
+
wsUrl: "wss://sfuserver-production.up.railway.app/ws",
|
|
44
|
+
baseUrl: "https://sfuserver-production.up.railway.app"
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
// src/core/MeetingState.ts
|
|
@@ -200,7 +200,9 @@ var VideoSDKCore = class {
|
|
|
200
200
|
this.ws = null;
|
|
201
201
|
this.pubPC = null;
|
|
202
202
|
this.subPC = null;
|
|
203
|
-
this.pendingTracks =
|
|
203
|
+
this.pendingTracks = /* @__PURE__ */ new Map();
|
|
204
|
+
this.subscriberNegotiating = false;
|
|
205
|
+
this.subscriberOfferQueue = [];
|
|
204
206
|
this.iceServers = [];
|
|
205
207
|
this.lastPong = Date.now();
|
|
206
208
|
this.intentionalDisconnect = false;
|
|
@@ -224,33 +226,84 @@ var VideoSDKCore = class {
|
|
|
224
226
|
this.myId = localStorage.getItem("vsdk_id") || crypto.randomUUID();
|
|
225
227
|
localStorage.setItem("vsdk_id", this.myId);
|
|
226
228
|
}
|
|
229
|
+
async acquireLocalMedia(options) {
|
|
230
|
+
const { videoConstraints = true, audioConstraints = true } = options;
|
|
231
|
+
try {
|
|
232
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
233
|
+
video: videoConstraints,
|
|
234
|
+
audio: audioConstraints
|
|
235
|
+
});
|
|
236
|
+
const hasVideo = stream.getVideoTracks().some((t) => t.readyState === "live");
|
|
237
|
+
const hasAudio = stream.getAudioTracks().some((t) => t.readyState === "live");
|
|
238
|
+
return { stream, camEnabled: hasVideo, micEnabled: hasAudio };
|
|
239
|
+
} catch (err) {
|
|
240
|
+
console.warn(
|
|
241
|
+
"[VideoSDKCore] Primary getUserMedia failed:",
|
|
242
|
+
err?.name || err?.message
|
|
243
|
+
);
|
|
244
|
+
const isDeviceLocked = err?.name === "NotReadableError" || err?.name === "TrackStartError" || err?.message?.toLowerCase().includes("allocate videosource") || err?.message?.toLowerCase().includes("could not start video source");
|
|
245
|
+
if (isDeviceLocked) {
|
|
246
|
+
console.warn(
|
|
247
|
+
"[VideoSDKCore] Camera is locked by another browser/app. Falling back to Audio-Only."
|
|
248
|
+
);
|
|
249
|
+
try {
|
|
250
|
+
const audioOnlyStream = await navigator.mediaDevices.getUserMedia({
|
|
251
|
+
video: false,
|
|
252
|
+
audio: audioConstraints
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
stream: audioOnlyStream,
|
|
256
|
+
camEnabled: false,
|
|
257
|
+
micEnabled: audioOnlyStream.getAudioTracks().some((t) => t.readyState === "live")
|
|
258
|
+
};
|
|
259
|
+
} catch (audioErr) {
|
|
260
|
+
console.warn(
|
|
261
|
+
"[VideoSDKCore] Audio acquisition also failed. Falling back to View-Only stream."
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
stream: new MediaStream(),
|
|
267
|
+
camEnabled: false,
|
|
268
|
+
micEnabled: false
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
227
272
|
// ---------------- MEDIA SETUP ----------------
|
|
228
273
|
async initLocal(video, name) {
|
|
229
274
|
this.participantName = name;
|
|
230
275
|
try {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
276
|
+
const { stream, camEnabled, micEnabled } = await this.acquireLocalMedia({
|
|
277
|
+
videoConstraints: { width: { ideal: 1280 }, height: { ideal: 720 } },
|
|
278
|
+
audioConstraints: {
|
|
234
279
|
echoCancellation: true,
|
|
235
280
|
noiseSuppression: true,
|
|
236
281
|
autoGainControl: true
|
|
237
282
|
}
|
|
238
283
|
});
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
284
|
+
this.localStream = stream;
|
|
285
|
+
console.log(
|
|
286
|
+
"[LOCAL MEDIA]",
|
|
287
|
+
this.localStream.getTracks().map((t) => ({
|
|
288
|
+
kind: t.kind,
|
|
289
|
+
enabled: t.enabled,
|
|
290
|
+
ready: t.readyState
|
|
291
|
+
}))
|
|
292
|
+
);
|
|
293
|
+
if (video && this.localStream.getVideoTracks().length > 0) {
|
|
294
|
+
video.srcObject = this.localStream;
|
|
243
295
|
}
|
|
244
|
-
|
|
296
|
+
const cameraTrack = this.localStream.getVideoTracks()[0] || void 0;
|
|
297
|
+
const audioTrack = this.localStream.getAudioTracks()[0] || void 0;
|
|
245
298
|
this.state.updateLocalParticipant({
|
|
246
299
|
id: this.myId,
|
|
247
300
|
name: this.participantName,
|
|
248
301
|
media: {
|
|
249
302
|
stream: this.localStream,
|
|
250
|
-
cameraTrack
|
|
251
|
-
audioTrack
|
|
252
|
-
micEnabled
|
|
253
|
-
camEnabled
|
|
303
|
+
cameraTrack,
|
|
304
|
+
audioTrack,
|
|
305
|
+
micEnabled,
|
|
306
|
+
camEnabled,
|
|
254
307
|
isScreenSharing: false
|
|
255
308
|
}
|
|
256
309
|
});
|
|
@@ -266,23 +319,38 @@ var VideoSDKCore = class {
|
|
|
266
319
|
throw new Error("roomId and name are required to join meeting");
|
|
267
320
|
}
|
|
268
321
|
this.participantName = name;
|
|
322
|
+
let camEnabled = !videoMuted;
|
|
323
|
+
let micEnabled = !audioMuted;
|
|
269
324
|
if (!this.localStream) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
325
|
+
const acquired = await this.acquireLocalMedia({
|
|
326
|
+
videoConstraints: !videoMuted,
|
|
327
|
+
audioConstraints: !audioMuted
|
|
273
328
|
});
|
|
329
|
+
this.localStream = acquired.stream;
|
|
330
|
+
console.log(
|
|
331
|
+
"[LOCAL MEDIA]",
|
|
332
|
+
this.localStream.getTracks().map((t) => ({
|
|
333
|
+
kind: t.kind,
|
|
334
|
+
enabled: t.enabled,
|
|
335
|
+
ready: t.readyState
|
|
336
|
+
}))
|
|
337
|
+
);
|
|
338
|
+
camEnabled = acquired.camEnabled && !videoMuted;
|
|
339
|
+
micEnabled = acquired.micEnabled && !audioMuted;
|
|
274
340
|
}
|
|
275
|
-
this.localStream.getAudioTracks().forEach((t) => t.enabled =
|
|
276
|
-
this.localStream.getVideoTracks().forEach((t) => t.enabled =
|
|
341
|
+
this.localStream.getAudioTracks().forEach((t) => t.enabled = micEnabled);
|
|
342
|
+
this.localStream.getVideoTracks().forEach((t) => t.enabled = camEnabled);
|
|
343
|
+
const cameraTrack = this.localStream.getVideoTracks()[0] || void 0;
|
|
344
|
+
const audioTrack = this.localStream.getAudioTracks()[0] || void 0;
|
|
277
345
|
this.state.updateLocalParticipant({
|
|
278
346
|
id: this.myId,
|
|
279
347
|
name: this.participantName,
|
|
280
348
|
media: {
|
|
281
349
|
stream: this.localStream,
|
|
282
|
-
cameraTrack
|
|
283
|
-
audioTrack
|
|
284
|
-
micEnabled
|
|
285
|
-
camEnabled
|
|
350
|
+
cameraTrack,
|
|
351
|
+
audioTrack,
|
|
352
|
+
micEnabled,
|
|
353
|
+
camEnabled,
|
|
286
354
|
isScreenSharing: false
|
|
287
355
|
}
|
|
288
356
|
});
|
|
@@ -296,9 +364,39 @@ var VideoSDKCore = class {
|
|
|
296
364
|
iceServers: this.iceServers,
|
|
297
365
|
iceTransportPolicy: this.iceTransportPolicy
|
|
298
366
|
});
|
|
367
|
+
const tracksByKind = /* @__PURE__ */ new Map();
|
|
299
368
|
this.localStream.getTracks().forEach((track) => {
|
|
300
|
-
|
|
369
|
+
tracksByKind.set(track.kind, track);
|
|
301
370
|
});
|
|
371
|
+
const audioTrack = this.localStream.getAudioTracks()[0];
|
|
372
|
+
if (audioTrack) {
|
|
373
|
+
console.log("[Publisher] Adding audio track:", {
|
|
374
|
+
kind: audioTrack.kind,
|
|
375
|
+
id: audioTrack.id,
|
|
376
|
+
enabled: audioTrack.enabled,
|
|
377
|
+
state: audioTrack.readyState
|
|
378
|
+
});
|
|
379
|
+
try {
|
|
380
|
+
this.pubPC?.addTrack(audioTrack, this.localStream);
|
|
381
|
+
} catch (e) {
|
|
382
|
+
console.error("[Publisher] Failed to add audio track:", e);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const videoTrack = this.localStream.getVideoTracks()[0];
|
|
386
|
+
if (videoTrack) {
|
|
387
|
+
console.log("[Publisher] Adding video track:", {
|
|
388
|
+
kind: videoTrack.kind,
|
|
389
|
+
id: videoTrack.id,
|
|
390
|
+
enabled: videoTrack.enabled,
|
|
391
|
+
// Can be false, that's OK
|
|
392
|
+
state: videoTrack.readyState
|
|
393
|
+
});
|
|
394
|
+
try {
|
|
395
|
+
this.pubPC?.addTrack(videoTrack, this.localStream);
|
|
396
|
+
} catch (e) {
|
|
397
|
+
console.error("[Publisher] Failed to add video track:", e);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
302
400
|
this.pubPC.onicecandidate = (e) => {
|
|
303
401
|
if (e.candidate) {
|
|
304
402
|
this.send({
|
|
@@ -309,8 +407,13 @@ var VideoSDKCore = class {
|
|
|
309
407
|
}
|
|
310
408
|
};
|
|
311
409
|
this.pubPC.onconnectionstatechange = () => {
|
|
312
|
-
console.log(
|
|
410
|
+
console.log("[Publisher PC State]", {
|
|
411
|
+
connection: this.pubPC?.connectionState,
|
|
412
|
+
ice: this.pubPC?.iceConnectionState,
|
|
413
|
+
signaling: this.pubPC?.signalingState
|
|
414
|
+
});
|
|
313
415
|
if (this.pubPC?.connectionState === "failed") {
|
|
416
|
+
console.warn("[Publisher] Connection failed, restarting ICE");
|
|
314
417
|
this.restartPublisherIce();
|
|
315
418
|
}
|
|
316
419
|
};
|
|
@@ -330,36 +433,70 @@ var VideoSDKCore = class {
|
|
|
330
433
|
}
|
|
331
434
|
};
|
|
332
435
|
this.subPC.ontrack = (event) => {
|
|
333
|
-
|
|
436
|
+
console.log("[SFU ontrack Event]", {
|
|
437
|
+
kind: event.track.kind,
|
|
438
|
+
id: event.track.id,
|
|
439
|
+
mid: event.transceiver.mid,
|
|
440
|
+
streams: event.streams.length
|
|
441
|
+
});
|
|
442
|
+
const stream = event.streams[0] || new MediaStream([event.track]);
|
|
443
|
+
const mid = event.transceiver.mid;
|
|
444
|
+
if (!mid) {
|
|
445
|
+
console.warn("[Subscriber] Track received without MID", event.track);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
console.log("[Subscriber] Looking for descriptor with MID:", mid, {
|
|
449
|
+
available: [...this.pendingTracks.keys()]
|
|
450
|
+
});
|
|
451
|
+
const descriptor = this.pendingTracks.get(mid);
|
|
334
452
|
if (!descriptor) {
|
|
335
|
-
console.warn("
|
|
453
|
+
console.warn("[Subscriber] No descriptor found for MID:", mid);
|
|
454
|
+
console.log("[Subscriber] Pending tracks:", [
|
|
455
|
+
...this.pendingTracks.entries()
|
|
456
|
+
]);
|
|
336
457
|
return;
|
|
337
458
|
}
|
|
338
|
-
|
|
459
|
+
console.log("[Subscriber] Found descriptor:", descriptor);
|
|
460
|
+
this.pendingTracks.delete(mid);
|
|
339
461
|
switch (descriptor.source) {
|
|
340
462
|
case "camera":
|
|
463
|
+
console.log(
|
|
464
|
+
"[Subscriber] Updating camera for:",
|
|
465
|
+
descriptor.publisher_id
|
|
466
|
+
);
|
|
341
467
|
this.state.updateParticipantMedia(descriptor.publisher_id, {
|
|
342
468
|
stream,
|
|
343
469
|
cameraTrack: event.track
|
|
344
470
|
});
|
|
345
471
|
break;
|
|
472
|
+
case "audio":
|
|
473
|
+
console.log(
|
|
474
|
+
"[Subscriber] Updating audio for:",
|
|
475
|
+
descriptor.publisher_id
|
|
476
|
+
);
|
|
477
|
+
this.state.updateParticipantMedia(descriptor.publisher_id, {
|
|
478
|
+
stream,
|
|
479
|
+
audioTrack: event.track
|
|
480
|
+
});
|
|
481
|
+
break;
|
|
346
482
|
case "screen":
|
|
483
|
+
console.log(
|
|
484
|
+
"[Subscriber] Updating screen for:",
|
|
485
|
+
descriptor.publisher_id
|
|
486
|
+
);
|
|
347
487
|
this.state.updateParticipantMedia(descriptor.publisher_id, {
|
|
348
488
|
screenStream: stream,
|
|
349
489
|
screenTrack: event.track,
|
|
350
490
|
isScreenSharing: true
|
|
351
491
|
});
|
|
352
492
|
break;
|
|
353
|
-
case "audio":
|
|
354
|
-
this.state.updateParticipantMedia(descriptor.publisher_id, {
|
|
355
|
-
stream,
|
|
356
|
-
audioTrack: event.track
|
|
357
|
-
});
|
|
358
|
-
break;
|
|
359
493
|
}
|
|
360
494
|
};
|
|
361
495
|
this.subPC.onconnectionstatechange = () => {
|
|
362
|
-
console.log(
|
|
496
|
+
console.log("[SFU Subscriber PC State]", this.subPC?.connectionState);
|
|
497
|
+
if (this.subPC?.connectionState === "failed") {
|
|
498
|
+
console.warn("Subscriber connection failed");
|
|
499
|
+
}
|
|
363
500
|
};
|
|
364
501
|
}
|
|
365
502
|
// ---------------- WEBSOCKET CONNECTION & SIGNALING ----------------
|
|
@@ -422,6 +559,19 @@ var VideoSDKCore = class {
|
|
|
422
559
|
this.setupPublisherPC();
|
|
423
560
|
this.setupSubscriberPC();
|
|
424
561
|
await this.createPublisherOffer();
|
|
562
|
+
const media = this.state.localParticipant?.media;
|
|
563
|
+
if (media) {
|
|
564
|
+
this.send({
|
|
565
|
+
type: "MEDIA_STATE",
|
|
566
|
+
kind: "audio",
|
|
567
|
+
enabled: !!media.micEnabled
|
|
568
|
+
});
|
|
569
|
+
this.send({
|
|
570
|
+
type: "MEDIA_STATE",
|
|
571
|
+
kind: "video",
|
|
572
|
+
enabled: !!media.camEnabled
|
|
573
|
+
});
|
|
574
|
+
}
|
|
425
575
|
this.startHeartbeat();
|
|
426
576
|
this.joinResolver?.();
|
|
427
577
|
this.joinResolver = void 0;
|
|
@@ -438,7 +588,6 @@ var VideoSDKCore = class {
|
|
|
438
588
|
break;
|
|
439
589
|
}
|
|
440
590
|
case "SUB_OFFER": {
|
|
441
|
-
this.pendingTracks.push(msg.track);
|
|
442
591
|
if (this.subPC) {
|
|
443
592
|
await this.subPC.setRemoteDescription({
|
|
444
593
|
type: "offer",
|
|
@@ -452,6 +601,7 @@ var VideoSDKCore = class {
|
|
|
452
601
|
user_id: this.myId
|
|
453
602
|
});
|
|
454
603
|
}
|
|
604
|
+
await this.handleSubscriberOffer(msg);
|
|
455
605
|
break;
|
|
456
606
|
}
|
|
457
607
|
case "PUB_ICE": {
|
|
@@ -598,6 +748,31 @@ var VideoSDKCore = class {
|
|
|
598
748
|
}
|
|
599
749
|
}
|
|
600
750
|
}
|
|
751
|
+
async handleSubscriberOffer(msg) {
|
|
752
|
+
if (!this.subPC) return;
|
|
753
|
+
try {
|
|
754
|
+
this.subscriberNegotiating = true;
|
|
755
|
+
await this.subPC.setRemoteDescription({
|
|
756
|
+
type: "offer",
|
|
757
|
+
sdp: msg.payload
|
|
758
|
+
});
|
|
759
|
+
const answer = await this.subPC.createAnswer();
|
|
760
|
+
await this.subPC.setLocalDescription(answer);
|
|
761
|
+
this.send({
|
|
762
|
+
type: "SUB_ANSWER",
|
|
763
|
+
payload: answer.sdp,
|
|
764
|
+
user_id: this.myId
|
|
765
|
+
});
|
|
766
|
+
} catch (err) {
|
|
767
|
+
console.error("[SUB OFFER ERROR]", err);
|
|
768
|
+
} finally {
|
|
769
|
+
this.subscriberNegotiating = false;
|
|
770
|
+
const next = this.subscriberOfferQueue.shift();
|
|
771
|
+
if (next) {
|
|
772
|
+
await this.handleSubscriberOffer(next);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
601
776
|
// ---------------- PUBLISHER RENEGOTIATION ----------------
|
|
602
777
|
async createPublisherOffer() {
|
|
603
778
|
if (!this.pubPC) return;
|