@afosecure/meetingsdk 1.3.0 → 1.3.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 +16 -3
- package/dist/index.d.ts +16 -3
- package/dist/index.js +158 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +158 -61
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
133
|
+
private peerTransceivers;
|
|
134
134
|
private pingInterval;
|
|
135
135
|
private pendingIceCandidates;
|
|
136
136
|
private pendingOffers;
|
|
@@ -160,14 +160,27 @@ 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;
|
|
163
168
|
private createOffer;
|
|
164
169
|
private shouldInitiate;
|
|
165
170
|
private handleOffer;
|
|
166
171
|
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
|
+
*/
|
|
167
177
|
startScreenShare(): Promise<MediaStream>;
|
|
168
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
|
|
180
|
+
*/
|
|
181
|
+
stopScreenShare(): Promise<void>;
|
|
169
182
|
sendChatMessage(payload: ChatInput): void;
|
|
170
|
-
disconnect(): void
|
|
183
|
+
disconnect(): Promise<void>;
|
|
171
184
|
private flushIce;
|
|
172
185
|
private send;
|
|
173
186
|
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
|
|
133
|
+
private peerTransceivers;
|
|
134
134
|
private pingInterval;
|
|
135
135
|
private pendingIceCandidates;
|
|
136
136
|
private pendingOffers;
|
|
@@ -160,14 +160,27 @@ 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;
|
|
163
168
|
private createOffer;
|
|
164
169
|
private shouldInitiate;
|
|
165
170
|
private handleOffer;
|
|
166
171
|
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
|
+
*/
|
|
167
177
|
startScreenShare(): Promise<MediaStream>;
|
|
168
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
|
|
180
|
+
*/
|
|
181
|
+
stopScreenShare(): Promise<void>;
|
|
169
182
|
sendChatMessage(payload: ChatInput): void;
|
|
170
|
-
disconnect(): void
|
|
183
|
+
disconnect(): Promise<void>;
|
|
171
184
|
private flushIce;
|
|
172
185
|
private send;
|
|
173
186
|
approveJoinRequest(requestId: string): void;
|
package/dist/index.js
CHANGED
|
@@ -210,7 +210,8 @@ var VideoSDKCore = class {
|
|
|
210
210
|
this.localStream = null;
|
|
211
211
|
this.screenStream = null;
|
|
212
212
|
this.isScreenSharing = false;
|
|
213
|
-
|
|
213
|
+
// Transceiver-based tracking: maps peerId -> { cameraTransceiver, screenTransceiver, screenMid }
|
|
214
|
+
this.peerTransceivers = {};
|
|
214
215
|
this.pingInterval = null;
|
|
215
216
|
this.pendingIceCandidates = {};
|
|
216
217
|
this.pendingOffers = {};
|
|
@@ -239,7 +240,7 @@ var VideoSDKCore = class {
|
|
|
239
240
|
this.joinRejecter = void 0;
|
|
240
241
|
console.error("[MeetingSDK Error]", err);
|
|
241
242
|
}
|
|
242
|
-
//
|
|
243
|
+
// STREAM
|
|
243
244
|
async initLocal(video, name) {
|
|
244
245
|
this.participantName = name;
|
|
245
246
|
try {
|
|
@@ -276,7 +277,7 @@ var VideoSDKCore = class {
|
|
|
276
277
|
throw err;
|
|
277
278
|
}
|
|
278
279
|
}
|
|
279
|
-
//
|
|
280
|
+
// CONNECT
|
|
280
281
|
async connect(roomId, name) {
|
|
281
282
|
this.room.id = roomId;
|
|
282
283
|
this.reset();
|
|
@@ -422,10 +423,11 @@ var VideoSDKCore = class {
|
|
|
422
423
|
this.pingInterval = null;
|
|
423
424
|
}
|
|
424
425
|
}
|
|
425
|
-
//
|
|
426
|
+
// RESET
|
|
426
427
|
reset() {
|
|
427
428
|
Object.values(this.peers).forEach((pc) => pc.close());
|
|
428
429
|
this.peers = {};
|
|
430
|
+
this.peerTransceivers = {};
|
|
429
431
|
this.initiators.clear();
|
|
430
432
|
this.pendingIceCandidates = {};
|
|
431
433
|
this.state.resetRemoteState();
|
|
@@ -480,6 +482,7 @@ var VideoSDKCore = class {
|
|
|
480
482
|
type: "answer",
|
|
481
483
|
sdp: msg.payload
|
|
482
484
|
});
|
|
485
|
+
this.captureScreenMid(msg.sender);
|
|
483
486
|
await this.flushIce(msg.sender, pc);
|
|
484
487
|
} catch (err) {
|
|
485
488
|
console.error("[Signaling] Failed to apply answer:", err);
|
|
@@ -516,7 +519,6 @@ var VideoSDKCore = class {
|
|
|
516
519
|
if (msg.presenterId) {
|
|
517
520
|
this.state.setPresenterId(msg.presenterId);
|
|
518
521
|
this.events.onScreenShareStarted?.(msg.presenterId, null);
|
|
519
|
-
this.state.setPresenterId(msg.presenterId);
|
|
520
522
|
}
|
|
521
523
|
for (const p of msg.participants || []) {
|
|
522
524
|
if (!p?.id || p.id === this.myId) continue;
|
|
@@ -599,12 +601,10 @@ var VideoSDKCore = class {
|
|
|
599
601
|
});
|
|
600
602
|
break;
|
|
601
603
|
}
|
|
602
|
-
// ============ NEW: HANDLE JOIN_APPROVED WITH RECONNECT ============
|
|
603
604
|
case "JOIN_APPROVED": {
|
|
604
605
|
await this.handleJoinApproved(msg);
|
|
605
606
|
break;
|
|
606
607
|
}
|
|
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,8 +657,7 @@ var VideoSDKCore = class {
|
|
|
657
657
|
if (!this.state.presenterId) {
|
|
658
658
|
this.state.setPresenterId(peerId2);
|
|
659
659
|
}
|
|
660
|
-
|
|
661
|
-
this.events.onScreenShareStarted?.(peerId2, screenStream || null);
|
|
660
|
+
this.events.onScreenShareStarted?.(peerId2, null);
|
|
662
661
|
break;
|
|
663
662
|
}
|
|
664
663
|
case "SCREEN_SHARE_STOP": {
|
|
@@ -685,8 +684,7 @@ var VideoSDKCore = class {
|
|
|
685
684
|
}
|
|
686
685
|
}
|
|
687
686
|
}
|
|
688
|
-
|
|
689
|
-
createPeer(id) {
|
|
687
|
+
async createPeer(id) {
|
|
690
688
|
if (!this.localStream) throw new Error("No local stream");
|
|
691
689
|
if (!this.iceServers || this.iceServers.length === 0) {
|
|
692
690
|
throw new Error(
|
|
@@ -694,7 +692,9 @@ var VideoSDKCore = class {
|
|
|
694
692
|
);
|
|
695
693
|
}
|
|
696
694
|
console.log(
|
|
697
|
-
"
|
|
695
|
+
"Creating peer connection for",
|
|
696
|
+
id,
|
|
697
|
+
"with tracks:",
|
|
698
698
|
this.localStream.getTracks().map((t) => ({
|
|
699
699
|
kind: t.kind,
|
|
700
700
|
enabled: t.enabled,
|
|
@@ -704,20 +704,52 @@ 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
|
+
};
|
|
707
736
|
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
742
|
const incomingStream = event.streams?.[0] || new MediaStream([event.track]);
|
|
709
|
-
const participant = this.state.getParticipant(id);
|
|
710
|
-
const isScreenStream = participant?.media?.isScreenSharing && incomingStream.id === participant?.media?.remoteScreenStreamId;
|
|
711
743
|
if (event.track.muted) {
|
|
712
744
|
event.track.onunmute = () => {
|
|
713
|
-
console.log(
|
|
745
|
+
console.log(`[ontrack] ${event.track.kind} track unmuted for ${id}`);
|
|
714
746
|
};
|
|
715
747
|
}
|
|
716
|
-
if (
|
|
717
|
-
const
|
|
748
|
+
if (isScreenTrack) {
|
|
749
|
+
const videoTrack2 = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0];
|
|
718
750
|
this.state.updateParticipantMedia(id, {
|
|
719
751
|
screenStream: incomingStream,
|
|
720
|
-
screenTrack:
|
|
752
|
+
screenTrack: videoTrack2,
|
|
721
753
|
isScreenSharing: true
|
|
722
754
|
});
|
|
723
755
|
if (!this.state.presenterId) {
|
|
@@ -743,29 +775,41 @@ var VideoSDKCore = class {
|
|
|
743
775
|
});
|
|
744
776
|
};
|
|
745
777
|
pc.oniceconnectionstatechange = () => {
|
|
746
|
-
console.log(`ICE Connection
|
|
778
|
+
console.log(`[ICE Connection] ${id}: ${pc.iceConnectionState}`);
|
|
747
779
|
};
|
|
748
780
|
pc.onconnectionstatechange = () => {
|
|
781
|
+
console.log(`[Connection] ${id}: ${pc.connectionState}`);
|
|
749
782
|
if (pc.connectionState === "failed") {
|
|
750
783
|
try {
|
|
751
784
|
pc.restartIce();
|
|
752
|
-
} catch {
|
|
785
|
+
} catch (e) {
|
|
786
|
+
console.warn("Failed to restart ICE:", e);
|
|
753
787
|
}
|
|
754
788
|
}
|
|
755
789
|
};
|
|
756
|
-
this.localStream.getTracks().forEach((track) => {
|
|
757
|
-
pc.addTrack(track, this.localStream);
|
|
758
|
-
});
|
|
759
|
-
if (this.isScreenSharing && this.screenStream) {
|
|
760
|
-
this.screenSenders[id] = [];
|
|
761
|
-
this.screenStream.getTracks().forEach((track) => {
|
|
762
|
-
const sender = pc.addTrack(track, this.screenStream);
|
|
763
|
-
this.screenSenders[id].push(sender);
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
790
|
return pc;
|
|
767
791
|
}
|
|
768
|
-
|
|
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
|
+
);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
// OFFER
|
|
769
813
|
async createOffer(id, isRenegotiation = false) {
|
|
770
814
|
if (!isRenegotiation && !this.shouldInitiate(id)) {
|
|
771
815
|
console.debug(
|
|
@@ -783,12 +827,13 @@ var VideoSDKCore = class {
|
|
|
783
827
|
this.initiators.add(id);
|
|
784
828
|
}
|
|
785
829
|
if (!this.peers[id]) {
|
|
786
|
-
this.peers[id] = this.createPeer(id);
|
|
830
|
+
this.peers[id] = await this.createPeer(id);
|
|
787
831
|
}
|
|
788
832
|
const pc = this.peers[id];
|
|
789
833
|
try {
|
|
790
834
|
const offer = await pc.createOffer();
|
|
791
835
|
await pc.setLocalDescription(offer);
|
|
836
|
+
this.captureScreenMid(id);
|
|
792
837
|
this.send({
|
|
793
838
|
type: "OFFER",
|
|
794
839
|
payload: offer.sdp,
|
|
@@ -798,12 +843,18 @@ var VideoSDKCore = class {
|
|
|
798
843
|
console.debug(`[Offer] Sent to ${id}`);
|
|
799
844
|
} catch (err) {
|
|
800
845
|
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
|
+
);
|
|
801
852
|
}
|
|
802
853
|
}
|
|
803
854
|
shouldInitiate(peerId) {
|
|
804
855
|
return this.myId < peerId;
|
|
805
856
|
}
|
|
806
|
-
//
|
|
857
|
+
// ANSWER
|
|
807
858
|
async handleOffer(sdp, id) {
|
|
808
859
|
if (!this.iceServers || this.iceServers.length === 0) {
|
|
809
860
|
console.warn("[Offer] Waiting for iceServers, queuing offer from", id);
|
|
@@ -811,7 +862,7 @@ var VideoSDKCore = class {
|
|
|
811
862
|
return;
|
|
812
863
|
}
|
|
813
864
|
if (!this.peers[id]) {
|
|
814
|
-
this.peers[id] = this.createPeer(id);
|
|
865
|
+
this.peers[id] = await this.createPeer(id);
|
|
815
866
|
}
|
|
816
867
|
const pc = this.peers[id];
|
|
817
868
|
try {
|
|
@@ -827,8 +878,9 @@ var VideoSDKCore = class {
|
|
|
827
878
|
);
|
|
828
879
|
pc.close();
|
|
829
880
|
delete this.peers[id];
|
|
881
|
+
delete this.peerTransceivers[id];
|
|
830
882
|
this.initiators.delete(id);
|
|
831
|
-
this.peers[id] = this.createPeer(id);
|
|
883
|
+
this.peers[id] = await this.createPeer(id);
|
|
832
884
|
}
|
|
833
885
|
}
|
|
834
886
|
if (this.peers[id].signalingState !== "stable" && this.peers[id].signalingState !== "have-local-offer") {
|
|
@@ -841,6 +893,7 @@ var VideoSDKCore = class {
|
|
|
841
893
|
type: "offer",
|
|
842
894
|
sdp
|
|
843
895
|
});
|
|
896
|
+
this.captureScreenMid(id);
|
|
844
897
|
const pending = this.pendingIceCandidates[id] || [];
|
|
845
898
|
for (const candidate of pending) {
|
|
846
899
|
try {
|
|
@@ -870,18 +923,26 @@ var VideoSDKCore = class {
|
|
|
870
923
|
);
|
|
871
924
|
}
|
|
872
925
|
}
|
|
873
|
-
//
|
|
926
|
+
// CLEANUP
|
|
874
927
|
closePeer(id) {
|
|
875
928
|
const pc = this.peers[id];
|
|
876
929
|
if (!pc) return;
|
|
877
930
|
pc.ontrack = null;
|
|
878
931
|
pc.onicecandidate = null;
|
|
879
932
|
pc.onconnectionstatechange = null;
|
|
933
|
+
pc.oniceconnectionstatechange = null;
|
|
880
934
|
pc.close();
|
|
881
935
|
delete this.peers[id];
|
|
936
|
+
delete this.peerTransceivers[id];
|
|
882
937
|
this.initiators.delete(id);
|
|
883
938
|
this.state.removeParticipant(id);
|
|
884
939
|
}
|
|
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
|
+
*/
|
|
885
946
|
async startScreenShare() {
|
|
886
947
|
try {
|
|
887
948
|
if (this.state.presenterId && this.state.presenterId !== this.myId) {
|
|
@@ -892,34 +953,55 @@ var VideoSDKCore = class {
|
|
|
892
953
|
}
|
|
893
954
|
this.screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
894
955
|
video: true
|
|
895
|
-
// audio: true,
|
|
896
956
|
});
|
|
957
|
+
const screenTrack = this.screenStream.getVideoTracks()[0];
|
|
958
|
+
if (!screenTrack) {
|
|
959
|
+
throw new Error("No video track in screen stream");
|
|
960
|
+
}
|
|
897
961
|
this.isScreenSharing = true;
|
|
898
962
|
this.state.updateLocalParticipant({
|
|
899
963
|
media: {
|
|
900
964
|
isScreenSharing: true,
|
|
901
965
|
screenStream: this.screenStream,
|
|
902
|
-
screenTrack
|
|
966
|
+
screenTrack
|
|
903
967
|
}
|
|
904
968
|
});
|
|
905
969
|
this.state.setPresenterId(this.myId);
|
|
906
|
-
|
|
970
|
+
screenTrack.onended = () => {
|
|
971
|
+
console.log("[Screen Share] User stopped via browser button");
|
|
907
972
|
this.stopScreenShare();
|
|
908
973
|
};
|
|
909
|
-
Object.entries(this.peers)
|
|
910
|
-
this.
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
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
|
+
}
|
|
917
998
|
this.send({
|
|
918
999
|
type: "SCREEN_SHARE_START",
|
|
919
1000
|
sender: this.myId,
|
|
920
1001
|
room_id: this.room.id,
|
|
921
1002
|
stream_id: this.screenStream.id.replace(/[{}]/g, "")
|
|
922
1003
|
});
|
|
1004
|
+
console.log("[Screen Share] Started successfully");
|
|
923
1005
|
return this.screenStream;
|
|
924
1006
|
} catch (err) {
|
|
925
1007
|
this.emitError(
|
|
@@ -933,21 +1015,32 @@ var VideoSDKCore = class {
|
|
|
933
1015
|
throw err;
|
|
934
1016
|
}
|
|
935
1017
|
}
|
|
936
|
-
|
|
1018
|
+
/**
|
|
1019
|
+
* Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
|
|
1020
|
+
*/
|
|
1021
|
+
async stopScreenShare() {
|
|
937
1022
|
if (!this.screenStream) return;
|
|
1023
|
+
console.log("[Screen Share] Stopping...");
|
|
938
1024
|
this.screenStream.getTracks().forEach((t) => t.stop());
|
|
939
|
-
Object.entries(this.peers)
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
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);
|
|
946
1036
|
}
|
|
947
|
-
})
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1037
|
+
} catch (err) {
|
|
1038
|
+
console.error(
|
|
1039
|
+
`[Screen Share] Failed to clear transceiver for ${peerId}:`,
|
|
1040
|
+
err
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
951
1044
|
this.screenStream = null;
|
|
952
1045
|
this.isScreenSharing = false;
|
|
953
1046
|
this.state.updateLocalParticipant({
|
|
@@ -965,7 +1058,9 @@ var VideoSDKCore = class {
|
|
|
965
1058
|
sender: this.myId,
|
|
966
1059
|
room_id: this.room.id
|
|
967
1060
|
});
|
|
1061
|
+
console.log("[Screen Share] Stopped");
|
|
968
1062
|
}
|
|
1063
|
+
// CHAT
|
|
969
1064
|
sendChatMessage(payload) {
|
|
970
1065
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
971
1066
|
console.warn("WS not connected");
|
|
@@ -998,11 +1093,13 @@ var VideoSDKCore = class {
|
|
|
998
1093
|
client_ts: Date.now()
|
|
999
1094
|
});
|
|
1000
1095
|
}
|
|
1001
|
-
|
|
1096
|
+
// DISCONNECT
|
|
1097
|
+
async disconnect() {
|
|
1002
1098
|
this.intentionalDisconnect = true;
|
|
1003
|
-
this.stopScreenShare();
|
|
1099
|
+
await this.stopScreenShare();
|
|
1004
1100
|
Object.values(this.peers).forEach((pc) => pc.close());
|
|
1005
1101
|
this.peers = {};
|
|
1102
|
+
this.peerTransceivers = {};
|
|
1006
1103
|
this.initiators.clear();
|
|
1007
1104
|
this.stopHeartbeat();
|
|
1008
1105
|
if (this.ws?.readyState === WebSocket.OPEN) {
|