@defcomm/meetingsdk 0.5.5 → 0.5.7
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 +60 -2
- package/dist/index.d.ts +60 -2
- package/dist/index.js +384 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +382 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24,10 +24,12 @@ __export(index_exports, {
|
|
|
24
24
|
MeetingProvider: () => MeetingProvider,
|
|
25
25
|
MeetingState: () => MeetingState,
|
|
26
26
|
VideoSDKCore: () => VideoSDKCore,
|
|
27
|
+
useLiveTranscript: () => useLiveTranscript,
|
|
27
28
|
useLocalParticipant: () => useLocalParticipant,
|
|
28
29
|
useMeeting: () => useMeeting,
|
|
29
30
|
useMeetingContext: () => useMeetingContext,
|
|
30
31
|
useMeetingPreview: () => useMeetingPreview,
|
|
32
|
+
useNetworkQuality: () => useNetworkQuality,
|
|
31
33
|
useParticipants: () => useParticipants,
|
|
32
34
|
usePubSub: () => usePubSub,
|
|
33
35
|
useRemoteMedia: () => useRemoteMedia
|
|
@@ -227,6 +229,8 @@ var MeetingState = class {
|
|
|
227
229
|
this.presenterId = null;
|
|
228
230
|
this.activeSpeakerIds = /* @__PURE__ */ new Set();
|
|
229
231
|
this.recording = null;
|
|
232
|
+
this.liveTranscripts = [];
|
|
233
|
+
this.networkQuality = null;
|
|
230
234
|
this.listeners = /* @__PURE__ */ new Map();
|
|
231
235
|
}
|
|
232
236
|
// ---- reactive system ----
|
|
@@ -264,6 +268,21 @@ var MeetingState = class {
|
|
|
264
268
|
this.recording = null;
|
|
265
269
|
this.notify("recording");
|
|
266
270
|
}
|
|
271
|
+
addLiveTranscript(transcript) {
|
|
272
|
+
this.liveTranscripts = [...this.liveTranscripts.slice(-499), transcript];
|
|
273
|
+
this.notify("transcript");
|
|
274
|
+
}
|
|
275
|
+
getLiveTranscripts() {
|
|
276
|
+
return this.liveTranscripts;
|
|
277
|
+
}
|
|
278
|
+
clearLiveTranscripts() {
|
|
279
|
+
this.liveTranscripts = [];
|
|
280
|
+
this.notify("transcript");
|
|
281
|
+
}
|
|
282
|
+
setNetworkQuality(quality) {
|
|
283
|
+
this.networkQuality = quality;
|
|
284
|
+
this.notify("networkQuality");
|
|
285
|
+
}
|
|
267
286
|
// ---- participants ----
|
|
268
287
|
addParticipant(p) {
|
|
269
288
|
if (this.participants.has(p.id)) return false;
|
|
@@ -384,10 +403,14 @@ var MeetingState = class {
|
|
|
384
403
|
this.chatMessages.clear();
|
|
385
404
|
this.presenterId = null;
|
|
386
405
|
this.activeSpeakerIds = /* @__PURE__ */ new Set();
|
|
406
|
+
this.liveTranscripts = [];
|
|
407
|
+
this.networkQuality = null;
|
|
387
408
|
this.notify("participants");
|
|
388
409
|
this.notify("chat");
|
|
389
410
|
this.notify("presenter");
|
|
390
411
|
this.notify("activeSpeakers");
|
|
412
|
+
this.notify("transcript");
|
|
413
|
+
this.notify("networkQuality");
|
|
391
414
|
}
|
|
392
415
|
};
|
|
393
416
|
|
|
@@ -449,6 +472,12 @@ var SFUClient = class {
|
|
|
449
472
|
this.trackToSource = /* @__PURE__ */ new Map();
|
|
450
473
|
this.localTrackIds = /* @__PURE__ */ new Map();
|
|
451
474
|
this.subscriberStatsTimer = null;
|
|
475
|
+
this.liveTranscriptionActive = false;
|
|
476
|
+
this.liveTranscriptionSequence = 0;
|
|
477
|
+
this.liveTranscriptionStartedAt = 0;
|
|
478
|
+
this.liveTranscriptionRecorder = null;
|
|
479
|
+
this.liveTranscriptionLoopPromise = null;
|
|
480
|
+
this.networkProfile = null;
|
|
452
481
|
this.heartbeatTimer = null;
|
|
453
482
|
this.apiBase = options.apiBase || "https://api.example.com/api";
|
|
454
483
|
this.wsBase = options.wsBase || "wss://api.example.com/ws";
|
|
@@ -505,6 +534,10 @@ var SFUClient = class {
|
|
|
505
534
|
});
|
|
506
535
|
this.onRoomUpdate = options.onRoomUpdate || (() => {
|
|
507
536
|
});
|
|
537
|
+
this.onLiveTranscript = options.onLiveTranscript || (() => {
|
|
538
|
+
});
|
|
539
|
+
this.onNetworkQuality = options.onNetworkQuality || (() => {
|
|
540
|
+
});
|
|
508
541
|
this.onParticipantMediaState = options.onParticipantMediaState || (() => {
|
|
509
542
|
});
|
|
510
543
|
this.autoSubscribe = options.autoSubscribe !== false;
|
|
@@ -1099,6 +1132,40 @@ var SFUClient = class {
|
|
|
1099
1132
|
if (reaction?.id && reaction?.emoji) this.onReaction(reaction);
|
|
1100
1133
|
break;
|
|
1101
1134
|
}
|
|
1135
|
+
case "live_transcript": {
|
|
1136
|
+
const transcript = {
|
|
1137
|
+
transcript_id: String(payload.transcript_id),
|
|
1138
|
+
participant_id: String(payload.participant_id),
|
|
1139
|
+
speaker_name: payload.speaker_name ?? null,
|
|
1140
|
+
sequence: Number(payload.sequence ?? 0),
|
|
1141
|
+
text: String(payload.text ?? ""),
|
|
1142
|
+
offset_ms: payload.offset_ms == null ? null : Number(payload.offset_ms),
|
|
1143
|
+
start_ms: payload.start_ms == null ? null : Number(payload.start_ms),
|
|
1144
|
+
end_ms: payload.end_ms == null ? null : Number(payload.end_ms),
|
|
1145
|
+
timestamp: String(payload.timestamp ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
1146
|
+
};
|
|
1147
|
+
if (transcript.text.trim()) this.onLiveTranscript(transcript);
|
|
1148
|
+
break;
|
|
1149
|
+
}
|
|
1150
|
+
case "network_quality": {
|
|
1151
|
+
const raw = payload.quality || payload;
|
|
1152
|
+
const quality = {
|
|
1153
|
+
participant_id: String(raw.participant_id ?? this.currentParticipantId ?? this.participantId),
|
|
1154
|
+
quality: String(raw.quality ?? "unknown"),
|
|
1155
|
+
score: Number(raw.score ?? 0),
|
|
1156
|
+
recommended_action: String(raw.recommended_action ?? "maintain"),
|
|
1157
|
+
packet_loss_percent: Number(raw.packet_loss_percent ?? 0),
|
|
1158
|
+
upload_kbps: Number(raw.upload_kbps ?? 0),
|
|
1159
|
+
forwarded_drop_percent: Number(raw.forwarded_drop_percent ?? 0),
|
|
1160
|
+
queued_packets: Number(raw.queued_packets ?? 0),
|
|
1161
|
+
packets_received: Number(raw.packets_received ?? 0),
|
|
1162
|
+
packets_lost: Number(raw.packets_lost ?? 0),
|
|
1163
|
+
observed_at: String(raw.observed_at ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
1164
|
+
};
|
|
1165
|
+
this.onNetworkQuality(quality);
|
|
1166
|
+
void this.applyNetworkRecommendation(quality.recommended_action);
|
|
1167
|
+
break;
|
|
1168
|
+
}
|
|
1102
1169
|
case "error": {
|
|
1103
1170
|
const message2 = payload.message || "SFU signaling error";
|
|
1104
1171
|
if (this.state === "reconnecting" && message2.includes("participant session is stale")) {
|
|
@@ -1758,6 +1825,208 @@ var SFUClient = class {
|
|
|
1758
1825
|
}
|
|
1759
1826
|
});
|
|
1760
1827
|
}
|
|
1828
|
+
getLiveTranscriptionMimeType() {
|
|
1829
|
+
if (typeof MediaRecorder === "undefined") {
|
|
1830
|
+
throw new Error("MediaRecorder is not supported by this browser");
|
|
1831
|
+
}
|
|
1832
|
+
const candidates = [
|
|
1833
|
+
"audio/webm;codecs=opus",
|
|
1834
|
+
"audio/webm",
|
|
1835
|
+
"audio/ogg;codecs=opus"
|
|
1836
|
+
];
|
|
1837
|
+
return candidates.find(
|
|
1838
|
+
(type) => MediaRecorder.isTypeSupported(type)
|
|
1839
|
+
) || "";
|
|
1840
|
+
}
|
|
1841
|
+
async startLiveTranscription() {
|
|
1842
|
+
if (this.liveTranscriptionActive) {
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
if (!this.room) {
|
|
1846
|
+
throw new Error("Cannot start live transcription without a room");
|
|
1847
|
+
}
|
|
1848
|
+
if (!this.authToken) {
|
|
1849
|
+
throw new Error(
|
|
1850
|
+
"Cannot start live transcription without an authenticated token"
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
const audioTrack = this.localStream?.getAudioTracks()[0];
|
|
1854
|
+
if (!audioTrack || audioTrack.readyState !== "live") {
|
|
1855
|
+
throw new Error(
|
|
1856
|
+
"Cannot start live transcription without a live microphone track"
|
|
1857
|
+
);
|
|
1858
|
+
}
|
|
1859
|
+
const mimeType = this.getLiveTranscriptionMimeType();
|
|
1860
|
+
const stream = new MediaStream([audioTrack]);
|
|
1861
|
+
this.liveTranscriptionActive = true;
|
|
1862
|
+
this.liveTranscriptionSequence = 0;
|
|
1863
|
+
this.liveTranscriptionStartedAt = Date.now();
|
|
1864
|
+
console.log("[Transcript] starting", {
|
|
1865
|
+
room: this.room,
|
|
1866
|
+
trackId: audioTrack.id,
|
|
1867
|
+
readyState: audioTrack.readyState,
|
|
1868
|
+
enabled: audioTrack.enabled,
|
|
1869
|
+
mimeType
|
|
1870
|
+
});
|
|
1871
|
+
this.liveTranscriptionLoopPromise = this.runLiveTranscriptionLoop(stream, mimeType).finally(() => {
|
|
1872
|
+
this.liveTranscriptionRecorder = null;
|
|
1873
|
+
this.liveTranscriptionLoopPromise = null;
|
|
1874
|
+
});
|
|
1875
|
+
await Promise.resolve();
|
|
1876
|
+
}
|
|
1877
|
+
async captureLiveChunk(stream, mimeType) {
|
|
1878
|
+
return new Promise((resolve, reject) => {
|
|
1879
|
+
const chunks = [];
|
|
1880
|
+
const recorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream);
|
|
1881
|
+
this.liveTranscriptionRecorder = recorder;
|
|
1882
|
+
const timeout = window.setTimeout(() => {
|
|
1883
|
+
if (recorder.state !== "inactive") {
|
|
1884
|
+
recorder.stop();
|
|
1885
|
+
}
|
|
1886
|
+
}, 1500);
|
|
1887
|
+
recorder.onstart = () => {
|
|
1888
|
+
console.log("[Transcript] MediaRecorder started", {
|
|
1889
|
+
mimeType: recorder.mimeType
|
|
1890
|
+
});
|
|
1891
|
+
};
|
|
1892
|
+
recorder.ondataavailable = (event) => {
|
|
1893
|
+
if (event.data.size > 0) {
|
|
1894
|
+
chunks.push(event.data);
|
|
1895
|
+
}
|
|
1896
|
+
};
|
|
1897
|
+
recorder.onerror = () => {
|
|
1898
|
+
window.clearTimeout(timeout);
|
|
1899
|
+
reject(new Error("Live transcription recorder failed"));
|
|
1900
|
+
};
|
|
1901
|
+
recorder.onstop = () => {
|
|
1902
|
+
window.clearTimeout(timeout);
|
|
1903
|
+
this.liveTranscriptionRecorder = null;
|
|
1904
|
+
resolve(
|
|
1905
|
+
chunks.length ? new Blob(chunks, {
|
|
1906
|
+
type: recorder.mimeType || mimeType || "audio/webm"
|
|
1907
|
+
}) : null
|
|
1908
|
+
);
|
|
1909
|
+
};
|
|
1910
|
+
recorder.start();
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
async runLiveTranscriptionLoop(stream, mimeType) {
|
|
1914
|
+
while (this.liveTranscriptionActive && stream.getAudioTracks()[0]?.readyState === "live") {
|
|
1915
|
+
try {
|
|
1916
|
+
const blob = await this.captureLiveChunk(stream, mimeType);
|
|
1917
|
+
if (!this.liveTranscriptionActive) {
|
|
1918
|
+
break;
|
|
1919
|
+
}
|
|
1920
|
+
if (!blob || blob.size === 0) {
|
|
1921
|
+
continue;
|
|
1922
|
+
}
|
|
1923
|
+
const sequence = this.liveTranscriptionSequence++;
|
|
1924
|
+
const offsetMs = Math.max(
|
|
1925
|
+
0,
|
|
1926
|
+
Date.now() - this.liveTranscriptionStartedAt
|
|
1927
|
+
);
|
|
1928
|
+
await this.uploadLiveTranscriptionChunk(
|
|
1929
|
+
blob,
|
|
1930
|
+
sequence,
|
|
1931
|
+
offsetMs,
|
|
1932
|
+
blob.type || mimeType
|
|
1933
|
+
);
|
|
1934
|
+
} catch (error) {
|
|
1935
|
+
console.error(
|
|
1936
|
+
"[Transcript] chunk processing failed",
|
|
1937
|
+
error
|
|
1938
|
+
);
|
|
1939
|
+
this.onError(error);
|
|
1940
|
+
await new Promise(
|
|
1941
|
+
(resolve) => setTimeout(resolve, 750)
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
async uploadLiveTranscriptionChunk(blob, sequence, offsetMs, mimeType) {
|
|
1947
|
+
if (!this.room || !this.authToken) {
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
const form = new FormData();
|
|
1951
|
+
form.append("sequence", String(sequence));
|
|
1952
|
+
form.append("offset_ms", String(offsetMs));
|
|
1953
|
+
const extension = mimeType.includes("ogg") || blob.type.includes("ogg") ? "ogg" : "webm";
|
|
1954
|
+
form.append(
|
|
1955
|
+
"audio",
|
|
1956
|
+
blob,
|
|
1957
|
+
`live-${sequence}.${extension}`
|
|
1958
|
+
);
|
|
1959
|
+
const url = `${this.apiBase}/rooms/${encodeURIComponent(this.room)}/live-transcription`;
|
|
1960
|
+
console.log("[Transcript] POST", {
|
|
1961
|
+
url,
|
|
1962
|
+
sequence,
|
|
1963
|
+
size: blob.size,
|
|
1964
|
+
mimeType
|
|
1965
|
+
});
|
|
1966
|
+
const response = await fetch(url, {
|
|
1967
|
+
method: "POST",
|
|
1968
|
+
headers: {
|
|
1969
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
1970
|
+
Accept: "application/json"
|
|
1971
|
+
},
|
|
1972
|
+
body: form
|
|
1973
|
+
});
|
|
1974
|
+
const responseText = await response.text();
|
|
1975
|
+
console.log("[Transcript] response", {
|
|
1976
|
+
status: response.status,
|
|
1977
|
+
body: responseText
|
|
1978
|
+
});
|
|
1979
|
+
if (!response.ok) {
|
|
1980
|
+
throw new Error(
|
|
1981
|
+
`Live transcription request failed: ${response.status} ${responseText}`
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
stopLiveTranscription() {
|
|
1986
|
+
console.log("[Transcript] stopping");
|
|
1987
|
+
this.liveTranscriptionActive = false;
|
|
1988
|
+
try {
|
|
1989
|
+
if (this.liveTranscriptionRecorder && this.liveTranscriptionRecorder.state !== "inactive") {
|
|
1990
|
+
this.liveTranscriptionRecorder.stop();
|
|
1991
|
+
}
|
|
1992
|
+
} catch (error) {
|
|
1993
|
+
console.warn(
|
|
1994
|
+
"[Transcript] recorder shutdown failed",
|
|
1995
|
+
error
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
this.liveTranscriptionRecorder = null;
|
|
1999
|
+
}
|
|
2000
|
+
isLiveTranscriptionActive() {
|
|
2001
|
+
return this.liveTranscriptionActive;
|
|
2002
|
+
}
|
|
2003
|
+
async applyNetworkRecommendation(action) {
|
|
2004
|
+
if (!this.videoSender || this.networkProfile === action) return;
|
|
2005
|
+
const params = this.videoSender.getParameters();
|
|
2006
|
+
const encodings = params.encodings?.length ? params.encodings : [{}];
|
|
2007
|
+
const encoding = encodings[0];
|
|
2008
|
+
switch (action) {
|
|
2009
|
+
case "reduce_video":
|
|
2010
|
+
encoding.maxBitrate = 7e5;
|
|
2011
|
+
encoding.maxFramerate = 20;
|
|
2012
|
+
break;
|
|
2013
|
+
case "audio_priority":
|
|
2014
|
+
encoding.maxBitrate = 35e4;
|
|
2015
|
+
encoding.maxFramerate = 10;
|
|
2016
|
+
break;
|
|
2017
|
+
default:
|
|
2018
|
+
encoding.maxBitrate = 15e5;
|
|
2019
|
+
encoding.maxFramerate = 30;
|
|
2020
|
+
break;
|
|
2021
|
+
}
|
|
2022
|
+
params.encodings = encodings;
|
|
2023
|
+
try {
|
|
2024
|
+
await this.videoSender.setParameters(params);
|
|
2025
|
+
this.networkProfile = action;
|
|
2026
|
+
} catch (error) {
|
|
2027
|
+
this.onError(error);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
1761
2030
|
async startRecording() {
|
|
1762
2031
|
if (!this.send({ type: "start_recording" })) {
|
|
1763
2032
|
throw new Error("SFU signaling is not connected");
|
|
@@ -1890,6 +2159,7 @@ var SFUClient = class {
|
|
|
1890
2159
|
}
|
|
1891
2160
|
}
|
|
1892
2161
|
async leave() {
|
|
2162
|
+
this.stopLiveTranscription();
|
|
1893
2163
|
this.stopHeartbeat();
|
|
1894
2164
|
this.intentionalClose = true;
|
|
1895
2165
|
this.setState("leaving");
|
|
@@ -2298,6 +2568,14 @@ var VideoSDKCore = class {
|
|
|
2298
2568
|
console.warn(`[SFU] Reconnecting, attempt ${attempt}`);
|
|
2299
2569
|
},
|
|
2300
2570
|
// ADMISSION CONTROL
|
|
2571
|
+
onLiveTranscript: (transcript) => {
|
|
2572
|
+
this.state.addLiveTranscript(transcript);
|
|
2573
|
+
this.events.onLiveTranscript?.(transcript);
|
|
2574
|
+
},
|
|
2575
|
+
onNetworkQuality: (quality) => {
|
|
2576
|
+
this.state.setNetworkQuality(quality);
|
|
2577
|
+
this.events.onNetworkQuality?.(quality);
|
|
2578
|
+
},
|
|
2301
2579
|
onRoomUpdate: (payload) => {
|
|
2302
2580
|
const participants = payload?.participants || [];
|
|
2303
2581
|
const local = participants.find(
|
|
@@ -2942,6 +3220,25 @@ var VideoSDKCore = class {
|
|
|
2942
3220
|
}
|
|
2943
3221
|
}
|
|
2944
3222
|
}
|
|
3223
|
+
async startLiveTranscription() {
|
|
3224
|
+
if (!this.sfuClient) {
|
|
3225
|
+
throw new Error("SFU client is not connected");
|
|
3226
|
+
}
|
|
3227
|
+
const audioTrack = this.localStream?.getAudioTracks()[0];
|
|
3228
|
+
if (!audioTrack || audioTrack.readyState !== "live") {
|
|
3229
|
+
throw new Error("Microphone audio track is not available");
|
|
3230
|
+
}
|
|
3231
|
+
await this.sfuClient.startLiveTranscription();
|
|
3232
|
+
}
|
|
3233
|
+
stopLiveTranscription() {
|
|
3234
|
+
this.sfuClient?.stopLiveTranscription();
|
|
3235
|
+
}
|
|
3236
|
+
isLiveTranscriptionActive() {
|
|
3237
|
+
return this.sfuClient?.isLiveTranscriptionActive() ?? false;
|
|
3238
|
+
}
|
|
3239
|
+
getNetworkQuality() {
|
|
3240
|
+
return this.state.networkQuality;
|
|
3241
|
+
}
|
|
2945
3242
|
// CLEANUP
|
|
2946
3243
|
cleanupRemoteParticipant(participantId) {
|
|
2947
3244
|
this.activeSpeakerDetector.removeParticipant(participantId);
|
|
@@ -2990,6 +3287,8 @@ var VideoSDKCore = class {
|
|
|
2990
3287
|
this.room.id = null;
|
|
2991
3288
|
this.room.name = null;
|
|
2992
3289
|
this.state.localParticipant = null;
|
|
3290
|
+
this.state.clearLiveTranscripts();
|
|
3291
|
+
this.state.setNetworkQuality(null);
|
|
2993
3292
|
this.state.notify("localParticipant");
|
|
2994
3293
|
this.state.resetRemoteState();
|
|
2995
3294
|
this.events.onMeetingLeft?.();
|
|
@@ -3022,9 +3321,15 @@ var MeetingProvider = ({
|
|
|
3022
3321
|
const entryResponseListeners = (0, import_react2.useRef)(
|
|
3023
3322
|
/* @__PURE__ */ new Set()
|
|
3024
3323
|
);
|
|
3025
|
-
const joinRequestCanceledListeners = (0, import_react2.useRef)(
|
|
3026
|
-
|
|
3027
|
-
|
|
3324
|
+
const joinRequestCanceledListeners = (0, import_react2.useRef)(
|
|
3325
|
+
/* @__PURE__ */ new Set()
|
|
3326
|
+
);
|
|
3327
|
+
const participantRemovedListeners = (0, import_react2.useRef)(
|
|
3328
|
+
/* @__PURE__ */ new Set()
|
|
3329
|
+
);
|
|
3330
|
+
const participantPermissionsChangedListeners = (0, import_react2.useRef)(
|
|
3331
|
+
/* @__PURE__ */ new Set()
|
|
3332
|
+
);
|
|
3028
3333
|
const meetingLeftListeners = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
|
|
3029
3334
|
const trackStateListeners = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
|
|
3030
3335
|
const recordingStartedListeners = (0, import_react2.useRef)(/* @__PURE__ */ new Set());
|
|
@@ -3037,6 +3342,12 @@ var MeetingProvider = ({
|
|
|
3037
3342
|
const activeSpeakerListeners = (0, import_react2.useRef)(
|
|
3038
3343
|
/* @__PURE__ */ new Set()
|
|
3039
3344
|
);
|
|
3345
|
+
const liveTranscriptListeners = (0, import_react2.useRef)(
|
|
3346
|
+
/* @__PURE__ */ new Set()
|
|
3347
|
+
);
|
|
3348
|
+
const networkQualityListeners = (0, import_react2.useRef)(
|
|
3349
|
+
/* @__PURE__ */ new Set()
|
|
3350
|
+
);
|
|
3040
3351
|
const connectionStateListeners = (0, import_react2.useRef)(
|
|
3041
3352
|
/* @__PURE__ */ new Set()
|
|
3042
3353
|
);
|
|
@@ -3060,10 +3371,14 @@ var MeetingProvider = ({
|
|
|
3060
3371
|
joinRequestCanceledListeners.current.forEach((fn) => fn(requestId));
|
|
3061
3372
|
},
|
|
3062
3373
|
onParticipantRemoved: (participantId, removedBy) => {
|
|
3063
|
-
participantRemovedListeners.current.forEach(
|
|
3374
|
+
participantRemovedListeners.current.forEach(
|
|
3375
|
+
(fn) => fn(participantId, removedBy)
|
|
3376
|
+
);
|
|
3064
3377
|
},
|
|
3065
3378
|
onParticipantPermissionsChanged: (participantId, permissions) => {
|
|
3066
|
-
participantPermissionsChangedListeners.current.forEach(
|
|
3379
|
+
participantPermissionsChangedListeners.current.forEach(
|
|
3380
|
+
(fn) => fn(participantId, permissions)
|
|
3381
|
+
);
|
|
3067
3382
|
},
|
|
3068
3383
|
onMeetingLeft: () => {
|
|
3069
3384
|
meetingLeftListeners.current.forEach((fn) => fn());
|
|
@@ -3116,6 +3431,12 @@ var MeetingProvider = ({
|
|
|
3116
3431
|
);
|
|
3117
3432
|
pubSubListeners.current.get("REACTION")?.forEach((fn) => fn(message));
|
|
3118
3433
|
},
|
|
3434
|
+
onLiveTranscript: (transcript) => {
|
|
3435
|
+
liveTranscriptListeners.current.forEach((fn) => fn(transcript));
|
|
3436
|
+
},
|
|
3437
|
+
onNetworkQuality: (quality) => {
|
|
3438
|
+
networkQualityListeners.current.forEach((fn) => fn(quality));
|
|
3439
|
+
},
|
|
3119
3440
|
onConnectionStateChanged: (state) => {
|
|
3120
3441
|
connectionStateListeners.current.forEach(
|
|
3121
3442
|
(fn) => fn(state)
|
|
@@ -3151,6 +3472,16 @@ var MeetingProvider = ({
|
|
|
3151
3472
|
"chat",
|
|
3152
3473
|
(s) => s.getChatMessages()
|
|
3153
3474
|
);
|
|
3475
|
+
const liveTranscripts = useMeetingStore(
|
|
3476
|
+
sdk.state,
|
|
3477
|
+
"transcript",
|
|
3478
|
+
(s) => s.getLiveTranscripts()
|
|
3479
|
+
);
|
|
3480
|
+
const networkQuality = useMeetingStore(
|
|
3481
|
+
sdk.state,
|
|
3482
|
+
"networkQuality",
|
|
3483
|
+
(s) => s.networkQuality
|
|
3484
|
+
);
|
|
3154
3485
|
const value = (0, import_react2.useMemo)(() => {
|
|
3155
3486
|
return {
|
|
3156
3487
|
sdk,
|
|
@@ -3175,6 +3506,11 @@ var MeetingProvider = ({
|
|
|
3175
3506
|
messages,
|
|
3176
3507
|
presenterId,
|
|
3177
3508
|
activeSpeakerIds,
|
|
3509
|
+
liveTranscripts,
|
|
3510
|
+
networkQuality,
|
|
3511
|
+
startLiveTranscription: sdk.startLiveTranscription.bind(sdk),
|
|
3512
|
+
stopLiveTranscription: sdk.stopLiveTranscription.bind(sdk),
|
|
3513
|
+
isLiveTranscriptionActive: sdk.isLiveTranscriptionActive.bind(sdk),
|
|
3178
3514
|
recording,
|
|
3179
3515
|
usePubSub: (topic) => {
|
|
3180
3516
|
if (topic === "SECURE_CHAT") {
|
|
@@ -3293,6 +3629,14 @@ var MeetingProvider = ({
|
|
|
3293
3629
|
reactionListeners.current.add(cb);
|
|
3294
3630
|
return () => reactionListeners.current.delete(cb);
|
|
3295
3631
|
},
|
|
3632
|
+
onLiveTranscript: (cb) => {
|
|
3633
|
+
liveTranscriptListeners.current.add(cb);
|
|
3634
|
+
return () => liveTranscriptListeners.current.delete(cb);
|
|
3635
|
+
},
|
|
3636
|
+
onNetworkQuality: (cb) => {
|
|
3637
|
+
networkQualityListeners.current.add(cb);
|
|
3638
|
+
return () => networkQualityListeners.current.delete(cb);
|
|
3639
|
+
},
|
|
3296
3640
|
onConnectionStateChanged: (cb) => {
|
|
3297
3641
|
connectionStateListeners.current.add(cb);
|
|
3298
3642
|
return () => {
|
|
@@ -3315,6 +3659,8 @@ var MeetingProvider = ({
|
|
|
3315
3659
|
presenterId,
|
|
3316
3660
|
recording,
|
|
3317
3661
|
activeSpeakerIds,
|
|
3662
|
+
liveTranscripts,
|
|
3663
|
+
networkQuality,
|
|
3318
3664
|
reactionPubSubMessages
|
|
3319
3665
|
]);
|
|
3320
3666
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MeetingContext.Provider, { value, children });
|
|
@@ -3399,7 +3745,9 @@ var useMeeting = (handlers) => {
|
|
|
3399
3745
|
}, [handlers?.onParticipantRemoved]);
|
|
3400
3746
|
(0, import_react4.useEffect)(() => {
|
|
3401
3747
|
if (!handlers?.onParticipantPermissionsChanged) return;
|
|
3402
|
-
return ctx.onParticipantPermissionsChanged(
|
|
3748
|
+
return ctx.onParticipantPermissionsChanged(
|
|
3749
|
+
handlers.onParticipantPermissionsChanged
|
|
3750
|
+
);
|
|
3403
3751
|
}, [handlers?.onParticipantPermissionsChanged]);
|
|
3404
3752
|
(0, import_react4.useEffect)(() => {
|
|
3405
3753
|
if (!handlers?.onMeetingLeft) return;
|
|
@@ -3421,6 +3769,14 @@ var useMeeting = (handlers) => {
|
|
|
3421
3769
|
if (!handlers?.onConnectionStateChanged) return;
|
|
3422
3770
|
return ctx.onConnectionStateChanged(handlers.onConnectionStateChanged);
|
|
3423
3771
|
}, [handlers?.onConnectionStateChanged]);
|
|
3772
|
+
(0, import_react4.useEffect)(() => {
|
|
3773
|
+
if (!handlers?.onLiveTranscript) return;
|
|
3774
|
+
return ctx.onLiveTranscript(handlers.onLiveTranscript);
|
|
3775
|
+
}, [handlers?.onLiveTranscript]);
|
|
3776
|
+
(0, import_react4.useEffect)(() => {
|
|
3777
|
+
if (!handlers?.onNetworkQuality) return;
|
|
3778
|
+
return ctx.onNetworkQuality(handlers.onNetworkQuality);
|
|
3779
|
+
}, [handlers?.onNetworkQuality]);
|
|
3424
3780
|
(0, import_react4.useEffect)(() => {
|
|
3425
3781
|
if (!handlers?.onReaction) return;
|
|
3426
3782
|
return ctx.onReaction(handlers.onReaction);
|
|
@@ -3558,6 +3914,26 @@ function useMeetingPreview(roomId, participantId) {
|
|
|
3558
3914
|
};
|
|
3559
3915
|
}
|
|
3560
3916
|
|
|
3917
|
+
// src/react/useLiveTranscript.ts
|
|
3918
|
+
var useLiveTranscript = () => {
|
|
3919
|
+
const { sdk } = useMeetingContext();
|
|
3920
|
+
return useMeetingStore(
|
|
3921
|
+
sdk.state,
|
|
3922
|
+
"transcript",
|
|
3923
|
+
(state) => state.getLiveTranscripts()
|
|
3924
|
+
);
|
|
3925
|
+
};
|
|
3926
|
+
|
|
3927
|
+
// src/react/useNetworkQuality.ts
|
|
3928
|
+
var useNetworkQuality = () => {
|
|
3929
|
+
const { sdk } = useMeetingContext();
|
|
3930
|
+
return useMeetingStore(
|
|
3931
|
+
sdk.state,
|
|
3932
|
+
"networkQuality",
|
|
3933
|
+
(state) => state.networkQuality
|
|
3934
|
+
);
|
|
3935
|
+
};
|
|
3936
|
+
|
|
3561
3937
|
// src/react/usePubSub.ts
|
|
3562
3938
|
var import_react8 = require("react");
|
|
3563
3939
|
function usePubSub(topic, options) {
|
|
@@ -3577,10 +3953,12 @@ function usePubSub(topic, options) {
|
|
|
3577
3953
|
MeetingProvider,
|
|
3578
3954
|
MeetingState,
|
|
3579
3955
|
VideoSDKCore,
|
|
3956
|
+
useLiveTranscript,
|
|
3580
3957
|
useLocalParticipant,
|
|
3581
3958
|
useMeeting,
|
|
3582
3959
|
useMeetingContext,
|
|
3583
3960
|
useMeetingPreview,
|
|
3961
|
+
useNetworkQuality,
|
|
3584
3962
|
useParticipants,
|
|
3585
3963
|
usePubSub,
|
|
3586
3964
|
useRemoteMedia
|