@corti/dictation-web 0.6.0-rc → 0.6.0
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/README.md +1 -1
- package/dist/bundle.js +6875 -5532
- package/dist/components/corti-dictation.d.ts +3 -3
- package/dist/components/corti-dictation.js.map +1 -1
- package/dist/components/recording-button.d.ts +2 -2
- package/dist/components/recording-button.js +16 -17
- package/dist/components/recording-button.js.map +1 -1
- package/dist/contexts/dictation-context.d.ts +6 -6
- package/dist/contexts/dictation-context.js.map +1 -1
- package/dist/controllers/dictation-controller.d.ts +7 -4
- package/dist/controllers/dictation-controller.js +140 -34
- package/dist/controllers/dictation-controller.js.map +1 -1
- package/dist/controllers/media-controller.d.ts +1 -3
- package/dist/controllers/media-controller.js +4 -22
- package/dist/controllers/media-controller.js.map +1 -1
- package/dist/icons/icons.d.ts +1 -1
- package/dist/icons/icons.js +7 -7
- package/dist/icons/icons.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/styles/audio-visualiser.js.map +1 -1
- package/dist/styles/callout.js +1 -1
- package/dist/styles/callout.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/auth.d.ts +2 -2
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/events.d.ts +2 -0
- package/dist/utils/events.js +22 -1
- package/dist/utils/events.js.map +1 -1
- package/package.json +3 -5
- package/dist/components/mode-selector.d.ts +0 -14
- package/dist/components/mode-selector.js +0 -73
- package/dist/components/mode-selector.js.map +0 -1
- package/dist/package.json +0 -94
- package/dist/styles/mode-selector.d.ts +0 -2
- package/dist/styles/mode-selector.js +0 -56
- package/dist/styles/mode-selector.js.map +0 -1
|
@@ -9,9 +9,10 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
10
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
11
|
};
|
|
12
|
-
var _DictationController_instances, _DictationController_cortiClient, _DictationController_webSocket, _DictationController_closeTimeout, _DictationController_callbacks, _DictationController_lastDictationConfig, _DictationController_lastSocketUrl, _DictationController_lastSocketProxy, _DictationController_configHasChanged, _DictationController_connectProxy, _DictationController_connectAuth, _DictationController_setupWebSocketHandlers;
|
|
13
|
-
import { CortiClient, CortiWebSocketProxyClient } from "@corti/sdk";
|
|
12
|
+
var _DictationController_instances, _DictationController_cortiClient, _DictationController_webSocket, _DictationController_closeTimeout, _DictationController_callbacks, _DictationController_lastDictationConfig, _DictationController_lastSocketUrl, _DictationController_lastSocketProxy, _DictationController_outboundQueue, _DictationController_socketReady, _DictationController_connectingPromise, _DictationController_connectionGeneration, _DictationController_isConnecting, _DictationController_configHasChanged, _DictationController_doConnect, _DictationController_connectProxy, _DictationController_connectAuth, _DictationController_setupWebSocketHandlers, _DictationController_isSocketOpen, _DictationController_drain;
|
|
13
|
+
import { CortiClient, CortiWebSocketProxyClient, } from "@corti/sdk";
|
|
14
14
|
import { DEFAULT_DICTATION_CONFIG } from "../constants.js";
|
|
15
|
+
import { errorEvent } from "../utils/events.js";
|
|
15
16
|
export class DictationController {
|
|
16
17
|
constructor(host) {
|
|
17
18
|
_DictationController_instances.add(this);
|
|
@@ -22,12 +23,21 @@ export class DictationController {
|
|
|
22
23
|
_DictationController_lastDictationConfig.set(this, null);
|
|
23
24
|
_DictationController_lastSocketUrl.set(this, void 0);
|
|
24
25
|
_DictationController_lastSocketProxy.set(this, void 0);
|
|
26
|
+
_DictationController_outboundQueue.set(this, []);
|
|
27
|
+
_DictationController_socketReady.set(this, false);
|
|
28
|
+
_DictationController_connectingPromise.set(this, null);
|
|
29
|
+
_DictationController_connectionGeneration.set(this, 0);
|
|
30
|
+
_DictationController_isConnecting.set(this, false);
|
|
25
31
|
this.mediaRecorderHandler = (data) => {
|
|
26
|
-
__classPrivateFieldGet(this,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
if (__classPrivateFieldGet(this, _DictationController_socketReady, "f") && __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_isSocketOpen).call(this)) {
|
|
33
|
+
__classPrivateFieldGet(this, _DictationController_webSocket, "f")?.send(data);
|
|
34
|
+
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", {
|
|
35
|
+
size: data.size,
|
|
36
|
+
type: "audio",
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
__classPrivateFieldGet(this, _DictationController_outboundQueue, "f").push(data);
|
|
31
41
|
};
|
|
32
42
|
this.host = host;
|
|
33
43
|
host.addController(this);
|
|
@@ -36,41 +46,49 @@ export class DictationController {
|
|
|
36
46
|
this.cleanup();
|
|
37
47
|
}
|
|
38
48
|
async connect(dictationConfig = DEFAULT_DICTATION_CONFIG, callbacks = {}) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
throw new Error("Already connected. Disconnect before reconnecting.");
|
|
44
|
-
}
|
|
45
|
-
__classPrivateFieldSet(this, _DictationController_webSocket, this.host._socketUrl || this.host._socketProxy
|
|
46
|
-
? await __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_connectProxy).call(this, dictationConfig)
|
|
47
|
-
: await __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_connectAuth).call(this, dictationConfig), "f");
|
|
48
|
-
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", {
|
|
49
|
-
configuration: dictationConfig,
|
|
50
|
-
type: "config",
|
|
51
|
-
});
|
|
52
|
-
__classPrivateFieldSet(this, _DictationController_lastDictationConfig, this.host._dictationConfig || null, "f");
|
|
53
|
-
__classPrivateFieldSet(this, _DictationController_lastSocketUrl, this.host._socketUrl, "f");
|
|
54
|
-
__classPrivateFieldSet(this, _DictationController_lastSocketProxy, this.host._socketProxy, "f");
|
|
49
|
+
// If a connection attempt is already in progress with the same config, reuse it
|
|
50
|
+
// to avoid opening multiple sockets when connect() is called concurrently.
|
|
51
|
+
if (__classPrivateFieldGet(this, _DictationController_connectingPromise, "f") && !__classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_configHasChanged).call(this)) {
|
|
52
|
+
return __classPrivateFieldGet(this, _DictationController_connectingPromise, "f");
|
|
55
53
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
// #isConnecting must be set synchronously before #doConnect runs, because
|
|
55
|
+
// #doConnect calls cleanup() which closes the old socket, firing its "close"
|
|
56
|
+
// event synchronously. Handlers that check isConnecting() need to see true
|
|
57
|
+
// at that point — before #connectingPromise is even assigned.
|
|
58
|
+
__classPrivateFieldSet(this, _DictationController_isConnecting, true, "f");
|
|
59
|
+
__classPrivateFieldSet(this, _DictationController_connectingPromise, __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_doConnect).call(this, dictationConfig, callbacks).finally(() => {
|
|
60
|
+
__classPrivateFieldSet(this, _DictationController_isConnecting, false, "f");
|
|
61
|
+
__classPrivateFieldSet(this, _DictationController_connectingPromise, null, "f");
|
|
62
|
+
}), "f");
|
|
63
|
+
return __classPrivateFieldGet(this, _DictationController_connectingPromise, "f");
|
|
59
64
|
}
|
|
60
65
|
async pause() {
|
|
61
|
-
__classPrivateFieldGet(this,
|
|
62
|
-
|
|
66
|
+
if (__classPrivateFieldGet(this, _DictationController_socketReady, "f") && __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_isSocketOpen).call(this)) {
|
|
67
|
+
__classPrivateFieldGet(this, _DictationController_webSocket, "f")?.send(JSON.stringify({ type: "flush" }));
|
|
68
|
+
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", { type: "flush" });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
__classPrivateFieldGet(this, _DictationController_outboundQueue, "f").push({ type: "flush" });
|
|
63
72
|
}
|
|
64
73
|
isConnectionOpen() {
|
|
65
74
|
return (__classPrivateFieldGet(this, _DictationController_webSocket, "f") !== null &&
|
|
66
75
|
(__classPrivateFieldGet(this, _DictationController_webSocket, "f").readyState === WebSocket.OPEN ||
|
|
67
76
|
__classPrivateFieldGet(this, _DictationController_webSocket, "f").readyState === WebSocket.CONNECTING));
|
|
68
77
|
}
|
|
78
|
+
isConnecting() {
|
|
79
|
+
return __classPrivateFieldGet(this, _DictationController_isConnecting, "f");
|
|
80
|
+
}
|
|
81
|
+
async waitForConnection() {
|
|
82
|
+
await __classPrivateFieldGet(this, _DictationController_connectingPromise, "f");
|
|
83
|
+
}
|
|
69
84
|
async closeConnection(onClose) {
|
|
70
85
|
await new Promise((resolve, reject) => {
|
|
71
86
|
const oldSocket = __classPrivateFieldGet(this, _DictationController_webSocket, "f");
|
|
72
87
|
__classPrivateFieldSet(this, _DictationController_webSocket, null, "f");
|
|
73
|
-
if (!oldSocket ||
|
|
88
|
+
if (!oldSocket ||
|
|
89
|
+
(oldSocket.readyState !== WebSocket.OPEN &&
|
|
90
|
+
oldSocket.readyState !== WebSocket.CONNECTING)) {
|
|
91
|
+
__classPrivateFieldSet(this, _DictationController_socketReady, false, "f");
|
|
74
92
|
resolve();
|
|
75
93
|
return;
|
|
76
94
|
}
|
|
@@ -84,11 +102,22 @@ export class DictationController {
|
|
|
84
102
|
}
|
|
85
103
|
resolve();
|
|
86
104
|
});
|
|
105
|
+
const wasReady = __classPrivateFieldGet(this, _DictationController_socketReady, "f");
|
|
106
|
+
__classPrivateFieldSet(this, _DictationController_socketReady, false, "f");
|
|
87
107
|
oldSocket.on("message", (message) => {
|
|
88
108
|
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("received", message);
|
|
89
109
|
if (__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onMessage) {
|
|
90
110
|
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onMessage(message);
|
|
91
111
|
}
|
|
112
|
+
// closeConnection() may be called before CONFIG_ACCEPTED arrives (e.g.
|
|
113
|
+
// openConnection() followed immediately by closeConnection()). We can't
|
|
114
|
+
// use the outbound queue here because #webSocket is already null, so we
|
|
115
|
+
// send "end" directly on oldSocket as soon as config is accepted.
|
|
116
|
+
if (!wasReady && message.type === "CONFIG_ACCEPTED") {
|
|
117
|
+
oldSocket.sendEnd({ type: "end" });
|
|
118
|
+
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", { type: "end" });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
92
121
|
if (message.type === "ended") {
|
|
93
122
|
if (__classPrivateFieldGet(this, _DictationController_closeTimeout, "f")) {
|
|
94
123
|
clearTimeout(__classPrivateFieldGet(this, _DictationController_closeTimeout, "f"));
|
|
@@ -98,8 +127,10 @@ export class DictationController {
|
|
|
98
127
|
return;
|
|
99
128
|
}
|
|
100
129
|
});
|
|
101
|
-
|
|
102
|
-
|
|
130
|
+
if (wasReady) {
|
|
131
|
+
oldSocket.sendEnd({ type: "end" });
|
|
132
|
+
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", { type: "end" });
|
|
133
|
+
}
|
|
103
134
|
__classPrivateFieldSet(this, _DictationController_closeTimeout, window.setTimeout(() => {
|
|
104
135
|
reject(new Error("Connection close timeout"));
|
|
105
136
|
if (oldSocket?.readyState === WebSocket.OPEN) {
|
|
@@ -109,26 +140,65 @@ export class DictationController {
|
|
|
109
140
|
});
|
|
110
141
|
}
|
|
111
142
|
cleanup() {
|
|
143
|
+
var _a;
|
|
144
|
+
// Incrementing generation invalidates any in-flight #doConnect awaits,
|
|
145
|
+
// causing them to discard their socket and return "superseded".
|
|
146
|
+
__classPrivateFieldSet(this, _DictationController_connectionGeneration, (_a = __classPrivateFieldGet(this, _DictationController_connectionGeneration, "f"), _a++, _a), "f");
|
|
147
|
+
__classPrivateFieldSet(this, _DictationController_socketReady, false, "f");
|
|
112
148
|
if (__classPrivateFieldGet(this, _DictationController_closeTimeout, "f")) {
|
|
113
149
|
clearTimeout(__classPrivateFieldGet(this, _DictationController_closeTimeout, "f"));
|
|
114
150
|
__classPrivateFieldSet(this, _DictationController_closeTimeout, undefined, "f");
|
|
115
151
|
}
|
|
116
|
-
if (
|
|
117
|
-
__classPrivateFieldGet(this, _DictationController_webSocket, "f")
|
|
152
|
+
if (this.isConnectionOpen()) {
|
|
153
|
+
__classPrivateFieldGet(this, _DictationController_webSocket, "f")?.close();
|
|
118
154
|
}
|
|
119
155
|
__classPrivateFieldSet(this, _DictationController_webSocket, null, "f");
|
|
120
156
|
__classPrivateFieldSet(this, _DictationController_cortiClient, null, "f");
|
|
121
157
|
__classPrivateFieldSet(this, _DictationController_lastDictationConfig, null, "f");
|
|
122
158
|
__classPrivateFieldSet(this, _DictationController_lastSocketUrl, undefined, "f");
|
|
123
159
|
__classPrivateFieldSet(this, _DictationController_lastSocketProxy, undefined, "f");
|
|
160
|
+
if (__classPrivateFieldGet(this, _DictationController_outboundQueue, "f").length > 0) {
|
|
161
|
+
this.host.dispatchEvent(errorEvent(`${__classPrivateFieldGet(this, _DictationController_outboundQueue, "f").length} unsent message(s) were discarded because the configuration changed before the connection was closed`));
|
|
162
|
+
}
|
|
163
|
+
__classPrivateFieldSet(this, _DictationController_outboundQueue, [], "f");
|
|
124
164
|
}
|
|
125
165
|
}
|
|
126
|
-
_DictationController_cortiClient = new WeakMap(), _DictationController_webSocket = new WeakMap(), _DictationController_closeTimeout = new WeakMap(), _DictationController_callbacks = new WeakMap(), _DictationController_lastDictationConfig = new WeakMap(), _DictationController_lastSocketUrl = new WeakMap(), _DictationController_lastSocketProxy = new WeakMap(), _DictationController_instances = new WeakSet(), _DictationController_configHasChanged = function _DictationController_configHasChanged() {
|
|
166
|
+
_DictationController_cortiClient = new WeakMap(), _DictationController_webSocket = new WeakMap(), _DictationController_closeTimeout = new WeakMap(), _DictationController_callbacks = new WeakMap(), _DictationController_lastDictationConfig = new WeakMap(), _DictationController_lastSocketUrl = new WeakMap(), _DictationController_lastSocketProxy = new WeakMap(), _DictationController_outboundQueue = new WeakMap(), _DictationController_socketReady = new WeakMap(), _DictationController_connectingPromise = new WeakMap(), _DictationController_connectionGeneration = new WeakMap(), _DictationController_isConnecting = new WeakMap(), _DictationController_instances = new WeakSet(), _DictationController_configHasChanged = function _DictationController_configHasChanged() {
|
|
127
167
|
return (JSON.stringify(this.host._dictationConfig) !==
|
|
128
168
|
JSON.stringify(__classPrivateFieldGet(this, _DictationController_lastDictationConfig, "f")) ||
|
|
129
169
|
this.host._socketUrl !== __classPrivateFieldGet(this, _DictationController_lastSocketUrl, "f") ||
|
|
130
170
|
JSON.stringify(this.host._socketProxy) !==
|
|
131
171
|
JSON.stringify(__classPrivateFieldGet(this, _DictationController_lastSocketProxy, "f")));
|
|
172
|
+
}, _DictationController_doConnect = async function _DictationController_doConnect(dictationConfig, callbacks) {
|
|
173
|
+
const newConnection = __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_configHasChanged).call(this) || !this.isConnectionOpen();
|
|
174
|
+
if (newConnection) {
|
|
175
|
+
this.cleanup();
|
|
176
|
+
__classPrivateFieldSet(this, _DictationController_lastDictationConfig, this.host._dictationConfig || null, "f");
|
|
177
|
+
__classPrivateFieldSet(this, _DictationController_lastSocketUrl, this.host._socketUrl, "f");
|
|
178
|
+
__classPrivateFieldSet(this, _DictationController_lastSocketProxy, this.host._socketProxy, "f");
|
|
179
|
+
const generation = __classPrivateFieldGet(this, _DictationController_connectionGeneration, "f");
|
|
180
|
+
const socket = this.host._socketUrl || this.host._socketProxy
|
|
181
|
+
? await __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_connectProxy).call(this, dictationConfig)
|
|
182
|
+
: await __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_connectAuth).call(this, dictationConfig);
|
|
183
|
+
// If cleanup() was called while we were awaiting (e.g. config changed),
|
|
184
|
+
// the generation counter will have advanced — discard this stale socket.
|
|
185
|
+
if (__classPrivateFieldGet(this, _DictationController_connectionGeneration, "f") !== generation) {
|
|
186
|
+
socket.close();
|
|
187
|
+
return "superseded";
|
|
188
|
+
}
|
|
189
|
+
__classPrivateFieldSet(this, _DictationController_webSocket, socket, "f");
|
|
190
|
+
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", {
|
|
191
|
+
configuration: dictationConfig,
|
|
192
|
+
type: "config",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
__classPrivateFieldSet(this, _DictationController_callbacks, callbacks, "f");
|
|
196
|
+
__classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_setupWebSocketHandlers).call(this, callbacks);
|
|
197
|
+
if (!newConnection && this.isConnectionOpen()) {
|
|
198
|
+
__classPrivateFieldSet(this, _DictationController_socketReady, true, "f");
|
|
199
|
+
__classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_drain).call(this);
|
|
200
|
+
}
|
|
201
|
+
return newConnection;
|
|
132
202
|
}, _DictationController_connectProxy = async function _DictationController_connectProxy(dictationConfig) {
|
|
133
203
|
const proxyOptions = this.host._socketProxy || {
|
|
134
204
|
url: this.host._socketUrl || "",
|
|
@@ -137,6 +207,8 @@ _DictationController_cortiClient = new WeakMap(), _DictationController_webSocket
|
|
|
137
207
|
throw new Error("Proxy URL is required when using proxy client");
|
|
138
208
|
}
|
|
139
209
|
return await CortiWebSocketProxyClient.transcribe.connect({
|
|
210
|
+
// setting to "false" to have CONFIG_* message in network activity events
|
|
211
|
+
awaitConfiguration: false,
|
|
140
212
|
configuration: dictationConfig,
|
|
141
213
|
proxy: proxyOptions,
|
|
142
214
|
});
|
|
@@ -157,6 +229,8 @@ _DictationController_cortiClient = new WeakMap(), _DictationController_webSocket
|
|
|
157
229
|
tenantName: this.host._tenantName,
|
|
158
230
|
}), "f");
|
|
159
231
|
return await __classPrivateFieldGet(this, _DictationController_cortiClient, "f").transcribe.connect({
|
|
232
|
+
// setting to "false" to have CONFIG_* message in network activity events
|
|
233
|
+
awaitConfiguration: false,
|
|
160
234
|
configuration: dictationConfig,
|
|
161
235
|
});
|
|
162
236
|
}, _DictationController_setupWebSocketHandlers = function _DictationController_setupWebSocketHandlers(callbacks) {
|
|
@@ -164,20 +238,52 @@ _DictationController_cortiClient = new WeakMap(), _DictationController_webSocket
|
|
|
164
238
|
throw new Error("WebSocket not initialized");
|
|
165
239
|
}
|
|
166
240
|
__classPrivateFieldGet(this, _DictationController_webSocket, "f").on("message", (message) => {
|
|
241
|
+
if (message.type === "CONFIG_ACCEPTED") {
|
|
242
|
+
__classPrivateFieldSet(this, _DictationController_socketReady, true, "f");
|
|
243
|
+
__classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_drain).call(this);
|
|
244
|
+
}
|
|
167
245
|
callbacks.onNetworkActivity?.("received", message);
|
|
168
246
|
if (callbacks.onMessage) {
|
|
169
247
|
callbacks.onMessage(message);
|
|
170
248
|
}
|
|
171
249
|
});
|
|
172
250
|
__classPrivateFieldGet(this, _DictationController_webSocket, "f").on("error", (event) => {
|
|
251
|
+
__classPrivateFieldSet(this, _DictationController_socketReady, false, "f");
|
|
173
252
|
if (callbacks.onError) {
|
|
174
253
|
callbacks.onError(event);
|
|
175
254
|
}
|
|
176
255
|
});
|
|
177
256
|
__classPrivateFieldGet(this, _DictationController_webSocket, "f").on("close", (event) => {
|
|
257
|
+
__classPrivateFieldSet(this, _DictationController_socketReady, false, "f");
|
|
178
258
|
if (callbacks.onClose) {
|
|
179
259
|
callbacks.onClose(event);
|
|
180
260
|
}
|
|
181
261
|
});
|
|
262
|
+
}, _DictationController_isSocketOpen = function _DictationController_isSocketOpen() {
|
|
263
|
+
return (__classPrivateFieldGet(this, _DictationController_webSocket, "f") !== null && __classPrivateFieldGet(this, _DictationController_webSocket, "f").readyState === WebSocket.OPEN);
|
|
264
|
+
}, _DictationController_drain = function _DictationController_drain() {
|
|
265
|
+
if (!__classPrivateFieldGet(this, _DictationController_socketReady, "f") ||
|
|
266
|
+
!__classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_isSocketOpen).call(this) ||
|
|
267
|
+
__classPrivateFieldGet(this, _DictationController_outboundQueue, "f").length === 0) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
while (__classPrivateFieldGet(this, _DictationController_outboundQueue, "f").length > 0 && __classPrivateFieldGet(this, _DictationController_instances, "m", _DictationController_isSocketOpen).call(this)) {
|
|
271
|
+
const item = __classPrivateFieldGet(this, _DictationController_outboundQueue, "f").shift();
|
|
272
|
+
if (item === undefined) {
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
if (item instanceof Blob) {
|
|
276
|
+
__classPrivateFieldGet(this, _DictationController_webSocket, "f").send(item);
|
|
277
|
+
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", {
|
|
278
|
+
size: item.size,
|
|
279
|
+
type: "audio",
|
|
280
|
+
});
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
__classPrivateFieldGet(this, _DictationController_webSocket, "f").send(JSON.stringify(item));
|
|
284
|
+
__classPrivateFieldGet(this, _DictationController_callbacks, "f")?.onNetworkActivity?.("sent", {
|
|
285
|
+
type: item.type,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
182
288
|
};
|
|
183
289
|
//# sourceMappingURL=dictation-controller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dictation-controller.js","sourceRoot":"","sources":["../../src/controllers/dictation-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Corti, CortiClient, CortiWebSocketProxyClient } from \"@corti/sdk\";\nimport type { ReactiveController, ReactiveControllerHost } from \"lit\";\nimport { DEFAULT_DICTATION_CONFIG } from \"../constants.js\";\nimport type { ProxyOptions } from \"../types.js\";\n\ntype TranscribeSocket = Awaited<\n ReturnType<CortiClient[\"transcribe\"][\"connect\"]>\n>;\n\ninterface DictationControllerHost extends ReactiveControllerHost {\n _accessToken?: string;\n _authConfig?: Corti.BearerOptions;\n _region?: string;\n _tenantName?: string;\n _socketUrl?: string;\n _socketProxy?: ProxyOptions;\n _dictationConfig?: Corti.TranscribeConfig;\n}\n\nexport type TranscribeMessage =\n | Corti.TranscribeConfigStatusMessage\n | Corti.TranscribeUsageMessage\n | Corti.TranscribeEndedMessage\n | Corti.TranscribeErrorMessage\n | Corti.TranscribeTranscriptMessage\n | Corti.TranscribeCommandMessage\n | Corti.TranscribeFlushedMessage;\n\ninterface WebSocketCallbacks {\n onMessage?: (message: TranscribeMessage) => void;\n onError?: (error: Error) => void;\n onClose?: (event: unknown) => void;\n onNetworkActivity?: (direction: \"sent\" | \"received\", data: unknown) => void;\n}\n\nexport class DictationController implements ReactiveController {\n host: DictationControllerHost;\n\n #cortiClient: CortiClient | null = null;\n #webSocket: TranscribeSocket | null = null;\n #closeTimeout?: number;\n #callbacks?: WebSocketCallbacks;\n #lastDictationConfig: Corti.TranscribeConfig | null = null;\n #lastSocketUrl?: string;\n #lastSocketProxy?: ProxyOptions;\n\n constructor(host: DictationControllerHost) {\n this.host = host;\n host.addController(this);\n }\n\n hostDisconnected(): void {\n this.cleanup();\n }\n\n #configHasChanged(): boolean {\n return (\n JSON.stringify(this.host._dictationConfig) !==\n JSON.stringify(this.#lastDictationConfig) ||\n this.host._socketUrl !== this.#lastSocketUrl ||\n JSON.stringify(this.host._socketProxy) !==\n JSON.stringify(this.#lastSocketProxy)\n );\n }\n\n async connect(\n dictationConfig: Corti.TranscribeConfig = DEFAULT_DICTATION_CONFIG,\n callbacks: WebSocketCallbacks = {},\n ): Promise<boolean> {\n const newConnection = this.#configHasChanged() || !this.isConnectionOpen();\n\n if (newConnection) {\n this.cleanup();\n\n if (this.#webSocket?.readyState === WebSocket.OPEN) {\n throw new Error(\"Already connected. Disconnect before reconnecting.\");\n }\n\n this.#webSocket =\n this.host._socketUrl || this.host._socketProxy\n ? await this.#connectProxy(dictationConfig)\n : await this.#connectAuth(dictationConfig);\n\n this.#callbacks?.onNetworkActivity?.(\"sent\", {\n configuration: dictationConfig,\n type: \"config\",\n });\n\n this.#lastDictationConfig = this.host._dictationConfig || null;\n this.#lastSocketUrl = this.host._socketUrl;\n this.#lastSocketProxy = this.host._socketProxy;\n }\n\n this.#callbacks = callbacks;\n this.#setupWebSocketHandlers(callbacks);\n\n return newConnection;\n }\n\n async #connectProxy(\n dictationConfig: Corti.TranscribeConfig,\n ): Promise<TranscribeSocket> {\n const proxyOptions = this.host._socketProxy || {\n url: this.host._socketUrl || \"\",\n };\n\n if (!proxyOptions.url) {\n throw new Error(\"Proxy URL is required when using proxy client\");\n }\n\n return await CortiWebSocketProxyClient.transcribe.connect({\n configuration: dictationConfig,\n proxy: proxyOptions,\n });\n }\n\n async #connectAuth(\n dictationConfig: Corti.TranscribeConfig,\n ): Promise<TranscribeSocket> {\n if (!this.host._authConfig && !this.host._accessToken) {\n throw new Error(\n \"Auth configuration or access token is required to connect\",\n );\n }\n\n // Use authConfig if available, otherwise create one from accessToken\n const auth: Corti.BearerOptions = this.host._authConfig || {\n accessToken: this.host._accessToken || \"\",\n refreshAccessToken: () => ({\n accessToken: this.host._accessToken || \"\",\n }),\n };\n\n this.#cortiClient = new CortiClient({\n auth,\n environment: this.host._region,\n tenantName: this.host._tenantName,\n });\n\n return await this.#cortiClient.transcribe.connect({\n configuration: dictationConfig,\n });\n }\n\n #setupWebSocketHandlers(callbacks: WebSocketCallbacks): void {\n if (!this.#webSocket) {\n throw new Error(\"WebSocket not initialized\");\n }\n\n this.#webSocket.on(\"message\", (message: TranscribeMessage) => {\n callbacks.onNetworkActivity?.(\"received\", message);\n\n if (callbacks.onMessage) {\n callbacks.onMessage(message);\n }\n });\n\n this.#webSocket.on(\"error\", (event: Error) => {\n if (callbacks.onError) {\n callbacks.onError(event);\n }\n });\n\n this.#webSocket.on(\"close\", (event: unknown) => {\n if (callbacks.onClose) {\n callbacks.onClose(event);\n }\n });\n }\n\n mediaRecorderHandler = (data: Blob): void => {\n this.#webSocket?.sendAudio(data);\n this.#callbacks?.onNetworkActivity?.(\"sent\", {\n size: data.size,\n type: \"audio\",\n });\n };\n\n async pause(): Promise<void> {\n this.#webSocket?.sendFlush({ type: \"flush\" });\n this.#callbacks?.onNetworkActivity?.(\"sent\", { type: \"flush\" });\n }\n\n isConnectionOpen(): boolean {\n return (\n this.#webSocket !== null &&\n (this.#webSocket.readyState === WebSocket.OPEN ||\n this.#webSocket.readyState === WebSocket.CONNECTING)\n );\n }\n\n async closeConnection(onClose?: (event: unknown) => void): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const oldSocket = this.#webSocket;\n this.#webSocket = null;\n\n if (!oldSocket || oldSocket.readyState !== WebSocket.OPEN) {\n resolve();\n return;\n }\n\n oldSocket.on(\"close\", (event) => {\n if (this.#closeTimeout) {\n clearTimeout(this.#closeTimeout);\n this.#closeTimeout = undefined;\n }\n\n if (onClose) {\n onClose(event);\n }\n\n resolve();\n });\n\n oldSocket.on(\"message\", (message) => {\n this.#callbacks?.onNetworkActivity?.(\"received\", message);\n\n if (this.#callbacks?.onMessage) {\n this.#callbacks?.onMessage(message);\n }\n\n if (message.type === \"ended\") {\n if (this.#closeTimeout) {\n clearTimeout(this.#closeTimeout);\n this.#closeTimeout = undefined;\n }\n\n resolve();\n return;\n }\n });\n\n oldSocket.sendEnd({ type: \"end\" });\n this.#callbacks?.onNetworkActivity?.(\"sent\", { type: \"end\" });\n\n this.#closeTimeout = window.setTimeout(() => {\n reject(new Error(\"Connection close timeout\"));\n\n if (oldSocket?.readyState === WebSocket.OPEN) {\n oldSocket.close();\n }\n }, 10000);\n });\n }\n\n cleanup(): void {\n if (this.#closeTimeout) {\n clearTimeout(this.#closeTimeout);\n this.#closeTimeout = undefined;\n }\n\n if (this.#webSocket?.readyState === WebSocket.OPEN) {\n this.#webSocket.close();\n }\n\n this.#webSocket = null;\n this.#cortiClient = null;\n this.#lastDictationConfig = null;\n this.#lastSocketUrl = undefined;\n this.#lastSocketProxy = undefined;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dictation-controller.js","sourceRoot":"","sources":["../../src/controllers/dictation-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Corti,\n type CortiAuth,\n CortiClient,\n CortiWebSocketProxyClient,\n} from \"@corti/sdk\";\nimport type { ReactiveController, ReactiveControllerHost } from \"lit\";\nimport { DEFAULT_DICTATION_CONFIG } from \"../constants.js\";\nimport type { ProxyOptions } from \"../types.js\";\nimport { errorEvent } from \"../utils/events.js\";\n\ntype TranscribeSocket = Awaited<\n ReturnType<CortiClient[\"transcribe\"][\"connect\"]>\n>;\n\ninterface DictationControllerHost extends ReactiveControllerHost {\n dispatchEvent: (event: Event) => void;\n _accessToken?: string;\n _authConfig?: CortiAuth.AuthTokenDerivable;\n _region?: string;\n _tenantName?: string;\n _socketUrl?: string;\n _socketProxy?: ProxyOptions;\n _dictationConfig?: Corti.TranscribeConfig;\n}\n\nexport type TranscribeMessage =\n | Corti.TranscribeConfigStatusMessage\n | Corti.TranscribeUsageMessage\n | Corti.TranscribeDeltaUsageMessage\n | Corti.TranscribeEndedMessage\n | Corti.TranscribeErrorMessage\n | Corti.TranscribeTranscriptMessage\n | Corti.TranscribeCommandMessage\n | Corti.TranscribeFlushedMessage;\n\ntype OutboundItem =\n | Blob\n | Corti.TranscribeFlushMessage\n | Corti.TranscribeEndMessage;\n\ninterface WebSocketCallbacks {\n onMessage?: (message: TranscribeMessage) => void;\n onError?: (error: Error) => void;\n onClose?: (event: unknown) => void;\n onNetworkActivity?: (direction: \"sent\" | \"received\", data: unknown) => void;\n}\n\nexport class DictationController implements ReactiveController {\n host: DictationControllerHost;\n\n #cortiClient: CortiClient | null = null;\n #webSocket: TranscribeSocket | null = null;\n #closeTimeout?: number;\n #callbacks?: WebSocketCallbacks;\n #lastDictationConfig: Corti.TranscribeConfig | null = null;\n #lastSocketUrl?: string;\n #lastSocketProxy?: ProxyOptions;\n #outboundQueue: OutboundItem[] = [];\n #socketReady = false;\n #connectingPromise: Promise<boolean | \"superseded\"> | null = null;\n #connectionGeneration = 0;\n #isConnecting = false;\n\n constructor(host: DictationControllerHost) {\n this.host = host;\n host.addController(this);\n }\n\n hostDisconnected(): void {\n this.cleanup();\n }\n\n #configHasChanged(): boolean {\n return (\n JSON.stringify(this.host._dictationConfig) !==\n JSON.stringify(this.#lastDictationConfig) ||\n this.host._socketUrl !== this.#lastSocketUrl ||\n JSON.stringify(this.host._socketProxy) !==\n JSON.stringify(this.#lastSocketProxy)\n );\n }\n\n async connect(\n dictationConfig: Corti.TranscribeConfig = DEFAULT_DICTATION_CONFIG,\n callbacks: WebSocketCallbacks = {},\n ): Promise<boolean | \"superseded\"> {\n // If a connection attempt is already in progress with the same config, reuse it\n // to avoid opening multiple sockets when connect() is called concurrently.\n if (this.#connectingPromise && !this.#configHasChanged()) {\n return this.#connectingPromise;\n }\n\n // #isConnecting must be set synchronously before #doConnect runs, because\n // #doConnect calls cleanup() which closes the old socket, firing its \"close\"\n // event synchronously. Handlers that check isConnecting() need to see true\n // at that point — before #connectingPromise is even assigned.\n this.#isConnecting = true;\n this.#connectingPromise = this.#doConnect(\n dictationConfig,\n callbacks,\n ).finally(() => {\n this.#isConnecting = false;\n this.#connectingPromise = null;\n });\n\n return this.#connectingPromise;\n }\n\n async #doConnect(\n dictationConfig: Corti.TranscribeConfig,\n callbacks: WebSocketCallbacks,\n ): Promise<boolean | \"superseded\"> {\n const newConnection = this.#configHasChanged() || !this.isConnectionOpen();\n\n if (newConnection) {\n this.cleanup();\n\n this.#lastDictationConfig = this.host._dictationConfig || null;\n this.#lastSocketUrl = this.host._socketUrl;\n this.#lastSocketProxy = this.host._socketProxy;\n\n const generation = this.#connectionGeneration;\n\n const socket =\n this.host._socketUrl || this.host._socketProxy\n ? await this.#connectProxy(dictationConfig)\n : await this.#connectAuth(dictationConfig);\n\n // If cleanup() was called while we were awaiting (e.g. config changed),\n // the generation counter will have advanced — discard this stale socket.\n if (this.#connectionGeneration !== generation) {\n socket.close();\n return \"superseded\";\n }\n\n this.#webSocket = socket;\n\n this.#callbacks?.onNetworkActivity?.(\"sent\", {\n configuration: dictationConfig,\n type: \"config\",\n });\n }\n\n this.#callbacks = callbacks;\n this.#setupWebSocketHandlers(callbacks);\n\n if (!newConnection && this.isConnectionOpen()) {\n this.#socketReady = true;\n this.#drain();\n }\n\n return newConnection;\n }\n\n async #connectProxy(\n dictationConfig: Corti.TranscribeConfig,\n ): Promise<TranscribeSocket> {\n const proxyOptions = this.host._socketProxy || {\n url: this.host._socketUrl || \"\",\n };\n\n if (!proxyOptions.url) {\n throw new Error(\"Proxy URL is required when using proxy client\");\n }\n\n return await CortiWebSocketProxyClient.transcribe.connect({\n // setting to \"false\" to have CONFIG_* message in network activity events\n awaitConfiguration: false,\n configuration: dictationConfig,\n proxy: proxyOptions,\n });\n }\n\n async #connectAuth(\n dictationConfig: Corti.TranscribeConfig,\n ): Promise<TranscribeSocket> {\n if (!this.host._authConfig && !this.host._accessToken) {\n throw new Error(\n \"Auth configuration or access token is required to connect\",\n );\n }\n\n // Use authConfig if available, otherwise create one from accessToken\n const auth: CortiAuth.AuthTokenDerivable = this.host._authConfig || {\n accessToken: this.host._accessToken || \"\",\n refreshAccessToken: () => ({\n accessToken: this.host._accessToken || \"\",\n }),\n };\n\n this.#cortiClient = new CortiClient({\n auth,\n environment: this.host._region,\n tenantName: this.host._tenantName,\n });\n\n return await this.#cortiClient.transcribe.connect({\n // setting to \"false\" to have CONFIG_* message in network activity events\n awaitConfiguration: false,\n configuration: dictationConfig,\n });\n }\n\n #setupWebSocketHandlers(callbacks: WebSocketCallbacks): void {\n if (!this.#webSocket) {\n throw new Error(\"WebSocket not initialized\");\n }\n\n this.#webSocket.on(\"message\", (message: TranscribeMessage) => {\n if (message.type === \"CONFIG_ACCEPTED\") {\n this.#socketReady = true;\n this.#drain();\n }\n\n callbacks.onNetworkActivity?.(\"received\", message);\n\n if (callbacks.onMessage) {\n callbacks.onMessage(message);\n }\n });\n\n this.#webSocket.on(\"error\", (event: Error) => {\n this.#socketReady = false;\n if (callbacks.onError) {\n callbacks.onError(event);\n }\n });\n\n this.#webSocket.on(\"close\", (event: unknown) => {\n this.#socketReady = false;\n if (callbacks.onClose) {\n callbacks.onClose(event);\n }\n });\n }\n\n #isSocketOpen(): boolean {\n return (\n this.#webSocket !== null && this.#webSocket.readyState === WebSocket.OPEN\n );\n }\n\n #drain(): void {\n if (\n !this.#socketReady ||\n !this.#isSocketOpen() ||\n this.#outboundQueue.length === 0\n ) {\n return;\n }\n\n while (this.#outboundQueue.length > 0 && this.#isSocketOpen()) {\n const item = this.#outboundQueue.shift();\n\n if (item === undefined) {\n break;\n }\n\n if (item instanceof Blob) {\n this.#webSocket!.send(item);\n this.#callbacks?.onNetworkActivity?.(\"sent\", {\n size: item.size,\n type: \"audio\",\n });\n continue;\n }\n\n this.#webSocket!.send(JSON.stringify(item));\n this.#callbacks?.onNetworkActivity?.(\"sent\", {\n type: item.type,\n });\n }\n }\n\n mediaRecorderHandler = (data: Blob): void => {\n if (this.#socketReady && this.#isSocketOpen()) {\n this.#webSocket?.send(data);\n this.#callbacks?.onNetworkActivity?.(\"sent\", {\n size: data.size,\n type: \"audio\",\n });\n return;\n }\n\n this.#outboundQueue.push(data);\n };\n\n async pause(): Promise<void> {\n if (this.#socketReady && this.#isSocketOpen()) {\n this.#webSocket?.send(JSON.stringify({ type: \"flush\" }));\n this.#callbacks?.onNetworkActivity?.(\"sent\", { type: \"flush\" });\n return;\n }\n\n this.#outboundQueue.push({ type: \"flush\" });\n }\n\n isConnectionOpen(): boolean {\n return (\n this.#webSocket !== null &&\n (this.#webSocket.readyState === WebSocket.OPEN ||\n this.#webSocket.readyState === WebSocket.CONNECTING)\n );\n }\n\n isConnecting(): boolean {\n return this.#isConnecting;\n }\n\n async waitForConnection(): Promise<void> {\n await this.#connectingPromise;\n }\n\n async closeConnection(onClose?: (event: unknown) => void): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const oldSocket = this.#webSocket;\n this.#webSocket = null;\n\n if (\n !oldSocket ||\n (oldSocket.readyState !== WebSocket.OPEN &&\n oldSocket.readyState !== WebSocket.CONNECTING)\n ) {\n this.#socketReady = false;\n resolve();\n return;\n }\n\n oldSocket.on(\"close\", (event) => {\n if (this.#closeTimeout) {\n clearTimeout(this.#closeTimeout);\n this.#closeTimeout = undefined;\n }\n\n if (onClose) {\n onClose(event);\n }\n\n resolve();\n });\n\n const wasReady = this.#socketReady;\n this.#socketReady = false;\n\n oldSocket.on(\"message\", (message) => {\n this.#callbacks?.onNetworkActivity?.(\"received\", message);\n\n if (this.#callbacks?.onMessage) {\n this.#callbacks?.onMessage(message);\n }\n\n // closeConnection() may be called before CONFIG_ACCEPTED arrives (e.g.\n // openConnection() followed immediately by closeConnection()). We can't\n // use the outbound queue here because #webSocket is already null, so we\n // send \"end\" directly on oldSocket as soon as config is accepted.\n if (!wasReady && message.type === \"CONFIG_ACCEPTED\") {\n oldSocket.sendEnd({ type: \"end\" });\n this.#callbacks?.onNetworkActivity?.(\"sent\", { type: \"end\" });\n return;\n }\n\n if (message.type === \"ended\") {\n if (this.#closeTimeout) {\n clearTimeout(this.#closeTimeout);\n this.#closeTimeout = undefined;\n }\n\n resolve();\n return;\n }\n });\n\n if (wasReady) {\n oldSocket.sendEnd({ type: \"end\" });\n this.#callbacks?.onNetworkActivity?.(\"sent\", { type: \"end\" });\n }\n\n this.#closeTimeout = window.setTimeout(() => {\n reject(new Error(\"Connection close timeout\"));\n\n if (oldSocket?.readyState === WebSocket.OPEN) {\n oldSocket.close();\n }\n }, 10000);\n });\n }\n\n cleanup(): void {\n // Incrementing generation invalidates any in-flight #doConnect awaits,\n // causing them to discard their socket and return \"superseded\".\n this.#connectionGeneration++;\n this.#socketReady = false;\n\n if (this.#closeTimeout) {\n clearTimeout(this.#closeTimeout);\n this.#closeTimeout = undefined;\n }\n\n if (this.isConnectionOpen()) {\n this.#webSocket?.close();\n }\n\n this.#webSocket = null;\n this.#cortiClient = null;\n this.#lastDictationConfig = null;\n this.#lastSocketUrl = undefined;\n this.#lastSocketProxy = undefined;\n\n if (this.#outboundQueue.length > 0) {\n this.host.dispatchEvent(\n errorEvent(\n `${this.#outboundQueue.length} unsent message(s) were discarded because the configuration changed before the connection was closed`,\n ),\n );\n }\n\n this.#outboundQueue = [];\n }\n}\n"]}
|
|
@@ -9,7 +9,7 @@ export declare class MediaController implements ReactiveController {
|
|
|
9
9
|
host: MediaControllerHost;
|
|
10
10
|
constructor(host: MediaControllerHost);
|
|
11
11
|
hostDisconnected(): void;
|
|
12
|
-
initialize(onTrackEnded?: () => void): Promise<void>;
|
|
12
|
+
initialize(onTrackEnded?: () => void, dataHandler?: (data: Blob) => void): Promise<void>;
|
|
13
13
|
getAudioLevel(): number;
|
|
14
14
|
startAudioLevelMonitoring(onAudioLevelChange?: (level: number) => void): void;
|
|
15
15
|
stopAudioLevelMonitoring(): void;
|
|
@@ -19,8 +19,6 @@ export declare class MediaController implements ReactiveController {
|
|
|
19
19
|
* This ensures the final ondataavailable event fires before resolving.
|
|
20
20
|
*/
|
|
21
21
|
stopRecording(): Promise<void>;
|
|
22
|
-
addDataHandler(handler: (data: Blob) => void): void;
|
|
23
|
-
removeDataHandler(): void;
|
|
24
22
|
get mediaRecorder(): MediaRecorder | null;
|
|
25
23
|
get audioLevel(): number;
|
|
26
24
|
}
|
|
@@ -9,8 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _MediaController_mediaStream, _MediaController_audioContext, _MediaController_analyser, _MediaController_mediaRecorder, _MediaController_visualiserInterval, _MediaController_audioLevel, _MediaController_onTrackEnded, _MediaController_onAudioLevelChange, _MediaController_dataHandler
|
|
13
|
-
import { errorEvent } from "../utils/events.js";
|
|
12
|
+
var _MediaController_mediaStream, _MediaController_audioContext, _MediaController_analyser, _MediaController_mediaRecorder, _MediaController_visualiserInterval, _MediaController_audioLevel, _MediaController_onTrackEnded, _MediaController_onAudioLevelChange, _MediaController_dataHandler;
|
|
14
13
|
import { calculateAudioLevel, createAudioAnalyzer, getMediaStream, } from "../utils/media.js";
|
|
15
14
|
export class MediaController {
|
|
16
15
|
constructor(host) {
|
|
@@ -23,16 +22,16 @@ export class MediaController {
|
|
|
23
22
|
_MediaController_onTrackEnded.set(this, void 0);
|
|
24
23
|
_MediaController_onAudioLevelChange.set(this, void 0);
|
|
25
24
|
_MediaController_dataHandler.set(this, void 0);
|
|
26
|
-
_MediaController_bufferedChunks.set(this, []);
|
|
27
25
|
this.host = host;
|
|
28
26
|
host.addController(this);
|
|
29
27
|
}
|
|
30
28
|
hostDisconnected() {
|
|
31
29
|
this.cleanup();
|
|
32
30
|
}
|
|
33
|
-
async initialize(onTrackEnded) {
|
|
31
|
+
async initialize(onTrackEnded, dataHandler) {
|
|
34
32
|
await this.cleanup();
|
|
35
33
|
__classPrivateFieldSet(this, _MediaController_onTrackEnded, onTrackEnded, "f");
|
|
34
|
+
__classPrivateFieldSet(this, _MediaController_dataHandler, dataHandler, "f");
|
|
36
35
|
__classPrivateFieldSet(this, _MediaController_mediaStream, await getMediaStream(this.host._selectedDevice?.deviceId, this.host._debug_displayAudio), "f");
|
|
37
36
|
__classPrivateFieldGet(this, _MediaController_mediaStream, "f").getTracks().forEach((track) => {
|
|
38
37
|
track.addEventListener("ended", () => {
|
|
@@ -48,9 +47,7 @@ export class MediaController {
|
|
|
48
47
|
__classPrivateFieldGet(this, _MediaController_mediaRecorder, "f").ondataavailable = (event) => {
|
|
49
48
|
if (__classPrivateFieldGet(this, _MediaController_dataHandler, "f")) {
|
|
50
49
|
__classPrivateFieldGet(this, _MediaController_dataHandler, "f").call(this, event.data);
|
|
51
|
-
return;
|
|
52
50
|
}
|
|
53
|
-
__classPrivateFieldGet(this, _MediaController_bufferedChunks, "f").push(event.data);
|
|
54
51
|
};
|
|
55
52
|
}
|
|
56
53
|
getAudioLevel() {
|
|
@@ -101,7 +98,6 @@ export class MediaController {
|
|
|
101
98
|
__classPrivateFieldSet(this, _MediaController_onTrackEnded, undefined, "f");
|
|
102
99
|
__classPrivateFieldSet(this, _MediaController_onAudioLevelChange, undefined, "f");
|
|
103
100
|
__classPrivateFieldSet(this, _MediaController_dataHandler, undefined, "f");
|
|
104
|
-
__classPrivateFieldSet(this, _MediaController_bufferedChunks, [], "f");
|
|
105
101
|
}
|
|
106
102
|
/**
|
|
107
103
|
* Stops the media recorder and waits for all buffered data to be flushed.
|
|
@@ -119,20 +115,6 @@ export class MediaController {
|
|
|
119
115
|
__classPrivateFieldGet(this, _MediaController_mediaRecorder, "f").stop();
|
|
120
116
|
});
|
|
121
117
|
}
|
|
122
|
-
addDataHandler(handler) {
|
|
123
|
-
for (const chunk of __classPrivateFieldGet(this, _MediaController_bufferedChunks, "f")) {
|
|
124
|
-
handler(chunk);
|
|
125
|
-
}
|
|
126
|
-
__classPrivateFieldSet(this, _MediaController_bufferedChunks, [], "f");
|
|
127
|
-
__classPrivateFieldSet(this, _MediaController_dataHandler, handler, "f");
|
|
128
|
-
}
|
|
129
|
-
removeDataHandler() {
|
|
130
|
-
if (__classPrivateFieldGet(this, _MediaController_bufferedChunks, "f").length > 0) {
|
|
131
|
-
this.host.dispatchEvent(errorEvent("Connection timeout: server did not respond in time. Buffered audio was not processed."));
|
|
132
|
-
__classPrivateFieldSet(this, _MediaController_bufferedChunks, [], "f");
|
|
133
|
-
}
|
|
134
|
-
__classPrivateFieldSet(this, _MediaController_dataHandler, undefined, "f");
|
|
135
|
-
}
|
|
136
118
|
get mediaRecorder() {
|
|
137
119
|
return __classPrivateFieldGet(this, _MediaController_mediaRecorder, "f");
|
|
138
120
|
}
|
|
@@ -140,5 +122,5 @@ export class MediaController {
|
|
|
140
122
|
return __classPrivateFieldGet(this, _MediaController_audioLevel, "f");
|
|
141
123
|
}
|
|
142
124
|
}
|
|
143
|
-
_MediaController_mediaStream = new WeakMap(), _MediaController_audioContext = new WeakMap(), _MediaController_analyser = new WeakMap(), _MediaController_mediaRecorder = new WeakMap(), _MediaController_visualiserInterval = new WeakMap(), _MediaController_audioLevel = new WeakMap(), _MediaController_onTrackEnded = new WeakMap(), _MediaController_onAudioLevelChange = new WeakMap(), _MediaController_dataHandler = new WeakMap()
|
|
125
|
+
_MediaController_mediaStream = new WeakMap(), _MediaController_audioContext = new WeakMap(), _MediaController_analyser = new WeakMap(), _MediaController_mediaRecorder = new WeakMap(), _MediaController_visualiserInterval = new WeakMap(), _MediaController_audioLevel = new WeakMap(), _MediaController_onTrackEnded = new WeakMap(), _MediaController_onAudioLevelChange = new WeakMap(), _MediaController_dataHandler = new WeakMap();
|
|
144
126
|
//# sourceMappingURL=media-controller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-controller.js","sourceRoot":"","sources":["../../src/controllers/media-controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"media-controller.js","sourceRoot":"","sources":["../../src/controllers/media-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from \"lit\";\nimport {\n calculateAudioLevel,\n createAudioAnalyzer,\n getMediaStream,\n} from \"../utils/media.js\";\n\ninterface MediaControllerHost extends ReactiveControllerHost {\n _selectedDevice?: MediaDeviceInfo;\n _debug_displayAudio?: boolean;\n dispatchEvent(event: Event): boolean;\n}\n\nexport class MediaController implements ReactiveController {\n host: MediaControllerHost;\n\n #mediaStream: MediaStream | null = null;\n #audioContext: AudioContext | null = null;\n #analyser: AnalyserNode | null = null;\n #mediaRecorder: MediaRecorder | null = null;\n #visualiserInterval?: number;\n #audioLevel: number = 0;\n #onTrackEnded?: () => void;\n #onAudioLevelChange?: (level: number) => void;\n #dataHandler?: (data: Blob) => void;\n\n constructor(host: MediaControllerHost) {\n this.host = host;\n host.addController(this);\n }\n\n hostDisconnected(): void {\n this.cleanup();\n }\n\n async initialize(\n onTrackEnded?: () => void,\n dataHandler?: (data: Blob) => void,\n ): Promise<void> {\n await this.cleanup();\n\n this.#onTrackEnded = onTrackEnded;\n this.#dataHandler = dataHandler;\n this.#mediaStream = await getMediaStream(\n this.host._selectedDevice?.deviceId,\n this.host._debug_displayAudio,\n );\n\n this.#mediaStream.getTracks().forEach((track: MediaStreamTrack) => {\n track.addEventListener(\"ended\", () => {\n if (this.#onTrackEnded) {\n this.#onTrackEnded();\n }\n });\n });\n\n const { audioContext, analyser } = createAudioAnalyzer(this.#mediaStream);\n\n this.#audioContext = audioContext;\n this.#analyser = analyser;\n\n this.#mediaRecorder = new MediaRecorder(this.#mediaStream);\n this.#mediaRecorder.ondataavailable = (event) => {\n if (this.#dataHandler) {\n this.#dataHandler(event.data);\n }\n };\n }\n\n getAudioLevel(): number {\n return this.#analyser ? calculateAudioLevel(this.#analyser) : 0;\n }\n\n startAudioLevelMonitoring(\n onAudioLevelChange?: (level: number) => void,\n ): void {\n this.stopAudioLevelMonitoring();\n\n this.#onAudioLevelChange = onAudioLevelChange;\n\n this.#visualiserInterval = window.setInterval(() => {\n this.#audioLevel = this.getAudioLevel() * 3;\n this.host.requestUpdate();\n\n if (this.#onAudioLevelChange) {\n this.#onAudioLevelChange(this.#audioLevel);\n }\n }, 150);\n }\n\n stopAudioLevelMonitoring(): void {\n if (this.#visualiserInterval) {\n clearInterval(this.#visualiserInterval);\n this.#visualiserInterval = undefined;\n }\n\n this.#audioLevel = 0;\n this.host.requestUpdate();\n\n if (this.#onAudioLevelChange) {\n this.#onAudioLevelChange(this.#audioLevel);\n }\n }\n\n async cleanup(): Promise<void> {\n this.stopAudioLevelMonitoring();\n\n if (this.#mediaRecorder?.state === \"recording\") {\n this.#mediaRecorder.stop();\n }\n\n if (this.#mediaRecorder) {\n this.#mediaRecorder.ondataavailable = null;\n }\n\n if (this.#mediaStream) {\n this.#mediaStream.getTracks().forEach((track) => {\n track.stop();\n });\n this.#mediaStream = null;\n }\n\n if (this.#audioContext && this.#audioContext.state !== \"closed\") {\n await this.#audioContext.close();\n }\n\n this.#audioContext = null;\n\n this.#analyser = null;\n this.#mediaRecorder = null;\n this.#onTrackEnded = undefined;\n this.#onAudioLevelChange = undefined;\n this.#dataHandler = undefined;\n }\n\n /**\n * Stops the media recorder and waits for all buffered data to be flushed.\n * This ensures the final ondataavailable event fires before resolving.\n */\n async stopRecording(): Promise<void> {\n return new Promise<void>((resolve) => {\n if (!this.#mediaRecorder || this.#mediaRecorder.state !== \"recording\") {\n resolve();\n return;\n }\n\n this.#mediaRecorder.onstop = () => {\n resolve();\n };\n\n this.#mediaRecorder.stop();\n });\n }\n\n get mediaRecorder(): MediaRecorder | null {\n return this.#mediaRecorder;\n }\n\n get audioLevel(): number {\n return this.#audioLevel;\n }\n}\n"]}
|
package/dist/icons/icons.d.ts
CHANGED
package/dist/icons/icons.js
CHANGED
|
@@ -5,8 +5,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
/* eslint-disable max-classes-per-file */
|
|
8
|
-
import {
|
|
9
|
-
import { customElement } from
|
|
8
|
+
import { css, html, LitElement } from "lit";
|
|
9
|
+
import { customElement } from "lit/decorators.js";
|
|
10
10
|
let IconMicOn = class IconMicOn extends LitElement {
|
|
11
11
|
render() {
|
|
12
12
|
return html `
|
|
@@ -32,7 +32,7 @@ let IconMicOn = class IconMicOn extends LitElement {
|
|
|
32
32
|
}
|
|
33
33
|
};
|
|
34
34
|
IconMicOn = __decorate([
|
|
35
|
-
customElement(
|
|
35
|
+
customElement("icon-mic-on")
|
|
36
36
|
], IconMicOn);
|
|
37
37
|
export { IconMicOn };
|
|
38
38
|
let IconMicOff = class IconMicOff extends LitElement {
|
|
@@ -61,7 +61,7 @@ let IconMicOff = class IconMicOff extends LitElement {
|
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
IconMicOff = __decorate([
|
|
64
|
-
customElement(
|
|
64
|
+
customElement("icon-mic-off")
|
|
65
65
|
], IconMicOff);
|
|
66
66
|
export { IconMicOff };
|
|
67
67
|
let IconRecording = class IconRecording extends LitElement {
|
|
@@ -88,7 +88,7 @@ let IconRecording = class IconRecording extends LitElement {
|
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
90
|
IconRecording = __decorate([
|
|
91
|
-
customElement(
|
|
91
|
+
customElement("icon-recording")
|
|
92
92
|
], IconRecording);
|
|
93
93
|
export { IconRecording };
|
|
94
94
|
let IconSettings = class IconSettings extends LitElement {
|
|
@@ -115,7 +115,7 @@ let IconSettings = class IconSettings extends LitElement {
|
|
|
115
115
|
}
|
|
116
116
|
};
|
|
117
117
|
IconSettings = __decorate([
|
|
118
|
-
customElement(
|
|
118
|
+
customElement("icon-settings")
|
|
119
119
|
], IconSettings);
|
|
120
120
|
export { IconSettings };
|
|
121
121
|
let IconLoadingSpinner = class IconLoadingSpinner extends LitElement {
|
|
@@ -152,7 +152,7 @@ IconLoadingSpinner.styles = css `
|
|
|
152
152
|
}
|
|
153
153
|
`;
|
|
154
154
|
IconLoadingSpinner = __decorate([
|
|
155
|
-
customElement(
|
|
155
|
+
customElement("icon-loading-spinner")
|
|
156
156
|
], IconLoadingSpinner);
|
|
157
157
|
export { IconLoadingSpinner };
|
|
158
158
|
//# sourceMappingURL=icons.js.map
|
package/dist/icons/icons.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icons.js","sourceRoot":"","sources":["../../src/icons/icons.ts"],"names":[],"mappings":";;;;;;AAAA,yCAAyC;AACzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"icons.js","sourceRoot":"","sources":["../../src/icons/icons.ts"],"names":[],"mappings":";;;;;;AAAA,yCAAyC;AACzC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAG3C,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,UAAU;IACvC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;KAmBV,CAAC;IACJ,CAAC;CACF,CAAA;AAvBY,SAAS;IADrB,aAAa,CAAC,aAAa,CAAC;GAChB,SAAS,CAuBrB;;AAGM,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IACxC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;WAoBJ,CAAC;IACV,CAAC;CACF,CAAA;AAxBY,UAAU;IADtB,aAAa,CAAC,cAAc,CAAC;GACjB,UAAU,CAwBtB;;AAGM,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;IAC3C,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;KAkBV,CAAC;IACJ,CAAC;CACF,CAAA;AAtBY,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAsBzB;;AAEM,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAC1C,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;WAkBJ,CAAC;IACV,CAAC;CACF,CAAA;AAtBY,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CAsBxB;;AAGM,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,UAAU;IAehD,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;WAeJ,CAAC;IACV,CAAC;;AA/BM,yBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;GAYlB,AAZY,CAYX;AAbS,kBAAkB;IAD9B,aAAa,CAAC,sBAAsB,CAAC;GACzB,kBAAkB,CAiC9B","sourcesContent":["/* eslint-disable max-classes-per-file */\nimport { css, html, LitElement } from \"lit\";\nimport { customElement } from \"lit/decorators.js\";\n\n@customElement(\"icon-mic-on\")\nexport class IconMicOn extends LitElement {\n render() {\n return html`\n <div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-mic\"\n >\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\" />\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n </div>\n `;\n }\n}\n\n@customElement(\"icon-mic-off\")\nexport class IconMicOff extends LitElement {\n render() {\n return html` <div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-mic-off\"\n >\n <line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\" />\n <path d=\"M18.89 13.23A7.12 7.12 0 0 0 19 12v-2\" />\n <path d=\"M5 10v2a7 7 0 0 0 12 5\" />\n <path d=\"M15 9.34V5a3 3 0 0 0-5.68-1.33\" />\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12\" />\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\" />\n </svg>\n </div>`;\n }\n}\n\n@customElement(\"icon-recording\")\nexport class IconRecording extends LitElement {\n render() {\n return html`\n <div style=\"display: flex;\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-circle-stop\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <rect x=\"9\" y=\"9\" width=\"6\" height=\"6\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </div>\n `;\n }\n}\n@customElement(\"icon-settings\")\nexport class IconSettings extends LitElement {\n render() {\n return html`<div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-settings-2\"\n >\n <path d=\"M20 7h-9\" />\n <path d=\"M14 17H5\" />\n <circle cx=\"17\" cy=\"17\" r=\"3\" />\n <circle cx=\"7\" cy=\"7\" r=\"3\" />\n </svg>\n </div>`;\n }\n}\n\n@customElement(\"icon-loading-spinner\")\nexport class IconLoadingSpinner extends LitElement {\n static styles = css`\n @keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n .spin {\n animation: spin 1s linear infinite;\n }\n `;\n\n render() {\n return html`<div style=\"display: flex\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"lucide lucide-loader-circle spin\"\n >\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n </div>`;\n }\n}\n"]}
|