@absolutejs/voice 0.0.22-beta.647 → 0.0.22-beta.649
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/angular/index.js +67 -29
- package/dist/client/connection.d.ts +2 -1
- package/dist/client/htmxBootstrap.js +67 -29
- package/dist/client/index.js +67 -29
- package/dist/core/types.d.ts +21 -2
- package/dist/embed/index.js +66 -28
- package/dist/embed/voice-widget.js +7 -7
- package/dist/index.js +34 -1
- package/dist/react/index.js +67 -29
- package/dist/svelte/index.js +67 -29
- package/dist/testing/index.js +69 -31
- package/dist/vue/index.js +67 -29
- package/package.json +2 -2
package/dist/svelte/index.js
CHANGED
|
@@ -525,29 +525,34 @@ var createMicrophoneCapture = (options) => {
|
|
|
525
525
|
if (!AudioContextCtor) {
|
|
526
526
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
527
527
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
528
|
+
try {
|
|
529
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
530
|
+
audio: {
|
|
531
|
+
autoGainControl: true,
|
|
532
|
+
channelCount: options.channelCount ?? 1,
|
|
533
|
+
echoCancellation: true,
|
|
534
|
+
noiseSuppression: true
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
audioContext = new AudioContextCtor;
|
|
538
|
+
if (audioContext.state === "suspended") {
|
|
539
|
+
await audioContext.resume();
|
|
534
540
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
processorNode.connect(audioContext.destination);
|
|
541
|
+
sourceNode = audioContext.createMediaStreamSource(mediaStream);
|
|
542
|
+
processorNode = audioContext.createScriptProcessor(4096, 1, 1);
|
|
543
|
+
processorNode.onaudioprocess = (event) => {
|
|
544
|
+
const channel = event.inputBuffer.getChannelData(0);
|
|
545
|
+
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
546
|
+
const pcm = floatTo16BitPCM(downsampled);
|
|
547
|
+
options.onLevel?.(getPcmLevel(pcm));
|
|
548
|
+
options.onAudio(pcm);
|
|
549
|
+
};
|
|
550
|
+
sourceNode.connect(processorNode);
|
|
551
|
+
processorNode.connect(audioContext.destination);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
stop();
|
|
554
|
+
throw error;
|
|
555
|
+
}
|
|
551
556
|
};
|
|
552
557
|
const stop = () => {
|
|
553
558
|
processorNode?.disconnect();
|
|
@@ -767,6 +772,7 @@ var noopUnsubscribe = () => noop;
|
|
|
767
772
|
var NOOP_CONNECTION = {
|
|
768
773
|
callControl: noop,
|
|
769
774
|
close: noop,
|
|
775
|
+
disconnect: noop,
|
|
770
776
|
endTurn: noop,
|
|
771
777
|
send: noop,
|
|
772
778
|
sendAudio: noop,
|
|
@@ -778,7 +784,7 @@ var NOOP_CONNECTION = {
|
|
|
778
784
|
start: () => {}
|
|
779
785
|
};
|
|
780
786
|
var createSessionId = () => crypto.randomUUID();
|
|
781
|
-
var buildWsUrl = (path, sessionId, scenarioId) => {
|
|
787
|
+
var buildWsUrl = (path, sessionId, scenarioId, query) => {
|
|
782
788
|
const { hostname, port, protocol } = window.location;
|
|
783
789
|
const wsProtocol = protocol === "https:" ? "wss:" : "ws:";
|
|
784
790
|
const portSuffix = port ? `:${port}` : "";
|
|
@@ -787,6 +793,11 @@ var buildWsUrl = (path, sessionId, scenarioId) => {
|
|
|
787
793
|
if (scenarioId) {
|
|
788
794
|
url.searchParams.set(DEFAULT_SCENARIO_QUERY_PARAM, scenarioId);
|
|
789
795
|
}
|
|
796
|
+
for (const [key, value] of Object.entries(query)) {
|
|
797
|
+
if (key !== "sessionId" && key !== DEFAULT_SCENARIO_QUERY_PARAM && value) {
|
|
798
|
+
url.searchParams.set(key, value);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
790
801
|
return url.toString();
|
|
791
802
|
};
|
|
792
803
|
var isVoiceServerMessage = (value) => {
|
|
@@ -896,7 +907,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
896
907
|
}, delayMs);
|
|
897
908
|
};
|
|
898
909
|
const connect = () => {
|
|
899
|
-
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId));
|
|
910
|
+
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId, options.query ?? {}));
|
|
900
911
|
ws.binaryType = "arraybuffer";
|
|
901
912
|
ws.onopen = () => {
|
|
902
913
|
const wasReconnecting = state.reconnectAttempts > 0;
|
|
@@ -992,7 +1003,19 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
992
1003
|
type: "call_control"
|
|
993
1004
|
});
|
|
994
1005
|
};
|
|
995
|
-
const close = () => {
|
|
1006
|
+
const close = (reason = "client-close") => {
|
|
1007
|
+
clearTimers();
|
|
1008
|
+
if (state.ws) {
|
|
1009
|
+
if (state.ws.readyState === WS_OPEN) {
|
|
1010
|
+
state.ws.send(JSON.stringify({ reason, type: "close" }));
|
|
1011
|
+
}
|
|
1012
|
+
state.ws.close(WS_NORMAL_CLOSURE);
|
|
1013
|
+
state.ws = null;
|
|
1014
|
+
}
|
|
1015
|
+
state.isConnected = false;
|
|
1016
|
+
listeners.clear();
|
|
1017
|
+
};
|
|
1018
|
+
const disconnect = () => {
|
|
996
1019
|
clearTimers();
|
|
997
1020
|
if (state.ws) {
|
|
998
1021
|
state.ws.close(WS_NORMAL_CLOSURE);
|
|
@@ -1016,6 +1039,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
1016
1039
|
return {
|
|
1017
1040
|
callControl,
|
|
1018
1041
|
close,
|
|
1042
|
+
disconnect,
|
|
1019
1043
|
endTurn,
|
|
1020
1044
|
send,
|
|
1021
1045
|
sendAudio,
|
|
@@ -1296,10 +1320,17 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
1296
1320
|
callControl(message) {
|
|
1297
1321
|
connection.callControl(message);
|
|
1298
1322
|
},
|
|
1299
|
-
close() {
|
|
1323
|
+
close(reason) {
|
|
1300
1324
|
unsubscribeConnection();
|
|
1301
1325
|
browserMediaReporter?.close();
|
|
1302
|
-
connection.close();
|
|
1326
|
+
connection.close(reason);
|
|
1327
|
+
store.dispatch({ type: "disconnected" });
|
|
1328
|
+
notify();
|
|
1329
|
+
},
|
|
1330
|
+
disconnect() {
|
|
1331
|
+
unsubscribeConnection();
|
|
1332
|
+
browserMediaReporter?.close();
|
|
1333
|
+
connection.disconnect();
|
|
1303
1334
|
store.dispatch({ type: "disconnected" });
|
|
1304
1335
|
notify();
|
|
1305
1336
|
},
|
|
@@ -1781,6 +1812,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1781
1812
|
};
|
|
1782
1813
|
notify();
|
|
1783
1814
|
} catch (error) {
|
|
1815
|
+
capture?.stop();
|
|
1784
1816
|
capture = null;
|
|
1785
1817
|
state = {
|
|
1786
1818
|
...state,
|
|
@@ -1791,13 +1823,19 @@ var createVoiceController = (path, options = {}) => {
|
|
|
1791
1823
|
throw error;
|
|
1792
1824
|
}
|
|
1793
1825
|
};
|
|
1794
|
-
const close = () => {
|
|
1826
|
+
const close = (reason) => {
|
|
1827
|
+
unsubscribeStream();
|
|
1828
|
+
stopRecording();
|
|
1829
|
+
stream.close(reason);
|
|
1830
|
+
};
|
|
1831
|
+
const disconnect = () => {
|
|
1795
1832
|
unsubscribeStream();
|
|
1796
1833
|
stopRecording();
|
|
1797
|
-
stream.
|
|
1834
|
+
stream.disconnect();
|
|
1798
1835
|
};
|
|
1799
1836
|
return {
|
|
1800
1837
|
close,
|
|
1838
|
+
disconnect,
|
|
1801
1839
|
startRecording,
|
|
1802
1840
|
stopRecording,
|
|
1803
1841
|
get assistantAudio() {
|
package/dist/testing/index.js
CHANGED
|
@@ -2746,29 +2746,34 @@ var createMicrophoneCapture = (options) => {
|
|
|
2746
2746
|
if (!AudioContextCtor) {
|
|
2747
2747
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
2748
2748
|
}
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2749
|
+
try {
|
|
2750
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
2751
|
+
audio: {
|
|
2752
|
+
autoGainControl: true,
|
|
2753
|
+
channelCount: options.channelCount ?? 1,
|
|
2754
|
+
echoCancellation: true,
|
|
2755
|
+
noiseSuppression: true
|
|
2756
|
+
}
|
|
2757
|
+
});
|
|
2758
|
+
audioContext = new AudioContextCtor;
|
|
2759
|
+
if (audioContext.state === "suspended") {
|
|
2760
|
+
await audioContext.resume();
|
|
2761
|
+
}
|
|
2762
|
+
sourceNode = audioContext.createMediaStreamSource(mediaStream);
|
|
2763
|
+
processorNode = audioContext.createScriptProcessor(4096, 1, 1);
|
|
2764
|
+
processorNode.onaudioprocess = (event) => {
|
|
2765
|
+
const channel = event.inputBuffer.getChannelData(0);
|
|
2766
|
+
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
2767
|
+
const pcm = floatTo16BitPCM(downsampled);
|
|
2768
|
+
options.onLevel?.(getPcmLevel(pcm));
|
|
2769
|
+
options.onAudio(pcm);
|
|
2770
|
+
};
|
|
2771
|
+
sourceNode.connect(processorNode);
|
|
2772
|
+
processorNode.connect(audioContext.destination);
|
|
2773
|
+
} catch (error) {
|
|
2774
|
+
stop();
|
|
2775
|
+
throw error;
|
|
2776
|
+
}
|
|
2772
2777
|
};
|
|
2773
2778
|
const stop = () => {
|
|
2774
2779
|
processorNode?.disconnect();
|
|
@@ -2988,6 +2993,7 @@ var noopUnsubscribe = () => noop;
|
|
|
2988
2993
|
var NOOP_CONNECTION = {
|
|
2989
2994
|
callControl: noop,
|
|
2990
2995
|
close: noop,
|
|
2996
|
+
disconnect: noop,
|
|
2991
2997
|
endTurn: noop,
|
|
2992
2998
|
send: noop,
|
|
2993
2999
|
sendAudio: noop,
|
|
@@ -2999,7 +3005,7 @@ var NOOP_CONNECTION = {
|
|
|
2999
3005
|
start: () => {}
|
|
3000
3006
|
};
|
|
3001
3007
|
var createSessionId = () => crypto.randomUUID();
|
|
3002
|
-
var buildWsUrl = (path, sessionId, scenarioId) => {
|
|
3008
|
+
var buildWsUrl = (path, sessionId, scenarioId, query) => {
|
|
3003
3009
|
const { hostname, port, protocol } = window.location;
|
|
3004
3010
|
const wsProtocol = protocol === "https:" ? "wss:" : "ws:";
|
|
3005
3011
|
const portSuffix = port ? `:${port}` : "";
|
|
@@ -3008,6 +3014,11 @@ var buildWsUrl = (path, sessionId, scenarioId) => {
|
|
|
3008
3014
|
if (scenarioId) {
|
|
3009
3015
|
url.searchParams.set(DEFAULT_SCENARIO_QUERY_PARAM, scenarioId);
|
|
3010
3016
|
}
|
|
3017
|
+
for (const [key, value] of Object.entries(query)) {
|
|
3018
|
+
if (key !== "sessionId" && key !== DEFAULT_SCENARIO_QUERY_PARAM && value) {
|
|
3019
|
+
url.searchParams.set(key, value);
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3011
3022
|
return url.toString();
|
|
3012
3023
|
};
|
|
3013
3024
|
var isVoiceServerMessage = (value) => {
|
|
@@ -3117,7 +3128,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
3117
3128
|
}, delayMs);
|
|
3118
3129
|
};
|
|
3119
3130
|
const connect = () => {
|
|
3120
|
-
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId));
|
|
3131
|
+
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId, options.query ?? {}));
|
|
3121
3132
|
ws.binaryType = "arraybuffer";
|
|
3122
3133
|
ws.onopen = () => {
|
|
3123
3134
|
const wasReconnecting = state.reconnectAttempts > 0;
|
|
@@ -3213,7 +3224,19 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
3213
3224
|
type: "call_control"
|
|
3214
3225
|
});
|
|
3215
3226
|
};
|
|
3216
|
-
const close = () => {
|
|
3227
|
+
const close = (reason = "client-close") => {
|
|
3228
|
+
clearTimers();
|
|
3229
|
+
if (state.ws) {
|
|
3230
|
+
if (state.ws.readyState === WS_OPEN) {
|
|
3231
|
+
state.ws.send(JSON.stringify({ reason, type: "close" }));
|
|
3232
|
+
}
|
|
3233
|
+
state.ws.close(WS_NORMAL_CLOSURE);
|
|
3234
|
+
state.ws = null;
|
|
3235
|
+
}
|
|
3236
|
+
state.isConnected = false;
|
|
3237
|
+
listeners.clear();
|
|
3238
|
+
};
|
|
3239
|
+
const disconnect = () => {
|
|
3217
3240
|
clearTimers();
|
|
3218
3241
|
if (state.ws) {
|
|
3219
3242
|
state.ws.close(WS_NORMAL_CLOSURE);
|
|
@@ -3237,6 +3260,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
3237
3260
|
return {
|
|
3238
3261
|
callControl,
|
|
3239
3262
|
close,
|
|
3263
|
+
disconnect,
|
|
3240
3264
|
endTurn,
|
|
3241
3265
|
send,
|
|
3242
3266
|
sendAudio,
|
|
@@ -3517,10 +3541,17 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
3517
3541
|
callControl(message) {
|
|
3518
3542
|
connection.callControl(message);
|
|
3519
3543
|
},
|
|
3520
|
-
close() {
|
|
3544
|
+
close(reason) {
|
|
3545
|
+
unsubscribeConnection();
|
|
3546
|
+
browserMediaReporter?.close();
|
|
3547
|
+
connection.close(reason);
|
|
3548
|
+
store.dispatch({ type: "disconnected" });
|
|
3549
|
+
notify();
|
|
3550
|
+
},
|
|
3551
|
+
disconnect() {
|
|
3521
3552
|
unsubscribeConnection();
|
|
3522
3553
|
browserMediaReporter?.close();
|
|
3523
|
-
connection.
|
|
3554
|
+
connection.disconnect();
|
|
3524
3555
|
store.dispatch({ type: "disconnected" });
|
|
3525
3556
|
notify();
|
|
3526
3557
|
},
|
|
@@ -4002,6 +4033,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
4002
4033
|
};
|
|
4003
4034
|
notify();
|
|
4004
4035
|
} catch (error) {
|
|
4036
|
+
capture?.stop();
|
|
4005
4037
|
capture = null;
|
|
4006
4038
|
state = {
|
|
4007
4039
|
...state,
|
|
@@ -4012,13 +4044,19 @@ var createVoiceController = (path, options = {}) => {
|
|
|
4012
4044
|
throw error;
|
|
4013
4045
|
}
|
|
4014
4046
|
};
|
|
4015
|
-
const close = () => {
|
|
4047
|
+
const close = (reason) => {
|
|
4016
4048
|
unsubscribeStream();
|
|
4017
4049
|
stopRecording();
|
|
4018
|
-
stream.close();
|
|
4050
|
+
stream.close(reason);
|
|
4051
|
+
};
|
|
4052
|
+
const disconnect = () => {
|
|
4053
|
+
unsubscribeStream();
|
|
4054
|
+
stopRecording();
|
|
4055
|
+
stream.disconnect();
|
|
4019
4056
|
};
|
|
4020
4057
|
return {
|
|
4021
4058
|
close,
|
|
4059
|
+
disconnect,
|
|
4022
4060
|
startRecording,
|
|
4023
4061
|
stopRecording,
|
|
4024
4062
|
get assistantAudio() {
|
|
@@ -7702,7 +7740,7 @@ var createVoiceSession = (options) => {
|
|
|
7702
7740
|
clearSilenceTimer();
|
|
7703
7741
|
let didFail = false;
|
|
7704
7742
|
const session = await writeSession((currentSession) => {
|
|
7705
|
-
if (currentSession.status === "failed") {
|
|
7743
|
+
if (currentSession.status === "completed" || currentSession.status === "failed") {
|
|
7706
7744
|
return;
|
|
7707
7745
|
}
|
|
7708
7746
|
didFail = true;
|
package/dist/vue/index.js
CHANGED
|
@@ -10840,6 +10840,7 @@ var noopUnsubscribe = () => noop;
|
|
|
10840
10840
|
var NOOP_CONNECTION = {
|
|
10841
10841
|
callControl: noop,
|
|
10842
10842
|
close: noop,
|
|
10843
|
+
disconnect: noop,
|
|
10843
10844
|
endTurn: noop,
|
|
10844
10845
|
send: noop,
|
|
10845
10846
|
sendAudio: noop,
|
|
@@ -10851,7 +10852,7 @@ var NOOP_CONNECTION = {
|
|
|
10851
10852
|
start: () => {}
|
|
10852
10853
|
};
|
|
10853
10854
|
var createSessionId = () => crypto.randomUUID();
|
|
10854
|
-
var buildWsUrl = (path, sessionId, scenarioId) => {
|
|
10855
|
+
var buildWsUrl = (path, sessionId, scenarioId, query) => {
|
|
10855
10856
|
const { hostname, port, protocol } = window.location;
|
|
10856
10857
|
const wsProtocol = protocol === "https:" ? "wss:" : "ws:";
|
|
10857
10858
|
const portSuffix = port ? `:${port}` : "";
|
|
@@ -10860,6 +10861,11 @@ var buildWsUrl = (path, sessionId, scenarioId) => {
|
|
|
10860
10861
|
if (scenarioId) {
|
|
10861
10862
|
url.searchParams.set(DEFAULT_SCENARIO_QUERY_PARAM, scenarioId);
|
|
10862
10863
|
}
|
|
10864
|
+
for (const [key, value] of Object.entries(query)) {
|
|
10865
|
+
if (key !== "sessionId" && key !== DEFAULT_SCENARIO_QUERY_PARAM && value) {
|
|
10866
|
+
url.searchParams.set(key, value);
|
|
10867
|
+
}
|
|
10868
|
+
}
|
|
10863
10869
|
return url.toString();
|
|
10864
10870
|
};
|
|
10865
10871
|
var isVoiceServerMessage = (value) => {
|
|
@@ -10969,7 +10975,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
10969
10975
|
}, delayMs);
|
|
10970
10976
|
};
|
|
10971
10977
|
const connect = () => {
|
|
10972
|
-
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId));
|
|
10978
|
+
const ws = new WebSocket(buildWsUrl(path, state.sessionId, state.scenarioId, options.query ?? {}));
|
|
10973
10979
|
ws.binaryType = "arraybuffer";
|
|
10974
10980
|
ws.onopen = () => {
|
|
10975
10981
|
const wasReconnecting = state.reconnectAttempts > 0;
|
|
@@ -11065,7 +11071,19 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
11065
11071
|
type: "call_control"
|
|
11066
11072
|
});
|
|
11067
11073
|
};
|
|
11068
|
-
const close = () => {
|
|
11074
|
+
const close = (reason = "client-close") => {
|
|
11075
|
+
clearTimers();
|
|
11076
|
+
if (state.ws) {
|
|
11077
|
+
if (state.ws.readyState === WS_OPEN) {
|
|
11078
|
+
state.ws.send(JSON.stringify({ reason, type: "close" }));
|
|
11079
|
+
}
|
|
11080
|
+
state.ws.close(WS_NORMAL_CLOSURE);
|
|
11081
|
+
state.ws = null;
|
|
11082
|
+
}
|
|
11083
|
+
state.isConnected = false;
|
|
11084
|
+
listeners.clear();
|
|
11085
|
+
};
|
|
11086
|
+
const disconnect = () => {
|
|
11069
11087
|
clearTimers();
|
|
11070
11088
|
if (state.ws) {
|
|
11071
11089
|
state.ws.close(WS_NORMAL_CLOSURE);
|
|
@@ -11089,6 +11107,7 @@ var createVoiceConnection = (path, options = {}) => {
|
|
|
11089
11107
|
return {
|
|
11090
11108
|
callControl,
|
|
11091
11109
|
close,
|
|
11110
|
+
disconnect,
|
|
11092
11111
|
endTurn,
|
|
11093
11112
|
send,
|
|
11094
11113
|
sendAudio,
|
|
@@ -11369,10 +11388,17 @@ var createVoiceStream = (path, options = {}) => {
|
|
|
11369
11388
|
callControl(message) {
|
|
11370
11389
|
connection.callControl(message);
|
|
11371
11390
|
},
|
|
11372
|
-
close() {
|
|
11391
|
+
close(reason) {
|
|
11392
|
+
unsubscribeConnection();
|
|
11393
|
+
browserMediaReporter?.close();
|
|
11394
|
+
connection.close(reason);
|
|
11395
|
+
store.dispatch({ type: "disconnected" });
|
|
11396
|
+
notify();
|
|
11397
|
+
},
|
|
11398
|
+
disconnect() {
|
|
11373
11399
|
unsubscribeConnection();
|
|
11374
11400
|
browserMediaReporter?.close();
|
|
11375
|
-
connection.
|
|
11401
|
+
connection.disconnect();
|
|
11376
11402
|
store.dispatch({ type: "disconnected" });
|
|
11377
11403
|
notify();
|
|
11378
11404
|
},
|
|
@@ -11596,29 +11622,34 @@ var createMicrophoneCapture = (options) => {
|
|
|
11596
11622
|
if (!AudioContextCtor) {
|
|
11597
11623
|
throw new Error("Browser microphone capture requires AudioContext support.");
|
|
11598
11624
|
}
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11625
|
+
try {
|
|
11626
|
+
mediaStream = options.stream ?? await navigator.mediaDevices.getUserMedia({
|
|
11627
|
+
audio: {
|
|
11628
|
+
autoGainControl: true,
|
|
11629
|
+
channelCount: options.channelCount ?? 1,
|
|
11630
|
+
echoCancellation: true,
|
|
11631
|
+
noiseSuppression: true
|
|
11632
|
+
}
|
|
11633
|
+
});
|
|
11634
|
+
audioContext = new AudioContextCtor;
|
|
11635
|
+
if (audioContext.state === "suspended") {
|
|
11636
|
+
await audioContext.resume();
|
|
11605
11637
|
}
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
processorNode.connect(audioContext.destination);
|
|
11638
|
+
sourceNode = audioContext.createMediaStreamSource(mediaStream);
|
|
11639
|
+
processorNode = audioContext.createScriptProcessor(4096, 1, 1);
|
|
11640
|
+
processorNode.onaudioprocess = (event) => {
|
|
11641
|
+
const channel = event.inputBuffer.getChannelData(0);
|
|
11642
|
+
const downsampled = downsampleBuffer(channel, audioContext?.sampleRate ?? 48000, options.sampleRateHz ?? 16000);
|
|
11643
|
+
const pcm = floatTo16BitPCM(downsampled);
|
|
11644
|
+
options.onLevel?.(getPcmLevel(pcm));
|
|
11645
|
+
options.onAudio(pcm);
|
|
11646
|
+
};
|
|
11647
|
+
sourceNode.connect(processorNode);
|
|
11648
|
+
processorNode.connect(audioContext.destination);
|
|
11649
|
+
} catch (error) {
|
|
11650
|
+
stop();
|
|
11651
|
+
throw error;
|
|
11652
|
+
}
|
|
11622
11653
|
};
|
|
11623
11654
|
const stop = () => {
|
|
11624
11655
|
processorNode?.disconnect();
|
|
@@ -12061,6 +12092,7 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12061
12092
|
};
|
|
12062
12093
|
notify();
|
|
12063
12094
|
} catch (error) {
|
|
12095
|
+
capture?.stop();
|
|
12064
12096
|
capture = null;
|
|
12065
12097
|
state = {
|
|
12066
12098
|
...state,
|
|
@@ -12071,13 +12103,19 @@ var createVoiceController = (path, options = {}) => {
|
|
|
12071
12103
|
throw error;
|
|
12072
12104
|
}
|
|
12073
12105
|
};
|
|
12074
|
-
const close = () => {
|
|
12106
|
+
const close = (reason) => {
|
|
12075
12107
|
unsubscribeStream();
|
|
12076
12108
|
stopRecording();
|
|
12077
|
-
stream.close();
|
|
12109
|
+
stream.close(reason);
|
|
12110
|
+
};
|
|
12111
|
+
const disconnect = () => {
|
|
12112
|
+
unsubscribeStream();
|
|
12113
|
+
stopRecording();
|
|
12114
|
+
stream.disconnect();
|
|
12078
12115
|
};
|
|
12079
12116
|
return {
|
|
12080
12117
|
close,
|
|
12118
|
+
disconnect,
|
|
12081
12119
|
startRecording,
|
|
12082
12120
|
stopRecording,
|
|
12083
12121
|
get assistantAudio() {
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@absolutejs/voice",
|
|
3
|
-
"version": "0.0.22-beta.
|
|
3
|
+
"version": "0.0.22-beta.649",
|
|
4
4
|
"description": "Voice primitives and Elysia plugin for AbsoluteJS",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/absolutejs/voice.git"
|
|
7
|
+
"url": "git+https://github.com/absolutejs/voice.git"
|
|
8
8
|
},
|
|
9
9
|
"homepage": "https://github.com/absolutejs/voice",
|
|
10
10
|
"bugs": {
|