@defcomm/meetingsdk 0.2.2 → 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 +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +239 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +239 -29
- 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;
|
|
@@ -392,6 +395,8 @@ var SFUClient = class {
|
|
|
392
395
|
this.trackToSource = /* @__PURE__ */ new Map();
|
|
393
396
|
this.localTrackIds = /* @__PURE__ */ new Map();
|
|
394
397
|
this.subscriberStatsTimer = null;
|
|
398
|
+
this.roomSyncTimer = null;
|
|
399
|
+
this.roomSyncInFlight = false;
|
|
395
400
|
this.heartbeatTimer = null;
|
|
396
401
|
this.apiBase = options.apiBase || "https://api.example.com/api";
|
|
397
402
|
this.wsBase = options.wsBase || "wss://api.example.com/ws";
|
|
@@ -430,10 +435,14 @@ var SFUClient = class {
|
|
|
430
435
|
});
|
|
431
436
|
this.onTrackStateChanged = options.onTrackStateChanged || (() => {
|
|
432
437
|
});
|
|
438
|
+
this.onParticipantMediaState = options.onParticipantMediaState || (() => {
|
|
439
|
+
});
|
|
433
440
|
this.onRecordingStarted = options.onRecordingStarted || (() => {
|
|
434
441
|
});
|
|
435
442
|
this.onRecordingStopped = options.onRecordingStopped || (() => {
|
|
436
443
|
});
|
|
444
|
+
this.onRoomState = options.onRoomState || (() => {
|
|
445
|
+
});
|
|
437
446
|
this.onError = options.onError || console.error;
|
|
438
447
|
this.autoSubscribe = options.autoSubscribe !== false;
|
|
439
448
|
}
|
|
@@ -455,6 +464,29 @@ var SFUClient = class {
|
|
|
455
464
|
this.heartbeatTimer = null;
|
|
456
465
|
}
|
|
457
466
|
}
|
|
467
|
+
startRoomStateSync() {
|
|
468
|
+
this.stopRoomStateSync();
|
|
469
|
+
this.roomSyncTimer = setInterval(() => {
|
|
470
|
+
if (this.state !== "connected") return;
|
|
471
|
+
void this.syncRoomState();
|
|
472
|
+
}, 5e3);
|
|
473
|
+
}
|
|
474
|
+
stopRoomStateSync() {
|
|
475
|
+
if (this.roomSyncTimer) {
|
|
476
|
+
clearInterval(this.roomSyncTimer);
|
|
477
|
+
this.roomSyncTimer = null;
|
|
478
|
+
}
|
|
479
|
+
this.roomSyncInFlight = false;
|
|
480
|
+
}
|
|
481
|
+
async syncRoomState() {
|
|
482
|
+
if (this.roomSyncInFlight || !this.isSocketOpen()) return;
|
|
483
|
+
this.roomSyncInFlight = true;
|
|
484
|
+
try {
|
|
485
|
+
this.send({ type: "sync_room_state" });
|
|
486
|
+
} finally {
|
|
487
|
+
this.roomSyncInFlight = false;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
458
490
|
createId() {
|
|
459
491
|
return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : `id_${Math.random().toString(36).slice(2)}_${Date.now()}`;
|
|
460
492
|
}
|
|
@@ -552,9 +584,13 @@ var SFUClient = class {
|
|
|
552
584
|
this.resumeToken = null;
|
|
553
585
|
}
|
|
554
586
|
this.room = nextRoom;
|
|
587
|
+
this.audioMuted = Boolean(options.audioMuted);
|
|
588
|
+
this.videoMuted = Boolean(options.videoMuted);
|
|
555
589
|
this.joinOptions = {
|
|
556
590
|
displayName: options.displayName,
|
|
557
|
-
avatarUrl: options.avatarUrl
|
|
591
|
+
avatarUrl: options.avatarUrl,
|
|
592
|
+
audioMuted: this.audioMuted,
|
|
593
|
+
videoMuted: this.videoMuted
|
|
558
594
|
};
|
|
559
595
|
if (options.participantId) this.participantId = options.participantId;
|
|
560
596
|
if (!this.resumeToken) {
|
|
@@ -623,7 +659,9 @@ var SFUClient = class {
|
|
|
623
659
|
room_code: this.room,
|
|
624
660
|
resume_token: this.resumeToken,
|
|
625
661
|
display_name: options.displayName,
|
|
626
|
-
avatar_url: options.avatarUrl
|
|
662
|
+
avatar_url: options.avatarUrl,
|
|
663
|
+
audio_muted: this.audioMuted,
|
|
664
|
+
video_muted: this.videoMuted
|
|
627
665
|
};
|
|
628
666
|
if (this.pendingJoinRequestId) {
|
|
629
667
|
this.send({
|
|
@@ -664,8 +702,20 @@ var SFUClient = class {
|
|
|
664
702
|
scheduleReconnect() {
|
|
665
703
|
if (this.reconnectTimer || this.intentionalClose) return;
|
|
666
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();
|
|
667
711
|
this.setState("disconnected");
|
|
668
|
-
this.
|
|
712
|
+
this.onError({
|
|
713
|
+
code: "RECONNECT_TIMEOUT",
|
|
714
|
+
message: error.message,
|
|
715
|
+
recoverable: false
|
|
716
|
+
});
|
|
717
|
+
this.onDisconnected();
|
|
718
|
+
this.failJoin(error);
|
|
669
719
|
return;
|
|
670
720
|
}
|
|
671
721
|
this.reconnectAttempt += 1;
|
|
@@ -737,7 +787,9 @@ var SFUClient = class {
|
|
|
737
787
|
room_code: this.room,
|
|
738
788
|
resume_token: this.resumeToken,
|
|
739
789
|
display_name: this.joinOptions.displayName,
|
|
740
|
-
avatar_url: this.joinOptions.avatarUrl
|
|
790
|
+
avatar_url: this.joinOptions.avatarUrl,
|
|
791
|
+
audio_muted: this.audioMuted,
|
|
792
|
+
video_muted: this.videoMuted
|
|
741
793
|
}
|
|
742
794
|
});
|
|
743
795
|
}
|
|
@@ -812,22 +864,8 @@ var SFUClient = class {
|
|
|
812
864
|
if (!track?.track_id) break;
|
|
813
865
|
this.rememberTrack(track);
|
|
814
866
|
if (track.participant_id === this.currentParticipantId) {
|
|
815
|
-
if (track.source === "audio")
|
|
816
|
-
|
|
817
|
-
const muted = !(this.localStream?.getAudioTracks()[0]?.enabled ?? true);
|
|
818
|
-
this.send({
|
|
819
|
-
type: "track_state",
|
|
820
|
-
payload: { track_id: track.track_id, muted }
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
if (track.source === "camera") {
|
|
824
|
-
this.localTrackIds.set("camera", track.track_id);
|
|
825
|
-
const muted = !(this.localStream?.getVideoTracks()[0]?.enabled ?? true);
|
|
826
|
-
this.send({
|
|
827
|
-
type: "track_state",
|
|
828
|
-
payload: { track_id: track.track_id, muted }
|
|
829
|
-
});
|
|
830
|
-
}
|
|
867
|
+
if (track.source === "audio") this.localTrackIds.set("audio", track.track_id);
|
|
868
|
+
if (track.source === "camera") this.localTrackIds.set("camera", track.track_id);
|
|
831
869
|
if (track.source === "screen")
|
|
832
870
|
this.localTrackIds.set("screen", track.track_id);
|
|
833
871
|
break;
|
|
@@ -856,6 +894,27 @@ var SFUClient = class {
|
|
|
856
894
|
this.onTrackUnpublished(track);
|
|
857
895
|
break;
|
|
858
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
|
+
}
|
|
859
918
|
case "track_state_changed": {
|
|
860
919
|
const trackId = payload.track_id || payload.track?.track_id;
|
|
861
920
|
if (!trackId) break;
|
|
@@ -877,14 +936,20 @@ var SFUClient = class {
|
|
|
877
936
|
case "subscription_updated": {
|
|
878
937
|
break;
|
|
879
938
|
}
|
|
939
|
+
case "room_state": {
|
|
940
|
+
await this.applyRoomState(payload);
|
|
941
|
+
break;
|
|
942
|
+
}
|
|
880
943
|
case "recording_started": {
|
|
881
|
-
this.
|
|
944
|
+
this.activeRecording = {
|
|
882
945
|
recording_id: payload.recording_id,
|
|
883
946
|
started_at: payload.started_at
|
|
884
|
-
}
|
|
947
|
+
};
|
|
948
|
+
this.onRecordingStarted(this.activeRecording);
|
|
885
949
|
break;
|
|
886
950
|
}
|
|
887
951
|
case "recording_stopped": {
|
|
952
|
+
this.activeRecording = null;
|
|
888
953
|
this.onRecordingStopped({
|
|
889
954
|
recording_id: payload.recording_id,
|
|
890
955
|
stopped_at: payload.stopped_at
|
|
@@ -942,6 +1007,67 @@ var SFUClient = class {
|
|
|
942
1007
|
console.debug("[SFU] Ignoring unknown server message", message);
|
|
943
1008
|
}
|
|
944
1009
|
}
|
|
1010
|
+
async applyRoomState(payload) {
|
|
1011
|
+
const authoritative = /* @__PURE__ */ new Map();
|
|
1012
|
+
for (const participant of payload?.participants || []) {
|
|
1013
|
+
if (participant?.participant_id) authoritative.set(participant.participant_id, participant);
|
|
1014
|
+
}
|
|
1015
|
+
for (const id of [...this.participants.keys()]) {
|
|
1016
|
+
if (!authoritative.has(id) && id !== this.currentParticipantId) {
|
|
1017
|
+
this.participants.delete(id);
|
|
1018
|
+
this.removeRemoteParticipant(id);
|
|
1019
|
+
this.onParticipantLeft(id);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
for (const [id, participant] of authoritative) {
|
|
1023
|
+
if (id === this.currentParticipantId) continue;
|
|
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));
|
|
1033
|
+
}
|
|
1034
|
+
const nextTracks = /* @__PURE__ */ new Map();
|
|
1035
|
+
for (const track of payload?.tracks || []) {
|
|
1036
|
+
if (!track?.track_id) continue;
|
|
1037
|
+
nextTracks.set(track.track_id, track);
|
|
1038
|
+
this.rememberTrack(track);
|
|
1039
|
+
}
|
|
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);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
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
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
if (this.autoSubscribe) {
|
|
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);
|
|
1068
|
+
}
|
|
1069
|
+
this.onRoomState(payload);
|
|
1070
|
+
}
|
|
945
1071
|
rememberTrack(track) {
|
|
946
1072
|
this.trackMetadata.set(track.track_id, track);
|
|
947
1073
|
this.trackToParticipant.set(track.track_id, track.participant_id);
|
|
@@ -971,8 +1097,23 @@ var SFUClient = class {
|
|
|
971
1097
|
for (const track of payload.tracks || []) {
|
|
972
1098
|
if (track?.track_id) this.rememberTrack(track);
|
|
973
1099
|
}
|
|
1100
|
+
if (payload.recording) {
|
|
1101
|
+
this.activeRecording = {
|
|
1102
|
+
recording_id: payload.recording.recording_id,
|
|
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()
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
974
1114
|
await this.initializePeerConnections();
|
|
975
1115
|
this.setState("connected");
|
|
1116
|
+
this.startRoomStateSync();
|
|
976
1117
|
this.onConnected(payload, resumed);
|
|
977
1118
|
for (const participant of this.participants.values()) {
|
|
978
1119
|
if (participant.participant_id !== this.currentParticipantId) {
|
|
@@ -1527,6 +1668,7 @@ var SFUClient = class {
|
|
|
1527
1668
|
}
|
|
1528
1669
|
async leave() {
|
|
1529
1670
|
this.stopHeartbeat();
|
|
1671
|
+
this.stopRoomStateSync();
|
|
1530
1672
|
this.intentionalClose = true;
|
|
1531
1673
|
this.setState("leaving");
|
|
1532
1674
|
if (this.reconnectTimer) {
|
|
@@ -1894,9 +2036,13 @@ var VideoSDKCore = class {
|
|
|
1894
2036
|
);
|
|
1895
2037
|
return;
|
|
1896
2038
|
}
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
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
|
+
}
|
|
1900
2046
|
}
|
|
1901
2047
|
const client = new SFUClient({
|
|
1902
2048
|
apiBase: this.apiBase,
|
|
@@ -1914,6 +2060,48 @@ var VideoSDKCore = class {
|
|
|
1914
2060
|
name: this.participantName
|
|
1915
2061
|
});
|
|
1916
2062
|
},
|
|
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();
|
|
2077
|
+
for (const participant of roomState?.participants || []) {
|
|
2078
|
+
const pid = participant?.participant_id;
|
|
2079
|
+
if (!pid || pid === this.myId) continue;
|
|
2080
|
+
const current = this.state.getParticipant(pid);
|
|
2081
|
+
if (!current) continue;
|
|
2082
|
+
if (participant.screen_sharing) {
|
|
2083
|
+
presenters.add(pid);
|
|
2084
|
+
this.state.updateParticipantMedia(pid, {
|
|
2085
|
+
isScreenSharing: true,
|
|
2086
|
+
screenStream: current.media?.screenStream ?? null
|
|
2087
|
+
});
|
|
2088
|
+
} else if (current.media?.isScreenSharing) {
|
|
2089
|
+
const screen = this.remoteScreenStreams.get(pid);
|
|
2090
|
+
screen?.getTracks().forEach((track) => track.stop());
|
|
2091
|
+
this.remoteScreenStreams.delete(pid);
|
|
2092
|
+
this.state.updateParticipantMedia(pid, {
|
|
2093
|
+
isScreenSharing: false,
|
|
2094
|
+
screenStream: null,
|
|
2095
|
+
screenTrack: void 0
|
|
2096
|
+
});
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
const presenter = [...presenters][0] ?? null;
|
|
2100
|
+
if (this.state.presenterId !== presenter) {
|
|
2101
|
+
this.state.setPresenterId(presenter);
|
|
2102
|
+
}
|
|
2103
|
+
this.events.onRoomUpdate?.(roomState);
|
|
2104
|
+
},
|
|
1917
2105
|
onDisconnected: () => {
|
|
1918
2106
|
console.log("[SFU] Signaling WebSocket disconnected; reconnecting");
|
|
1919
2107
|
},
|
|
@@ -1985,8 +2173,8 @@ var VideoSDKCore = class {
|
|
|
1985
2173
|
name: pname,
|
|
1986
2174
|
connectionState: "connected",
|
|
1987
2175
|
media: {
|
|
1988
|
-
micEnabled:
|
|
1989
|
-
camEnabled:
|
|
2176
|
+
micEnabled: !Boolean(participant.audio_muted),
|
|
2177
|
+
camEnabled: !Boolean(participant.video_muted),
|
|
1990
2178
|
isScreenSharing: false,
|
|
1991
2179
|
stream: null
|
|
1992
2180
|
}
|
|
@@ -2059,6 +2247,18 @@ var VideoSDKCore = class {
|
|
|
2059
2247
|
camEnabled: track.kind === "video" ? false : current.media?.camEnabled ?? true
|
|
2060
2248
|
});
|
|
2061
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
|
+
},
|
|
2062
2262
|
onTrackStateChanged: (track) => {
|
|
2063
2263
|
const pid = track.participant_id;
|
|
2064
2264
|
if (!pid || pid === this.myId) {
|
|
@@ -2159,7 +2359,9 @@ var VideoSDKCore = class {
|
|
|
2159
2359
|
client.setLocalStream(this.localStream);
|
|
2160
2360
|
await client.getToken(roomId, {
|
|
2161
2361
|
displayName: name,
|
|
2162
|
-
participantId: this.myId
|
|
2362
|
+
participantId: this.myId,
|
|
2363
|
+
audioMuted: this.state.localParticipant?.media?.micEnabled,
|
|
2364
|
+
videoMuted: this.state.localParticipant?.media?.camEnabled
|
|
2163
2365
|
});
|
|
2164
2366
|
}
|
|
2165
2367
|
// SFU STATE
|
|
@@ -2473,6 +2675,7 @@ var MeetingProvider = ({
|
|
|
2473
2675
|
/* @__PURE__ */ new Set()
|
|
2474
2676
|
);
|
|
2475
2677
|
const meetingLeftListeners = useRef(/* @__PURE__ */ new Set());
|
|
2678
|
+
const roomUpdateListeners = useRef(/* @__PURE__ */ new Set());
|
|
2476
2679
|
const trackStateListeners = useRef(/* @__PURE__ */ new Set());
|
|
2477
2680
|
const recordingStartedListeners = useRef(/* @__PURE__ */ new Set());
|
|
2478
2681
|
const recordingStoppedListeners = useRef(/* @__PURE__ */ new Set());
|
|
@@ -2497,6 +2700,9 @@ var MeetingProvider = ({
|
|
|
2497
2700
|
onMeetingLeft: () => {
|
|
2498
2701
|
meetingLeftListeners.current.forEach((fn) => fn());
|
|
2499
2702
|
},
|
|
2703
|
+
onRoomUpdate: (data) => {
|
|
2704
|
+
roomUpdateListeners.current.forEach((fn) => fn(data));
|
|
2705
|
+
},
|
|
2500
2706
|
onTrackStateChanged: (track) => {
|
|
2501
2707
|
trackStateListeners.current.forEach((fn) => fn(track));
|
|
2502
2708
|
},
|
|
@@ -2595,6 +2801,10 @@ var MeetingProvider = ({
|
|
|
2595
2801
|
meetingLeftListeners.current.delete(cb);
|
|
2596
2802
|
};
|
|
2597
2803
|
},
|
|
2804
|
+
onRoomUpdate: (cb) => {
|
|
2805
|
+
roomUpdateListeners.current.add(cb);
|
|
2806
|
+
return () => roomUpdateListeners.current.delete(cb);
|
|
2807
|
+
},
|
|
2598
2808
|
onTrackStateChanged: (cb) => {
|
|
2599
2809
|
trackStateListeners.current.add(cb);
|
|
2600
2810
|
return () => trackStateListeners.current.delete(cb);
|