@afosecure/meetingsdk 1.3.0 → 1.3.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.d.mts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +163 -59
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -59
- 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;
|
|
@@ -159,13 +159,32 @@ declare class VideoSDKCore {
|
|
|
159
159
|
private reset;
|
|
160
160
|
private handleJoinApproved;
|
|
161
161
|
private handle;
|
|
162
|
+
/**
|
|
163
|
+
* Create a peer connection with pre-established transceiver layout:
|
|
164
|
+
* - Audio transceiver (sendrecv)
|
|
165
|
+
* - Camera video transceiver (sendrecv)
|
|
166
|
+
* - Screen video transceiver (initially recvonly, becomes sendrecv when sharing)
|
|
167
|
+
*
|
|
168
|
+
* This fixed layout ensures late joiners get the screen transceiver m-line
|
|
169
|
+
* negotiated from the very first offer, even if no one is sharing yet.
|
|
170
|
+
*/
|
|
162
171
|
private createPeer;
|
|
172
|
+
/**
|
|
173
|
+
* Capture the screen transceiver's MID after SDP negotiation completes.
|
|
174
|
+
* The MID is assigned during negotiation and is stable for the life of the connection.
|
|
175
|
+
*/
|
|
176
|
+
private captureScreenMid;
|
|
163
177
|
private createOffer;
|
|
164
178
|
private shouldInitiate;
|
|
165
179
|
private handleOffer;
|
|
166
180
|
private closePeer;
|
|
181
|
+
/**
|
|
182
|
+
* Start screen sharing using replaceTrack on the pre-established screen transceiver.
|
|
183
|
+
* No need to add/remove tracks, no renegotiation needed (transceiver already in SDP).
|
|
184
|
+
* Just swap the track and update direction if needed.
|
|
185
|
+
*/
|
|
167
186
|
startScreenShare(): Promise<MediaStream>;
|
|
168
|
-
stopScreenShare(): void
|
|
187
|
+
stopScreenShare(): Promise<void>;
|
|
169
188
|
sendChatMessage(payload: ChatInput): void;
|
|
170
189
|
disconnect(): void;
|
|
171
190
|
private flushIce;
|
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;
|
|
@@ -159,13 +159,32 @@ declare class VideoSDKCore {
|
|
|
159
159
|
private reset;
|
|
160
160
|
private handleJoinApproved;
|
|
161
161
|
private handle;
|
|
162
|
+
/**
|
|
163
|
+
* Create a peer connection with pre-established transceiver layout:
|
|
164
|
+
* - Audio transceiver (sendrecv)
|
|
165
|
+
* - Camera video transceiver (sendrecv)
|
|
166
|
+
* - Screen video transceiver (initially recvonly, becomes sendrecv when sharing)
|
|
167
|
+
*
|
|
168
|
+
* This fixed layout ensures late joiners get the screen transceiver m-line
|
|
169
|
+
* negotiated from the very first offer, even if no one is sharing yet.
|
|
170
|
+
*/
|
|
162
171
|
private createPeer;
|
|
172
|
+
/**
|
|
173
|
+
* Capture the screen transceiver's MID after SDP negotiation completes.
|
|
174
|
+
* The MID is assigned during negotiation and is stable for the life of the connection.
|
|
175
|
+
*/
|
|
176
|
+
private captureScreenMid;
|
|
163
177
|
private createOffer;
|
|
164
178
|
private shouldInitiate;
|
|
165
179
|
private handleOffer;
|
|
166
180
|
private closePeer;
|
|
181
|
+
/**
|
|
182
|
+
* Start screen sharing using replaceTrack on the pre-established screen transceiver.
|
|
183
|
+
* No need to add/remove tracks, no renegotiation needed (transceiver already in SDP).
|
|
184
|
+
* Just swap the track and update direction if needed.
|
|
185
|
+
*/
|
|
167
186
|
startScreenShare(): Promise<MediaStream>;
|
|
168
|
-
stopScreenShare(): void
|
|
187
|
+
stopScreenShare(): Promise<void>;
|
|
169
188
|
sendChatMessage(payload: ChatInput): void;
|
|
170
189
|
disconnect(): void;
|
|
171
190
|
private flushIce;
|
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,17 @@ var VideoSDKCore = class {
|
|
|
685
684
|
}
|
|
686
685
|
}
|
|
687
686
|
}
|
|
688
|
-
//
|
|
689
|
-
|
|
687
|
+
// PEER
|
|
688
|
+
/**
|
|
689
|
+
* Create a peer connection with pre-established transceiver layout:
|
|
690
|
+
* - Audio transceiver (sendrecv)
|
|
691
|
+
* - Camera video transceiver (sendrecv)
|
|
692
|
+
* - Screen video transceiver (initially recvonly, becomes sendrecv when sharing)
|
|
693
|
+
*
|
|
694
|
+
* This fixed layout ensures late joiners get the screen transceiver m-line
|
|
695
|
+
* negotiated from the very first offer, even if no one is sharing yet.
|
|
696
|
+
*/
|
|
697
|
+
async createPeer(id) {
|
|
690
698
|
if (!this.localStream) throw new Error("No local stream");
|
|
691
699
|
if (!this.iceServers || this.iceServers.length === 0) {
|
|
692
700
|
throw new Error(
|
|
@@ -694,7 +702,9 @@ var VideoSDKCore = class {
|
|
|
694
702
|
);
|
|
695
703
|
}
|
|
696
704
|
console.log(
|
|
697
|
-
"
|
|
705
|
+
"Creating peer connection for",
|
|
706
|
+
id,
|
|
707
|
+
"with tracks:",
|
|
698
708
|
this.localStream.getTracks().map((t) => ({
|
|
699
709
|
kind: t.kind,
|
|
700
710
|
enabled: t.enabled,
|
|
@@ -704,20 +714,52 @@ var VideoSDKCore = class {
|
|
|
704
714
|
const pc = new RTCPeerConnection({
|
|
705
715
|
iceServers: this.iceServers
|
|
706
716
|
});
|
|
717
|
+
const audioTransceiver = pc.addTransceiver("audio", {
|
|
718
|
+
direction: "sendrecv"
|
|
719
|
+
});
|
|
720
|
+
const audioTrack = this.localStream.getAudioTracks()[0];
|
|
721
|
+
if (audioTrack) {
|
|
722
|
+
await audioTransceiver.sender.replaceTrack(audioTrack);
|
|
723
|
+
}
|
|
724
|
+
const cameraTransceiver = pc.addTransceiver("video", {
|
|
725
|
+
direction: "sendrecv"
|
|
726
|
+
});
|
|
727
|
+
const videoTrack = this.localStream.getVideoTracks()[0];
|
|
728
|
+
if (videoTrack) {
|
|
729
|
+
await cameraTransceiver.sender.replaceTrack(videoTrack);
|
|
730
|
+
}
|
|
731
|
+
const screenTransceiver = pc.addTransceiver("video", {
|
|
732
|
+
direction: this.isScreenSharing ? "sendrecv" : "recvonly"
|
|
733
|
+
});
|
|
734
|
+
if (this.isScreenSharing && this.screenStream) {
|
|
735
|
+
const screenTrack = this.screenStream.getVideoTracks()[0];
|
|
736
|
+
if (screenTrack) {
|
|
737
|
+
await screenTransceiver.sender.replaceTrack(screenTrack);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
this.peerTransceivers[id] = {
|
|
741
|
+
cameraTransceiver,
|
|
742
|
+
screenTransceiver,
|
|
743
|
+
screenMid: null
|
|
744
|
+
// will be populated after negotiation
|
|
745
|
+
};
|
|
707
746
|
pc.ontrack = (event) => {
|
|
747
|
+
const transceiver = event.transceiver;
|
|
748
|
+
const isScreenTrack = transceiver.mid === this.peerTransceivers[id]?.screenMid;
|
|
749
|
+
console.log(
|
|
750
|
+
`[ontrack] ${id}: kind=${event.track.kind}, mid=${transceiver.mid}, isScreen=${isScreenTrack}`
|
|
751
|
+
);
|
|
708
752
|
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
753
|
if (event.track.muted) {
|
|
712
754
|
event.track.onunmute = () => {
|
|
713
|
-
console.log(
|
|
755
|
+
console.log(`[ontrack] ${event.track.kind} track unmuted for ${id}`);
|
|
714
756
|
};
|
|
715
757
|
}
|
|
716
|
-
if (
|
|
717
|
-
const
|
|
758
|
+
if (isScreenTrack) {
|
|
759
|
+
const videoTrack2 = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0];
|
|
718
760
|
this.state.updateParticipantMedia(id, {
|
|
719
761
|
screenStream: incomingStream,
|
|
720
|
-
screenTrack:
|
|
762
|
+
screenTrack: videoTrack2,
|
|
721
763
|
isScreenSharing: true
|
|
722
764
|
});
|
|
723
765
|
if (!this.state.presenterId) {
|
|
@@ -743,29 +785,41 @@ var VideoSDKCore = class {
|
|
|
743
785
|
});
|
|
744
786
|
};
|
|
745
787
|
pc.oniceconnectionstatechange = () => {
|
|
746
|
-
console.log(`ICE Connection
|
|
788
|
+
console.log(`[ICE Connection] ${id}: ${pc.iceConnectionState}`);
|
|
747
789
|
};
|
|
748
790
|
pc.onconnectionstatechange = () => {
|
|
791
|
+
console.log(`[Connection] ${id}: ${pc.connectionState}`);
|
|
749
792
|
if (pc.connectionState === "failed") {
|
|
750
793
|
try {
|
|
751
794
|
pc.restartIce();
|
|
752
|
-
} catch {
|
|
795
|
+
} catch (e) {
|
|
796
|
+
console.warn("Failed to restart ICE:", e);
|
|
753
797
|
}
|
|
754
798
|
}
|
|
755
799
|
};
|
|
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
800
|
return pc;
|
|
767
801
|
}
|
|
768
|
-
|
|
802
|
+
/**
|
|
803
|
+
* Capture the screen transceiver's MID after SDP negotiation completes.
|
|
804
|
+
* The MID is assigned during negotiation and is stable for the life of the connection.
|
|
805
|
+
*/
|
|
806
|
+
captureScreenMid(peerId) {
|
|
807
|
+
const pc = this.peers[peerId];
|
|
808
|
+
if (!pc) return;
|
|
809
|
+
const transceivers = pc.getTransceivers();
|
|
810
|
+
const screenTransceiver = this.peerTransceivers[peerId]?.screenTransceiver;
|
|
811
|
+
if (!screenTransceiver) return;
|
|
812
|
+
const negotiatedTransceiver = transceivers.find(
|
|
813
|
+
(t) => t === screenTransceiver
|
|
814
|
+
);
|
|
815
|
+
if (negotiatedTransceiver?.mid) {
|
|
816
|
+
this.peerTransceivers[peerId].screenMid = negotiatedTransceiver.mid;
|
|
817
|
+
console.log(
|
|
818
|
+
`[Negotiation] Captured screenMid for ${peerId}: ${negotiatedTransceiver.mid}`
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
// OFFER
|
|
769
823
|
async createOffer(id, isRenegotiation = false) {
|
|
770
824
|
if (!isRenegotiation && !this.shouldInitiate(id)) {
|
|
771
825
|
console.debug(
|
|
@@ -783,12 +837,13 @@ var VideoSDKCore = class {
|
|
|
783
837
|
this.initiators.add(id);
|
|
784
838
|
}
|
|
785
839
|
if (!this.peers[id]) {
|
|
786
|
-
this.peers[id] = this.createPeer(id);
|
|
840
|
+
this.peers[id] = await this.createPeer(id);
|
|
787
841
|
}
|
|
788
842
|
const pc = this.peers[id];
|
|
789
843
|
try {
|
|
790
844
|
const offer = await pc.createOffer();
|
|
791
845
|
await pc.setLocalDescription(offer);
|
|
846
|
+
this.captureScreenMid(id);
|
|
792
847
|
this.send({
|
|
793
848
|
type: "OFFER",
|
|
794
849
|
payload: offer.sdp,
|
|
@@ -798,12 +853,18 @@ var VideoSDKCore = class {
|
|
|
798
853
|
console.debug(`[Offer] Sent to ${id}`);
|
|
799
854
|
} catch (err) {
|
|
800
855
|
console.error(`[Offer] Failed for ${id}:`, err);
|
|
856
|
+
this.emitError(
|
|
857
|
+
"OFFER_CREATION_FAILED",
|
|
858
|
+
`Failed to create offer for ${id}`,
|
|
859
|
+
err,
|
|
860
|
+
true
|
|
861
|
+
);
|
|
801
862
|
}
|
|
802
863
|
}
|
|
803
864
|
shouldInitiate(peerId) {
|
|
804
865
|
return this.myId < peerId;
|
|
805
866
|
}
|
|
806
|
-
//
|
|
867
|
+
// ANSWER
|
|
807
868
|
async handleOffer(sdp, id) {
|
|
808
869
|
if (!this.iceServers || this.iceServers.length === 0) {
|
|
809
870
|
console.warn("[Offer] Waiting for iceServers, queuing offer from", id);
|
|
@@ -811,7 +872,7 @@ var VideoSDKCore = class {
|
|
|
811
872
|
return;
|
|
812
873
|
}
|
|
813
874
|
if (!this.peers[id]) {
|
|
814
|
-
this.peers[id] = this.createPeer(id);
|
|
875
|
+
this.peers[id] = await this.createPeer(id);
|
|
815
876
|
}
|
|
816
877
|
const pc = this.peers[id];
|
|
817
878
|
try {
|
|
@@ -827,8 +888,9 @@ var VideoSDKCore = class {
|
|
|
827
888
|
);
|
|
828
889
|
pc.close();
|
|
829
890
|
delete this.peers[id];
|
|
891
|
+
delete this.peerTransceivers[id];
|
|
830
892
|
this.initiators.delete(id);
|
|
831
|
-
this.peers[id] = this.createPeer(id);
|
|
893
|
+
this.peers[id] = await this.createPeer(id);
|
|
832
894
|
}
|
|
833
895
|
}
|
|
834
896
|
if (this.peers[id].signalingState !== "stable" && this.peers[id].signalingState !== "have-local-offer") {
|
|
@@ -841,6 +903,7 @@ var VideoSDKCore = class {
|
|
|
841
903
|
type: "offer",
|
|
842
904
|
sdp
|
|
843
905
|
});
|
|
906
|
+
this.captureScreenMid(id);
|
|
844
907
|
const pending = this.pendingIceCandidates[id] || [];
|
|
845
908
|
for (const candidate of pending) {
|
|
846
909
|
try {
|
|
@@ -870,18 +933,26 @@ var VideoSDKCore = class {
|
|
|
870
933
|
);
|
|
871
934
|
}
|
|
872
935
|
}
|
|
873
|
-
//
|
|
936
|
+
// CLEANUP
|
|
874
937
|
closePeer(id) {
|
|
875
938
|
const pc = this.peers[id];
|
|
876
939
|
if (!pc) return;
|
|
877
940
|
pc.ontrack = null;
|
|
878
941
|
pc.onicecandidate = null;
|
|
879
942
|
pc.onconnectionstatechange = null;
|
|
943
|
+
pc.oniceconnectionstatechange = null;
|
|
880
944
|
pc.close();
|
|
881
945
|
delete this.peers[id];
|
|
946
|
+
delete this.peerTransceivers[id];
|
|
882
947
|
this.initiators.delete(id);
|
|
883
948
|
this.state.removeParticipant(id);
|
|
884
949
|
}
|
|
950
|
+
// SCREEN SHARE (TRANSCEIVER-BASED)
|
|
951
|
+
/**
|
|
952
|
+
* Start screen sharing using replaceTrack on the pre-established screen transceiver.
|
|
953
|
+
* No need to add/remove tracks, no renegotiation needed (transceiver already in SDP).
|
|
954
|
+
* Just swap the track and update direction if needed.
|
|
955
|
+
*/
|
|
885
956
|
async startScreenShare() {
|
|
886
957
|
try {
|
|
887
958
|
if (this.state.presenterId && this.state.presenterId !== this.myId) {
|
|
@@ -892,34 +963,55 @@ var VideoSDKCore = class {
|
|
|
892
963
|
}
|
|
893
964
|
this.screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
894
965
|
video: true
|
|
895
|
-
// audio: true,
|
|
896
966
|
});
|
|
967
|
+
const screenTrack = this.screenStream.getVideoTracks()[0];
|
|
968
|
+
if (!screenTrack) {
|
|
969
|
+
throw new Error("No video track in screen stream");
|
|
970
|
+
}
|
|
897
971
|
this.isScreenSharing = true;
|
|
898
972
|
this.state.updateLocalParticipant({
|
|
899
973
|
media: {
|
|
900
974
|
isScreenSharing: true,
|
|
901
975
|
screenStream: this.screenStream,
|
|
902
|
-
screenTrack
|
|
976
|
+
screenTrack
|
|
903
977
|
}
|
|
904
978
|
});
|
|
905
979
|
this.state.setPresenterId(this.myId);
|
|
906
|
-
|
|
980
|
+
screenTrack.onended = () => {
|
|
981
|
+
console.log("[Screen Share] User stopped via browser button");
|
|
907
982
|
this.stopScreenShare();
|
|
908
983
|
};
|
|
909
|
-
Object.entries(this.peers)
|
|
910
|
-
this.
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
984
|
+
for (const [peerId, pc] of Object.entries(this.peers)) {
|
|
985
|
+
const txInfo = this.peerTransceivers[peerId];
|
|
986
|
+
if (!txInfo) {
|
|
987
|
+
console.warn(
|
|
988
|
+
`[Screen Share] No transceiver info for ${peerId}, skipping`
|
|
989
|
+
);
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
try {
|
|
993
|
+
await txInfo.screenTransceiver.sender.replaceTrack(screenTrack);
|
|
994
|
+
if (txInfo.screenTransceiver.currentDirection === "recvonly") {
|
|
995
|
+
txInfo.screenTransceiver.direction = "sendrecv";
|
|
996
|
+
console.log(
|
|
997
|
+
`[Screen Share] Flipped ${peerId} screen transceiver to sendrecv`
|
|
998
|
+
);
|
|
999
|
+
await this.createOffer(peerId, true);
|
|
1000
|
+
}
|
|
1001
|
+
} catch (err) {
|
|
1002
|
+
console.error(
|
|
1003
|
+
`[Screen Share] Failed to update transceiver for ${peerId}:`,
|
|
1004
|
+
err
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
917
1008
|
this.send({
|
|
918
1009
|
type: "SCREEN_SHARE_START",
|
|
919
1010
|
sender: this.myId,
|
|
920
1011
|
room_id: this.room.id,
|
|
921
1012
|
stream_id: this.screenStream.id.replace(/[{}]/g, "")
|
|
922
1013
|
});
|
|
1014
|
+
console.log("[Screen Share] Started successfully");
|
|
923
1015
|
return this.screenStream;
|
|
924
1016
|
} catch (err) {
|
|
925
1017
|
this.emitError(
|
|
@@ -933,21 +1025,29 @@ var VideoSDKCore = class {
|
|
|
933
1025
|
throw err;
|
|
934
1026
|
}
|
|
935
1027
|
}
|
|
936
|
-
stopScreenShare() {
|
|
1028
|
+
async stopScreenShare() {
|
|
937
1029
|
if (!this.screenStream) return;
|
|
1030
|
+
console.log("[Screen Share] Stopping...");
|
|
938
1031
|
this.screenStream.getTracks().forEach((t) => t.stop());
|
|
939
|
-
Object.entries(this.peers)
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
1032
|
+
for (const [peerId, pc] of Object.entries(this.peers)) {
|
|
1033
|
+
const txInfo = this.peerTransceivers[peerId];
|
|
1034
|
+
if (!txInfo) continue;
|
|
1035
|
+
try {
|
|
1036
|
+
await txInfo.screenTransceiver.sender.replaceTrack(null);
|
|
1037
|
+
if (txInfo.screenTransceiver.currentDirection === "sendrecv") {
|
|
1038
|
+
txInfo.screenTransceiver.direction = "recvonly";
|
|
1039
|
+
console.log(
|
|
1040
|
+
`[Screen Share] Flipped ${peerId} screen transceiver to recvonly`
|
|
1041
|
+
);
|
|
1042
|
+
await this.createOffer(peerId, true);
|
|
946
1043
|
}
|
|
947
|
-
})
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
console.error(
|
|
1046
|
+
`[Screen Share] Failed to clear transceiver for ${peerId}:`,
|
|
1047
|
+
err
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
951
1051
|
this.screenStream = null;
|
|
952
1052
|
this.isScreenSharing = false;
|
|
953
1053
|
this.state.updateLocalParticipant({
|
|
@@ -965,7 +1065,9 @@ var VideoSDKCore = class {
|
|
|
965
1065
|
sender: this.myId,
|
|
966
1066
|
room_id: this.room.id
|
|
967
1067
|
});
|
|
1068
|
+
console.log("[Screen Share] Stopped");
|
|
968
1069
|
}
|
|
1070
|
+
// CHAT
|
|
969
1071
|
sendChatMessage(payload) {
|
|
970
1072
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
971
1073
|
console.warn("WS not connected");
|
|
@@ -998,11 +1100,13 @@ var VideoSDKCore = class {
|
|
|
998
1100
|
client_ts: Date.now()
|
|
999
1101
|
});
|
|
1000
1102
|
}
|
|
1103
|
+
// DISCONNECT
|
|
1001
1104
|
disconnect() {
|
|
1002
1105
|
this.intentionalDisconnect = true;
|
|
1003
1106
|
this.stopScreenShare();
|
|
1004
1107
|
Object.values(this.peers).forEach((pc) => pc.close());
|
|
1005
1108
|
this.peers = {};
|
|
1109
|
+
this.peerTransceivers = {};
|
|
1006
1110
|
this.initiators.clear();
|
|
1007
1111
|
this.stopHeartbeat();
|
|
1008
1112
|
if (this.ws?.readyState === WebSocket.OPEN) {
|