@defcomm/meetingsdk 0.5.6 → 0.5.8
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 +56 -1
- package/dist/index.d.ts +56 -1
- package/dist/index.js +56 -108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -108
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -440,11 +440,7 @@ var SFUClient = class {
|
|
|
440
440
|
this.trackToSource = /* @__PURE__ */ new Map();
|
|
441
441
|
this.localTrackIds = /* @__PURE__ */ new Map();
|
|
442
442
|
this.subscriberStatsTimer = null;
|
|
443
|
-
this.
|
|
444
|
-
this.liveTranscriptionSequence = 0;
|
|
445
|
-
this.liveTranscriptionStartedAt = 0;
|
|
446
|
-
this.liveTranscriptionRecorder = null;
|
|
447
|
-
this.liveTranscriptionLoopPromise = null;
|
|
443
|
+
this.liveTranscriptionSeen = false;
|
|
448
444
|
this.networkProfile = null;
|
|
449
445
|
this.heartbeatTimer = null;
|
|
450
446
|
this.apiBase = options.apiBase || "https://api.example.com/api";
|
|
@@ -1112,7 +1108,10 @@ var SFUClient = class {
|
|
|
1112
1108
|
end_ms: payload.end_ms == null ? null : Number(payload.end_ms),
|
|
1113
1109
|
timestamp: String(payload.timestamp ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
1114
1110
|
};
|
|
1115
|
-
if (transcript.text.trim())
|
|
1111
|
+
if (transcript.text.trim()) {
|
|
1112
|
+
this.liveTranscriptionSeen = true;
|
|
1113
|
+
this.onLiveTranscript(transcript);
|
|
1114
|
+
}
|
|
1116
1115
|
break;
|
|
1117
1116
|
}
|
|
1118
1117
|
case "network_quality": {
|
|
@@ -1793,119 +1792,63 @@ var SFUClient = class {
|
|
|
1793
1792
|
}
|
|
1794
1793
|
});
|
|
1795
1794
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1795
|
+
/**
|
|
1796
|
+
* Transcription is server-authoritative. The SFU reads the already-published
|
|
1797
|
+
* microphone RTP stream, sends audio to the configured transcription service,
|
|
1798
|
+
* persists final segments, and broadcasts LiveTranscript events.
|
|
1799
|
+
*
|
|
1800
|
+
* These methods remain as compatibility shims for applications that used the
|
|
1801
|
+
* previous browser MediaRecorder-based API. They intentionally do not capture
|
|
1802
|
+
* or upload microphone audio from the browser.
|
|
1803
|
+
*/
|
|
1804
|
+
async startLiveTranscription() {
|
|
1805
|
+
if (!this.room) {
|
|
1806
|
+
throw new Error("Cannot start live transcription without a room");
|
|
1799
1807
|
}
|
|
1800
|
-
|
|
1801
|
-
"audio/webm;codecs=opus",
|
|
1802
|
-
"audio/webm",
|
|
1803
|
-
"audio/ogg;codecs=opus"
|
|
1804
|
-
];
|
|
1805
|
-
return candidates.find((type) => MediaRecorder.isTypeSupported(type)) || "";
|
|
1806
|
-
}
|
|
1807
|
-
async startLiveTranscription(audioTrack, speakerName) {
|
|
1808
|
-
if (this.liveTranscriptionActive) return;
|
|
1809
|
-
if (!this.room) throw new Error("Cannot start live transcription without a room");
|
|
1810
|
-
if (!this.authToken) throw new Error("Cannot start live transcription without an authenticated token");
|
|
1811
|
-
if (!audioTrack || audioTrack.kind !== "audio") {
|
|
1812
|
-
throw new Error("A live microphone audio track is required");
|
|
1813
|
-
}
|
|
1814
|
-
const mimeType = this.getLiveTranscriptionMimeType();
|
|
1815
|
-
this.liveTranscriptionActive = true;
|
|
1816
|
-
this.liveTranscriptionSequence = 0;
|
|
1817
|
-
this.liveTranscriptionStartedAt = Date.now();
|
|
1818
|
-
const stream = new MediaStream([audioTrack]);
|
|
1819
|
-
this.liveTranscriptionLoopPromise = this.runLiveTranscriptionLoop(
|
|
1820
|
-
stream,
|
|
1821
|
-
mimeType
|
|
1822
|
-
).finally(() => {
|
|
1823
|
-
this.liveTranscriptionRecorder = null;
|
|
1824
|
-
this.liveTranscriptionLoopPromise = null;
|
|
1825
|
-
});
|
|
1826
|
-
void speakerName;
|
|
1827
|
-
await Promise.resolve();
|
|
1808
|
+
console.info("[Transcript] server-authoritative live transcription is managed by the SFU");
|
|
1828
1809
|
}
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
const chunks = [];
|
|
1832
|
-
const recorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream);
|
|
1833
|
-
this.liveTranscriptionRecorder = recorder;
|
|
1834
|
-
const timeout = setTimeout(() => {
|
|
1835
|
-
if (recorder.state !== "inactive") recorder.stop();
|
|
1836
|
-
}, 4500);
|
|
1837
|
-
recorder.ondataavailable = (event) => {
|
|
1838
|
-
if (event.data.size > 0) chunks.push(event.data);
|
|
1839
|
-
};
|
|
1840
|
-
recorder.onerror = () => {
|
|
1841
|
-
clearTimeout(timeout);
|
|
1842
|
-
reject(new Error("Live transcription recorder failed"));
|
|
1843
|
-
};
|
|
1844
|
-
recorder.onstop = () => {
|
|
1845
|
-
clearTimeout(timeout);
|
|
1846
|
-
this.liveTranscriptionRecorder = null;
|
|
1847
|
-
resolve(
|
|
1848
|
-
chunks.length ? new Blob(chunks, { type: recorder.mimeType || mimeType || "audio/webm" }) : null
|
|
1849
|
-
);
|
|
1850
|
-
};
|
|
1851
|
-
recorder.start();
|
|
1852
|
-
});
|
|
1810
|
+
stopLiveTranscription() {
|
|
1811
|
+
console.info("[Transcript] server-authoritative live transcription remains managed by the SFU");
|
|
1853
1812
|
}
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
try {
|
|
1857
|
-
const blob = await this.captureLiveChunk(stream, mimeType);
|
|
1858
|
-
if (!this.liveTranscriptionActive) break;
|
|
1859
|
-
if (!blob || blob.size === 0) continue;
|
|
1860
|
-
const sequence = this.liveTranscriptionSequence++;
|
|
1861
|
-
const offsetMs = Math.max(0, Date.now() - this.liveTranscriptionStartedAt);
|
|
1862
|
-
await this.uploadLiveTranscriptionChunk(blob, sequence, offsetMs, mimeType);
|
|
1863
|
-
} catch (error) {
|
|
1864
|
-
this.onError(error);
|
|
1865
|
-
await new Promise((resolve) => setTimeout(resolve, 750));
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1813
|
+
isLiveTranscriptionActive() {
|
|
1814
|
+
return this.liveTranscriptionSeen;
|
|
1868
1815
|
}
|
|
1869
|
-
async
|
|
1870
|
-
if (!this.
|
|
1871
|
-
const
|
|
1872
|
-
form.append("sequence", String(sequence));
|
|
1873
|
-
form.append("offset_ms", String(offsetMs));
|
|
1874
|
-
const extension = mimeType.includes("ogg") || blob.type.includes("ogg") ? "ogg" : "webm";
|
|
1875
|
-
form.append("audio", blob, `live-${sequence}.${extension}`);
|
|
1816
|
+
async getTranscript(roomCode, sessionId) {
|
|
1817
|
+
if (!this.authToken) throw new Error("Authentication token is required");
|
|
1818
|
+
const query = sessionId ? `?session_id=${encodeURIComponent(sessionId)}` : "";
|
|
1876
1819
|
const response = await fetch(
|
|
1877
|
-
`${this.apiBase}/rooms/${encodeURIComponent(
|
|
1820
|
+
`${this.apiBase}/rooms/${encodeURIComponent(roomCode)}/transcript${query}`,
|
|
1878
1821
|
{
|
|
1879
|
-
method: "
|
|
1822
|
+
method: "GET",
|
|
1880
1823
|
headers: {
|
|
1881
1824
|
Authorization: `Bearer ${this.authToken}`,
|
|
1882
1825
|
Accept: "application/json"
|
|
1883
|
-
}
|
|
1884
|
-
body: form
|
|
1826
|
+
}
|
|
1885
1827
|
}
|
|
1886
1828
|
);
|
|
1829
|
+
const text = await response.text();
|
|
1887
1830
|
if (!response.ok) {
|
|
1888
|
-
|
|
1889
|
-
try {
|
|
1890
|
-
const body = await response.json();
|
|
1891
|
-
detail = body?.message || body?.detail || detail;
|
|
1892
|
-
} catch {
|
|
1893
|
-
}
|
|
1894
|
-
throw new Error(detail);
|
|
1831
|
+
throw new Error(`Transcript request failed: ${response.status} ${text}`);
|
|
1895
1832
|
}
|
|
1833
|
+
return JSON.parse(text);
|
|
1896
1834
|
}
|
|
1897
|
-
|
|
1898
|
-
this.
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1835
|
+
async getMeetingSummary(roomCode, sessionId) {
|
|
1836
|
+
if (!this.authToken) throw new Error("Authentication token is required");
|
|
1837
|
+
const response = await fetch(
|
|
1838
|
+
`${this.apiBase}/rooms/${encodeURIComponent(roomCode)}/transcript/${encodeURIComponent(sessionId)}/summary`,
|
|
1839
|
+
{
|
|
1840
|
+
method: "GET",
|
|
1841
|
+
headers: {
|
|
1842
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
1843
|
+
Accept: "application/json"
|
|
1844
|
+
}
|
|
1902
1845
|
}
|
|
1903
|
-
|
|
1846
|
+
);
|
|
1847
|
+
const text = await response.text();
|
|
1848
|
+
if (!response.ok) {
|
|
1849
|
+
throw new Error(`Meeting summary request failed: ${response.status} ${text}`);
|
|
1904
1850
|
}
|
|
1905
|
-
|
|
1906
|
-
}
|
|
1907
|
-
isLiveTranscriptionActive() {
|
|
1908
|
-
return this.liveTranscriptionActive;
|
|
1851
|
+
return JSON.parse(text);
|
|
1909
1852
|
}
|
|
1910
1853
|
async applyNetworkRecommendation(action) {
|
|
1911
1854
|
if (!this.videoSender || this.networkProfile === action) return;
|
|
@@ -2348,6 +2291,12 @@ var VideoSDKCore = class {
|
|
|
2348
2291
|
async deleteRoom(roomCode) {
|
|
2349
2292
|
return this.sfuClient.deleteRoom(roomCode);
|
|
2350
2293
|
}
|
|
2294
|
+
async getTranscript(roomCode, sessionId) {
|
|
2295
|
+
return this.sfuClient.getTranscript(roomCode, sessionId);
|
|
2296
|
+
}
|
|
2297
|
+
async getMeetingSummary(roomCode, sessionId) {
|
|
2298
|
+
return this.sfuClient.getMeetingSummary(roomCode, sessionId);
|
|
2299
|
+
}
|
|
2351
2300
|
// JOIN
|
|
2352
2301
|
async joinMeeting(config) {
|
|
2353
2302
|
const { roomId, name, audioMuted = false, videoMuted = false } = config;
|
|
@@ -3132,13 +3081,10 @@ var VideoSDKCore = class {
|
|
|
3132
3081
|
throw new Error("SFU client is not connected");
|
|
3133
3082
|
}
|
|
3134
3083
|
const audioTrack = this.localStream?.getAudioTracks()[0];
|
|
3135
|
-
if (!audioTrack) {
|
|
3084
|
+
if (!audioTrack || audioTrack.readyState !== "live") {
|
|
3136
3085
|
throw new Error("Microphone audio track is not available");
|
|
3137
3086
|
}
|
|
3138
|
-
await this.sfuClient.startLiveTranscription(
|
|
3139
|
-
audioTrack,
|
|
3140
|
-
this.participantName
|
|
3141
|
-
);
|
|
3087
|
+
await this.sfuClient.startLiveTranscription();
|
|
3142
3088
|
}
|
|
3143
3089
|
stopLiveTranscription() {
|
|
3144
3090
|
this.sfuClient?.stopLiveTranscription();
|
|
@@ -3404,6 +3350,8 @@ var MeetingProvider = ({
|
|
|
3404
3350
|
createRoom: sdk.createRoom.bind(sdk),
|
|
3405
3351
|
getRoom: sdk.getRoom.bind(sdk),
|
|
3406
3352
|
deleteRoom: sdk.deleteRoom.bind(sdk),
|
|
3353
|
+
getTranscript: sdk.getTranscript.bind(sdk),
|
|
3354
|
+
getMeetingSummary: sdk.getMeetingSummary.bind(sdk),
|
|
3407
3355
|
toggleMic: sdk.toggleMic.bind(sdk),
|
|
3408
3356
|
toggleCam: sdk.toggleCam.bind(sdk),
|
|
3409
3357
|
startScreenShare: sdk.startScreenShare.bind(sdk),
|