@afosecure/meetingsdk 1.3.2 → 1.3.4
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 +6 -16
- package/dist/index.d.ts +6 -16
- package/dist/index.js +81 -162
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -162
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -38,6 +38,8 @@ type ChatMessage = {
|
|
|
38
38
|
type Participant = {
|
|
39
39
|
id: string;
|
|
40
40
|
name?: string;
|
|
41
|
+
isHost?: boolean;
|
|
42
|
+
isLocal?: boolean;
|
|
41
43
|
media?: ParticipantMedia;
|
|
42
44
|
};
|
|
43
45
|
type ParticipantMedia = {
|
|
@@ -50,6 +52,7 @@ type ParticipantMedia = {
|
|
|
50
52
|
camEnabled: boolean;
|
|
51
53
|
isScreenSharing: boolean;
|
|
52
54
|
remoteScreenStreamId?: string;
|
|
55
|
+
cameraStreamId?: string;
|
|
53
56
|
};
|
|
54
57
|
type Listener = () => void;
|
|
55
58
|
type ChatInput = {
|
|
@@ -130,7 +133,7 @@ declare class VideoSDKCore {
|
|
|
130
133
|
private localStream;
|
|
131
134
|
private screenStream;
|
|
132
135
|
private isScreenSharing;
|
|
133
|
-
private
|
|
136
|
+
private screenSenders;
|
|
134
137
|
private pingInterval;
|
|
135
138
|
private pendingIceCandidates;
|
|
136
139
|
private pendingOffers;
|
|
@@ -160,27 +163,14 @@ declare class VideoSDKCore {
|
|
|
160
163
|
private handleJoinApproved;
|
|
161
164
|
private handle;
|
|
162
165
|
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
166
|
private createOffer;
|
|
169
167
|
private shouldInitiate;
|
|
170
168
|
private handleOffer;
|
|
171
169
|
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
170
|
startScreenShare(): Promise<MediaStream>;
|
|
178
|
-
|
|
179
|
-
* Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
|
|
180
|
-
*/
|
|
181
|
-
stopScreenShare(): Promise<void>;
|
|
171
|
+
stopScreenShare(): void;
|
|
182
172
|
sendChatMessage(payload: ChatInput): void;
|
|
183
|
-
disconnect():
|
|
173
|
+
disconnect(): void;
|
|
184
174
|
private flushIce;
|
|
185
175
|
private send;
|
|
186
176
|
approveJoinRequest(requestId: string): void;
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ type ChatMessage = {
|
|
|
38
38
|
type Participant = {
|
|
39
39
|
id: string;
|
|
40
40
|
name?: string;
|
|
41
|
+
isHost?: boolean;
|
|
42
|
+
isLocal?: boolean;
|
|
41
43
|
media?: ParticipantMedia;
|
|
42
44
|
};
|
|
43
45
|
type ParticipantMedia = {
|
|
@@ -50,6 +52,7 @@ type ParticipantMedia = {
|
|
|
50
52
|
camEnabled: boolean;
|
|
51
53
|
isScreenSharing: boolean;
|
|
52
54
|
remoteScreenStreamId?: string;
|
|
55
|
+
cameraStreamId?: string;
|
|
53
56
|
};
|
|
54
57
|
type Listener = () => void;
|
|
55
58
|
type ChatInput = {
|
|
@@ -130,7 +133,7 @@ declare class VideoSDKCore {
|
|
|
130
133
|
private localStream;
|
|
131
134
|
private screenStream;
|
|
132
135
|
private isScreenSharing;
|
|
133
|
-
private
|
|
136
|
+
private screenSenders;
|
|
134
137
|
private pingInterval;
|
|
135
138
|
private pendingIceCandidates;
|
|
136
139
|
private pendingOffers;
|
|
@@ -160,27 +163,14 @@ declare class VideoSDKCore {
|
|
|
160
163
|
private handleJoinApproved;
|
|
161
164
|
private handle;
|
|
162
165
|
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
166
|
private createOffer;
|
|
169
167
|
private shouldInitiate;
|
|
170
168
|
private handleOffer;
|
|
171
169
|
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
170
|
startScreenShare(): Promise<MediaStream>;
|
|
178
|
-
|
|
179
|
-
* Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
|
|
180
|
-
*/
|
|
181
|
-
stopScreenShare(): Promise<void>;
|
|
171
|
+
stopScreenShare(): void;
|
|
182
172
|
sendChatMessage(payload: ChatInput): void;
|
|
183
|
-
disconnect():
|
|
173
|
+
disconnect(): void;
|
|
184
174
|
private flushIce;
|
|
185
175
|
private send;
|
|
186
176
|
approveJoinRequest(requestId: string): void;
|
package/dist/index.js
CHANGED
|
@@ -101,9 +101,7 @@ var MeetingState = class {
|
|
|
101
101
|
camEnabled: true,
|
|
102
102
|
isScreenSharing: false,
|
|
103
103
|
...p.media,
|
|
104
|
-
// preserve existing media items if they happen to exist
|
|
105
104
|
...patch
|
|
106
|
-
// apply the incoming stream updates
|
|
107
105
|
}
|
|
108
106
|
};
|
|
109
107
|
const next = new Map(this.participants);
|
|
@@ -210,8 +208,7 @@ var VideoSDKCore = class {
|
|
|
210
208
|
this.localStream = null;
|
|
211
209
|
this.screenStream = null;
|
|
212
210
|
this.isScreenSharing = false;
|
|
213
|
-
|
|
214
|
-
this.peerTransceivers = {};
|
|
211
|
+
this.screenSenders = {};
|
|
215
212
|
this.pingInterval = null;
|
|
216
213
|
this.pendingIceCandidates = {};
|
|
217
214
|
this.pendingOffers = {};
|
|
@@ -240,7 +237,7 @@ var VideoSDKCore = class {
|
|
|
240
237
|
this.joinRejecter = void 0;
|
|
241
238
|
console.error("[MeetingSDK Error]", err);
|
|
242
239
|
}
|
|
243
|
-
// STREAM
|
|
240
|
+
// ---------------- STREAM ----------------
|
|
244
241
|
async initLocal(video, name) {
|
|
245
242
|
this.participantName = name;
|
|
246
243
|
try {
|
|
@@ -277,7 +274,7 @@ var VideoSDKCore = class {
|
|
|
277
274
|
throw err;
|
|
278
275
|
}
|
|
279
276
|
}
|
|
280
|
-
// CONNECT
|
|
277
|
+
// ---------------- CONNECT ----------------
|
|
281
278
|
async connect(roomId, name) {
|
|
282
279
|
this.room.id = roomId;
|
|
283
280
|
this.reset();
|
|
@@ -291,7 +288,8 @@ var VideoSDKCore = class {
|
|
|
291
288
|
type: "JOIN",
|
|
292
289
|
room_id: roomId,
|
|
293
290
|
user_id: this.myId,
|
|
294
|
-
sender_name: name
|
|
291
|
+
sender_name: name,
|
|
292
|
+
camera_stream_id: this.localStream?.id.replace(/[{}]/g, "")
|
|
295
293
|
});
|
|
296
294
|
};
|
|
297
295
|
this.ws.onerror = (err) => {
|
|
@@ -423,11 +421,10 @@ var VideoSDKCore = class {
|
|
|
423
421
|
this.pingInterval = null;
|
|
424
422
|
}
|
|
425
423
|
}
|
|
426
|
-
// RESET
|
|
424
|
+
// ---------------- RESET ----------------
|
|
427
425
|
reset() {
|
|
428
426
|
Object.values(this.peers).forEach((pc) => pc.close());
|
|
429
427
|
this.peers = {};
|
|
430
|
-
this.peerTransceivers = {};
|
|
431
428
|
this.initiators.clear();
|
|
432
429
|
this.pendingIceCandidates = {};
|
|
433
430
|
this.state.resetRemoteState();
|
|
@@ -482,7 +479,6 @@ var VideoSDKCore = class {
|
|
|
482
479
|
type: "answer",
|
|
483
480
|
sdp: msg.payload
|
|
484
481
|
});
|
|
485
|
-
this.captureScreenMid(msg.sender);
|
|
486
482
|
await this.flushIce(msg.sender, pc);
|
|
487
483
|
} catch (err) {
|
|
488
484
|
console.error("[Signaling] Failed to apply answer:", err);
|
|
@@ -519,6 +515,7 @@ var VideoSDKCore = class {
|
|
|
519
515
|
if (msg.presenterId) {
|
|
520
516
|
this.state.setPresenterId(msg.presenterId);
|
|
521
517
|
this.events.onScreenShareStarted?.(msg.presenterId, null);
|
|
518
|
+
this.state.setPresenterId(msg.presenterId);
|
|
522
519
|
}
|
|
523
520
|
for (const p of msg.participants || []) {
|
|
524
521
|
if (!p?.id || p.id === this.myId) continue;
|
|
@@ -531,7 +528,8 @@ var VideoSDKCore = class {
|
|
|
531
528
|
this.state.setPresenterId(p.id);
|
|
532
529
|
this.state.updateParticipantMedia(p.id, {
|
|
533
530
|
isScreenSharing: true,
|
|
534
|
-
remoteScreenStreamId: p.remoteScreenStreamId
|
|
531
|
+
remoteScreenStreamId: p.remoteScreenStreamId,
|
|
532
|
+
cameraStreamId: p.cameraStreamId || null
|
|
535
533
|
});
|
|
536
534
|
console.log(
|
|
537
535
|
`[EXISTING_USERS] Pre-seeded screen state for ${p.id}, waiting for ontrack`
|
|
@@ -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");
|
|
@@ -652,12 +652,14 @@ var VideoSDKCore = class {
|
|
|
652
652
|
const peerId2 = msg.peerId;
|
|
653
653
|
this.state.updateParticipantMedia(peerId2, {
|
|
654
654
|
isScreenSharing: true,
|
|
655
|
-
remoteScreenStreamId: msg.stream_id
|
|
655
|
+
remoteScreenStreamId: msg.stream_id,
|
|
656
|
+
cameraStreamId: msg.camera_stream_id || null
|
|
656
657
|
});
|
|
657
658
|
if (!this.state.presenterId) {
|
|
658
659
|
this.state.setPresenterId(peerId2);
|
|
659
660
|
}
|
|
660
|
-
this.
|
|
661
|
+
const screenStream = this.state.getParticipant(peerId2)?.media?.screenStream;
|
|
662
|
+
this.events.onScreenShareStarted?.(peerId2, screenStream || null);
|
|
661
663
|
break;
|
|
662
664
|
}
|
|
663
665
|
case "SCREEN_SHARE_STOP": {
|
|
@@ -684,7 +686,8 @@ var VideoSDKCore = class {
|
|
|
684
686
|
}
|
|
685
687
|
}
|
|
686
688
|
}
|
|
687
|
-
|
|
689
|
+
// ---------------- PEER ----------------
|
|
690
|
+
createPeer(id) {
|
|
688
691
|
if (!this.localStream) throw new Error("No local stream");
|
|
689
692
|
if (!this.iceServers || this.iceServers.length === 0) {
|
|
690
693
|
throw new Error(
|
|
@@ -692,9 +695,7 @@ var VideoSDKCore = class {
|
|
|
692
695
|
);
|
|
693
696
|
}
|
|
694
697
|
console.log(
|
|
695
|
-
"
|
|
696
|
-
id,
|
|
697
|
-
"with tracks:",
|
|
698
|
+
"Adding tracks",
|
|
698
699
|
this.localStream.getTracks().map((t) => ({
|
|
699
700
|
kind: t.kind,
|
|
700
701
|
enabled: t.enabled,
|
|
@@ -704,58 +705,40 @@ var VideoSDKCore = class {
|
|
|
704
705
|
const pc = new RTCPeerConnection({
|
|
705
706
|
iceServers: this.iceServers
|
|
706
707
|
});
|
|
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
708
|
pc.ontrack = (event) => {
|
|
737
|
-
|
|
738
|
-
|
|
709
|
+
console.log("ontrack");
|
|
710
|
+
console.log("kind:", event.track.kind);
|
|
711
|
+
console.log("mid:", event.transceiver.mid);
|
|
712
|
+
console.log("streams:", event.streams);
|
|
713
|
+
const incomingStream = event.streams?.[0] || new MediaStream([event.track]);
|
|
714
|
+
const streamId = incomingStream?.id;
|
|
715
|
+
const participant = this.state.getParticipant(id);
|
|
716
|
+
const isScreenStream = streamId && (streamId === participant?.media?.remoteScreenStreamId || participant?.media?.isScreenSharing && streamId !== participant?.media?.stream?.id && event.track.kind === "video");
|
|
739
717
|
console.log(
|
|
740
|
-
`[ontrack] ${id}:
|
|
718
|
+
`[ontrack] peerId: ${id}, streamId: ${streamId}, isScreen: ${isScreenStream}`
|
|
719
|
+
);
|
|
720
|
+
console.log(` - cameraStreamId: ${participant?.media?.cameraStreamId}`);
|
|
721
|
+
console.log(
|
|
722
|
+
` - screenStreamId: ${participant?.media?.remoteScreenStreamId}`
|
|
741
723
|
);
|
|
742
|
-
const incomingStream = event.streams?.[0] || new MediaStream([event.track]);
|
|
743
724
|
if (event.track.muted) {
|
|
744
725
|
event.track.onunmute = () => {
|
|
745
|
-
console.log(
|
|
726
|
+
console.log(`${event.track.kind} track unmuted for ${id}`);
|
|
746
727
|
};
|
|
747
728
|
}
|
|
748
|
-
if (
|
|
749
|
-
const
|
|
729
|
+
if (isScreenStream) {
|
|
730
|
+
const videoTrack = event.track.kind === "video" ? event.track : incomingStream.getVideoTracks()[0] || participant?.media?.screenTrack;
|
|
750
731
|
this.state.updateParticipantMedia(id, {
|
|
751
732
|
screenStream: incomingStream,
|
|
752
|
-
screenTrack:
|
|
733
|
+
screenTrack: videoTrack,
|
|
734
|
+
remoteScreenStreamId: incomingStream.id,
|
|
753
735
|
isScreenSharing: true
|
|
754
736
|
});
|
|
755
737
|
if (!this.state.presenterId) {
|
|
756
738
|
this.state.setPresenterId(id);
|
|
757
739
|
}
|
|
758
740
|
this.events.onScreenShareStarted?.(id, incomingStream);
|
|
741
|
+
console.log(`Screen share stream detected and stored for ${id}`);
|
|
759
742
|
} else {
|
|
760
743
|
this.state.updateParticipantMedia(id, {
|
|
761
744
|
stream: incomingStream,
|
|
@@ -775,41 +758,29 @@ var VideoSDKCore = class {
|
|
|
775
758
|
});
|
|
776
759
|
};
|
|
777
760
|
pc.oniceconnectionstatechange = () => {
|
|
778
|
-
console.log(`
|
|
761
|
+
console.log(`ICE Connection State: ${pc.iceConnectionState}`);
|
|
779
762
|
};
|
|
780
763
|
pc.onconnectionstatechange = () => {
|
|
781
|
-
console.log(`[Connection] ${id}: ${pc.connectionState}`);
|
|
782
764
|
if (pc.connectionState === "failed") {
|
|
783
765
|
try {
|
|
784
766
|
pc.restartIce();
|
|
785
|
-
} catch
|
|
786
|
-
console.warn("Failed to restart ICE:", e);
|
|
767
|
+
} catch {
|
|
787
768
|
}
|
|
788
769
|
}
|
|
789
770
|
};
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
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
|
-
);
|
|
771
|
+
this.localStream.getTracks().forEach((track) => {
|
|
772
|
+
pc.addTrack(track, this.localStream);
|
|
773
|
+
});
|
|
774
|
+
if (this.isScreenSharing && this.screenStream) {
|
|
775
|
+
this.screenSenders[id] = [];
|
|
776
|
+
this.screenStream.getTracks().forEach((track) => {
|
|
777
|
+
const sender = pc.addTrack(track, this.screenStream);
|
|
778
|
+
this.screenSenders[id].push(sender);
|
|
779
|
+
});
|
|
810
780
|
}
|
|
781
|
+
return pc;
|
|
811
782
|
}
|
|
812
|
-
// OFFER
|
|
783
|
+
// ---------------- OFFER ----------------
|
|
813
784
|
async createOffer(id, isRenegotiation = false) {
|
|
814
785
|
if (!isRenegotiation && !this.shouldInitiate(id)) {
|
|
815
786
|
console.debug(
|
|
@@ -827,13 +798,12 @@ var VideoSDKCore = class {
|
|
|
827
798
|
this.initiators.add(id);
|
|
828
799
|
}
|
|
829
800
|
if (!this.peers[id]) {
|
|
830
|
-
this.peers[id] =
|
|
801
|
+
this.peers[id] = this.createPeer(id);
|
|
831
802
|
}
|
|
832
803
|
const pc = this.peers[id];
|
|
833
804
|
try {
|
|
834
805
|
const offer = await pc.createOffer();
|
|
835
806
|
await pc.setLocalDescription(offer);
|
|
836
|
-
this.captureScreenMid(id);
|
|
837
807
|
this.send({
|
|
838
808
|
type: "OFFER",
|
|
839
809
|
payload: offer.sdp,
|
|
@@ -843,18 +813,12 @@ var VideoSDKCore = class {
|
|
|
843
813
|
console.debug(`[Offer] Sent to ${id}`);
|
|
844
814
|
} catch (err) {
|
|
845
815
|
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
816
|
}
|
|
853
817
|
}
|
|
854
818
|
shouldInitiate(peerId) {
|
|
855
819
|
return this.myId < peerId;
|
|
856
820
|
}
|
|
857
|
-
// ANSWER
|
|
821
|
+
// ---------------- ANSWER ----------------
|
|
858
822
|
async handleOffer(sdp, id) {
|
|
859
823
|
if (!this.iceServers || this.iceServers.length === 0) {
|
|
860
824
|
console.warn("[Offer] Waiting for iceServers, queuing offer from", id);
|
|
@@ -862,7 +826,7 @@ var VideoSDKCore = class {
|
|
|
862
826
|
return;
|
|
863
827
|
}
|
|
864
828
|
if (!this.peers[id]) {
|
|
865
|
-
this.peers[id] =
|
|
829
|
+
this.peers[id] = this.createPeer(id);
|
|
866
830
|
}
|
|
867
831
|
const pc = this.peers[id];
|
|
868
832
|
try {
|
|
@@ -878,9 +842,8 @@ var VideoSDKCore = class {
|
|
|
878
842
|
);
|
|
879
843
|
pc.close();
|
|
880
844
|
delete this.peers[id];
|
|
881
|
-
delete this.peerTransceivers[id];
|
|
882
845
|
this.initiators.delete(id);
|
|
883
|
-
this.peers[id] =
|
|
846
|
+
this.peers[id] = this.createPeer(id);
|
|
884
847
|
}
|
|
885
848
|
}
|
|
886
849
|
if (this.peers[id].signalingState !== "stable" && this.peers[id].signalingState !== "have-local-offer") {
|
|
@@ -893,7 +856,6 @@ var VideoSDKCore = class {
|
|
|
893
856
|
type: "offer",
|
|
894
857
|
sdp
|
|
895
858
|
});
|
|
896
|
-
this.captureScreenMid(id);
|
|
897
859
|
const pending = this.pendingIceCandidates[id] || [];
|
|
898
860
|
for (const candidate of pending) {
|
|
899
861
|
try {
|
|
@@ -923,26 +885,18 @@ var VideoSDKCore = class {
|
|
|
923
885
|
);
|
|
924
886
|
}
|
|
925
887
|
}
|
|
926
|
-
// CLEANUP
|
|
888
|
+
// ---------------- CLEANUP ----------------
|
|
927
889
|
closePeer(id) {
|
|
928
890
|
const pc = this.peers[id];
|
|
929
891
|
if (!pc) return;
|
|
930
892
|
pc.ontrack = null;
|
|
931
893
|
pc.onicecandidate = null;
|
|
932
894
|
pc.onconnectionstatechange = null;
|
|
933
|
-
pc.oniceconnectionstatechange = null;
|
|
934
895
|
pc.close();
|
|
935
896
|
delete this.peers[id];
|
|
936
|
-
delete this.peerTransceivers[id];
|
|
937
897
|
this.initiators.delete(id);
|
|
938
898
|
this.state.removeParticipant(id);
|
|
939
899
|
}
|
|
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
900
|
async startScreenShare() {
|
|
947
901
|
try {
|
|
948
902
|
if (this.state.presenterId && this.state.presenterId !== this.myId) {
|
|
@@ -953,55 +907,35 @@ var VideoSDKCore = class {
|
|
|
953
907
|
}
|
|
954
908
|
this.screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
955
909
|
video: true
|
|
910
|
+
// audio: true,
|
|
956
911
|
});
|
|
957
|
-
const screenTrack = this.screenStream.getVideoTracks()[0];
|
|
958
|
-
if (!screenTrack) {
|
|
959
|
-
throw new Error("No video track in screen stream");
|
|
960
|
-
}
|
|
961
912
|
this.isScreenSharing = true;
|
|
962
913
|
this.state.updateLocalParticipant({
|
|
963
914
|
media: {
|
|
964
915
|
isScreenSharing: true,
|
|
965
916
|
screenStream: this.screenStream,
|
|
966
|
-
screenTrack
|
|
917
|
+
screenTrack: this.screenStream.getVideoTracks()[0]
|
|
967
918
|
}
|
|
968
919
|
});
|
|
969
920
|
this.state.setPresenterId(this.myId);
|
|
970
|
-
|
|
971
|
-
console.log("[Screen Share] User stopped via browser button");
|
|
921
|
+
this.screenStream.getVideoTracks()[0].onended = () => {
|
|
972
922
|
this.stopScreenShare();
|
|
973
923
|
};
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
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
|
-
}
|
|
924
|
+
Object.entries(this.peers).forEach(([peerId, pc]) => {
|
|
925
|
+
this.screenSenders[peerId] = [];
|
|
926
|
+
this.screenStream.getTracks().forEach((track) => {
|
|
927
|
+
const sender = pc.addTrack(track, this.screenStream);
|
|
928
|
+
this.screenSenders[peerId].push(sender);
|
|
929
|
+
});
|
|
930
|
+
this.createOffer(peerId, true);
|
|
931
|
+
});
|
|
998
932
|
this.send({
|
|
999
933
|
type: "SCREEN_SHARE_START",
|
|
1000
934
|
sender: this.myId,
|
|
1001
935
|
room_id: this.room.id,
|
|
936
|
+
camera_id: this.localStream?.id.replace(/[{}]/g, ""),
|
|
1002
937
|
stream_id: this.screenStream.id.replace(/[{}]/g, "")
|
|
1003
938
|
});
|
|
1004
|
-
console.log("[Screen Share] Started successfully");
|
|
1005
939
|
return this.screenStream;
|
|
1006
940
|
} catch (err) {
|
|
1007
941
|
this.emitError(
|
|
@@ -1015,32 +949,21 @@ var VideoSDKCore = class {
|
|
|
1015
949
|
throw err;
|
|
1016
950
|
}
|
|
1017
951
|
}
|
|
1018
|
-
|
|
1019
|
-
* Stop screen sharing: clear the screen transceiver track and flip direction back to recvonly.
|
|
1020
|
-
*/
|
|
1021
|
-
async stopScreenShare() {
|
|
952
|
+
stopScreenShare() {
|
|
1022
953
|
if (!this.screenStream) return;
|
|
1023
|
-
console.log("[Screen Share] Stopping...");
|
|
1024
954
|
this.screenStream.getTracks().forEach((t) => t.stop());
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
console.log(
|
|
1033
|
-
`[Screen Share] Flipped ${peerId} screen transceiver to recvonly`
|
|
1034
|
-
);
|
|
1035
|
-
await this.createOffer(peerId, true);
|
|
955
|
+
Object.entries(this.peers).forEach(([peerId, pc]) => {
|
|
956
|
+
const senders = this.screenSenders[peerId] || [];
|
|
957
|
+
senders.forEach((sender) => {
|
|
958
|
+
try {
|
|
959
|
+
pc.removeTrack(sender);
|
|
960
|
+
} catch (err) {
|
|
961
|
+
console.warn(err);
|
|
1036
962
|
}
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
);
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
963
|
+
});
|
|
964
|
+
delete this.screenSenders[peerId];
|
|
965
|
+
this.createOffer(peerId, true);
|
|
966
|
+
});
|
|
1044
967
|
this.screenStream = null;
|
|
1045
968
|
this.isScreenSharing = false;
|
|
1046
969
|
this.state.updateLocalParticipant({
|
|
@@ -1058,9 +981,7 @@ var VideoSDKCore = class {
|
|
|
1058
981
|
sender: this.myId,
|
|
1059
982
|
room_id: this.room.id
|
|
1060
983
|
});
|
|
1061
|
-
console.log("[Screen Share] Stopped");
|
|
1062
984
|
}
|
|
1063
|
-
// CHAT
|
|
1064
985
|
sendChatMessage(payload) {
|
|
1065
986
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
1066
987
|
console.warn("WS not connected");
|
|
@@ -1093,13 +1014,11 @@ var VideoSDKCore = class {
|
|
|
1093
1014
|
client_ts: Date.now()
|
|
1094
1015
|
});
|
|
1095
1016
|
}
|
|
1096
|
-
|
|
1097
|
-
async disconnect() {
|
|
1017
|
+
disconnect() {
|
|
1098
1018
|
this.intentionalDisconnect = true;
|
|
1099
|
-
|
|
1019
|
+
this.stopScreenShare();
|
|
1100
1020
|
Object.values(this.peers).forEach((pc) => pc.close());
|
|
1101
1021
|
this.peers = {};
|
|
1102
|
-
this.peerTransceivers = {};
|
|
1103
1022
|
this.initiators.clear();
|
|
1104
1023
|
this.stopHeartbeat();
|
|
1105
1024
|
if (this.ws?.readyState === WebSocket.OPEN) {
|