@afosecure/meetingsdk 1.3.2 → 1.3.3

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.mjs CHANGED
@@ -177,8 +177,7 @@ var VideoSDKCore = class {
177
177
  this.localStream = null;
178
178
  this.screenStream = null;
179
179
  this.isScreenSharing = false;
180
- // Transceiver-based tracking: maps peerId -> { cameraTransceiver, screenTransceiver, screenMid }
181
- this.peerTransceivers = {};
180
+ this.screenSenders = {};
182
181
  this.pingInterval = null;
183
182
  this.pendingIceCandidates = {};
184
183
  this.pendingOffers = {};
@@ -207,7 +206,7 @@ var VideoSDKCore = class {
207
206
  this.joinRejecter = void 0;
208
207
  console.error("[MeetingSDK Error]", err);
209
208
  }
210
- // STREAM
209
+ // ---------------- STREAM ----------------
211
210
  async initLocal(video, name) {
212
211
  this.participantName = name;
213
212
  try {
@@ -244,7 +243,7 @@ var VideoSDKCore = class {
244
243
  throw err;
245
244
  }
246
245
  }
247
- // CONNECT
246
+ // ---------------- CONNECT ----------------
248
247
  async connect(roomId, name) {
249
248
  this.room.id = roomId;
250
249
  this.reset();
@@ -390,11 +389,10 @@ var VideoSDKCore = class {
390
389
  this.pingInterval = null;
391
390
  }
392
391
  }
393
- // RESET
392
+ // ---------------- RESET ----------------
394
393
  reset() {
395
394
  Object.values(this.peers).forEach((pc) => pc.close());
396
395
  this.peers = {};
397
- this.peerTransceivers = {};
398
396
  this.initiators.clear();
399
397
  this.pendingIceCandidates = {};
400
398
  this.state.resetRemoteState();
@@ -449,7 +447,6 @@ var VideoSDKCore = class {
449
447
  type: "answer",
450
448
  sdp: msg.payload
451
449
  });
452
- this.captureScreenMid(msg.sender);
453
450
  await this.flushIce(msg.sender, pc);
454
451
  } catch (err) {
455
452
  console.error("[Signaling] Failed to apply answer:", err);
@@ -486,6 +483,7 @@ var VideoSDKCore = class {
486
483
  if (msg.presenterId) {
487
484
  this.state.setPresenterId(msg.presenterId);
488
485
  this.events.onScreenShareStarted?.(msg.presenterId, null);
486
+ this.state.setPresenterId(msg.presenterId);
489
487
  }
490
488
  for (const p of msg.participants || []) {
491
489
  if (!p?.id || p.id === this.myId) continue;
@@ -568,10 +566,12 @@ var VideoSDKCore = class {
568
566
  });
569
567
  break;
570
568
  }
569
+ // ============ NEW: HANDLE JOIN_APPROVED WITH RECONNECT ============
571
570
  case "JOIN_APPROVED": {
572
571
  await this.handleJoinApproved(msg);
573
572
  break;
574
573
  }
574
+ // ============ END: JOIN_APPROVED ============
575
575
  case "JOIN_REJECTED": {
576
576
  const decision = "rejected";
577
577
  console.log("JOIN_REJECTED - user not allowed to join");
@@ -624,7 +624,8 @@ var VideoSDKCore = class {
624
624
  if (!this.state.presenterId) {
625
625
  this.state.setPresenterId(peerId2);
626
626
  }
627
- this.events.onScreenShareStarted?.(peerId2, null);
627
+ const screenStream = this.state.getParticipant(peerId2)?.media?.screenStream;
628
+ this.events.onScreenShareStarted?.(peerId2, screenStream || null);
628
629
  break;
629
630
  }
630
631
  case "SCREEN_SHARE_STOP": {
@@ -651,7 +652,8 @@ var VideoSDKCore = class {
651
652
  }
652
653
  }
653
654
  }
654
- async createPeer(id) {
655
+ // ---------------- PEER ----------------
656
+ createPeer(id) {
655
657
  if (!this.localStream) throw new Error("No local stream");
656
658
  if (!this.iceServers || this.iceServers.length === 0) {
657
659
  throw new Error(
@@ -659,9 +661,7 @@ var VideoSDKCore = class {
659
661
  );
660
662
  }
661
663
  console.log(
662
- "Creating peer connection for",
663
- id,
664
- "with tracks:",
664
+ "Adding tracks",
665
665
  this.localStream.getTracks().map((t) => ({
666
666
  kind: t.kind,
667
667
  enabled: t.enabled,
@@ -671,52 +671,25 @@ var VideoSDKCore = class {
671
671
  const pc = new RTCPeerConnection({
672
672
  iceServers: this.iceServers
673
673
  });
674
- const audioTransceiver = pc.addTransceiver("audio", {
675
- direction: "sendrecv"
676
- });
677
- const audioTrack = this.localStream.getAudioTracks()[0];
678
- if (audioTrack) {
679
- await audioTransceiver.sender.replaceTrack(audioTrack);
680
- }
681
- const cameraTransceiver = pc.addTransceiver("video", {
682
- direction: "sendrecv"
683
- });
684
- const videoTrack = this.localStream.getVideoTracks()[0];
685
- if (videoTrack) {
686
- await cameraTransceiver.sender.replaceTrack(videoTrack);
687
- }
688
- const screenTransceiver = pc.addTransceiver("video", {
689
- direction: this.isScreenSharing ? "sendrecv" : "recvonly"
690
- });
691
- if (this.isScreenSharing && this.screenStream) {
692
- const screenTrack = this.screenStream.getVideoTracks()[0];
693
- if (screenTrack) {
694
- await screenTransceiver.sender.replaceTrack(screenTrack);
695
- }
696
- }
697
- this.peerTransceivers[id] = {
698
- cameraTransceiver,
699
- screenTransceiver,
700
- screenMid: null
701
- // will be populated after negotiation
702
- };
703
674
  pc.ontrack = (event) => {
704
- const transceiver = event.transceiver;
705
- const isScreenTrack = transceiver === this.peerTransceivers[id]?.screenTransceiver;
706
- console.log(
707
- `[ontrack] ${id}: kind=${event.track.kind}, mid=${transceiver.mid}, isScreen=${isScreenTrack}`
708
- );
675
+ console.log("ontrack");
676
+ console.log("kind:", event.track.kind);
677
+ console.log("mid:", event.transceiver.mid);
678
+ console.log("streams:", event.streams);
679
+ console.log("stream id:", event.streams[0]?.id);
709
680
  const incomingStream = event.streams?.[0] || new MediaStream([event.track]);
681
+ const participant = this.state.getParticipant(id);
682
+ const isScreenStream = participant?.media?.isScreenSharing && incomingStream.id === participant?.media?.remoteScreenStreamId;
710
683
  if (event.track.muted) {
711
684
  event.track.onunmute = () => {
712
- console.log(`[ontrack] ${event.track.kind} track unmuted for ${id}`);
685
+ console.log(`${event.track.kind} track unmuted for ${id}`);
713
686
  };
714
687
  }
715
- if (isScreenTrack) {
716
- const videoTrack2 = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0];
688
+ if (isScreenStream) {
689
+ const videoTrack = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0] || participant?.media?.screenTrack;
717
690
  this.state.updateParticipantMedia(id, {
718
691
  screenStream: incomingStream,
719
- screenTrack: videoTrack2,
692
+ screenTrack: videoTrack,
720
693
  isScreenSharing: true
721
694
  });
722
695
  if (!this.state.presenterId) {
@@ -742,41 +715,29 @@ var VideoSDKCore = class {
742
715
  });
743
716
  };
744
717
  pc.oniceconnectionstatechange = () => {
745
- console.log(`[ICE Connection] ${id}: ${pc.iceConnectionState}`);
718
+ console.log(`ICE Connection State: ${pc.iceConnectionState}`);
746
719
  };
747
720
  pc.onconnectionstatechange = () => {
748
- console.log(`[Connection] ${id}: ${pc.connectionState}`);
749
721
  if (pc.connectionState === "failed") {
750
722
  try {
751
723
  pc.restartIce();
752
- } catch (e) {
753
- console.warn("Failed to restart ICE:", e);
724
+ } catch {
754
725
  }
755
726
  }
756
727
  };
757
- return pc;
758
- }
759
- /**
760
- * Capture the screen transceiver's MID after SDP negotiation completes.
761
- * The MID is assigned during negotiation and is stable for the life of the connection.
762
- */
763
- captureScreenMid(peerId) {
764
- const pc = this.peers[peerId];
765
- if (!pc) return;
766
- const transceivers = pc.getTransceivers();
767
- const screenTransceiver = this.peerTransceivers[peerId]?.screenTransceiver;
768
- if (!screenTransceiver) return;
769
- const negotiatedTransceiver = transceivers.find(
770
- (t) => t === screenTransceiver
771
- );
772
- if (negotiatedTransceiver?.mid) {
773
- this.peerTransceivers[peerId].screenMid = negotiatedTransceiver.mid;
774
- console.log(
775
- `[Negotiation] Captured screenMid for ${peerId}: ${negotiatedTransceiver.mid}`
776
- );
728
+ this.localStream.getTracks().forEach((track) => {
729
+ pc.addTrack(track, this.localStream);
730
+ });
731
+ if (this.isScreenSharing && this.screenStream) {
732
+ this.screenSenders[id] = [];
733
+ this.screenStream.getTracks().forEach((track) => {
734
+ const sender = pc.addTrack(track, this.screenStream);
735
+ this.screenSenders[id].push(sender);
736
+ });
777
737
  }
738
+ return pc;
778
739
  }
779
- // OFFER
740
+ // ---------------- OFFER ----------------
780
741
  async createOffer(id, isRenegotiation = false) {
781
742
  if (!isRenegotiation && !this.shouldInitiate(id)) {
782
743
  console.debug(
@@ -794,13 +755,12 @@ var VideoSDKCore = class {
794
755
  this.initiators.add(id);
795
756
  }
796
757
  if (!this.peers[id]) {
797
- this.peers[id] = await this.createPeer(id);
758
+ this.peers[id] = this.createPeer(id);
798
759
  }
799
760
  const pc = this.peers[id];
800
761
  try {
801
762
  const offer = await pc.createOffer();
802
763
  await pc.setLocalDescription(offer);
803
- this.captureScreenMid(id);
804
764
  this.send({
805
765
  type: "OFFER",
806
766
  payload: offer.sdp,
@@ -810,18 +770,12 @@ var VideoSDKCore = class {
810
770
  console.debug(`[Offer] Sent to ${id}`);
811
771
  } catch (err) {
812
772
  console.error(`[Offer] Failed for ${id}:`, err);
813
- this.emitError(
814
- "OFFER_CREATION_FAILED",
815
- `Failed to create offer for ${id}`,
816
- err,
817
- true
818
- );
819
773
  }
820
774
  }
821
775
  shouldInitiate(peerId) {
822
776
  return this.myId < peerId;
823
777
  }
824
- // ANSWER
778
+ // ---------------- ANSWER ----------------
825
779
  async handleOffer(sdp, id) {
826
780
  if (!this.iceServers || this.iceServers.length === 0) {
827
781
  console.warn("[Offer] Waiting for iceServers, queuing offer from", id);
@@ -829,7 +783,7 @@ var VideoSDKCore = class {
829
783
  return;
830
784
  }
831
785
  if (!this.peers[id]) {
832
- this.peers[id] = await this.createPeer(id);
786
+ this.peers[id] = this.createPeer(id);
833
787
  }
834
788
  const pc = this.peers[id];
835
789
  try {
@@ -845,9 +799,8 @@ var VideoSDKCore = class {
845
799
  );
846
800
  pc.close();
847
801
  delete this.peers[id];
848
- delete this.peerTransceivers[id];
849
802
  this.initiators.delete(id);
850
- this.peers[id] = await this.createPeer(id);
803
+ this.peers[id] = this.createPeer(id);
851
804
  }
852
805
  }
853
806
  if (this.peers[id].signalingState !== "stable" && this.peers[id].signalingState !== "have-local-offer") {
@@ -860,7 +813,6 @@ var VideoSDKCore = class {
860
813
  type: "offer",
861
814
  sdp
862
815
  });
863
- this.captureScreenMid(id);
864
816
  const pending = this.pendingIceCandidates[id] || [];
865
817
  for (const candidate of pending) {
866
818
  try {
@@ -890,26 +842,18 @@ var VideoSDKCore = class {
890
842
  );
891
843
  }
892
844
  }
893
- // CLEANUP
845
+ // ---------------- CLEANUP ----------------
894
846
  closePeer(id) {
895
847
  const pc = this.peers[id];
896
848
  if (!pc) return;
897
849
  pc.ontrack = null;
898
850
  pc.onicecandidate = null;
899
851
  pc.onconnectionstatechange = null;
900
- pc.oniceconnectionstatechange = null;
901
852
  pc.close();
902
853
  delete this.peers[id];
903
- delete this.peerTransceivers[id];
904
854
  this.initiators.delete(id);
905
855
  this.state.removeParticipant(id);
906
856
  }
907
- // SCREEN SHARE (TRANSCEIVER-BASED)
908
- /**
909
- * Start screen sharing using replaceTrack on the pre-established screen transceiver.
910
- * No need to add/remove tracks, no renegotiation needed (transceiver already in SDP).
911
- * Just swap the track and update direction if needed.
912
- */
913
857
  async startScreenShare() {
914
858
  try {
915
859
  if (this.state.presenterId && this.state.presenterId !== this.myId) {
@@ -920,55 +864,34 @@ var VideoSDKCore = class {
920
864
  }
921
865
  this.screenStream = await navigator.mediaDevices.getDisplayMedia({
922
866
  video: true
867
+ // audio: true,
923
868
  });
924
- const screenTrack = this.screenStream.getVideoTracks()[0];
925
- if (!screenTrack) {
926
- throw new Error("No video track in screen stream");
927
- }
928
869
  this.isScreenSharing = true;
929
870
  this.state.updateLocalParticipant({
930
871
  media: {
931
872
  isScreenSharing: true,
932
873
  screenStream: this.screenStream,
933
- screenTrack
874
+ screenTrack: this.screenStream.getVideoTracks()[0]
934
875
  }
935
876
  });
936
877
  this.state.setPresenterId(this.myId);
937
- screenTrack.onended = () => {
938
- console.log("[Screen Share] User stopped via browser button");
878
+ this.screenStream.getVideoTracks()[0].onended = () => {
939
879
  this.stopScreenShare();
940
880
  };
941
- for (const [peerId, pc] of Object.entries(this.peers)) {
942
- const txInfo = this.peerTransceivers[peerId];
943
- if (!txInfo) {
944
- console.warn(
945
- `[Screen Share] No transceiver info for ${peerId}, skipping`
946
- );
947
- continue;
948
- }
949
- try {
950
- await txInfo.screenTransceiver.sender.replaceTrack(screenTrack);
951
- if (txInfo.screenTransceiver.currentDirection === "recvonly") {
952
- txInfo.screenTransceiver.direction = "sendrecv";
953
- console.log(
954
- `[Screen Share] Flipped ${peerId} screen transceiver to sendrecv`
955
- );
956
- await this.createOffer(peerId, true);
957
- }
958
- } catch (err) {
959
- console.error(
960
- `[Screen Share] Failed to update transceiver for ${peerId}:`,
961
- err
962
- );
963
- }
964
- }
881
+ Object.entries(this.peers).forEach(([peerId, pc]) => {
882
+ this.screenSenders[peerId] = [];
883
+ this.screenStream.getTracks().forEach((track) => {
884
+ const sender = pc.addTrack(track, this.screenStream);
885
+ this.screenSenders[peerId].push(sender);
886
+ });
887
+ this.createOffer(peerId, true);
888
+ });
965
889
  this.send({
966
890
  type: "SCREEN_SHARE_START",
967
891
  sender: this.myId,
968
892
  room_id: this.room.id,
969
893
  stream_id: this.screenStream.id.replace(/[{}]/g, "")
970
894
  });
971
- console.log("[Screen Share] Started successfully");
972
895
  return this.screenStream;
973
896
  } catch (err) {
974
897
  this.emitError(
@@ -982,32 +905,21 @@ var VideoSDKCore = class {
982
905
  throw err;
983
906
  }
984
907
  }
985
- /**
986
- * Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
987
- */
988
- async stopScreenShare() {
908
+ stopScreenShare() {
989
909
  if (!this.screenStream) return;
990
- console.log("[Screen Share] Stopping...");
991
910
  this.screenStream.getTracks().forEach((t) => t.stop());
992
- for (const [peerId, pc] of Object.entries(this.peers)) {
993
- const txInfo = this.peerTransceivers[peerId];
994
- if (!txInfo) continue;
995
- try {
996
- await txInfo.screenTransceiver.sender.replaceTrack(null);
997
- if (txInfo.screenTransceiver.currentDirection === "sendrecv") {
998
- txInfo.screenTransceiver.direction = "recvonly";
999
- console.log(
1000
- `[Screen Share] Flipped ${peerId} screen transceiver to recvonly`
1001
- );
1002
- await this.createOffer(peerId, true);
911
+ Object.entries(this.peers).forEach(([peerId, pc]) => {
912
+ const senders = this.screenSenders[peerId] || [];
913
+ senders.forEach((sender) => {
914
+ try {
915
+ pc.removeTrack(sender);
916
+ } catch (err) {
917
+ console.warn(err);
1003
918
  }
1004
- } catch (err) {
1005
- console.error(
1006
- `[Screen Share] Failed to clear transceiver for ${peerId}:`,
1007
- err
1008
- );
1009
- }
1010
- }
919
+ });
920
+ delete this.screenSenders[peerId];
921
+ this.createOffer(peerId, true);
922
+ });
1011
923
  this.screenStream = null;
1012
924
  this.isScreenSharing = false;
1013
925
  this.state.updateLocalParticipant({
@@ -1025,9 +937,7 @@ var VideoSDKCore = class {
1025
937
  sender: this.myId,
1026
938
  room_id: this.room.id
1027
939
  });
1028
- console.log("[Screen Share] Stopped");
1029
940
  }
1030
- // CHAT
1031
941
  sendChatMessage(payload) {
1032
942
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
1033
943
  console.warn("WS not connected");
@@ -1060,13 +970,11 @@ var VideoSDKCore = class {
1060
970
  client_ts: Date.now()
1061
971
  });
1062
972
  }
1063
- // DISCONNECT
1064
- async disconnect() {
973
+ disconnect() {
1065
974
  this.intentionalDisconnect = true;
1066
- await this.stopScreenShare();
975
+ this.stopScreenShare();
1067
976
  Object.values(this.peers).forEach((pc) => pc.close());
1068
977
  this.peers = {};
1069
- this.peerTransceivers = {};
1070
978
  this.initiators.clear();
1071
979
  this.stopHeartbeat();
1072
980
  if (this.ws?.readyState === WebSocket.OPEN) {