@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.mjs
CHANGED
|
@@ -1802,28 +1802,44 @@ var SFUClient = class {
|
|
|
1802
1802
|
"audio/webm",
|
|
1803
1803
|
"audio/ogg;codecs=opus"
|
|
1804
1804
|
];
|
|
1805
|
-
return candidates.find(
|
|
1805
|
+
return candidates.find(
|
|
1806
|
+
(type) => MediaRecorder.isTypeSupported(type)
|
|
1807
|
+
) || "";
|
|
1806
1808
|
}
|
|
1807
|
-
async startLiveTranscription(
|
|
1808
|
-
if (this.liveTranscriptionActive)
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
if (!
|
|
1812
|
-
throw new Error("
|
|
1809
|
+
async startLiveTranscription() {
|
|
1810
|
+
if (this.liveTranscriptionActive) {
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
if (!this.room) {
|
|
1814
|
+
throw new Error("Cannot start live transcription without a room");
|
|
1815
|
+
}
|
|
1816
|
+
if (!this.authToken) {
|
|
1817
|
+
throw new Error(
|
|
1818
|
+
"Cannot start live transcription without an authenticated token"
|
|
1819
|
+
);
|
|
1820
|
+
}
|
|
1821
|
+
const audioTrack = this.localStream?.getAudioTracks()[0];
|
|
1822
|
+
if (!audioTrack || audioTrack.readyState !== "live") {
|
|
1823
|
+
throw new Error(
|
|
1824
|
+
"Cannot start live transcription without a live microphone track"
|
|
1825
|
+
);
|
|
1813
1826
|
}
|
|
1814
1827
|
const mimeType = this.getLiveTranscriptionMimeType();
|
|
1828
|
+
const stream = new MediaStream([audioTrack]);
|
|
1815
1829
|
this.liveTranscriptionActive = true;
|
|
1816
1830
|
this.liveTranscriptionSequence = 0;
|
|
1817
1831
|
this.liveTranscriptionStartedAt = Date.now();
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1832
|
+
console.log("[Transcript] starting", {
|
|
1833
|
+
room: this.room,
|
|
1834
|
+
trackId: audioTrack.id,
|
|
1835
|
+
readyState: audioTrack.readyState,
|
|
1836
|
+
enabled: audioTrack.enabled,
|
|
1821
1837
|
mimeType
|
|
1822
|
-
)
|
|
1838
|
+
});
|
|
1839
|
+
this.liveTranscriptionLoopPromise = this.runLiveTranscriptionLoop(stream, mimeType).finally(() => {
|
|
1823
1840
|
this.liveTranscriptionRecorder = null;
|
|
1824
1841
|
this.liveTranscriptionLoopPromise = null;
|
|
1825
1842
|
});
|
|
1826
|
-
void speakerName;
|
|
1827
1843
|
await Promise.resolve();
|
|
1828
1844
|
}
|
|
1829
1845
|
async captureLiveChunk(stream, mimeType) {
|
|
@@ -1831,21 +1847,32 @@ var SFUClient = class {
|
|
|
1831
1847
|
const chunks = [];
|
|
1832
1848
|
const recorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream);
|
|
1833
1849
|
this.liveTranscriptionRecorder = recorder;
|
|
1834
|
-
const timeout = setTimeout(() => {
|
|
1835
|
-
if (recorder.state !== "inactive")
|
|
1836
|
-
|
|
1850
|
+
const timeout = window.setTimeout(() => {
|
|
1851
|
+
if (recorder.state !== "inactive") {
|
|
1852
|
+
recorder.stop();
|
|
1853
|
+
}
|
|
1854
|
+
}, 1500);
|
|
1855
|
+
recorder.onstart = () => {
|
|
1856
|
+
console.log("[Transcript] MediaRecorder started", {
|
|
1857
|
+
mimeType: recorder.mimeType
|
|
1858
|
+
});
|
|
1859
|
+
};
|
|
1837
1860
|
recorder.ondataavailable = (event) => {
|
|
1838
|
-
if (event.data.size > 0)
|
|
1861
|
+
if (event.data.size > 0) {
|
|
1862
|
+
chunks.push(event.data);
|
|
1863
|
+
}
|
|
1839
1864
|
};
|
|
1840
1865
|
recorder.onerror = () => {
|
|
1841
|
-
clearTimeout(timeout);
|
|
1866
|
+
window.clearTimeout(timeout);
|
|
1842
1867
|
reject(new Error("Live transcription recorder failed"));
|
|
1843
1868
|
};
|
|
1844
1869
|
recorder.onstop = () => {
|
|
1845
|
-
clearTimeout(timeout);
|
|
1870
|
+
window.clearTimeout(timeout);
|
|
1846
1871
|
this.liveTranscriptionRecorder = null;
|
|
1847
1872
|
resolve(
|
|
1848
|
-
chunks.length ? new Blob(chunks, {
|
|
1873
|
+
chunks.length ? new Blob(chunks, {
|
|
1874
|
+
type: recorder.mimeType || mimeType || "audio/webm"
|
|
1875
|
+
}) : null
|
|
1849
1876
|
);
|
|
1850
1877
|
};
|
|
1851
1878
|
recorder.start();
|
|
@@ -1855,52 +1882,86 @@ var SFUClient = class {
|
|
|
1855
1882
|
while (this.liveTranscriptionActive && stream.getAudioTracks()[0]?.readyState === "live") {
|
|
1856
1883
|
try {
|
|
1857
1884
|
const blob = await this.captureLiveChunk(stream, mimeType);
|
|
1858
|
-
if (!this.liveTranscriptionActive)
|
|
1859
|
-
|
|
1885
|
+
if (!this.liveTranscriptionActive) {
|
|
1886
|
+
break;
|
|
1887
|
+
}
|
|
1888
|
+
if (!blob || blob.size === 0) {
|
|
1889
|
+
continue;
|
|
1890
|
+
}
|
|
1860
1891
|
const sequence = this.liveTranscriptionSequence++;
|
|
1861
|
-
const offsetMs = Math.max(
|
|
1862
|
-
|
|
1892
|
+
const offsetMs = Math.max(
|
|
1893
|
+
0,
|
|
1894
|
+
Date.now() - this.liveTranscriptionStartedAt
|
|
1895
|
+
);
|
|
1896
|
+
await this.uploadLiveTranscriptionChunk(
|
|
1897
|
+
blob,
|
|
1898
|
+
sequence,
|
|
1899
|
+
offsetMs,
|
|
1900
|
+
blob.type || mimeType
|
|
1901
|
+
);
|
|
1863
1902
|
} catch (error) {
|
|
1903
|
+
console.error(
|
|
1904
|
+
"[Transcript] chunk processing failed",
|
|
1905
|
+
error
|
|
1906
|
+
);
|
|
1864
1907
|
this.onError(error);
|
|
1865
|
-
await new Promise(
|
|
1908
|
+
await new Promise(
|
|
1909
|
+
(resolve) => setTimeout(resolve, 750)
|
|
1910
|
+
);
|
|
1866
1911
|
}
|
|
1867
1912
|
}
|
|
1868
1913
|
}
|
|
1869
1914
|
async uploadLiveTranscriptionChunk(blob, sequence, offsetMs, mimeType) {
|
|
1870
|
-
if (!this.room || !this.authToken)
|
|
1915
|
+
if (!this.room || !this.authToken) {
|
|
1916
|
+
return;
|
|
1917
|
+
}
|
|
1871
1918
|
const form = new FormData();
|
|
1872
1919
|
form.append("sequence", String(sequence));
|
|
1873
1920
|
form.append("offset_ms", String(offsetMs));
|
|
1874
1921
|
const extension = mimeType.includes("ogg") || blob.type.includes("ogg") ? "ogg" : "webm";
|
|
1875
|
-
form.append(
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
{
|
|
1879
|
-
method: "POST",
|
|
1880
|
-
headers: {
|
|
1881
|
-
Authorization: `Bearer ${this.authToken}`,
|
|
1882
|
-
Accept: "application/json"
|
|
1883
|
-
},
|
|
1884
|
-
body: form
|
|
1885
|
-
}
|
|
1922
|
+
form.append(
|
|
1923
|
+
"audio",
|
|
1924
|
+
blob,
|
|
1925
|
+
`live-${sequence}.${extension}`
|
|
1886
1926
|
);
|
|
1927
|
+
const url = `${this.apiBase}/rooms/${encodeURIComponent(this.room)}/live-transcription`;
|
|
1928
|
+
console.log("[Transcript] POST", {
|
|
1929
|
+
url,
|
|
1930
|
+
sequence,
|
|
1931
|
+
size: blob.size,
|
|
1932
|
+
mimeType
|
|
1933
|
+
});
|
|
1934
|
+
const response = await fetch(url, {
|
|
1935
|
+
method: "POST",
|
|
1936
|
+
headers: {
|
|
1937
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
1938
|
+
Accept: "application/json"
|
|
1939
|
+
},
|
|
1940
|
+
body: form
|
|
1941
|
+
});
|
|
1942
|
+
const responseText = await response.text();
|
|
1943
|
+
console.log("[Transcript] response", {
|
|
1944
|
+
status: response.status,
|
|
1945
|
+
body: responseText
|
|
1946
|
+
});
|
|
1887
1947
|
if (!response.ok) {
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
detail = body?.message || body?.detail || detail;
|
|
1892
|
-
} catch {
|
|
1893
|
-
}
|
|
1894
|
-
throw new Error(detail);
|
|
1948
|
+
throw new Error(
|
|
1949
|
+
`Live transcription request failed: ${response.status} ${responseText}`
|
|
1950
|
+
);
|
|
1895
1951
|
}
|
|
1896
1952
|
}
|
|
1897
1953
|
stopLiveTranscription() {
|
|
1954
|
+
console.log("[Transcript] stopping");
|
|
1898
1955
|
this.liveTranscriptionActive = false;
|
|
1899
1956
|
try {
|
|
1900
|
-
if (this.liveTranscriptionRecorder
|
|
1901
|
-
this.liveTranscriptionRecorder
|
|
1957
|
+
if (this.liveTranscriptionRecorder && this.liveTranscriptionRecorder.state !== "inactive") {
|
|
1958
|
+
this.liveTranscriptionRecorder.stop();
|
|
1902
1959
|
}
|
|
1903
|
-
} catch {
|
|
1960
|
+
} catch (error) {
|
|
1961
|
+
console.warn(
|
|
1962
|
+
"[Transcript] recorder shutdown failed",
|
|
1963
|
+
error
|
|
1964
|
+
);
|
|
1904
1965
|
}
|
|
1905
1966
|
this.liveTranscriptionRecorder = null;
|
|
1906
1967
|
}
|
|
@@ -3132,13 +3193,10 @@ var VideoSDKCore = class {
|
|
|
3132
3193
|
throw new Error("SFU client is not connected");
|
|
3133
3194
|
}
|
|
3134
3195
|
const audioTrack = this.localStream?.getAudioTracks()[0];
|
|
3135
|
-
if (!audioTrack) {
|
|
3196
|
+
if (!audioTrack || audioTrack.readyState !== "live") {
|
|
3136
3197
|
throw new Error("Microphone audio track is not available");
|
|
3137
3198
|
}
|
|
3138
|
-
await this.sfuClient.startLiveTranscription(
|
|
3139
|
-
audioTrack,
|
|
3140
|
-
this.participantName
|
|
3141
|
-
);
|
|
3199
|
+
await this.sfuClient.startLiveTranscription();
|
|
3142
3200
|
}
|
|
3143
3201
|
stopLiveTranscription() {
|
|
3144
3202
|
this.sfuClient?.stopLiveTranscription();
|