@estuary-ai/sdk 0.1.27 → 0.1.29
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 +34 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -49
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5045,9 +5045,9 @@ var init_livekit_voice = __esm({
|
|
|
5045
5045
|
_isActive = false;
|
|
5046
5046
|
speakingStateCallback = null;
|
|
5047
5047
|
audioLevelCallback = null;
|
|
5048
|
-
// Audio
|
|
5049
|
-
|
|
5050
|
-
|
|
5048
|
+
// Audio level polling (via LiveKit's server-pushed participant.audioLevel)
|
|
5049
|
+
botParticipant = null;
|
|
5050
|
+
smoothedAudioLevel = 0;
|
|
5051
5051
|
audioLevelPollTimer = null;
|
|
5052
5052
|
_isBotSpeaking = false;
|
|
5053
5053
|
constructor(socketManager, logger) {
|
|
@@ -5105,15 +5105,17 @@ var init_livekit_voice = __esm({
|
|
|
5105
5105
|
}
|
|
5106
5106
|
audioElement.play().catch(() => {
|
|
5107
5107
|
});
|
|
5108
|
-
this.
|
|
5108
|
+
this.botParticipant = participant;
|
|
5109
5109
|
if (this._isBotSpeaking) {
|
|
5110
|
-
|
|
5110
|
+
this.startAudioLevelPolling();
|
|
5111
5111
|
}
|
|
5112
5112
|
}
|
|
5113
5113
|
});
|
|
5114
5114
|
this.room.on(RoomEvent.TrackUnsubscribed, (track) => {
|
|
5115
5115
|
if (track.kind === Track.Kind.Audio) {
|
|
5116
|
-
this.
|
|
5116
|
+
this.stopAudioLevelPolling();
|
|
5117
|
+
this.botParticipant = null;
|
|
5118
|
+
this.smoothedAudioLevel = 0;
|
|
5117
5119
|
track.detach().forEach((el) => el.remove());
|
|
5118
5120
|
}
|
|
5119
5121
|
});
|
|
@@ -5121,7 +5123,9 @@ var init_livekit_voice = __esm({
|
|
|
5121
5123
|
this.logger.debug("LiveKit room disconnected");
|
|
5122
5124
|
this._isActive = false;
|
|
5123
5125
|
this._isBotSpeaking = false;
|
|
5124
|
-
this.
|
|
5126
|
+
this.stopAudioLevelPolling();
|
|
5127
|
+
this.botParticipant = null;
|
|
5128
|
+
this.smoothedAudioLevel = 0;
|
|
5125
5129
|
this.speakingStateCallback?.(false);
|
|
5126
5130
|
});
|
|
5127
5131
|
try {
|
|
@@ -5177,7 +5181,9 @@ var init_livekit_voice = __esm({
|
|
|
5177
5181
|
} catch {
|
|
5178
5182
|
}
|
|
5179
5183
|
this._isBotSpeaking = false;
|
|
5180
|
-
this.
|
|
5184
|
+
this.stopAudioLevelPolling();
|
|
5185
|
+
this.botParticipant = null;
|
|
5186
|
+
this.smoothedAudioLevel = 0;
|
|
5181
5187
|
this.speakingStateCallback?.(false);
|
|
5182
5188
|
if (this.room) {
|
|
5183
5189
|
for (const [, publication] of this.room.localParticipant.trackPublications) {
|
|
@@ -5202,7 +5208,9 @@ var init_livekit_voice = __esm({
|
|
|
5202
5208
|
this.speakingStateCallback = null;
|
|
5203
5209
|
this.audioLevelCallback = null;
|
|
5204
5210
|
this._isBotSpeaking = false;
|
|
5205
|
-
this.
|
|
5211
|
+
this.stopAudioLevelPolling();
|
|
5212
|
+
this.botParticipant = null;
|
|
5213
|
+
this.smoothedAudioLevel = 0;
|
|
5206
5214
|
if (this.room) {
|
|
5207
5215
|
this.room.disconnect();
|
|
5208
5216
|
this.room = null;
|
|
@@ -5210,44 +5218,19 @@ var init_livekit_voice = __esm({
|
|
|
5210
5218
|
this._isActive = false;
|
|
5211
5219
|
this._isMuted = false;
|
|
5212
5220
|
}
|
|
5213
|
-
// ─── Audio
|
|
5214
|
-
async setupAnalyser(track) {
|
|
5215
|
-
this.teardownAnalyser();
|
|
5216
|
-
try {
|
|
5217
|
-
const { createAudioAnalyser } = await import('livekit-client');
|
|
5218
|
-
const { analyser, calculateVolume, cleanup } = createAudioAnalyser(track, {
|
|
5219
|
-
fftSize: 256,
|
|
5220
|
-
smoothingTimeConstant: 0.3
|
|
5221
|
-
});
|
|
5222
|
-
if (analyser.context.state === "suspended") {
|
|
5223
|
-
await analyser.context.resume();
|
|
5224
|
-
}
|
|
5225
|
-
this.calculateVolume = calculateVolume;
|
|
5226
|
-
this.analyserCleanup = cleanup;
|
|
5227
|
-
this.logger.debug("Audio analyser created for bot track");
|
|
5228
|
-
} catch (err) {
|
|
5229
|
-
this.logger.debug("Failed to create audio analyser:", err);
|
|
5230
|
-
}
|
|
5231
|
-
}
|
|
5232
|
-
teardownAnalyser() {
|
|
5233
|
-
this.stopAudioLevelPolling();
|
|
5234
|
-
if (this.analyserCleanup) {
|
|
5235
|
-
this.analyserCleanup().catch(() => {
|
|
5236
|
-
});
|
|
5237
|
-
this.analyserCleanup = null;
|
|
5238
|
-
}
|
|
5239
|
-
this.calculateVolume = null;
|
|
5240
|
-
}
|
|
5221
|
+
// ─── Audio Level Polling (participant.audioLevel) ───────────────
|
|
5241
5222
|
startAudioLevelPolling() {
|
|
5242
5223
|
if (this.audioLevelPollTimer !== null) return;
|
|
5243
|
-
if (!this.
|
|
5224
|
+
if (!this.botParticipant) return;
|
|
5225
|
+
const alpha = 0.35;
|
|
5244
5226
|
this.audioLevelPollTimer = setInterval(() => {
|
|
5245
|
-
if (!this.
|
|
5227
|
+
if (!this.botParticipant) {
|
|
5246
5228
|
this.stopAudioLevelPolling();
|
|
5247
5229
|
return;
|
|
5248
5230
|
}
|
|
5249
|
-
const
|
|
5250
|
-
this.
|
|
5231
|
+
const raw = this.botParticipant.audioLevel ?? 0;
|
|
5232
|
+
this.smoothedAudioLevel += alpha * (raw - this.smoothedAudioLevel);
|
|
5233
|
+
this.audioLevelCallback?.(this.smoothedAudioLevel);
|
|
5251
5234
|
}, 33);
|
|
5252
5235
|
}
|
|
5253
5236
|
stopAudioLevelPolling() {
|
|
@@ -5255,6 +5238,7 @@ var init_livekit_voice = __esm({
|
|
|
5255
5238
|
clearInterval(this.audioLevelPollTimer);
|
|
5256
5239
|
this.audioLevelPollTimer = null;
|
|
5257
5240
|
}
|
|
5241
|
+
this.smoothedAudioLevel = 0;
|
|
5258
5242
|
}
|
|
5259
5243
|
// ─── Private ────────────────────────────────────────────────────
|
|
5260
5244
|
requestToken() {
|
|
@@ -9183,24 +9167,24 @@ async function isLiveKitAvailable() {
|
|
|
9183
9167
|
async function createVoiceManager(transport, socketManager, sampleRate, logger) {
|
|
9184
9168
|
if (transport === "websocket") {
|
|
9185
9169
|
const { WebSocketVoiceManager: WebSocketVoiceManager2 } = await Promise.resolve().then(() => (init_websocket_voice(), websocket_voice_exports));
|
|
9186
|
-
return new WebSocketVoiceManager2(socketManager, sampleRate, logger);
|
|
9170
|
+
return { manager: new WebSocketVoiceManager2(socketManager, sampleRate, logger), resolvedTransport: "websocket" };
|
|
9187
9171
|
}
|
|
9188
9172
|
if (transport === "livekit") {
|
|
9189
9173
|
if (await isLiveKitAvailable()) {
|
|
9190
9174
|
const { LiveKitVoiceManager: LiveKitVoiceManager2 } = await Promise.resolve().then(() => (init_livekit_voice(), livekit_voice_exports));
|
|
9191
|
-
return new LiveKitVoiceManager2(socketManager, logger);
|
|
9175
|
+
return { manager: new LiveKitVoiceManager2(socketManager, logger), resolvedTransport: "livekit" };
|
|
9192
9176
|
}
|
|
9193
9177
|
logger.warn("livekit-client not installed, falling back to WebSocket voice");
|
|
9194
9178
|
const { WebSocketVoiceManager: WebSocketVoiceManager2 } = await Promise.resolve().then(() => (init_websocket_voice(), websocket_voice_exports));
|
|
9195
|
-
return new WebSocketVoiceManager2(socketManager, sampleRate, logger);
|
|
9179
|
+
return { manager: new WebSocketVoiceManager2(socketManager, sampleRate, logger), resolvedTransport: "websocket" };
|
|
9196
9180
|
}
|
|
9197
9181
|
if (transport === "auto") {
|
|
9198
9182
|
if (await isLiveKitAvailable()) {
|
|
9199
9183
|
const { LiveKitVoiceManager: LiveKitVoiceManager2 } = await Promise.resolve().then(() => (init_livekit_voice(), livekit_voice_exports));
|
|
9200
|
-
return new LiveKitVoiceManager2(socketManager, logger);
|
|
9184
|
+
return { manager: new LiveKitVoiceManager2(socketManager, logger), resolvedTransport: "livekit" };
|
|
9201
9185
|
}
|
|
9202
9186
|
const { WebSocketVoiceManager: WebSocketVoiceManager2 } = await Promise.resolve().then(() => (init_websocket_voice(), websocket_voice_exports));
|
|
9203
|
-
return new WebSocketVoiceManager2(socketManager, sampleRate, logger);
|
|
9187
|
+
return { manager: new WebSocketVoiceManager2(socketManager, sampleRate, logger), resolvedTransport: "websocket" };
|
|
9204
9188
|
}
|
|
9205
9189
|
return null;
|
|
9206
9190
|
}
|
|
@@ -9688,11 +9672,12 @@ var EstuaryClient = class extends TypedEventEmitter {
|
|
|
9688
9672
|
}
|
|
9689
9673
|
const transport = this.config.voiceTransport ?? "auto";
|
|
9690
9674
|
const sampleRate = this.config.audioSampleRate ?? DEFAULT_SAMPLE_RATE;
|
|
9691
|
-
|
|
9692
|
-
if (!
|
|
9675
|
+
const result = await createVoiceManager(transport, this.socketManager, sampleRate, this.logger);
|
|
9676
|
+
if (!result) {
|
|
9693
9677
|
throw new exports.EstuaryError("VOICE_NOT_SUPPORTED" /* VOICE_NOT_SUPPORTED */, "No voice transport available");
|
|
9694
9678
|
}
|
|
9695
|
-
|
|
9679
|
+
this.voiceManager = result.manager;
|
|
9680
|
+
if (!this.audioPlayer && result.resolvedTransport === "websocket" && typeof AudioContext !== "undefined") {
|
|
9696
9681
|
this.audioPlayer = new AudioPlayer(sampleRate, (event) => {
|
|
9697
9682
|
if (event.type === "started") {
|
|
9698
9683
|
this._hasAutoInterrupted = true;
|