@defcomm/meetingsdk 0.5.6 → 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.js +109 -51
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +109 -51
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1834,28 +1834,44 @@ var SFUClient = class {
|
|
|
1834
1834
|
"audio/webm",
|
|
1835
1835
|
"audio/ogg;codecs=opus"
|
|
1836
1836
|
];
|
|
1837
|
-
return candidates.find(
|
|
1837
|
+
return candidates.find(
|
|
1838
|
+
(type) => MediaRecorder.isTypeSupported(type)
|
|
1839
|
+
) || "";
|
|
1838
1840
|
}
|
|
1839
|
-
async startLiveTranscription(
|
|
1840
|
-
if (this.liveTranscriptionActive)
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
if (!
|
|
1844
|
-
throw new Error("
|
|
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
|
+
);
|
|
1845
1858
|
}
|
|
1846
1859
|
const mimeType = this.getLiveTranscriptionMimeType();
|
|
1860
|
+
const stream = new MediaStream([audioTrack]);
|
|
1847
1861
|
this.liveTranscriptionActive = true;
|
|
1848
1862
|
this.liveTranscriptionSequence = 0;
|
|
1849
1863
|
this.liveTranscriptionStartedAt = Date.now();
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1864
|
+
console.log("[Transcript] starting", {
|
|
1865
|
+
room: this.room,
|
|
1866
|
+
trackId: audioTrack.id,
|
|
1867
|
+
readyState: audioTrack.readyState,
|
|
1868
|
+
enabled: audioTrack.enabled,
|
|
1853
1869
|
mimeType
|
|
1854
|
-
)
|
|
1870
|
+
});
|
|
1871
|
+
this.liveTranscriptionLoopPromise = this.runLiveTranscriptionLoop(stream, mimeType).finally(() => {
|
|
1855
1872
|
this.liveTranscriptionRecorder = null;
|
|
1856
1873
|
this.liveTranscriptionLoopPromise = null;
|
|
1857
1874
|
});
|
|
1858
|
-
void speakerName;
|
|
1859
1875
|
await Promise.resolve();
|
|
1860
1876
|
}
|
|
1861
1877
|
async captureLiveChunk(stream, mimeType) {
|
|
@@ -1863,21 +1879,32 @@ var SFUClient = class {
|
|
|
1863
1879
|
const chunks = [];
|
|
1864
1880
|
const recorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream);
|
|
1865
1881
|
this.liveTranscriptionRecorder = recorder;
|
|
1866
|
-
const timeout = setTimeout(() => {
|
|
1867
|
-
if (recorder.state !== "inactive")
|
|
1868
|
-
|
|
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
|
+
};
|
|
1869
1892
|
recorder.ondataavailable = (event) => {
|
|
1870
|
-
if (event.data.size > 0)
|
|
1893
|
+
if (event.data.size > 0) {
|
|
1894
|
+
chunks.push(event.data);
|
|
1895
|
+
}
|
|
1871
1896
|
};
|
|
1872
1897
|
recorder.onerror = () => {
|
|
1873
|
-
clearTimeout(timeout);
|
|
1898
|
+
window.clearTimeout(timeout);
|
|
1874
1899
|
reject(new Error("Live transcription recorder failed"));
|
|
1875
1900
|
};
|
|
1876
1901
|
recorder.onstop = () => {
|
|
1877
|
-
clearTimeout(timeout);
|
|
1902
|
+
window.clearTimeout(timeout);
|
|
1878
1903
|
this.liveTranscriptionRecorder = null;
|
|
1879
1904
|
resolve(
|
|
1880
|
-
chunks.length ? new Blob(chunks, {
|
|
1905
|
+
chunks.length ? new Blob(chunks, {
|
|
1906
|
+
type: recorder.mimeType || mimeType || "audio/webm"
|
|
1907
|
+
}) : null
|
|
1881
1908
|
);
|
|
1882
1909
|
};
|
|
1883
1910
|
recorder.start();
|
|
@@ -1887,52 +1914,86 @@ var SFUClient = class {
|
|
|
1887
1914
|
while (this.liveTranscriptionActive && stream.getAudioTracks()[0]?.readyState === "live") {
|
|
1888
1915
|
try {
|
|
1889
1916
|
const blob = await this.captureLiveChunk(stream, mimeType);
|
|
1890
|
-
if (!this.liveTranscriptionActive)
|
|
1891
|
-
|
|
1917
|
+
if (!this.liveTranscriptionActive) {
|
|
1918
|
+
break;
|
|
1919
|
+
}
|
|
1920
|
+
if (!blob || blob.size === 0) {
|
|
1921
|
+
continue;
|
|
1922
|
+
}
|
|
1892
1923
|
const sequence = this.liveTranscriptionSequence++;
|
|
1893
|
-
const offsetMs = Math.max(
|
|
1894
|
-
|
|
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
|
+
);
|
|
1895
1934
|
} catch (error) {
|
|
1935
|
+
console.error(
|
|
1936
|
+
"[Transcript] chunk processing failed",
|
|
1937
|
+
error
|
|
1938
|
+
);
|
|
1896
1939
|
this.onError(error);
|
|
1897
|
-
await new Promise(
|
|
1940
|
+
await new Promise(
|
|
1941
|
+
(resolve) => setTimeout(resolve, 750)
|
|
1942
|
+
);
|
|
1898
1943
|
}
|
|
1899
1944
|
}
|
|
1900
1945
|
}
|
|
1901
1946
|
async uploadLiveTranscriptionChunk(blob, sequence, offsetMs, mimeType) {
|
|
1902
|
-
if (!this.room || !this.authToken)
|
|
1947
|
+
if (!this.room || !this.authToken) {
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1903
1950
|
const form = new FormData();
|
|
1904
1951
|
form.append("sequence", String(sequence));
|
|
1905
1952
|
form.append("offset_ms", String(offsetMs));
|
|
1906
1953
|
const extension = mimeType.includes("ogg") || blob.type.includes("ogg") ? "ogg" : "webm";
|
|
1907
|
-
form.append(
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
{
|
|
1911
|
-
method: "POST",
|
|
1912
|
-
headers: {
|
|
1913
|
-
Authorization: `Bearer ${this.authToken}`,
|
|
1914
|
-
Accept: "application/json"
|
|
1915
|
-
},
|
|
1916
|
-
body: form
|
|
1917
|
-
}
|
|
1954
|
+
form.append(
|
|
1955
|
+
"audio",
|
|
1956
|
+
blob,
|
|
1957
|
+
`live-${sequence}.${extension}`
|
|
1918
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
|
+
});
|
|
1919
1979
|
if (!response.ok) {
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
detail = body?.message || body?.detail || detail;
|
|
1924
|
-
} catch {
|
|
1925
|
-
}
|
|
1926
|
-
throw new Error(detail);
|
|
1980
|
+
throw new Error(
|
|
1981
|
+
`Live transcription request failed: ${response.status} ${responseText}`
|
|
1982
|
+
);
|
|
1927
1983
|
}
|
|
1928
1984
|
}
|
|
1929
1985
|
stopLiveTranscription() {
|
|
1986
|
+
console.log("[Transcript] stopping");
|
|
1930
1987
|
this.liveTranscriptionActive = false;
|
|
1931
1988
|
try {
|
|
1932
|
-
if (this.liveTranscriptionRecorder
|
|
1933
|
-
this.liveTranscriptionRecorder
|
|
1989
|
+
if (this.liveTranscriptionRecorder && this.liveTranscriptionRecorder.state !== "inactive") {
|
|
1990
|
+
this.liveTranscriptionRecorder.stop();
|
|
1934
1991
|
}
|
|
1935
|
-
} catch {
|
|
1992
|
+
} catch (error) {
|
|
1993
|
+
console.warn(
|
|
1994
|
+
"[Transcript] recorder shutdown failed",
|
|
1995
|
+
error
|
|
1996
|
+
);
|
|
1936
1997
|
}
|
|
1937
1998
|
this.liveTranscriptionRecorder = null;
|
|
1938
1999
|
}
|
|
@@ -3164,13 +3225,10 @@ var VideoSDKCore = class {
|
|
|
3164
3225
|
throw new Error("SFU client is not connected");
|
|
3165
3226
|
}
|
|
3166
3227
|
const audioTrack = this.localStream?.getAudioTracks()[0];
|
|
3167
|
-
if (!audioTrack) {
|
|
3228
|
+
if (!audioTrack || audioTrack.readyState !== "live") {
|
|
3168
3229
|
throw new Error("Microphone audio track is not available");
|
|
3169
3230
|
}
|
|
3170
|
-
await this.sfuClient.startLiveTranscription(
|
|
3171
|
-
audioTrack,
|
|
3172
|
-
this.participantName
|
|
3173
|
-
);
|
|
3231
|
+
await this.sfuClient.startLiveTranscription();
|
|
3174
3232
|
}
|
|
3175
3233
|
stopLiveTranscription() {
|
|
3176
3234
|
this.sfuClient?.stopLiveTranscription();
|