@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.d.mts CHANGED
@@ -130,7 +130,7 @@ declare class VideoSDKCore {
130
130
  private localStream;
131
131
  private screenStream;
132
132
  private isScreenSharing;
133
- private peerTransceivers;
133
+ private screenSenders;
134
134
  private pingInterval;
135
135
  private pendingIceCandidates;
136
136
  private pendingOffers;
@@ -160,27 +160,14 @@ declare class VideoSDKCore {
160
160
  private handleJoinApproved;
161
161
  private handle;
162
162
  private createPeer;
163
- /**
164
- * Capture the screen transceiver's MID after SDP negotiation completes.
165
- * The MID is assigned during negotiation and is stable for the life of the connection.
166
- */
167
- private captureScreenMid;
168
163
  private createOffer;
169
164
  private shouldInitiate;
170
165
  private handleOffer;
171
166
  private closePeer;
172
- /**
173
- * Start screen sharing using replaceTrack on the pre-established screen transceiver.
174
- * No need to add/remove tracks, no renegotiation needed (transceiver already in SDP).
175
- * Just swap the track and update direction if needed.
176
- */
177
167
  startScreenShare(): Promise<MediaStream>;
178
- /**
179
- * Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
180
- */
181
- stopScreenShare(): Promise<void>;
168
+ stopScreenShare(): void;
182
169
  sendChatMessage(payload: ChatInput): void;
183
- disconnect(): Promise<void>;
170
+ disconnect(): void;
184
171
  private flushIce;
185
172
  private send;
186
173
  approveJoinRequest(requestId: string): void;
package/dist/index.d.ts CHANGED
@@ -130,7 +130,7 @@ declare class VideoSDKCore {
130
130
  private localStream;
131
131
  private screenStream;
132
132
  private isScreenSharing;
133
- private peerTransceivers;
133
+ private screenSenders;
134
134
  private pingInterval;
135
135
  private pendingIceCandidates;
136
136
  private pendingOffers;
@@ -160,27 +160,14 @@ declare class VideoSDKCore {
160
160
  private handleJoinApproved;
161
161
  private handle;
162
162
  private createPeer;
163
- /**
164
- * Capture the screen transceiver's MID after SDP negotiation completes.
165
- * The MID is assigned during negotiation and is stable for the life of the connection.
166
- */
167
- private captureScreenMid;
168
163
  private createOffer;
169
164
  private shouldInitiate;
170
165
  private handleOffer;
171
166
  private closePeer;
172
- /**
173
- * Start screen sharing using replaceTrack on the pre-established screen transceiver.
174
- * No need to add/remove tracks, no renegotiation needed (transceiver already in SDP).
175
- * Just swap the track and update direction if needed.
176
- */
177
167
  startScreenShare(): Promise<MediaStream>;
178
- /**
179
- * Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
180
- */
181
- stopScreenShare(): Promise<void>;
168
+ stopScreenShare(): void;
182
169
  sendChatMessage(payload: ChatInput): void;
183
- disconnect(): Promise<void>;
170
+ disconnect(): void;
184
171
  private flushIce;
185
172
  private send;
186
173
  approveJoinRequest(requestId: string): void;
package/dist/index.js CHANGED
@@ -210,8 +210,7 @@ var VideoSDKCore = class {
210
210
  this.localStream = null;
211
211
  this.screenStream = null;
212
212
  this.isScreenSharing = false;
213
- // Transceiver-based tracking: maps peerId -> { cameraTransceiver, screenTransceiver, screenMid }
214
- this.peerTransceivers = {};
213
+ this.screenSenders = {};
215
214
  this.pingInterval = null;
216
215
  this.pendingIceCandidates = {};
217
216
  this.pendingOffers = {};
@@ -240,7 +239,7 @@ var VideoSDKCore = class {
240
239
  this.joinRejecter = void 0;
241
240
  console.error("[MeetingSDK Error]", err);
242
241
  }
243
- // STREAM
242
+ // ---------------- STREAM ----------------
244
243
  async initLocal(video, name) {
245
244
  this.participantName = name;
246
245
  try {
@@ -277,7 +276,7 @@ var VideoSDKCore = class {
277
276
  throw err;
278
277
  }
279
278
  }
280
- // CONNECT
279
+ // ---------------- CONNECT ----------------
281
280
  async connect(roomId, name) {
282
281
  this.room.id = roomId;
283
282
  this.reset();
@@ -423,11 +422,10 @@ var VideoSDKCore = class {
423
422
  this.pingInterval = null;
424
423
  }
425
424
  }
426
- // RESET
425
+ // ---------------- RESET ----------------
427
426
  reset() {
428
427
  Object.values(this.peers).forEach((pc) => pc.close());
429
428
  this.peers = {};
430
- this.peerTransceivers = {};
431
429
  this.initiators.clear();
432
430
  this.pendingIceCandidates = {};
433
431
  this.state.resetRemoteState();
@@ -482,7 +480,6 @@ var VideoSDKCore = class {
482
480
  type: "answer",
483
481
  sdp: msg.payload
484
482
  });
485
- this.captureScreenMid(msg.sender);
486
483
  await this.flushIce(msg.sender, pc);
487
484
  } catch (err) {
488
485
  console.error("[Signaling] Failed to apply answer:", err);
@@ -519,6 +516,7 @@ var VideoSDKCore = class {
519
516
  if (msg.presenterId) {
520
517
  this.state.setPresenterId(msg.presenterId);
521
518
  this.events.onScreenShareStarted?.(msg.presenterId, null);
519
+ this.state.setPresenterId(msg.presenterId);
522
520
  }
523
521
  for (const p of msg.participants || []) {
524
522
  if (!p?.id || p.id === this.myId) continue;
@@ -601,10 +599,12 @@ var VideoSDKCore = class {
601
599
  });
602
600
  break;
603
601
  }
602
+ // ============ NEW: HANDLE JOIN_APPROVED WITH RECONNECT ============
604
603
  case "JOIN_APPROVED": {
605
604
  await this.handleJoinApproved(msg);
606
605
  break;
607
606
  }
607
+ // ============ END: JOIN_APPROVED ============
608
608
  case "JOIN_REJECTED": {
609
609
  const decision = "rejected";
610
610
  console.log("JOIN_REJECTED - user not allowed to join");
@@ -657,7 +657,8 @@ var VideoSDKCore = class {
657
657
  if (!this.state.presenterId) {
658
658
  this.state.setPresenterId(peerId2);
659
659
  }
660
- this.events.onScreenShareStarted?.(peerId2, null);
660
+ const screenStream = this.state.getParticipant(peerId2)?.media?.screenStream;
661
+ this.events.onScreenShareStarted?.(peerId2, screenStream || null);
661
662
  break;
662
663
  }
663
664
  case "SCREEN_SHARE_STOP": {
@@ -684,7 +685,8 @@ var VideoSDKCore = class {
684
685
  }
685
686
  }
686
687
  }
687
- async createPeer(id) {
688
+ // ---------------- PEER ----------------
689
+ createPeer(id) {
688
690
  if (!this.localStream) throw new Error("No local stream");
689
691
  if (!this.iceServers || this.iceServers.length === 0) {
690
692
  throw new Error(
@@ -692,9 +694,7 @@ var VideoSDKCore = class {
692
694
  );
693
695
  }
694
696
  console.log(
695
- "Creating peer connection for",
696
- id,
697
- "with tracks:",
697
+ "Adding tracks",
698
698
  this.localStream.getTracks().map((t) => ({
699
699
  kind: t.kind,
700
700
  enabled: t.enabled,
@@ -704,52 +704,25 @@ var VideoSDKCore = class {
704
704
  const pc = new RTCPeerConnection({
705
705
  iceServers: this.iceServers
706
706
  });
707
- const audioTransceiver = pc.addTransceiver("audio", {
708
- direction: "sendrecv"
709
- });
710
- const audioTrack = this.localStream.getAudioTracks()[0];
711
- if (audioTrack) {
712
- await audioTransceiver.sender.replaceTrack(audioTrack);
713
- }
714
- const cameraTransceiver = pc.addTransceiver("video", {
715
- direction: "sendrecv"
716
- });
717
- const videoTrack = this.localStream.getVideoTracks()[0];
718
- if (videoTrack) {
719
- await cameraTransceiver.sender.replaceTrack(videoTrack);
720
- }
721
- const screenTransceiver = pc.addTransceiver("video", {
722
- direction: this.isScreenSharing ? "sendrecv" : "recvonly"
723
- });
724
- if (this.isScreenSharing && this.screenStream) {
725
- const screenTrack = this.screenStream.getVideoTracks()[0];
726
- if (screenTrack) {
727
- await screenTransceiver.sender.replaceTrack(screenTrack);
728
- }
729
- }
730
- this.peerTransceivers[id] = {
731
- cameraTransceiver,
732
- screenTransceiver,
733
- screenMid: null
734
- // will be populated after negotiation
735
- };
736
707
  pc.ontrack = (event) => {
737
- const transceiver = event.transceiver;
738
- const isScreenTrack = transceiver === this.peerTransceivers[id]?.screenTransceiver;
739
- console.log(
740
- `[ontrack] ${id}: kind=${event.track.kind}, mid=${transceiver.mid}, isScreen=${isScreenTrack}`
741
- );
708
+ console.log("ontrack");
709
+ console.log("kind:", event.track.kind);
710
+ console.log("mid:", event.transceiver.mid);
711
+ console.log("streams:", event.streams);
712
+ console.log("stream id:", event.streams[0]?.id);
742
713
  const incomingStream = event.streams?.[0] || new MediaStream([event.track]);
714
+ const participant = this.state.getParticipant(id);
715
+ const isScreenStream = participant?.media?.isScreenSharing && incomingStream.id === participant?.media?.remoteScreenStreamId;
743
716
  if (event.track.muted) {
744
717
  event.track.onunmute = () => {
745
- console.log(`[ontrack] ${event.track.kind} track unmuted for ${id}`);
718
+ console.log(`${event.track.kind} track unmuted for ${id}`);
746
719
  };
747
720
  }
748
- if (isScreenTrack) {
749
- const videoTrack2 = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0];
721
+ if (isScreenStream) {
722
+ const videoTrack = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0] || participant?.media?.screenTrack;
750
723
  this.state.updateParticipantMedia(id, {
751
724
  screenStream: incomingStream,
752
- screenTrack: videoTrack2,
725
+ screenTrack: videoTrack,
753
726
  isScreenSharing: true
754
727
  });
755
728
  if (!this.state.presenterId) {
@@ -775,41 +748,29 @@ var VideoSDKCore = class {
775
748
  });
776
749
  };
777
750
  pc.oniceconnectionstatechange = () => {
778
- console.log(`[ICE Connection] ${id}: ${pc.iceConnectionState}`);
751
+ console.log(`ICE Connection State: ${pc.iceConnectionState}`);
779
752
  };
780
753
  pc.onconnectionstatechange = () => {
781
- console.log(`[Connection] ${id}: ${pc.connectionState}`);
782
754
  if (pc.connectionState === "failed") {
783
755
  try {
784
756
  pc.restartIce();
785
- } catch (e) {
786
- console.warn("Failed to restart ICE:", e);
757
+ } catch {
787
758
  }
788
759
  }
789
760
  };
790
- return pc;
791
- }
792
- /**
793
- * Capture the screen transceiver's MID after SDP negotiation completes.
794
- * The MID is assigned during negotiation and is stable for the life of the connection.
795
- */
796
- captureScreenMid(peerId) {
797
- const pc = this.peers[peerId];
798
- if (!pc) return;
799
- const transceivers = pc.getTransceivers();
800
- const screenTransceiver = this.peerTransceivers[peerId]?.screenTransceiver;
801
- if (!screenTransceiver) return;
802
- const negotiatedTransceiver = transceivers.find(
803
- (t) => t === screenTransceiver
804
- );
805
- if (negotiatedTransceiver?.mid) {
806
- this.peerTransceivers[peerId].screenMid = negotiatedTransceiver.mid;
807
- console.log(
808
- `[Negotiation] Captured screenMid for ${peerId}: ${negotiatedTransceiver.mid}`
809
- );
761
+ this.localStream.getTracks().forEach((track) => {
762
+ pc.addTrack(track, this.localStream);
763
+ });
764
+ if (this.isScreenSharing && this.screenStream) {
765
+ this.screenSenders[id] = [];
766
+ this.screenStream.getTracks().forEach((track) => {
767
+ const sender = pc.addTrack(track, this.screenStream);
768
+ this.screenSenders[id].push(sender);
769
+ });
810
770
  }
771
+ return pc;
811
772
  }
812
- // OFFER
773
+ // ---------------- OFFER ----------------
813
774
  async createOffer(id, isRenegotiation = false) {
814
775
  if (!isRenegotiation && !this.shouldInitiate(id)) {
815
776
  console.debug(
@@ -827,13 +788,12 @@ var VideoSDKCore = class {
827
788
  this.initiators.add(id);
828
789
  }
829
790
  if (!this.peers[id]) {
830
- this.peers[id] = await this.createPeer(id);
791
+ this.peers[id] = this.createPeer(id);
831
792
  }
832
793
  const pc = this.peers[id];
833
794
  try {
834
795
  const offer = await pc.createOffer();
835
796
  await pc.setLocalDescription(offer);
836
- this.captureScreenMid(id);
837
797
  this.send({
838
798
  type: "OFFER",
839
799
  payload: offer.sdp,
@@ -843,18 +803,12 @@ var VideoSDKCore = class {
843
803
  console.debug(`[Offer] Sent to ${id}`);
844
804
  } catch (err) {
845
805
  console.error(`[Offer] Failed for ${id}:`, err);
846
- this.emitError(
847
- "OFFER_CREATION_FAILED",
848
- `Failed to create offer for ${id}`,
849
- err,
850
- true
851
- );
852
806
  }
853
807
  }
854
808
  shouldInitiate(peerId) {
855
809
  return this.myId < peerId;
856
810
  }
857
- // ANSWER
811
+ // ---------------- ANSWER ----------------
858
812
  async handleOffer(sdp, id) {
859
813
  if (!this.iceServers || this.iceServers.length === 0) {
860
814
  console.warn("[Offer] Waiting for iceServers, queuing offer from", id);
@@ -862,7 +816,7 @@ var VideoSDKCore = class {
862
816
  return;
863
817
  }
864
818
  if (!this.peers[id]) {
865
- this.peers[id] = await this.createPeer(id);
819
+ this.peers[id] = this.createPeer(id);
866
820
  }
867
821
  const pc = this.peers[id];
868
822
  try {
@@ -878,9 +832,8 @@ var VideoSDKCore = class {
878
832
  );
879
833
  pc.close();
880
834
  delete this.peers[id];
881
- delete this.peerTransceivers[id];
882
835
  this.initiators.delete(id);
883
- this.peers[id] = await this.createPeer(id);
836
+ this.peers[id] = this.createPeer(id);
884
837
  }
885
838
  }
886
839
  if (this.peers[id].signalingState !== "stable" && this.peers[id].signalingState !== "have-local-offer") {
@@ -893,7 +846,6 @@ var VideoSDKCore = class {
893
846
  type: "offer",
894
847
  sdp
895
848
  });
896
- this.captureScreenMid(id);
897
849
  const pending = this.pendingIceCandidates[id] || [];
898
850
  for (const candidate of pending) {
899
851
  try {
@@ -923,26 +875,18 @@ var VideoSDKCore = class {
923
875
  );
924
876
  }
925
877
  }
926
- // CLEANUP
878
+ // ---------------- CLEANUP ----------------
927
879
  closePeer(id) {
928
880
  const pc = this.peers[id];
929
881
  if (!pc) return;
930
882
  pc.ontrack = null;
931
883
  pc.onicecandidate = null;
932
884
  pc.onconnectionstatechange = null;
933
- pc.oniceconnectionstatechange = null;
934
885
  pc.close();
935
886
  delete this.peers[id];
936
- delete this.peerTransceivers[id];
937
887
  this.initiators.delete(id);
938
888
  this.state.removeParticipant(id);
939
889
  }
940
- // SCREEN SHARE (TRANSCEIVER-BASED)
941
- /**
942
- * Start screen sharing using replaceTrack on the pre-established screen transceiver.
943
- * No need to add/remove tracks, no renegotiation needed (transceiver already in SDP).
944
- * Just swap the track and update direction if needed.
945
- */
946
890
  async startScreenShare() {
947
891
  try {
948
892
  if (this.state.presenterId && this.state.presenterId !== this.myId) {
@@ -953,55 +897,34 @@ var VideoSDKCore = class {
953
897
  }
954
898
  this.screenStream = await navigator.mediaDevices.getDisplayMedia({
955
899
  video: true
900
+ // audio: true,
956
901
  });
957
- const screenTrack = this.screenStream.getVideoTracks()[0];
958
- if (!screenTrack) {
959
- throw new Error("No video track in screen stream");
960
- }
961
902
  this.isScreenSharing = true;
962
903
  this.state.updateLocalParticipant({
963
904
  media: {
964
905
  isScreenSharing: true,
965
906
  screenStream: this.screenStream,
966
- screenTrack
907
+ screenTrack: this.screenStream.getVideoTracks()[0]
967
908
  }
968
909
  });
969
910
  this.state.setPresenterId(this.myId);
970
- screenTrack.onended = () => {
971
- console.log("[Screen Share] User stopped via browser button");
911
+ this.screenStream.getVideoTracks()[0].onended = () => {
972
912
  this.stopScreenShare();
973
913
  };
974
- for (const [peerId, pc] of Object.entries(this.peers)) {
975
- const txInfo = this.peerTransceivers[peerId];
976
- if (!txInfo) {
977
- console.warn(
978
- `[Screen Share] No transceiver info for ${peerId}, skipping`
979
- );
980
- continue;
981
- }
982
- try {
983
- await txInfo.screenTransceiver.sender.replaceTrack(screenTrack);
984
- if (txInfo.screenTransceiver.currentDirection === "recvonly") {
985
- txInfo.screenTransceiver.direction = "sendrecv";
986
- console.log(
987
- `[Screen Share] Flipped ${peerId} screen transceiver to sendrecv`
988
- );
989
- await this.createOffer(peerId, true);
990
- }
991
- } catch (err) {
992
- console.error(
993
- `[Screen Share] Failed to update transceiver for ${peerId}:`,
994
- err
995
- );
996
- }
997
- }
914
+ Object.entries(this.peers).forEach(([peerId, pc]) => {
915
+ this.screenSenders[peerId] = [];
916
+ this.screenStream.getTracks().forEach((track) => {
917
+ const sender = pc.addTrack(track, this.screenStream);
918
+ this.screenSenders[peerId].push(sender);
919
+ });
920
+ this.createOffer(peerId, true);
921
+ });
998
922
  this.send({
999
923
  type: "SCREEN_SHARE_START",
1000
924
  sender: this.myId,
1001
925
  room_id: this.room.id,
1002
926
  stream_id: this.screenStream.id.replace(/[{}]/g, "")
1003
927
  });
1004
- console.log("[Screen Share] Started successfully");
1005
928
  return this.screenStream;
1006
929
  } catch (err) {
1007
930
  this.emitError(
@@ -1015,32 +938,21 @@ var VideoSDKCore = class {
1015
938
  throw err;
1016
939
  }
1017
940
  }
1018
- /**
1019
- * Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
1020
- */
1021
- async stopScreenShare() {
941
+ stopScreenShare() {
1022
942
  if (!this.screenStream) return;
1023
- console.log("[Screen Share] Stopping...");
1024
943
  this.screenStream.getTracks().forEach((t) => t.stop());
1025
- for (const [peerId, pc] of Object.entries(this.peers)) {
1026
- const txInfo = this.peerTransceivers[peerId];
1027
- if (!txInfo) continue;
1028
- try {
1029
- await txInfo.screenTransceiver.sender.replaceTrack(null);
1030
- if (txInfo.screenTransceiver.currentDirection === "sendrecv") {
1031
- txInfo.screenTransceiver.direction = "recvonly";
1032
- console.log(
1033
- `[Screen Share] Flipped ${peerId} screen transceiver to recvonly`
1034
- );
1035
- await this.createOffer(peerId, true);
944
+ Object.entries(this.peers).forEach(([peerId, pc]) => {
945
+ const senders = this.screenSenders[peerId] || [];
946
+ senders.forEach((sender) => {
947
+ try {
948
+ pc.removeTrack(sender);
949
+ } catch (err) {
950
+ console.warn(err);
1036
951
  }
1037
- } catch (err) {
1038
- console.error(
1039
- `[Screen Share] Failed to clear transceiver for ${peerId}:`,
1040
- err
1041
- );
1042
- }
1043
- }
952
+ });
953
+ delete this.screenSenders[peerId];
954
+ this.createOffer(peerId, true);
955
+ });
1044
956
  this.screenStream = null;
1045
957
  this.isScreenSharing = false;
1046
958
  this.state.updateLocalParticipant({
@@ -1058,9 +970,7 @@ var VideoSDKCore = class {
1058
970
  sender: this.myId,
1059
971
  room_id: this.room.id
1060
972
  });
1061
- console.log("[Screen Share] Stopped");
1062
973
  }
1063
- // CHAT
1064
974
  sendChatMessage(payload) {
1065
975
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
1066
976
  console.warn("WS not connected");
@@ -1093,13 +1003,11 @@ var VideoSDKCore = class {
1093
1003
  client_ts: Date.now()
1094
1004
  });
1095
1005
  }
1096
- // DISCONNECT
1097
- async disconnect() {
1006
+ disconnect() {
1098
1007
  this.intentionalDisconnect = true;
1099
- await this.stopScreenShare();
1008
+ this.stopScreenShare();
1100
1009
  Object.values(this.peers).forEach((pc) => pc.close());
1101
1010
  this.peers = {};
1102
- this.peerTransceivers = {};
1103
1011
  this.initiators.clear();
1104
1012
  this.stopHeartbeat();
1105
1013
  if (this.ws?.readyState === WebSocket.OPEN) {