@absolutejs/voice 0.0.22-beta.643 → 0.0.22-beta.644
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 +30 -2
- package/dist/testing/index.js +30 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4574,6 +4574,8 @@ var createVoiceSession = (options) => {
|
|
|
4574
4574
|
user: 0
|
|
4575
4575
|
};
|
|
4576
4576
|
const recordingFormats = {};
|
|
4577
|
+
const recordingStartedAt = Date.now();
|
|
4578
|
+
let assistantRecordingEndsAtMs = 0;
|
|
4577
4579
|
let recordingPersisted = false;
|
|
4578
4580
|
const captureRecordingChunk = (channel, bytes, format) => {
|
|
4579
4581
|
if (!recordingConfig || recordingPersisted) {
|
|
@@ -4589,11 +4591,33 @@ var createVoiceSession = (options) => {
|
|
|
4589
4591
|
if (currentTotal >= recordingMaxBytes) {
|
|
4590
4592
|
return;
|
|
4591
4593
|
}
|
|
4592
|
-
const
|
|
4594
|
+
const bytesPerSample = 2;
|
|
4595
|
+
const bytesPerSecond = format.sampleRateHz * format.channels * bytesPerSample;
|
|
4596
|
+
let chunkStartMs = currentTotal / bytesPerSecond * 1000;
|
|
4597
|
+
if (channel === "assistant" || currentTotal === 0) {
|
|
4598
|
+
const wallClockOffsetMs = Math.max(0, Date.now() - recordingStartedAt);
|
|
4599
|
+
chunkStartMs = channel === "assistant" ? Math.max(wallClockOffsetMs, assistantRecordingEndsAtMs) : wallClockOffsetMs;
|
|
4600
|
+
const targetByteOffset = Math.floor(chunkStartMs * bytesPerSecond / 1000 / bytesPerSample) * bytesPerSample;
|
|
4601
|
+
const silenceByteLength = Math.min(Math.max(0, targetByteOffset - currentTotal), recordingMaxBytes - currentTotal);
|
|
4602
|
+
if (silenceByteLength > 0) {
|
|
4603
|
+
recordingBuffers[channel].push(new Uint8Array(silenceByteLength));
|
|
4604
|
+
recordingByteTotals[channel] += silenceByteLength;
|
|
4605
|
+
}
|
|
4606
|
+
if (channel === "assistant") {
|
|
4607
|
+
assistantRecordingEndsAtMs = chunkStartMs + bytes.byteLength / bytesPerSecond * 1000;
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
const updatedTotal = recordingByteTotals[channel];
|
|
4611
|
+
if (updatedTotal >= recordingMaxBytes) {
|
|
4612
|
+
recordingFormats[channel] = format;
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
4615
|
+
const remaining = recordingMaxBytes - updatedTotal;
|
|
4593
4616
|
const slice = bytes.byteLength <= remaining ? bytes : bytes.subarray(0, remaining);
|
|
4594
4617
|
recordingBuffers[channel].push(new Uint8Array(slice));
|
|
4595
4618
|
recordingByteTotals[channel] += slice.byteLength;
|
|
4596
4619
|
recordingFormats[channel] = format;
|
|
4620
|
+
return { byteLength: slice.byteLength, startMs: chunkStartMs };
|
|
4597
4621
|
};
|
|
4598
4622
|
const pruneTurnAudio = () => {
|
|
4599
4623
|
const replayWindowMs = sttFallback?.replayWindowMs ?? DEFAULT_FALLBACK_REPLAY_MS;
|
|
@@ -4921,7 +4945,7 @@ var createVoiceSession = (options) => {
|
|
|
4921
4945
|
};
|
|
4922
4946
|
const sendAssistantAudio = async (chunk, input) => {
|
|
4923
4947
|
const normalizedChunk = chunk instanceof Uint8Array ? new Uint8Array(chunk) : chunk instanceof ArrayBuffer ? new Uint8Array(chunk.slice(0)) : new Uint8Array(chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength));
|
|
4924
|
-
captureRecordingChunk("assistant", normalizedChunk, input.format);
|
|
4948
|
+
const recordingChunk = captureRecordingChunk("assistant", normalizedChunk, input.format);
|
|
4925
4949
|
kickCallSilenceWatchdog();
|
|
4926
4950
|
await send({
|
|
4927
4951
|
chunkBase64: encodeBase64(normalizedChunk),
|
|
@@ -4940,6 +4964,10 @@ var createVoiceSession = (options) => {
|
|
|
4940
4964
|
if (activeTTSTurnId) {
|
|
4941
4965
|
await appendTurnLatencyStage({
|
|
4942
4966
|
at: input.receivedAt,
|
|
4967
|
+
metadata: recordingChunk ? {
|
|
4968
|
+
recordingByteLength: recordingChunk.byteLength,
|
|
4969
|
+
recordingStartMs: recordingChunk.startMs
|
|
4970
|
+
} : undefined,
|
|
4943
4971
|
stage: "assistant_audio_received",
|
|
4944
4972
|
turnId: activeTTSTurnId
|
|
4945
4973
|
});
|
package/dist/testing/index.js
CHANGED
|
@@ -7211,6 +7211,8 @@ var createVoiceSession = (options) => {
|
|
|
7211
7211
|
user: 0
|
|
7212
7212
|
};
|
|
7213
7213
|
const recordingFormats = {};
|
|
7214
|
+
const recordingStartedAt = Date.now();
|
|
7215
|
+
let assistantRecordingEndsAtMs = 0;
|
|
7214
7216
|
let recordingPersisted = false;
|
|
7215
7217
|
const captureRecordingChunk = (channel, bytes2, format) => {
|
|
7216
7218
|
if (!recordingConfig || recordingPersisted) {
|
|
@@ -7226,11 +7228,33 @@ var createVoiceSession = (options) => {
|
|
|
7226
7228
|
if (currentTotal >= recordingMaxBytes) {
|
|
7227
7229
|
return;
|
|
7228
7230
|
}
|
|
7229
|
-
const
|
|
7231
|
+
const bytesPerSample = 2;
|
|
7232
|
+
const bytesPerSecond = format.sampleRateHz * format.channels * bytesPerSample;
|
|
7233
|
+
let chunkStartMs = currentTotal / bytesPerSecond * 1000;
|
|
7234
|
+
if (channel === "assistant" || currentTotal === 0) {
|
|
7235
|
+
const wallClockOffsetMs = Math.max(0, Date.now() - recordingStartedAt);
|
|
7236
|
+
chunkStartMs = channel === "assistant" ? Math.max(wallClockOffsetMs, assistantRecordingEndsAtMs) : wallClockOffsetMs;
|
|
7237
|
+
const targetByteOffset = Math.floor(chunkStartMs * bytesPerSecond / 1000 / bytesPerSample) * bytesPerSample;
|
|
7238
|
+
const silenceByteLength = Math.min(Math.max(0, targetByteOffset - currentTotal), recordingMaxBytes - currentTotal);
|
|
7239
|
+
if (silenceByteLength > 0) {
|
|
7240
|
+
recordingBuffers[channel].push(new Uint8Array(silenceByteLength));
|
|
7241
|
+
recordingByteTotals[channel] += silenceByteLength;
|
|
7242
|
+
}
|
|
7243
|
+
if (channel === "assistant") {
|
|
7244
|
+
assistantRecordingEndsAtMs = chunkStartMs + bytes2.byteLength / bytesPerSecond * 1000;
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7247
|
+
const updatedTotal = recordingByteTotals[channel];
|
|
7248
|
+
if (updatedTotal >= recordingMaxBytes) {
|
|
7249
|
+
recordingFormats[channel] = format;
|
|
7250
|
+
return;
|
|
7251
|
+
}
|
|
7252
|
+
const remaining = recordingMaxBytes - updatedTotal;
|
|
7230
7253
|
const slice = bytes2.byteLength <= remaining ? bytes2 : bytes2.subarray(0, remaining);
|
|
7231
7254
|
recordingBuffers[channel].push(new Uint8Array(slice));
|
|
7232
7255
|
recordingByteTotals[channel] += slice.byteLength;
|
|
7233
7256
|
recordingFormats[channel] = format;
|
|
7257
|
+
return { byteLength: slice.byteLength, startMs: chunkStartMs };
|
|
7234
7258
|
};
|
|
7235
7259
|
const pruneTurnAudio = () => {
|
|
7236
7260
|
const replayWindowMs = sttFallback?.replayWindowMs ?? DEFAULT_FALLBACK_REPLAY_MS;
|
|
@@ -7558,7 +7582,7 @@ var createVoiceSession = (options) => {
|
|
|
7558
7582
|
};
|
|
7559
7583
|
const sendAssistantAudio = async (chunk, input) => {
|
|
7560
7584
|
const normalizedChunk = chunk instanceof Uint8Array ? new Uint8Array(chunk) : chunk instanceof ArrayBuffer ? new Uint8Array(chunk.slice(0)) : new Uint8Array(chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength));
|
|
7561
|
-
captureRecordingChunk("assistant", normalizedChunk, input.format);
|
|
7585
|
+
const recordingChunk = captureRecordingChunk("assistant", normalizedChunk, input.format);
|
|
7562
7586
|
kickCallSilenceWatchdog();
|
|
7563
7587
|
await send({
|
|
7564
7588
|
chunkBase64: encodeBase64(normalizedChunk),
|
|
@@ -7577,6 +7601,10 @@ var createVoiceSession = (options) => {
|
|
|
7577
7601
|
if (activeTTSTurnId) {
|
|
7578
7602
|
await appendTurnLatencyStage({
|
|
7579
7603
|
at: input.receivedAt,
|
|
7604
|
+
metadata: recordingChunk ? {
|
|
7605
|
+
recordingByteLength: recordingChunk.byteLength,
|
|
7606
|
+
recordingStartMs: recordingChunk.startMs
|
|
7607
|
+
} : undefined,
|
|
7580
7608
|
stage: "assistant_audio_received",
|
|
7581
7609
|
turnId: activeTTSTurnId
|
|
7582
7610
|
});
|