@afosecure/meetingsdk 1.1.0 → 1.1.2
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 +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +182 -105
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +183 -106
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import react__default from 'react';
|
|
3
4
|
|
|
4
5
|
type Events = {
|
|
5
6
|
onMicToggled?: (peerId: string, enabled: boolean) => void;
|
|
@@ -107,6 +108,8 @@ declare class VideoSDKCore {
|
|
|
107
108
|
private ws;
|
|
108
109
|
private peers;
|
|
109
110
|
private initiators;
|
|
111
|
+
private lastPong;
|
|
112
|
+
private intentionalDisconnect;
|
|
110
113
|
private myId;
|
|
111
114
|
private roomId;
|
|
112
115
|
private localStream;
|
|
@@ -170,7 +173,7 @@ type MeetingContextValue = {
|
|
|
170
173
|
};
|
|
171
174
|
declare const MeetingProvider: ({ config, children, }: {
|
|
172
175
|
config: MeetingConfig;
|
|
173
|
-
children:
|
|
176
|
+
children: react__default.ReactNode;
|
|
174
177
|
}) => react_jsx_runtime.JSX.Element;
|
|
175
178
|
declare const useMeetingContext: () => MeetingContextValue;
|
|
176
179
|
|
|
@@ -200,8 +203,8 @@ declare const useMeeting: (handlers?: {
|
|
|
200
203
|
declare const useParticipants: () => Participant[];
|
|
201
204
|
|
|
202
205
|
declare const useRemoteMedia: (participantId: string) => {
|
|
203
|
-
videoRef:
|
|
204
|
-
audioRef:
|
|
206
|
+
videoRef: react.RefObject<HTMLVideoElement | null>;
|
|
207
|
+
audioRef: react.RefObject<HTMLAudioElement | null>;
|
|
205
208
|
isCamActive: boolean;
|
|
206
209
|
isMicEnabled: boolean;
|
|
207
210
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import react__default from 'react';
|
|
3
4
|
|
|
4
5
|
type Events = {
|
|
5
6
|
onMicToggled?: (peerId: string, enabled: boolean) => void;
|
|
@@ -107,6 +108,8 @@ declare class VideoSDKCore {
|
|
|
107
108
|
private ws;
|
|
108
109
|
private peers;
|
|
109
110
|
private initiators;
|
|
111
|
+
private lastPong;
|
|
112
|
+
private intentionalDisconnect;
|
|
110
113
|
private myId;
|
|
111
114
|
private roomId;
|
|
112
115
|
private localStream;
|
|
@@ -170,7 +173,7 @@ type MeetingContextValue = {
|
|
|
170
173
|
};
|
|
171
174
|
declare const MeetingProvider: ({ config, children, }: {
|
|
172
175
|
config: MeetingConfig;
|
|
173
|
-
children:
|
|
176
|
+
children: react__default.ReactNode;
|
|
174
177
|
}) => react_jsx_runtime.JSX.Element;
|
|
175
178
|
declare const useMeetingContext: () => MeetingContextValue;
|
|
176
179
|
|
|
@@ -200,8 +203,8 @@ declare const useMeeting: (handlers?: {
|
|
|
200
203
|
declare const useParticipants: () => Participant[];
|
|
201
204
|
|
|
202
205
|
declare const useRemoteMedia: (participantId: string) => {
|
|
203
|
-
videoRef:
|
|
204
|
-
audioRef:
|
|
206
|
+
videoRef: react.RefObject<HTMLVideoElement | null>;
|
|
207
|
+
audioRef: react.RefObject<HTMLAudioElement | null>;
|
|
205
208
|
isCamActive: boolean;
|
|
206
209
|
isMicEnabled: boolean;
|
|
207
210
|
};
|
package/dist/index.js
CHANGED
|
@@ -200,6 +200,8 @@ var VideoSDKCore = class {
|
|
|
200
200
|
this.ws = null;
|
|
201
201
|
this.peers = {};
|
|
202
202
|
this.initiators = /* @__PURE__ */ new Set();
|
|
203
|
+
this.lastPong = Date.now();
|
|
204
|
+
this.intentionalDisconnect = false;
|
|
203
205
|
this.roomId = null;
|
|
204
206
|
this.localStream = null;
|
|
205
207
|
this.screenStream = null;
|
|
@@ -271,18 +273,18 @@ var VideoSDKCore = class {
|
|
|
271
273
|
this.emitError("WS_ERROR", "WebSocket encountered an error", err, true);
|
|
272
274
|
};
|
|
273
275
|
this.ws.onclose = (e) => {
|
|
274
|
-
this.emitError(
|
|
275
|
-
"WS_CLOSED",
|
|
276
|
-
`Connection closed (${e.code}) ${e.reason || ""}`,
|
|
277
|
-
e,
|
|
278
|
-
true
|
|
279
|
-
);
|
|
280
276
|
this.joinRejecter?.({
|
|
281
277
|
code: "WS_CLOSED",
|
|
282
278
|
message: "Connection closed before join completed",
|
|
283
279
|
raw: e
|
|
284
280
|
});
|
|
285
281
|
this.joinRejecter = void 0;
|
|
282
|
+
if (this.intentionalDisconnect) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (e.code === 1e3 || e.code === 1001) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
286
288
|
this.scheduleReconnect();
|
|
287
289
|
};
|
|
288
290
|
this.ws.onmessage = async (e) => {
|
|
@@ -406,46 +408,36 @@ var VideoSDKCore = class {
|
|
|
406
408
|
var _a, _b, _c, _d;
|
|
407
409
|
if (msg.sender === this.myId) return;
|
|
408
410
|
switch (msg.type) {
|
|
409
|
-
case "
|
|
410
|
-
|
|
411
|
-
this.state.setPresenterId(msg.presenterId);
|
|
412
|
-
this.events.onScreenShareStarted?.(msg.presenterId, null);
|
|
413
|
-
}
|
|
414
|
-
for (const p of msg.participants || []) {
|
|
415
|
-
if (!p?.id || p.id === this.myId) continue;
|
|
416
|
-
this.state.addParticipant(p);
|
|
417
|
-
this.events.onUserJoined?.(p);
|
|
418
|
-
}
|
|
411
|
+
case "PONG":
|
|
412
|
+
this.lastPong = Date.now();
|
|
419
413
|
break;
|
|
420
|
-
case "JOINED": {
|
|
421
|
-
this.startHeartbeat();
|
|
422
|
-
this.joinResolver?.();
|
|
423
|
-
this.joinResolver = void 0;
|
|
424
|
-
this.joinRejecter = void 0;
|
|
425
|
-
break;
|
|
426
|
-
}
|
|
427
|
-
case "USER_JOINED": {
|
|
428
|
-
const p = msg.participant;
|
|
429
|
-
if (!p?.id || p.id === this.myId) return;
|
|
430
|
-
this.state.addParticipant(p);
|
|
431
|
-
this.events.onUserJoined?.(p);
|
|
432
|
-
break;
|
|
433
|
-
}
|
|
434
414
|
case "OFFER":
|
|
435
415
|
await this.handleOffer(msg.payload, msg.sender);
|
|
436
416
|
break;
|
|
437
417
|
case "ANSWER": {
|
|
438
418
|
const pc = this.peers[msg.sender];
|
|
439
419
|
if (!pc) return;
|
|
440
|
-
if (pc.signalingState
|
|
441
|
-
console.warn(
|
|
420
|
+
if (pc.signalingState !== "have-local-offer") {
|
|
421
|
+
console.warn(
|
|
422
|
+
`[Signaling] Unexpected ANSWER in state "${pc.signalingState}", ignoring`
|
|
423
|
+
);
|
|
442
424
|
return;
|
|
443
425
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
426
|
+
try {
|
|
427
|
+
await pc.setRemoteDescription({
|
|
428
|
+
type: "answer",
|
|
429
|
+
sdp: msg.payload
|
|
430
|
+
});
|
|
431
|
+
await this.flushIce(msg.sender, pc);
|
|
432
|
+
} catch (err) {
|
|
433
|
+
console.error("[Signaling] Failed to apply answer:", err);
|
|
434
|
+
this.emitError(
|
|
435
|
+
"ANSWER_FAILED",
|
|
436
|
+
`Failed to apply answer from ${msg.sender}`,
|
|
437
|
+
err,
|
|
438
|
+
true
|
|
439
|
+
);
|
|
440
|
+
}
|
|
449
441
|
break;
|
|
450
442
|
}
|
|
451
443
|
case "ICE": {
|
|
@@ -468,6 +460,35 @@ var VideoSDKCore = class {
|
|
|
468
460
|
}
|
|
469
461
|
break;
|
|
470
462
|
}
|
|
463
|
+
case "EXISTING_USERS":
|
|
464
|
+
if (msg.presenterId) {
|
|
465
|
+
this.state.setPresenterId(msg.presenterId);
|
|
466
|
+
this.events.onScreenShareStarted?.(msg.presenterId, null);
|
|
467
|
+
}
|
|
468
|
+
for (const p of msg.participants || []) {
|
|
469
|
+
if (!p?.id || p.id === this.myId) continue;
|
|
470
|
+
this.state.addParticipant(p);
|
|
471
|
+
this.events.onUserJoined?.(p);
|
|
472
|
+
await this.createOffer(p.id);
|
|
473
|
+
}
|
|
474
|
+
break;
|
|
475
|
+
case "JOINED": {
|
|
476
|
+
this.intentionalDisconnect = false;
|
|
477
|
+
this.reconnectAttempts = 0;
|
|
478
|
+
this.startHeartbeat();
|
|
479
|
+
this.joinResolver?.();
|
|
480
|
+
this.joinResolver = void 0;
|
|
481
|
+
this.joinRejecter = void 0;
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
case "USER_JOINED": {
|
|
485
|
+
const p = msg.participant;
|
|
486
|
+
if (!p?.id || p.id === this.myId) return;
|
|
487
|
+
this.state.addParticipant(p);
|
|
488
|
+
this.events.onUserJoined?.(p);
|
|
489
|
+
await this.createOffer(p.id);
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
471
492
|
case "USER_LEFT":
|
|
472
493
|
const peerId = msg.participant.id;
|
|
473
494
|
this.closePeer(peerId);
|
|
@@ -551,17 +572,44 @@ var VideoSDKCore = class {
|
|
|
551
572
|
const pc = new RTCPeerConnection({
|
|
552
573
|
iceServers: [
|
|
553
574
|
{
|
|
554
|
-
urls:
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
575
|
+
urls: "stun:stun.relay.metered.ca:80"
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
urls: "turn:global.relay.metered.ca:80",
|
|
579
|
+
username: "25aed888d2d360e9fae0e812",
|
|
580
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
urls: "turn:global.relay.metered.ca:80?transport=tcp",
|
|
584
|
+
username: "25aed888d2d360e9fae0e812",
|
|
585
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
urls: "turn:global.relay.metered.ca:443",
|
|
589
|
+
username: "25aed888d2d360e9fae0e812",
|
|
590
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
591
|
+
},
|
|
592
|
+
{
|
|
593
|
+
urls: "turns:global.relay.metered.ca:443?transport=tcp",
|
|
594
|
+
username: "25aed888d2d360e9fae0e812",
|
|
595
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
558
596
|
}
|
|
559
597
|
]
|
|
560
598
|
});
|
|
561
599
|
pc.ontrack = (event) => {
|
|
562
|
-
|
|
600
|
+
console.log(`Track received: ${event.track.kind}`, {
|
|
601
|
+
trackId: event.track.id,
|
|
602
|
+
streamCount: event.streams.length,
|
|
603
|
+
streamTrackCount: event.streams[0]?.getTracks().length
|
|
604
|
+
});
|
|
605
|
+
const incomingStream = event.streams?.[0] || new MediaStream([event.track]);
|
|
563
606
|
const participant = this.state.getParticipant(id);
|
|
564
607
|
const isScreenStream = incomingStream.id === participant?.media?.remoteScreenStreamId;
|
|
608
|
+
if (event.track.kind === "video") {
|
|
609
|
+
event.track.onunmute = () => {
|
|
610
|
+
console.log("Video track unmuted for", id);
|
|
611
|
+
};
|
|
612
|
+
}
|
|
565
613
|
if (isScreenStream) {
|
|
566
614
|
const videoTrack = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0] || participant?.media?.screenTrack;
|
|
567
615
|
this.state.updateParticipantMedia(id, {
|
|
@@ -591,6 +639,9 @@ var VideoSDKCore = class {
|
|
|
591
639
|
target: id
|
|
592
640
|
});
|
|
593
641
|
};
|
|
642
|
+
pc.oniceconnectionstatechange = () => {
|
|
643
|
+
console.log(`ICE Connection State: ${pc.iceConnectionState}`);
|
|
644
|
+
};
|
|
594
645
|
pc.onconnectionstatechange = () => {
|
|
595
646
|
if (pc.connectionState === "failed") {
|
|
596
647
|
try {
|
|
@@ -613,18 +664,45 @@ var VideoSDKCore = class {
|
|
|
613
664
|
}
|
|
614
665
|
// ---------------- OFFER ----------------
|
|
615
666
|
async createOffer(id, isRenegotiation = false) {
|
|
667
|
+
if (!isRenegotiation && this.initiators.has(id)) {
|
|
668
|
+
console.debug(
|
|
669
|
+
`[Offer] Already initiating with ${id}, skipping duplicate`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
if (isRenegotiation && this.peers[id]) {
|
|
673
|
+
const pc2 = this.peers[id];
|
|
674
|
+
if (pc2.signalingState !== "stable") {
|
|
675
|
+
console.warn(
|
|
676
|
+
`[Offer] Cannot renegotiate: peer in state "${pc2.signalingState}"`
|
|
677
|
+
);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (!isRenegotiation) {
|
|
681
|
+
this.initiators.add(id);
|
|
682
|
+
}
|
|
616
683
|
if (!this.peers[id]) {
|
|
617
684
|
this.peers[id] = this.createPeer(id);
|
|
618
685
|
}
|
|
619
686
|
const pc = this.peers[id];
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
687
|
+
try {
|
|
688
|
+
const offer = await pc.createOffer();
|
|
689
|
+
await pc.setLocalDescription(offer);
|
|
690
|
+
this.send({
|
|
691
|
+
type: "OFFER",
|
|
692
|
+
payload: offer.sdp,
|
|
693
|
+
sender: this.myId,
|
|
694
|
+
target: id
|
|
695
|
+
});
|
|
696
|
+
console.debug(`[Offer] Sent to ${id}`);
|
|
697
|
+
} catch (err) {
|
|
698
|
+
console.error(`[Offer] Failed for ${id}:`, err);
|
|
699
|
+
this.emitError(
|
|
700
|
+
"OFFER_FAILED",
|
|
701
|
+
`Failed to create offer for ${id}`,
|
|
702
|
+
err,
|
|
703
|
+
true
|
|
704
|
+
);
|
|
705
|
+
}
|
|
628
706
|
}
|
|
629
707
|
// ---------------- ANSWER ----------------
|
|
630
708
|
async handleOffer(sdp, id) {
|
|
@@ -632,28 +710,45 @@ var VideoSDKCore = class {
|
|
|
632
710
|
this.peers[id] = this.createPeer(id);
|
|
633
711
|
}
|
|
634
712
|
const pc = this.peers[id];
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
713
|
+
try {
|
|
714
|
+
if (pc.signalingState !== "stable" && pc.signalingState !== "have-local-offer") {
|
|
715
|
+
console.warn(
|
|
716
|
+
`[Signaling] Cannot accept OFFER in state "${pc.signalingState}"`
|
|
717
|
+
);
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
await pc.setRemoteDescription({
|
|
721
|
+
type: "offer",
|
|
722
|
+
sdp
|
|
723
|
+
});
|
|
724
|
+
const pending = this.pendingIceCandidates[id] || [];
|
|
725
|
+
for (const candidate of pending) {
|
|
726
|
+
try {
|
|
727
|
+
await pc.addIceCandidate(candidate);
|
|
728
|
+
} catch (err) {
|
|
729
|
+
console.warn("[ICE] Failed to add candidate:", err);
|
|
730
|
+
}
|
|
645
731
|
}
|
|
732
|
+
delete this.pendingIceCandidates[id];
|
|
733
|
+
const answer = await pc.createAnswer();
|
|
734
|
+
await pc.setLocalDescription(answer);
|
|
735
|
+
await this.flushIce(id, pc);
|
|
736
|
+
this.send({
|
|
737
|
+
type: "ANSWER",
|
|
738
|
+
payload: answer.sdp,
|
|
739
|
+
sender: this.myId,
|
|
740
|
+
target: id
|
|
741
|
+
});
|
|
742
|
+
console.debug(`[Answer] Sent to ${id}`);
|
|
743
|
+
} catch (err) {
|
|
744
|
+
console.error(`[Signaling] Failed to handle OFFER from ${id}:`, err);
|
|
745
|
+
this.emitError(
|
|
746
|
+
"OFFER_HANDLING_FAILED",
|
|
747
|
+
`Failed to handle offer from ${id}`,
|
|
748
|
+
err,
|
|
749
|
+
true
|
|
750
|
+
);
|
|
646
751
|
}
|
|
647
|
-
delete this.pendingIceCandidates[id];
|
|
648
|
-
const answer = await pc.createAnswer();
|
|
649
|
-
await pc.setLocalDescription(answer);
|
|
650
|
-
await this.flushIce(id, pc);
|
|
651
|
-
this.send({
|
|
652
|
-
type: "ANSWER",
|
|
653
|
-
payload: answer.sdp,
|
|
654
|
-
sender: this.myId,
|
|
655
|
-
target: id
|
|
656
|
-
});
|
|
657
752
|
}
|
|
658
753
|
// ---------------- CLEANUP ----------------
|
|
659
754
|
closePeer(id) {
|
|
@@ -784,6 +879,7 @@ var VideoSDKCore = class {
|
|
|
784
879
|
});
|
|
785
880
|
}
|
|
786
881
|
disconnect() {
|
|
882
|
+
this.intentionalDisconnect = true;
|
|
787
883
|
this.stopScreenShare();
|
|
788
884
|
Object.values(this.peers).forEach((pc) => pc.close());
|
|
789
885
|
this.peers = {};
|
|
@@ -1000,18 +1096,11 @@ var useParticipants = () => {
|
|
|
1000
1096
|
var import_react6 = require("react");
|
|
1001
1097
|
var useRemoteMedia = (participantId) => {
|
|
1002
1098
|
const { sdk } = useMeetingContext();
|
|
1099
|
+
const videoRef = (0, import_react6.useRef)(null);
|
|
1100
|
+
const audioRef = (0, import_react6.useRef)(null);
|
|
1003
1101
|
const [participant, setParticipant] = (0, import_react6.useState)(
|
|
1004
1102
|
() => sdk.state.getParticipant(participantId) || null
|
|
1005
1103
|
);
|
|
1006
|
-
const buildMediaStream = (participant2) => {
|
|
1007
|
-
if (!participant2?.media) return null;
|
|
1008
|
-
const stream = new MediaStream();
|
|
1009
|
-
const videoTrack = participant2.media.stream?.getVideoTracks?.()?.[0];
|
|
1010
|
-
const audioTrack = participant2.media.stream?.getAudioTracks?.()?.[0];
|
|
1011
|
-
if (videoTrack) stream.addTrack(videoTrack);
|
|
1012
|
-
if (audioTrack) stream.addTrack(audioTrack);
|
|
1013
|
-
return stream;
|
|
1014
|
-
};
|
|
1015
1104
|
(0, import_react6.useEffect)(() => {
|
|
1016
1105
|
const unsub = sdk.state.subscribe(`participant:${participantId}`, () => {
|
|
1017
1106
|
const p = sdk.state.getParticipant(participantId);
|
|
@@ -1019,34 +1108,22 @@ var useRemoteMedia = (participantId) => {
|
|
|
1019
1108
|
});
|
|
1020
1109
|
return unsub;
|
|
1021
1110
|
}, [participantId, sdk]);
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
node.playsInline = true;
|
|
1031
|
-
node.autoplay = true;
|
|
1032
|
-
node.play().catch(() => {
|
|
1111
|
+
(0, import_react6.useEffect)(() => {
|
|
1112
|
+
const stream = participant?.media?.stream;
|
|
1113
|
+
if (!stream) return;
|
|
1114
|
+
if (videoRef.current) {
|
|
1115
|
+
videoRef.current.srcObject = stream;
|
|
1116
|
+
videoRef.current.muted = true;
|
|
1117
|
+
videoRef.current.playsInline = true;
|
|
1118
|
+
videoRef.current.play().catch(() => {
|
|
1033
1119
|
});
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
(node) => {
|
|
1039
|
-
if (!node) return;
|
|
1040
|
-
const stream = participant?.media?.stream;
|
|
1041
|
-
if (!stream) return;
|
|
1042
|
-
node.pause();
|
|
1043
|
-
node.srcObject = stream;
|
|
1044
|
-
node.muted = false;
|
|
1045
|
-
node.play().catch(() => {
|
|
1120
|
+
}
|
|
1121
|
+
if (audioRef.current) {
|
|
1122
|
+
audioRef.current.srcObject = stream;
|
|
1123
|
+
audioRef.current.play().catch(() => {
|
|
1046
1124
|
});
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
);
|
|
1125
|
+
}
|
|
1126
|
+
}, [participant?.media?.stream]);
|
|
1050
1127
|
return {
|
|
1051
1128
|
videoRef,
|
|
1052
1129
|
audioRef,
|