@defcomm/meetingsdk 0.2.3 → 0.2.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 +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +151 -78
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +151 -78
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -349,6 +349,9 @@ var SFUClient = class {
|
|
|
349
349
|
this.localStream = null;
|
|
350
350
|
this.screenStream = null;
|
|
351
351
|
this.videoSender = null;
|
|
352
|
+
this.audioMuted = false;
|
|
353
|
+
this.videoMuted = false;
|
|
354
|
+
this.activeRecording = null;
|
|
352
355
|
this.audioSender = null;
|
|
353
356
|
this.screenSender = null;
|
|
354
357
|
this.audioTransceiver = null;
|
|
@@ -369,7 +372,7 @@ var SFUClient = class {
|
|
|
369
372
|
this.joiningWithResume = false;
|
|
370
373
|
this.reconnectTimer = null;
|
|
371
374
|
this.reconnectAttempt = 0;
|
|
372
|
-
this.maxReconnectAttempts =
|
|
375
|
+
this.maxReconnectAttempts = 6;
|
|
373
376
|
this.reconnectBaseMs = 750;
|
|
374
377
|
this.joinWaiter = null;
|
|
375
378
|
this.transportRecoveryInProgress = false;
|
|
@@ -432,6 +435,8 @@ var SFUClient = class {
|
|
|
432
435
|
});
|
|
433
436
|
this.onTrackStateChanged = options.onTrackStateChanged || (() => {
|
|
434
437
|
});
|
|
438
|
+
this.onParticipantMediaState = options.onParticipantMediaState || (() => {
|
|
439
|
+
});
|
|
435
440
|
this.onRecordingStarted = options.onRecordingStarted || (() => {
|
|
436
441
|
});
|
|
437
442
|
this.onRecordingStopped = options.onRecordingStopped || (() => {
|
|
@@ -579,9 +584,13 @@ var SFUClient = class {
|
|
|
579
584
|
this.resumeToken = null;
|
|
580
585
|
}
|
|
581
586
|
this.room = nextRoom;
|
|
587
|
+
this.audioMuted = Boolean(options.audioMuted);
|
|
588
|
+
this.videoMuted = Boolean(options.videoMuted);
|
|
582
589
|
this.joinOptions = {
|
|
583
590
|
displayName: options.displayName,
|
|
584
|
-
avatarUrl: options.avatarUrl
|
|
591
|
+
avatarUrl: options.avatarUrl,
|
|
592
|
+
audioMuted: this.audioMuted,
|
|
593
|
+
videoMuted: this.videoMuted
|
|
585
594
|
};
|
|
586
595
|
if (options.participantId) this.participantId = options.participantId;
|
|
587
596
|
if (!this.resumeToken) {
|
|
@@ -650,7 +659,9 @@ var SFUClient = class {
|
|
|
650
659
|
room_code: this.room,
|
|
651
660
|
resume_token: this.resumeToken,
|
|
652
661
|
display_name: options.displayName,
|
|
653
|
-
avatar_url: options.avatarUrl
|
|
662
|
+
avatar_url: options.avatarUrl,
|
|
663
|
+
audio_muted: this.audioMuted,
|
|
664
|
+
video_muted: this.videoMuted
|
|
654
665
|
};
|
|
655
666
|
if (this.pendingJoinRequestId) {
|
|
656
667
|
this.send({
|
|
@@ -691,8 +702,20 @@ var SFUClient = class {
|
|
|
691
702
|
scheduleReconnect() {
|
|
692
703
|
if (this.reconnectTimer || this.intentionalClose) return;
|
|
693
704
|
if (this.reconnectAttempt >= this.maxReconnectAttempts) {
|
|
705
|
+
const error = new Error("SFU reconnect attempts exhausted");
|
|
706
|
+
console.error("[SFU] Reconnect attempts exhausted; leaving meeting", error);
|
|
707
|
+
this.intentionalClose = true;
|
|
708
|
+
this.stopHeartbeat();
|
|
709
|
+
this.stopRoomStateSync();
|
|
710
|
+
this.cleanupAll();
|
|
694
711
|
this.setState("disconnected");
|
|
695
|
-
this.
|
|
712
|
+
this.onError({
|
|
713
|
+
code: "RECONNECT_TIMEOUT",
|
|
714
|
+
message: error.message,
|
|
715
|
+
recoverable: false
|
|
716
|
+
});
|
|
717
|
+
this.onDisconnected();
|
|
718
|
+
this.failJoin(error);
|
|
696
719
|
return;
|
|
697
720
|
}
|
|
698
721
|
this.reconnectAttempt += 1;
|
|
@@ -764,7 +787,9 @@ var SFUClient = class {
|
|
|
764
787
|
room_code: this.room,
|
|
765
788
|
resume_token: this.resumeToken,
|
|
766
789
|
display_name: this.joinOptions.displayName,
|
|
767
|
-
avatar_url: this.joinOptions.avatarUrl
|
|
790
|
+
avatar_url: this.joinOptions.avatarUrl,
|
|
791
|
+
audio_muted: this.audioMuted,
|
|
792
|
+
video_muted: this.videoMuted
|
|
768
793
|
}
|
|
769
794
|
});
|
|
770
795
|
}
|
|
@@ -839,22 +864,8 @@ var SFUClient = class {
|
|
|
839
864
|
if (!track?.track_id) break;
|
|
840
865
|
this.rememberTrack(track);
|
|
841
866
|
if (track.participant_id === this.currentParticipantId) {
|
|
842
|
-
if (track.source === "audio")
|
|
843
|
-
|
|
844
|
-
const muted = !(this.localStream?.getAudioTracks()[0]?.enabled ?? true);
|
|
845
|
-
this.send({
|
|
846
|
-
type: "track_state",
|
|
847
|
-
payload: { track_id: track.track_id, muted }
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
if (track.source === "camera") {
|
|
851
|
-
this.localTrackIds.set("camera", track.track_id);
|
|
852
|
-
const muted = !(this.localStream?.getVideoTracks()[0]?.enabled ?? true);
|
|
853
|
-
this.send({
|
|
854
|
-
type: "track_state",
|
|
855
|
-
payload: { track_id: track.track_id, muted }
|
|
856
|
-
});
|
|
857
|
-
}
|
|
867
|
+
if (track.source === "audio") this.localTrackIds.set("audio", track.track_id);
|
|
868
|
+
if (track.source === "camera") this.localTrackIds.set("camera", track.track_id);
|
|
858
869
|
if (track.source === "screen")
|
|
859
870
|
this.localTrackIds.set("screen", track.track_id);
|
|
860
871
|
break;
|
|
@@ -883,6 +894,27 @@ var SFUClient = class {
|
|
|
883
894
|
this.onTrackUnpublished(track);
|
|
884
895
|
break;
|
|
885
896
|
}
|
|
897
|
+
case "participant_media_state": {
|
|
898
|
+
const participantId = payload.participant_id;
|
|
899
|
+
if (!participantId) break;
|
|
900
|
+
const participant = this.participants.get(participantId);
|
|
901
|
+
if (participant) {
|
|
902
|
+
participant.audio_muted = Boolean(payload.audio_muted);
|
|
903
|
+
participant.video_muted = Boolean(payload.video_muted);
|
|
904
|
+
this.participants.set(participantId, participant);
|
|
905
|
+
}
|
|
906
|
+
for (const track of this.trackMetadata.values()) {
|
|
907
|
+
if (track.participant_id !== participantId) continue;
|
|
908
|
+
if (track.source === "audio") track.muted = Boolean(payload.audio_muted);
|
|
909
|
+
if (track.source === "camera") track.muted = Boolean(payload.video_muted);
|
|
910
|
+
}
|
|
911
|
+
this.onParticipantMediaState(
|
|
912
|
+
participantId,
|
|
913
|
+
Boolean(payload.audio_muted),
|
|
914
|
+
Boolean(payload.video_muted)
|
|
915
|
+
);
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
886
918
|
case "track_state_changed": {
|
|
887
919
|
const trackId = payload.track_id || payload.track?.track_id;
|
|
888
920
|
if (!trackId) break;
|
|
@@ -909,13 +941,15 @@ var SFUClient = class {
|
|
|
909
941
|
break;
|
|
910
942
|
}
|
|
911
943
|
case "recording_started": {
|
|
912
|
-
this.
|
|
944
|
+
this.activeRecording = {
|
|
913
945
|
recording_id: payload.recording_id,
|
|
914
946
|
started_at: payload.started_at
|
|
915
|
-
}
|
|
947
|
+
};
|
|
948
|
+
this.onRecordingStarted(this.activeRecording);
|
|
916
949
|
break;
|
|
917
950
|
}
|
|
918
951
|
case "recording_stopped": {
|
|
952
|
+
this.activeRecording = null;
|
|
919
953
|
this.onRecordingStopped({
|
|
920
954
|
recording_id: payload.recording_id,
|
|
921
955
|
stopped_at: payload.stopped_at
|
|
@@ -974,68 +1008,63 @@ var SFUClient = class {
|
|
|
974
1008
|
}
|
|
975
1009
|
}
|
|
976
1010
|
async applyRoomState(payload) {
|
|
977
|
-
const
|
|
978
|
-
for (const participant of payload
|
|
979
|
-
|
|
980
|
-
if (!id) continue;
|
|
981
|
-
nextParticipants.set(id, participant);
|
|
1011
|
+
const authoritative = /* @__PURE__ */ new Map();
|
|
1012
|
+
for (const participant of payload?.participants || []) {
|
|
1013
|
+
if (participant?.participant_id) authoritative.set(participant.participant_id, participant);
|
|
982
1014
|
}
|
|
983
|
-
for (const
|
|
984
|
-
if (id
|
|
985
|
-
if (!nextParticipants.has(id)) {
|
|
1015
|
+
for (const id of [...this.participants.keys()]) {
|
|
1016
|
+
if (!authoritative.has(id) && id !== this.currentParticipantId) {
|
|
986
1017
|
this.participants.delete(id);
|
|
987
1018
|
this.removeRemoteParticipant(id);
|
|
988
1019
|
this.onParticipantLeft(id);
|
|
989
1020
|
}
|
|
990
1021
|
}
|
|
991
|
-
for (const [id, participant] of
|
|
1022
|
+
for (const [id, participant] of authoritative) {
|
|
992
1023
|
if (id === this.currentParticipantId) continue;
|
|
993
|
-
const
|
|
994
|
-
this.participants.set(id,
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
if (
|
|
1001
|
-
|
|
1002
|
-
(candidate) => String(candidate.track_id) === screenTrackId
|
|
1003
|
-
) : void 0;
|
|
1004
|
-
this.onScreenShareStarted(id, track);
|
|
1005
|
-
} else if (this.remoteScreenStreams.has(id)) {
|
|
1006
|
-
this.remoteScreenStreams.get(id)?.getTracks().forEach((track) => track.stop());
|
|
1007
|
-
this.remoteScreenStreams.delete(id);
|
|
1008
|
-
this.onScreenShareStopped(id, screenTrackId);
|
|
1009
|
-
}
|
|
1024
|
+
const previous = this.participants.get(id);
|
|
1025
|
+
this.participants.set(id, {
|
|
1026
|
+
...previous,
|
|
1027
|
+
...participant,
|
|
1028
|
+
audio_muted: Boolean(participant.audio_muted),
|
|
1029
|
+
video_muted: Boolean(participant.video_muted)
|
|
1030
|
+
});
|
|
1031
|
+
if (!previous) this.onParticipantJoined(participant);
|
|
1032
|
+
if (participant.presence) this.onParticipantPresence(id, String(participant.presence));
|
|
1010
1033
|
}
|
|
1011
1034
|
const nextTracks = /* @__PURE__ */ new Map();
|
|
1012
|
-
for (const track of payload
|
|
1013
|
-
if (track?.track_id)
|
|
1035
|
+
for (const track of payload?.tracks || []) {
|
|
1036
|
+
if (!track?.track_id) continue;
|
|
1037
|
+
nextTracks.set(track.track_id, track);
|
|
1038
|
+
this.rememberTrack(track);
|
|
1014
1039
|
}
|
|
1015
|
-
for (const
|
|
1016
|
-
if (!nextTracks.has(
|
|
1017
|
-
this.trackMetadata.delete(
|
|
1018
|
-
this.
|
|
1019
|
-
this.
|
|
1020
|
-
this.
|
|
1021
|
-
for (const [source, localId] of this.localTrackIds) {
|
|
1022
|
-
if (localId === trackId) this.localTrackIds.delete(source);
|
|
1023
|
-
}
|
|
1024
|
-
if (existing.participant_id !== this.currentParticipantId) {
|
|
1025
|
-
this.onTrackUnpublished(existing);
|
|
1026
|
-
}
|
|
1040
|
+
for (const id of [...this.trackMetadata.keys()]) {
|
|
1041
|
+
if (!nextTracks.has(id)) {
|
|
1042
|
+
this.trackMetadata.delete(id);
|
|
1043
|
+
this.subscribedTracks.delete(id);
|
|
1044
|
+
this.trackToParticipant.delete(id);
|
|
1045
|
+
this.trackToSource.delete(id);
|
|
1027
1046
|
}
|
|
1028
1047
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1048
|
+
if (payload?.recording) {
|
|
1049
|
+
const current = {
|
|
1050
|
+
recording_id: payload.recording.recording_id,
|
|
1051
|
+
started_at: payload.recording.started_at
|
|
1052
|
+
};
|
|
1053
|
+
if (!this.activeRecording || this.activeRecording.recording_id !== current.recording_id) {
|
|
1054
|
+
this.activeRecording = current;
|
|
1055
|
+
this.onRecordingStarted(current);
|
|
1056
|
+
}
|
|
1057
|
+
} else if (this.activeRecording) {
|
|
1058
|
+
const previous = this.activeRecording;
|
|
1059
|
+
this.activeRecording = null;
|
|
1060
|
+
this.onRecordingStopped({
|
|
1061
|
+
recording_id: previous.recording_id,
|
|
1062
|
+
stopped_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1063
|
+
});
|
|
1031
1064
|
}
|
|
1032
1065
|
if (this.autoSubscribe) {
|
|
1033
|
-
const missing = [...nextTracks.values()].filter(
|
|
1034
|
-
|
|
1035
|
-
).map((track) => track.track_id);
|
|
1036
|
-
if (missing.length) {
|
|
1037
|
-
await this.subscribeMultiple(missing);
|
|
1038
|
-
}
|
|
1066
|
+
const missing = [...nextTracks.values()].filter((t) => t.participant_id !== this.currentParticipantId && !this.subscribedTracks.has(t.track_id)).map((t) => t.track_id);
|
|
1067
|
+
if (missing.length) await this.subscribeMultiple(missing);
|
|
1039
1068
|
}
|
|
1040
1069
|
this.onRoomState(payload);
|
|
1041
1070
|
}
|
|
@@ -1069,9 +1098,17 @@ var SFUClient = class {
|
|
|
1069
1098
|
if (track?.track_id) this.rememberTrack(track);
|
|
1070
1099
|
}
|
|
1071
1100
|
if (payload.recording) {
|
|
1072
|
-
this.
|
|
1101
|
+
this.activeRecording = {
|
|
1073
1102
|
recording_id: payload.recording.recording_id,
|
|
1074
1103
|
started_at: payload.recording.started_at
|
|
1104
|
+
};
|
|
1105
|
+
this.onRecordingStarted(this.activeRecording);
|
|
1106
|
+
} else if (this.activeRecording) {
|
|
1107
|
+
const previous = this.activeRecording;
|
|
1108
|
+
this.activeRecording = null;
|
|
1109
|
+
this.onRecordingStopped({
|
|
1110
|
+
recording_id: previous.recording_id,
|
|
1111
|
+
stopped_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1075
1112
|
});
|
|
1076
1113
|
}
|
|
1077
1114
|
await this.initializePeerConnections();
|
|
@@ -1999,9 +2036,13 @@ var VideoSDKCore = class {
|
|
|
1999
2036
|
);
|
|
2000
2037
|
return;
|
|
2001
2038
|
}
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2039
|
+
if (state === "disconnected" || state === "idle") {
|
|
2040
|
+
this.sfuClient = null;
|
|
2041
|
+
} else {
|
|
2042
|
+
throw new Error(
|
|
2043
|
+
`SFU client already exists in state "${state}". Disconnect explicitly before creating another connection.`
|
|
2044
|
+
);
|
|
2045
|
+
}
|
|
2005
2046
|
}
|
|
2006
2047
|
const client = new SFUClient({
|
|
2007
2048
|
apiBase: this.apiBase,
|
|
@@ -2020,12 +2061,26 @@ var VideoSDKCore = class {
|
|
|
2020
2061
|
});
|
|
2021
2062
|
},
|
|
2022
2063
|
onRoomState: (roomState) => {
|
|
2064
|
+
for (const participant of roomState?.participants || []) {
|
|
2065
|
+
const pid = participant?.participant_id;
|
|
2066
|
+
if (!pid || pid === this.myId) continue;
|
|
2067
|
+
const current = this.state.getParticipant(pid);
|
|
2068
|
+
if (!current) continue;
|
|
2069
|
+
this.state.updateParticipantMedia(pid, {
|
|
2070
|
+
stream: current.media?.stream ?? null,
|
|
2071
|
+
micEnabled: !Boolean(participant.audio_muted),
|
|
2072
|
+
camEnabled: !Boolean(participant.video_muted),
|
|
2073
|
+
isScreenSharing: Boolean(participant.screen_sharing)
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
const presenters = /* @__PURE__ */ new Set();
|
|
2023
2077
|
for (const participant of roomState?.participants || []) {
|
|
2024
2078
|
const pid = participant?.participant_id;
|
|
2025
2079
|
if (!pid || pid === this.myId) continue;
|
|
2026
2080
|
const current = this.state.getParticipant(pid);
|
|
2027
2081
|
if (!current) continue;
|
|
2028
2082
|
if (participant.screen_sharing) {
|
|
2083
|
+
presenters.add(pid);
|
|
2029
2084
|
this.state.updateParticipantMedia(pid, {
|
|
2030
2085
|
isScreenSharing: true,
|
|
2031
2086
|
screenStream: current.media?.screenStream ?? null
|
|
@@ -2041,6 +2096,10 @@ var VideoSDKCore = class {
|
|
|
2041
2096
|
});
|
|
2042
2097
|
}
|
|
2043
2098
|
}
|
|
2099
|
+
const presenter = [...presenters][0] ?? null;
|
|
2100
|
+
if (this.state.presenterId !== presenter) {
|
|
2101
|
+
this.state.setPresenterId(presenter);
|
|
2102
|
+
}
|
|
2044
2103
|
this.events.onRoomUpdate?.(roomState);
|
|
2045
2104
|
},
|
|
2046
2105
|
onDisconnected: () => {
|
|
@@ -2114,8 +2173,8 @@ var VideoSDKCore = class {
|
|
|
2114
2173
|
name: pname,
|
|
2115
2174
|
connectionState: "connected",
|
|
2116
2175
|
media: {
|
|
2117
|
-
micEnabled:
|
|
2118
|
-
camEnabled:
|
|
2176
|
+
micEnabled: !Boolean(participant.audio_muted),
|
|
2177
|
+
camEnabled: !Boolean(participant.video_muted),
|
|
2119
2178
|
isScreenSharing: false,
|
|
2120
2179
|
stream: null
|
|
2121
2180
|
}
|
|
@@ -2188,6 +2247,18 @@ var VideoSDKCore = class {
|
|
|
2188
2247
|
camEnabled: track.kind === "video" ? false : current.media?.camEnabled ?? true
|
|
2189
2248
|
});
|
|
2190
2249
|
},
|
|
2250
|
+
onParticipantMediaState: (participantId, audioMuted, videoMuted) => {
|
|
2251
|
+
if (participantId === this.myId) return;
|
|
2252
|
+
const current = this.state.getParticipant(participantId);
|
|
2253
|
+
if (!current) return;
|
|
2254
|
+
this.state.updateParticipantMedia(participantId, {
|
|
2255
|
+
stream: current.media?.stream ?? null,
|
|
2256
|
+
micEnabled: !audioMuted,
|
|
2257
|
+
camEnabled: !videoMuted
|
|
2258
|
+
});
|
|
2259
|
+
this.events.onMuteStateChanged?.(participantId, "audio", audioMuted);
|
|
2260
|
+
this.events.onMuteStateChanged?.(participantId, "video", videoMuted);
|
|
2261
|
+
},
|
|
2191
2262
|
onTrackStateChanged: (track) => {
|
|
2192
2263
|
const pid = track.participant_id;
|
|
2193
2264
|
if (!pid || pid === this.myId) {
|
|
@@ -2288,7 +2359,9 @@ var VideoSDKCore = class {
|
|
|
2288
2359
|
client.setLocalStream(this.localStream);
|
|
2289
2360
|
await client.getToken(roomId, {
|
|
2290
2361
|
displayName: name,
|
|
2291
|
-
participantId: this.myId
|
|
2362
|
+
participantId: this.myId,
|
|
2363
|
+
audioMuted: this.state.localParticipant?.media?.micEnabled,
|
|
2364
|
+
videoMuted: this.state.localParticipant?.media?.camEnabled
|
|
2292
2365
|
});
|
|
2293
2366
|
}
|
|
2294
2367
|
// SFU STATE
|