@afosecure/meetingsdk 1.0.8 → 1.1.1
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.js +208 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +208 -83
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -397,6 +397,7 @@ var VideoSDKCore = class {
|
|
|
397
397
|
if (!p?.id || p.id === this.myId) return;
|
|
398
398
|
this.state.addParticipant(p);
|
|
399
399
|
this.events.onUserJoined?.(p);
|
|
400
|
+
await this.createOffer(p.id);
|
|
400
401
|
break;
|
|
401
402
|
}
|
|
402
403
|
case "OFFER":
|
|
@@ -406,14 +407,26 @@ var VideoSDKCore = class {
|
|
|
406
407
|
const pc = this.peers[msg.sender];
|
|
407
408
|
if (!pc) return;
|
|
408
409
|
if (pc.signalingState !== "have-local-offer") {
|
|
409
|
-
console.warn(
|
|
410
|
+
console.warn(
|
|
411
|
+
`[Signaling] Unexpected ANSWER in state "${pc.signalingState}", ignoring`
|
|
412
|
+
);
|
|
410
413
|
return;
|
|
411
414
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
415
|
+
try {
|
|
416
|
+
await pc.setRemoteDescription({
|
|
417
|
+
type: "answer",
|
|
418
|
+
sdp: msg.payload
|
|
419
|
+
});
|
|
420
|
+
await this.flushIce(msg.sender, pc);
|
|
421
|
+
} catch (err) {
|
|
422
|
+
console.error("[Signaling] Failed to apply answer:", err);
|
|
423
|
+
this.emitError(
|
|
424
|
+
"ANSWER_FAILED",
|
|
425
|
+
`Failed to apply answer from ${msg.sender}`,
|
|
426
|
+
err,
|
|
427
|
+
true
|
|
428
|
+
);
|
|
429
|
+
}
|
|
417
430
|
break;
|
|
418
431
|
}
|
|
419
432
|
case "ICE": {
|
|
@@ -508,17 +521,47 @@ var VideoSDKCore = class {
|
|
|
508
521
|
// ---------------- PEER ----------------
|
|
509
522
|
createPeer(id) {
|
|
510
523
|
if (!this.localStream) throw new Error("No local stream");
|
|
524
|
+
console.log(
|
|
525
|
+
"Adding tracks",
|
|
526
|
+
this.localStream.getTracks().map((t) => ({
|
|
527
|
+
kind: t.kind,
|
|
528
|
+
enabled: t.enabled,
|
|
529
|
+
state: t.readyState
|
|
530
|
+
}))
|
|
531
|
+
);
|
|
511
532
|
const pc = new RTCPeerConnection({
|
|
512
533
|
iceServers: [
|
|
513
534
|
{
|
|
514
|
-
urls:
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
535
|
+
urls: "stun:stun.relay.metered.ca:80"
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
urls: "turn:global.relay.metered.ca:80",
|
|
539
|
+
username: "25aed888d2d360e9fae0e812",
|
|
540
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
urls: "turn:global.relay.metered.ca:80?transport=tcp",
|
|
544
|
+
username: "25aed888d2d360e9fae0e812",
|
|
545
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
urls: "turn:global.relay.metered.ca:443",
|
|
549
|
+
username: "25aed888d2d360e9fae0e812",
|
|
550
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
urls: "turns:global.relay.metered.ca:443?transport=tcp",
|
|
554
|
+
username: "25aed888d2d360e9fae0e812",
|
|
555
|
+
credential: "WPYstojO9Wf3+HsQ"
|
|
518
556
|
}
|
|
519
557
|
]
|
|
520
558
|
});
|
|
521
559
|
pc.ontrack = (event) => {
|
|
560
|
+
console.log(`Track received: ${event.track.kind}`, {
|
|
561
|
+
trackId: event.track.id,
|
|
562
|
+
streamCount: event.streams.length,
|
|
563
|
+
streamTrackCount: event.streams[0]?.getTracks().length
|
|
564
|
+
});
|
|
522
565
|
const incomingStream = event.streams[0];
|
|
523
566
|
const participant = this.state.getParticipant(id);
|
|
524
567
|
const isScreenStream = incomingStream.id === participant?.media?.remoteScreenStreamId;
|
|
@@ -551,6 +594,15 @@ var VideoSDKCore = class {
|
|
|
551
594
|
target: id
|
|
552
595
|
});
|
|
553
596
|
};
|
|
597
|
+
pc.oniceconnectionstatechange = () => {
|
|
598
|
+
console.log(`ICE Connection State: ${pc.iceConnectionState}`);
|
|
599
|
+
if (pc.iceConnectionState === "failed" || pc.iceConnectionState === "disconnected") {
|
|
600
|
+
this.emitError(
|
|
601
|
+
"ICE_FAILED",
|
|
602
|
+
"Connection failed. Please check your network or refresh."
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
554
606
|
pc.onconnectionstatechange = () => {
|
|
555
607
|
if (pc.connectionState === "failed") {
|
|
556
608
|
try {
|
|
@@ -573,7 +625,21 @@ var VideoSDKCore = class {
|
|
|
573
625
|
}
|
|
574
626
|
// ---------------- OFFER ----------------
|
|
575
627
|
async createOffer(id, isRenegotiation = false) {
|
|
576
|
-
if (!isRenegotiation && this.initiators.has(id))
|
|
628
|
+
if (!isRenegotiation && this.initiators.has(id)) {
|
|
629
|
+
console.debug(
|
|
630
|
+
`[Offer] Already initiating with ${id}, skipping duplicate`
|
|
631
|
+
);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
if (isRenegotiation && this.peers[id]) {
|
|
635
|
+
const pc2 = this.peers[id];
|
|
636
|
+
if (pc2.signalingState !== "stable") {
|
|
637
|
+
console.warn(
|
|
638
|
+
`[Offer] Cannot renegotiate: peer in state "${pc2.signalingState}"`
|
|
639
|
+
);
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
577
643
|
if (!isRenegotiation) {
|
|
578
644
|
this.initiators.add(id);
|
|
579
645
|
}
|
|
@@ -581,46 +647,80 @@ var VideoSDKCore = class {
|
|
|
581
647
|
this.peers[id] = this.createPeer(id);
|
|
582
648
|
}
|
|
583
649
|
const pc = this.peers[id];
|
|
584
|
-
|
|
585
|
-
|
|
650
|
+
try {
|
|
651
|
+
const offer = await pc.createOffer();
|
|
652
|
+
await pc.setLocalDescription(offer);
|
|
653
|
+
this.send({
|
|
654
|
+
type: "OFFER",
|
|
655
|
+
payload: offer.sdp,
|
|
656
|
+
sender: this.myId,
|
|
657
|
+
target: id
|
|
658
|
+
});
|
|
659
|
+
console.debug(`[Offer] Sent to ${id}`);
|
|
660
|
+
} catch (err) {
|
|
661
|
+
console.error(`[Offer] Failed for ${id}:`, err);
|
|
662
|
+
this.emitError(
|
|
663
|
+
"OFFER_FAILED",
|
|
664
|
+
`Failed to create offer for ${id}`,
|
|
665
|
+
err,
|
|
666
|
+
true
|
|
667
|
+
);
|
|
586
668
|
}
|
|
587
|
-
const offer = await pc.createOffer();
|
|
588
|
-
await pc.setLocalDescription(offer);
|
|
589
|
-
this.send({
|
|
590
|
-
type: "OFFER",
|
|
591
|
-
payload: offer.sdp,
|
|
592
|
-
sender: this.myId,
|
|
593
|
-
target: id
|
|
594
|
-
});
|
|
595
669
|
}
|
|
596
670
|
// ---------------- ANSWER ----------------
|
|
597
671
|
async handleOffer(sdp, id) {
|
|
672
|
+
if (this.initiators.has(id) && this.peers[id]) {
|
|
673
|
+
const pc2 = this.peers[id];
|
|
674
|
+
if (pc2.signalingState !== "stable") {
|
|
675
|
+
console.warn(
|
|
676
|
+
`[Signaling] Offer collision with ${id}. We initiated, ignoring their offer.`
|
|
677
|
+
);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
598
681
|
if (!this.peers[id]) {
|
|
599
682
|
this.peers[id] = this.createPeer(id);
|
|
600
683
|
}
|
|
601
684
|
const pc = this.peers[id];
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
685
|
+
try {
|
|
686
|
+
if (pc.signalingState !== "stable" && pc.signalingState !== "have-local-offer") {
|
|
687
|
+
console.warn(
|
|
688
|
+
`[Signaling] Cannot accept OFFER in state "${pc.signalingState}"`
|
|
689
|
+
);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
await pc.setRemoteDescription({
|
|
693
|
+
type: "offer",
|
|
694
|
+
sdp
|
|
695
|
+
});
|
|
696
|
+
const pending = this.pendingIceCandidates[id] || [];
|
|
697
|
+
for (const candidate of pending) {
|
|
698
|
+
try {
|
|
699
|
+
await pc.addIceCandidate(candidate);
|
|
700
|
+
} catch (err) {
|
|
701
|
+
console.warn("[ICE] Failed to add candidate:", err);
|
|
702
|
+
}
|
|
612
703
|
}
|
|
704
|
+
delete this.pendingIceCandidates[id];
|
|
705
|
+
const answer = await pc.createAnswer();
|
|
706
|
+
await pc.setLocalDescription(answer);
|
|
707
|
+
await this.flushIce(id, pc);
|
|
708
|
+
this.send({
|
|
709
|
+
type: "ANSWER",
|
|
710
|
+
payload: answer.sdp,
|
|
711
|
+
sender: this.myId,
|
|
712
|
+
target: id
|
|
713
|
+
});
|
|
714
|
+
console.debug(`[Answer] Sent to ${id}`);
|
|
715
|
+
} catch (err) {
|
|
716
|
+
console.error(`[Signaling] Failed to handle OFFER from ${id}:`, err);
|
|
717
|
+
this.emitError(
|
|
718
|
+
"OFFER_HANDLING_FAILED",
|
|
719
|
+
`Failed to handle offer from ${id}`,
|
|
720
|
+
err,
|
|
721
|
+
true
|
|
722
|
+
);
|
|
613
723
|
}
|
|
614
|
-
delete this.pendingIceCandidates[id];
|
|
615
|
-
const answer = await pc.createAnswer();
|
|
616
|
-
await pc.setLocalDescription(answer);
|
|
617
|
-
await this.flushIce(id, pc);
|
|
618
|
-
this.send({
|
|
619
|
-
type: "ANSWER",
|
|
620
|
-
payload: answer.sdp,
|
|
621
|
-
sender: this.myId,
|
|
622
|
-
target: id
|
|
623
|
-
});
|
|
624
724
|
}
|
|
625
725
|
// ---------------- CLEANUP ----------------
|
|
626
726
|
closePeer(id) {
|
|
@@ -635,39 +735,55 @@ var VideoSDKCore = class {
|
|
|
635
735
|
this.state.removeParticipant(id);
|
|
636
736
|
}
|
|
637
737
|
async startScreenShare() {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
this.screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
642
|
-
video: true,
|
|
643
|
-
audio: true
|
|
644
|
-
});
|
|
645
|
-
this.isScreenSharing = true;
|
|
646
|
-
this.state.updateLocalParticipant({
|
|
647
|
-
media: {
|
|
648
|
-
isScreenSharing: true,
|
|
649
|
-
screenStream: this.screenStream
|
|
738
|
+
try {
|
|
739
|
+
if (this.state.presenterId && this.state.presenterId !== this.myId) {
|
|
740
|
+
throw new Error("Another user is already sharing their screen.");
|
|
650
741
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
this.
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
this.screenSenders[peerId] = [];
|
|
658
|
-
this.screenStream.getTracks().forEach((track) => {
|
|
659
|
-
const sender = pc.addTrack(track, this.screenStream);
|
|
660
|
-
this.screenSenders[peerId].push(sender);
|
|
742
|
+
if (!navigator.mediaDevices?.getDisplayMedia) {
|
|
743
|
+
throw new Error("Screen sharing not supported on this device");
|
|
744
|
+
}
|
|
745
|
+
this.screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
746
|
+
video: true
|
|
747
|
+
// audio: true,
|
|
661
748
|
});
|
|
662
|
-
this.
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
749
|
+
this.isScreenSharing = true;
|
|
750
|
+
this.state.updateLocalParticipant({
|
|
751
|
+
media: {
|
|
752
|
+
isScreenSharing: true,
|
|
753
|
+
screenStream: this.screenStream,
|
|
754
|
+
screenTrack: this.screenStream.getVideoTracks()[0]
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
this.state.setPresenterId(this.myId);
|
|
758
|
+
this.screenStream.getVideoTracks()[0].onended = () => {
|
|
759
|
+
this.stopScreenShare();
|
|
760
|
+
};
|
|
761
|
+
Object.entries(this.peers).forEach(([peerId, pc]) => {
|
|
762
|
+
this.screenSenders[peerId] = [];
|
|
763
|
+
this.screenStream.getTracks().forEach((track) => {
|
|
764
|
+
const sender = pc.addTrack(track, this.screenStream);
|
|
765
|
+
this.screenSenders[peerId].push(sender);
|
|
766
|
+
});
|
|
767
|
+
this.createOffer(peerId, true);
|
|
768
|
+
});
|
|
769
|
+
this.send({
|
|
770
|
+
type: "SCREEN_SHARE_START",
|
|
771
|
+
sender: this.myId,
|
|
772
|
+
room_id: this.roomId,
|
|
773
|
+
stream_id: this.screenStream.id.replace(/[{}]/g, "")
|
|
774
|
+
});
|
|
775
|
+
return this.screenStream;
|
|
776
|
+
} catch (err) {
|
|
777
|
+
this.emitError(
|
|
778
|
+
"SCREEN_SHARE_FAILED",
|
|
779
|
+
err?.message || "Failed to start screen sharing",
|
|
780
|
+
err,
|
|
781
|
+
true
|
|
782
|
+
);
|
|
783
|
+
this.isScreenSharing = false;
|
|
784
|
+
this.screenStream = null;
|
|
785
|
+
throw err;
|
|
786
|
+
}
|
|
671
787
|
}
|
|
672
788
|
stopScreenShare() {
|
|
673
789
|
if (!this.screenStream) return;
|
|
@@ -905,7 +1021,6 @@ var useLocalParticipant = () => {
|
|
|
905
1021
|
video.srcObject = stream;
|
|
906
1022
|
video.autoplay = true;
|
|
907
1023
|
video.playsInline = true;
|
|
908
|
-
video.muted = true;
|
|
909
1024
|
video.play().catch((err) => {
|
|
910
1025
|
console.warn(`Autoplay failed for local view:`, err);
|
|
911
1026
|
});
|
|
@@ -955,6 +1070,15 @@ var useRemoteMedia = (participantId) => {
|
|
|
955
1070
|
const [participant, setParticipant] = useState4(
|
|
956
1071
|
() => sdk.state.getParticipant(participantId) || null
|
|
957
1072
|
);
|
|
1073
|
+
const buildMediaStream = (participant2) => {
|
|
1074
|
+
if (!participant2?.media) return null;
|
|
1075
|
+
const stream = new MediaStream();
|
|
1076
|
+
const videoTrack = participant2.media.stream?.getVideoTracks?.()?.[0];
|
|
1077
|
+
const audioTrack = participant2.media.stream?.getAudioTracks?.()?.[0];
|
|
1078
|
+
if (videoTrack) stream.addTrack(videoTrack);
|
|
1079
|
+
if (audioTrack) stream.addTrack(audioTrack);
|
|
1080
|
+
return stream;
|
|
1081
|
+
};
|
|
958
1082
|
useEffect5(() => {
|
|
959
1083
|
const unsub = sdk.state.subscribe(`participant:${participantId}`, () => {
|
|
960
1084
|
const p = sdk.state.getParticipant(participantId);
|
|
@@ -968,13 +1092,14 @@ var useRemoteMedia = (participantId) => {
|
|
|
968
1092
|
const stream = participant?.media?.stream;
|
|
969
1093
|
if (!stream) return;
|
|
970
1094
|
node.srcObject = stream;
|
|
971
|
-
node.autoplay = true;
|
|
972
|
-
node.playsInline = true;
|
|
973
1095
|
node.muted = true;
|
|
974
|
-
node.
|
|
1096
|
+
node.playsInline = true;
|
|
1097
|
+
node.autoplay = true;
|
|
1098
|
+
node.play().catch((err) => {
|
|
1099
|
+
console.log("can't play video:", err);
|
|
1100
|
+
});
|
|
975
1101
|
},
|
|
976
|
-
|
|
977
|
-
[participant?.media?.stream, participant?.media?.cameraTrack]
|
|
1102
|
+
[participant?.media?.stream]
|
|
978
1103
|
);
|
|
979
1104
|
const audioRef = useCallback2(
|
|
980
1105
|
(node) => {
|
|
@@ -982,12 +1107,12 @@ var useRemoteMedia = (participantId) => {
|
|
|
982
1107
|
const stream = participant?.media?.stream;
|
|
983
1108
|
if (!stream) return;
|
|
984
1109
|
node.srcObject = stream;
|
|
985
|
-
node.
|
|
986
|
-
node.
|
|
987
|
-
|
|
1110
|
+
node.muted = false;
|
|
1111
|
+
node.play().catch((err) => {
|
|
1112
|
+
console.log("can't play Audio:", err);
|
|
1113
|
+
});
|
|
988
1114
|
},
|
|
989
|
-
|
|
990
|
-
[participant?.media?.stream, participant?.media?.micEnabled]
|
|
1115
|
+
[participant?.media?.stream]
|
|
991
1116
|
);
|
|
992
1117
|
return {
|
|
993
1118
|
videoRef,
|